From 8e507160c4511da3e9cfcbe885d969e73c6ec12b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 11:06:47 -0500 Subject: [PATCH 001/117] Add BroadcastChannel and the remaining Node 24 worker_threads surfaces --- .../limitations/builtin-apis/exit-status.mdx | 2 +- .../limitations/native-worker-threads.mdx | 4 +- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 106 ++-- .../generated/node-v24-backlog.json | 289 +++++---- .../generated/node-v24-internal.json | 185 ++++-- internal/compatibility/static-support.json | 11 +- .../ambient/scriptc-node-fallback.d.ts | 42 +- packages/compiler/src/backend/llvm/emitter.ts | 25 +- .../compiler/src/backend/llvm/lib-shared.ts | 10 + .../src/frontend/lowering/builtin-calls.ts | 18 +- .../src/frontend/lowering/builtins/workers.ts | 192 +++++- .../src/frontend/lowering/lower-classes.ts | 8 +- .../src/frontend/lowering/surfaces.ts | 9 +- packages/compiler/src/frontend/type-mapper.ts | 4 +- packages/compiler/src/ir/builtin-effects.ts | 4 + .../compiler/src/ir/builtin-signatures.ts | 21 + packages/compiler/src/ir/runtime-features.ts | 1 + packages/compiler/src/library/ir-policy.ts | 5 + .../corpus/5800-broadcast-channel.ts.json | 6 + .../corpus/5801-broadcast-channel.cjs.json | 6 + .../5802-broadcast-channel-workers.ts.json | 6 + .../5803-worker-environment-data.ts.json | 6 + .../5804-worker-environment-data.cjs.json | 6 + ...worker-receive-message-parent-port.ts.json | 6 + .../5806-worker-resource-limits.ts.json | 6 + .../corpus/5807-worker-error-values.ts.json | 6 + .../5808-worker-unhandled-rejections.ts.json | 6 + .../5809-process-exit-and-rejections.cjs.json | 6 + .../corpus/5870-worker-thread-names.ts.json | 6 + .../5871-worker-untransferable.cjs.json | 6 + .../corpus/5874-worker-stdio-streams.ts.json | 6 + .../corpus/5875-worker-stdout-pipe.cjs.json | 6 + .../tests/corpus/5879-worker-stdin.ts.json | 6 + packages/runtime/src/scr_async.c | 2 + packages/runtime/src/scr_async_dyn.c | 91 +++ packages/runtime/src/scr_bytes.h | 17 + packages/runtime/src/scr_console.c | 58 +- packages/runtime/src/scr_context.c | 8 + packages/runtime/src/scr_core.h | 2 + packages/runtime/src/scr_dyn.h | 2 + packages/runtime/src/scr_event_target.c | 68 +- packages/runtime/src/scr_event_target.h | 23 +- packages/runtime/src/scr_events.c | 58 +- packages/runtime/src/scr_exception.h | 5 + packages/runtime/src/scr_json.c | 3 + packages/runtime/src/scr_lib.c | 24 +- packages/runtime/src/scr_lib.h | 17 + packages/runtime/src/scr_mailbox.c | 96 +++ packages/runtime/src/scr_mailbox.h | 12 + packages/runtime/src/scr_message.c | 90 ++- packages/runtime/src/scr_message.h | 6 + packages/runtime/src/scr_stream.c | 9 + packages/runtime/src/scr_stream.h | 1 + packages/runtime/src/scr_worker.c | 139 ++++- packages/runtime/src/scr_worker.h | 28 +- packages/runtime/src/scr_worker.test.c | 4 +- packages/runtime/src/scr_worker.test.ts | 1 + packages/runtime/src/scr_worker_events.c | 585 +++++++++++++++++- tests/corpus/5800-broadcast-channel.ts | 35 ++ tests/corpus/5801-broadcast-channel.cjs | 30 + .../corpus/5802-broadcast-channel-workers.ts | 25 + tests/corpus/5803-worker-environment-data.ts | 53 ++ tests/corpus/5804-worker-environment-data.cjs | 26 + ...5805-worker-receive-message-parent-port.ts | 43 ++ tests/corpus/5806-worker-resource-limits.ts | 38 ++ tests/corpus/5807-worker-error-values.ts | 68 ++ .../5808-worker-unhandled-rejections.ts | 39 ++ .../5809-process-exit-and-rejections.cjs | 46 ++ tests/corpus/5870-worker-thread-names.ts | 35 ++ tests/corpus/5871-worker-untransferable.cjs | 56 ++ tests/corpus/5874-worker-stdio-streams.ts | 28 + tests/corpus/5875-worker-stdout-pipe.cjs | 24 + tests/corpus/5879-worker-stdin.ts | 42 ++ 74 files changed, 2682 insertions(+), 283 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5800-broadcast-channel.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5801-broadcast-channel.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5802-broadcast-channel-workers.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5803-worker-environment-data.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5804-worker-environment-data.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5805-worker-receive-message-parent-port.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5806-worker-resource-limits.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5807-worker-error-values.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5808-worker-unhandled-rejections.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5809-process-exit-and-rejections.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5870-worker-thread-names.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5871-worker-untransferable.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5874-worker-stdio-streams.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5875-worker-stdout-pipe.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5879-worker-stdin.ts.json create mode 100644 tests/corpus/5800-broadcast-channel.ts create mode 100644 tests/corpus/5801-broadcast-channel.cjs create mode 100644 tests/corpus/5802-broadcast-channel-workers.ts create mode 100644 tests/corpus/5803-worker-environment-data.ts create mode 100644 tests/corpus/5804-worker-environment-data.cjs create mode 100644 tests/corpus/5805-worker-receive-message-parent-port.ts create mode 100644 tests/corpus/5806-worker-resource-limits.ts create mode 100644 tests/corpus/5807-worker-error-values.ts create mode 100644 tests/corpus/5808-worker-unhandled-rejections.ts create mode 100644 tests/corpus/5809-process-exit-and-rejections.cjs create mode 100644 tests/corpus/5870-worker-thread-names.ts create mode 100644 tests/corpus/5871-worker-untransferable.cjs create mode 100644 tests/corpus/5874-worker-stdio-streams.ts create mode 100644 tests/corpus/5875-worker-stdout-pipe.cjs create mode 100644 tests/corpus/5879-worker-stdin.ts diff --git a/docs/content/limitations/builtin-apis/exit-status.mdx b/docs/content/limitations/builtin-apis/exit-status.mdx index e2b681daf..f13782ff2 100644 --- a/docs/content/limitations/builtin-apis/exit-status.mdx +++ b/docs/content/limitations/builtin-apis/exit-status.mdx @@ -1 +1 @@ -- **Exit status:** Numeric `process.exitCode = value` writes in statement position set the implicit exit status, which `process.exit()` uses when called without an argument. Reads, resets, and assignments used as values are unsupported. +- **Exit status:** Numeric `process.exitCode = value` writes in statement position set the implicit exit status, which `process.exit()` uses when called without an argument. `process.exit(code)` and `process.exitCode` throw a `RangeError` (`ERR_OUT_OF_RANGE`) for a code that is not a safe integer, and convert other codes to int32, as Node does. Reads, resets, and assignments used as values are unsupported. diff --git a/docs/content/limitations/native-worker-threads.mdx b/docs/content/limitations/native-worker-threads.mdx index 0527c24b0..972eadeca 100644 --- a/docs/content/limitations/native-worker-threads.mdx +++ b/docs/content/limitations/native-worker-threads.mdx @@ -1,6 +1,6 @@ -`node:worker_threads` runs workers as native threads. Worker entry points must resolve at build time: use a source-relative `new URL("./worker.ts", import.meta.url)`, the current module URL, an absolute path, or CommonJS `__filename`. Each worker initializes its own module state, event loop, environment snapshot, and reference-counted heap. Nested workers inherit their parent's environment snapshot. Supported constructor options are `workerData`, `argv`, and a `transferList` of MessagePorts; runtime paths, `eval`, loaders, custom stdio, shared environments, and resource limits are unsupported. Worker argument strings containing null bytes are also unsupported. +`node:worker_threads` runs workers as native threads. Worker entry points must resolve at build time: use a source-relative `new URL("./worker.ts", import.meta.url)`, the current module URL, an absolute path, or CommonJS `__filename`. Each worker initializes its own module state, event loop, environment snapshot, and reference-counted heap. Nested workers inherit their parent's environment snapshot. Supported constructor options are `workerData`, `argv`, a `transferList` of MessagePorts, `name` (reported by `threadName` and `worker.threadName`), `stdout`, `stderr` and `stdin`, and `resourceLimits.stackSizeMb`, which sets the worker thread's stack size (at least 192 KiB; without it a worker's stack is 8 MiB, where Node's is 4 MiB). The `resourceLimits` heap limits (`maxOldGenerationSizeMb`, `maxYoungGenerationSizeMb`, and `codeRangeSizeMb`), `worker.resourceLimits` while the worker runs, and `resourceLimits` read inside a worker are refused; in the main thread `resourceLimits` is `{}`, and after a worker exits `worker.resourceLimits` is `{}`, as in Node. With the `stdout` or `stderr` option, the worker's writes to that stream reach `worker.stdout` or `worker.stderr`, a Readable that ends after the worker's `'exit'` event; its chunks arrive in order with the worker's other events. Without the option a worker writes to the process's own output, and reading `worker.stdout` or `worker.stderr` is refused. With the `stdin` option, `worker.stdin` is a Writable whose chunks the worker reads from `process.stdin`, in order with the worker's other events, and `process.stdin` ends when `worker.stdin` ends; without it `worker.stdin` is `null` and the worker's `process.stdin` ends without data, as in Node. Runtime paths, `eval`, loaders, and shared environments are unsupported. `setEnvironmentData` and `getEnvironmentData` keep a map per thread with SameValueZero keys; each new Worker starts from a clone of its parent's entries taken by the constructor, which throws `DataCloneError` when an entry cannot be cloned. Worker argument strings containing null bytes are also unsupported. -Workers support `online`, `message`, `error`, and `exit` events, `postMessage`, `terminate`, `ref`, and `unref`. `new MessageChannel()` from `node:worker_threads` makes two entangled MessagePorts, in one thread or across threads once a port is transferred, with `receiveMessageOnPort`. Port messages arrive in Node's order: each port's queued messages as one batch before `setImmediate` callbacks, a port's own `'close'` after the poll phase, and the other port's `'close'` after its queued messages while the loop keeps running. A port's `onmessage` property, `addEventListener`, `receiveMessageOnPort(parentPort)`, and `BroadcastChannel` are unsupported. The parent port supports message listeners, `postMessage`, `close`, `start`, `ref`, `unref`, and `hasRef`. Messages clone primitives, plain object graphs, arrays, errors, ArrayBuffers, typed arrays, and DataViews, preserving cycles and aliases. Program class instances arrive as plain objects with their own data properties, without their prototype, methods, accessors, or private fields, as in Node. A MessagePort travels with a message when the message's transfer list (an array or `{ transfer }`) names it, and the sending port is unusable afterwards; a port in a message without that listing throws `DataCloneError`. Other transferable values, functions, proxies, and other native handles are refused. SharedArrayBuffers share their backing storage while retaining separate wrappers in each thread. Graphs made immutable with `@scriptc/threads` are passed by reference instead of cloned; see [Sharing Data Between Workers](/docs/threads). +Workers support `online`, `message`, `error`, and `exit` events, `postMessage`, `terminate`, `ref`, and `unref`. A worker's uncaught exception reaches its `error` listeners as Node's error serializer sends it: an Error keeps the nearest of `Error` and its six native subclasses (an `AggregateError` arrives as an `Error` named `AggregateError`) along with its name, message, cause, and other data properties and their enumerability, and other thrown values clone as messages do. An unhandled rejection whose reason is not error-like arrives as an `UnhandledPromiseRejection` Error with code `ERR_UNHANDLED_REJECTION` quoting the reason. A thrown value that does not clone, such as a function, arrives as an `ERR_WORKER_UNSERIALIZABLE_ERROR` Error, where Node sends its `util.inspect` string. `new MessageChannel()` from `node:worker_threads` makes two entangled MessagePorts, in one thread or across threads once a port is transferred, with `receiveMessageOnPort`. Port messages arrive in Node's order: each port's queued messages as one batch before `setImmediate` callbacks, a port's own `'close'` after the poll phase, and the other port's `'close'` after its queued messages while the loop keeps running. `receiveMessageOnPort(parentPort)` in a worker takes the parent's next message. A port's `onmessage` property and `addEventListener` are unsupported. `BroadcastChannel` delivers each message to every other open channel with the same name, in any thread, as a `'message'` `MessageEvent` through `onmessage` and `addEventListener`; an open channel keeps the process alive until `close()` or `unref()`. A `messageerror` event is never dispatched. The parent port supports message listeners, `postMessage`, `close`, `start`, `ref`, `unref`, and `hasRef`. Messages clone primitives, plain object graphs, arrays, errors, ArrayBuffers, typed arrays, and DataViews, preserving cycles and aliases. Program class instances arrive as plain objects with their own data properties, without their prototype, methods, accessors, or private fields, as in Node. `markAsUntransferable` marks objects for the current thread, and a marked ArrayBuffer or MessagePort in a transfer list throws `DataCloneError`, as does the ArrayBuffer of a pooled Buffer; marked objects other than ArrayBuffers stay alive until their thread exits. A MessagePort travels with a message when the message's transfer list (an array or `{ transfer }`) names it, and the sending port is unusable afterwards; a port in a message without that listing throws `DataCloneError`. Other transferable values, functions, proxies, and other native handles are refused. SharedArrayBuffers share their backing storage while retaining separate wrappers in each thread. Graphs made immutable with `@scriptc/threads` are passed by reference instead of cloned; see [Sharing Data Between Workers](/docs/threads). SharedArrayBuffer storage is fixed-length. Atomics supports integer `load`, `store`, `exchange`, `compareExchange`, `add`, `sub`, `and`, `or`, and `xor` over 8-, 16-, and 32-bit integer arrays. `wait` and `notify` use Int32Array views; BigInt atomics, `waitAsync`, and growable buffers are unsupported. Atomics operations run as sequentially consistent atomic instructions and take no lock. Other reads and writes of shared storage access each element atomically; a copy, fill, or conversion that runs while another thread writes the same storage can observe some of those writes, as in Node. `terminate` unwinds at runtime checkpoints, including loops and parked atomic waits, without running JavaScript catch or finally blocks. Blocking native calls finish before the next checkpoint. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index b38921019..34e62df24 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "aaeede2b0768674adb1e", + "artifactVersion": "f50c9093bab741e6434b", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 409896d64..c3d09b2a5 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -884,9 +884,9 @@ "apiEntries": 66, "static": { "supported": 0, - "partial": 26, + "partial": 43, "refused": 0, - "not-implemented": 40, + "not-implemented": 23, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -82920,9 +82920,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -82943,9 +82943,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -82966,9 +82966,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -82989,9 +82989,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83012,9 +83012,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83035,9 +83035,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83633,9 +83633,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83656,9 +83656,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83679,9 +83679,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83702,9 +83702,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83748,9 +83748,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83886,9 +83886,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83909,9 +83909,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83932,9 +83932,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -84047,9 +84047,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -84139,9 +84139,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -84208,9 +84208,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 4854fbccb..385016fe0 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3472, "tiers": { "static": { - "audit-partial": 1066, - "verify-gap": 2279, + "audit-partial": 1083, + "verify-gap": 2262, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -57871,6 +57871,7 @@ "confidence": "high", "source": "surface-manifest:node-builtin.process.exitCode", "tests": [ + "tests/corpus/5809-process-exit-and-rejections.cjs", "tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", @@ -83864,12 +83865,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.BroadcastChannel extends EventTarget", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] } } }, @@ -83889,12 +83894,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.broadcastChannel.close", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] } } }, @@ -83914,12 +83923,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.broadcastChannel.postMessage", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] } } }, @@ -83939,12 +83952,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.broadcastChannel.ref", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] } } }, @@ -83964,12 +83981,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.broadcastChannel.unref", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] } } }, @@ -83989,12 +84010,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.onmessage", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] } } }, @@ -84047,7 +84072,8 @@ "tests": [ "tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", - "tests/corpus/5797-worker-message-port-transfer.ts" + "tests/corpus/5797-worker-message-port-transfer.ts", + "tests/corpus/5805-worker-receive-message-parent-port.ts" ] } } @@ -84687,12 +84713,14 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.resourceLimits", + "tests": [ + "tests/corpus/5806-worker-resource-limits.ts" + ] } } }, @@ -84712,12 +84740,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.stderr", + "tests": [ + "tests/corpus/5874-worker-stdio-streams.ts", + "tests/corpus/5875-worker-stdout-pipe.cjs", + "tests/corpus/5879-worker-stdin.ts" + ] } } }, @@ -84737,12 +84769,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.stdin", + "tests": [ + "tests/corpus/5874-worker-stdio-streams.ts", + "tests/corpus/5875-worker-stdout-pipe.cjs", + "tests/corpus/5879-worker-stdin.ts" + ] } } }, @@ -84762,12 +84798,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.stdout", + "tests": [ + "tests/corpus/5874-worker-stdio-streams.ts", + "tests/corpus/5875-worker-stdout-pipe.cjs", + "tests/corpus/5879-worker-stdin.ts" + ] } } }, @@ -84816,12 +84856,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.threadName", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] } } }, @@ -84849,7 +84892,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] } } @@ -84878,7 +84923,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] } } @@ -84907,7 +84954,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] } } @@ -84961,7 +85010,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] } } @@ -84982,12 +85033,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.worker_threads.getEnvironmentData", + "tests": [ + "tests/corpus/5803-worker-environment-data.ts", + "tests/corpus/5804-worker-environment-data.cjs" + ] } } }, @@ -85007,12 +85061,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.worker_threads.markAsUntransferable", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] } } }, @@ -85032,12 +85089,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.worker_threads.isMarkedAsUntransferable", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] } } }, @@ -85140,7 +85200,8 @@ "tests": [ "tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", - "tests/corpus/5797-worker-message-port-transfer.ts" + "tests/corpus/5797-worker-message-port-transfer.ts", + "tests/corpus/5805-worker-receive-message-parent-port.ts" ] } } @@ -85161,12 +85222,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.worker_threads.setEnvironmentData", + "tests": [ + "tests/corpus/5803-worker-environment-data.ts", + "tests/corpus/5804-worker-environment-data.cjs" + ] } } }, @@ -85269,12 +85333,14 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.resourceLimits", + "tests": [ + "tests/corpus/5806-worker-resource-limits.ts" + ] } } }, @@ -85348,12 +85414,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.threadName", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 56fc214b2..7c99fd33e 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -941,9 +941,9 @@ "apiEntries": 66, "static": { "supported": 0, - "partial": 26, + "partial": 43, "refused": 0, - "not-implemented": 40, + "not-implemented": 23, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -79208,6 +79208,7 @@ "tests/corpus/5194-process-emit-warning-tick.cjs", "tests/corpus/5210-process-memory-usage.ts", "tests/corpus/5211-process-identity.ts", + "tests/corpus/5809-process-exit-and-rejections.cjs", "tests/corpus/990-process-basics.ts", "tests/corpus/node24-env-files-errors.ts", "tests/corpus/node24-env-files.ts", @@ -80902,6 +80903,7 @@ "status": "partial", "evidence": "surface-manifest:node-builtin.process.exitCode", "tests": [ + "tests/corpus/5809-process-exit-and-rejections.cjs", "tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", @@ -112617,6 +112619,20 @@ "tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", "tests/corpus/5797-worker-message-port-transfer.ts", + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts", + "tests/corpus/5803-worker-environment-data.ts", + "tests/corpus/5804-worker-environment-data.cjs", + "tests/corpus/5805-worker-receive-message-parent-port.ts", + "tests/corpus/5806-worker-resource-limits.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts", + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs", + "tests/corpus/5874-worker-stdio-streams.ts", + "tests/corpus/5875-worker-stdout-pipe.cjs", + "tests/corpus/5879-worker-stdin.ts", "tests/corpus/native-worker-clone-errors.ts", "tests/corpus/native-worker-commonjs.cjs", "tests/corpus/native-worker-delayed-messages.ts", @@ -112724,8 +112740,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.BroadcastChannel extends EventTarget", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] }, "anchorSource": "exact" }, @@ -112747,8 +112768,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.broadcastChannel.close", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] }, "anchorSource": "exact" }, @@ -112770,8 +112796,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.broadcastChannel.postMessage", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] }, "anchorSource": "exact" }, @@ -112793,8 +112824,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.broadcastChannel.ref", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] }, "anchorSource": "exact" }, @@ -112816,8 +112852,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.broadcastChannel.unref", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] }, "anchorSource": "exact" }, @@ -112839,8 +112880,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.onmessage", + "tests": [ + "tests/corpus/5800-broadcast-channel.ts", + "tests/corpus/5801-broadcast-channel.cjs", + "tests/corpus/5802-broadcast-channel-workers.ts" + ] }, "anchorSource": "ancestor" }, @@ -112890,7 +112936,8 @@ "tests": [ "tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", - "tests/corpus/5797-worker-message-port-transfer.ts" + "tests/corpus/5797-worker-message-port-transfer.ts", + "tests/corpus/5805-worker-receive-message-parent-port.ts" ] }, "anchorSource": "exact" @@ -113546,8 +113593,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.resourceLimits", + "tests": [ + "tests/corpus/5806-worker-resource-limits.ts" + ] }, "anchorSource": "ancestor" }, @@ -113569,8 +113619,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.stderr", + "tests": [ + "tests/corpus/5874-worker-stdio-streams.ts", + "tests/corpus/5875-worker-stdout-pipe.cjs", + "tests/corpus/5879-worker-stdin.ts" + ] }, "anchorSource": "ancestor" }, @@ -113592,8 +113647,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.stdin", + "tests": [ + "tests/corpus/5874-worker-stdio-streams.ts", + "tests/corpus/5875-worker-stdout-pipe.cjs", + "tests/corpus/5879-worker-stdin.ts" + ] }, "anchorSource": "ancestor" }, @@ -113615,8 +113675,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.stdout", + "tests": [ + "tests/corpus/5874-worker-stdio-streams.ts", + "tests/corpus/5875-worker-stdout-pipe.cjs", + "tests/corpus/5879-worker-stdin.ts" + ] }, "anchorSource": "ancestor" }, @@ -113666,8 +113731,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.threadName", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] }, "anchorSource": "ancestor" }, @@ -113694,7 +113763,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] }, "anchorSource": "exact" @@ -113722,7 +113793,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] }, "anchorSource": "exact" @@ -113750,7 +113823,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] }, "anchorSource": "exact" @@ -113801,7 +113876,9 @@ "tests": [ "tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", - "tests/corpus/native-worker-exit-listeners.ts" + "tests/corpus/native-worker-exit-listeners.ts", + "tests/corpus/5807-worker-error-values.ts", + "tests/corpus/5808-worker-unhandled-rejections.ts" ] }, "anchorSource": "exact" @@ -113824,8 +113901,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.worker_threads.getEnvironmentData", + "tests": [ + "tests/corpus/5803-worker-environment-data.ts", + "tests/corpus/5804-worker-environment-data.cjs" + ] }, "anchorSource": "exact" }, @@ -113847,8 +113928,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.worker_threads.markAsUntransferable", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] }, "anchorSource": "exact" }, @@ -113870,8 +113955,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.worker_threads.isMarkedAsUntransferable", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] }, "anchorSource": "exact" }, @@ -113967,7 +114056,8 @@ "tests": [ "tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", - "tests/corpus/5797-worker-message-port-transfer.ts" + "tests/corpus/5797-worker-message-port-transfer.ts", + "tests/corpus/5805-worker-receive-message-parent-port.ts" ] }, "anchorSource": "exact" @@ -113990,8 +114080,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.worker_threads.setEnvironmentData", + "tests": [ + "tests/corpus/5803-worker-environment-data.ts", + "tests/corpus/5804-worker-environment-data.cjs" + ] }, "anchorSource": "exact" }, @@ -114092,8 +114186,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.resourceLimits", + "tests": [ + "tests/corpus/5806-worker-resource-limits.ts" + ] }, "anchorSource": "chapter" }, @@ -114166,8 +114263,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.threadName", + "tests": [ + "tests/corpus/5870-worker-thread-names.ts", + "tests/corpus/5871-worker-untransferable.cjs" + ] }, "anchorSource": "chapter" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 6cc2cd1df..e2011c2fe 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -145,7 +145,7 @@ "node-builtin.process.versions": ["tests/corpus/process-versions-storage.ts"], "node-builtin.process.rows": ["tests/corpus/2992-stream-rows.ts", "tests/harness/terminal-geometry.test.ts"], "node-builtin.process.columns": ["tests/corpus/1448-stream-columns.ts", "tests/harness/terminal-geometry.test.ts"], - "node-builtin.process.exitCode": ["tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", "tests/corpus/2944-process-exit-code-wrap.ts"], + "node-builtin.process.exitCode": ["tests/corpus/5809-process-exit-and-rejections.cjs", "tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", "tests/corpus/2944-process-exit-code-wrap.ts"], "node-builtin.querystring": ["tests/corpus/957-builtins-namespace.ts", "tests/corpus/2917-builtin-callable-widths.ts"], "node-builtin.readline": ["tests/corpus/1475-readline-closed-stdin.ts"], "node-builtin.stream": ["tests/corpus/1685-stream-readable-basics.ts", "tests/corpus/1746-stream-for-await.ts", "tests/corpus/1814-stream-pipeline.cjs", "tests/corpus/2629-stream-consumers.ts", "tests/corpus/2861-readable-iterator-close.ts"], @@ -200,9 +200,14 @@ {"chapter": "worker_threads", "symbols": ["worker.terminate"], "status": "partial", "evidence": ["tests/corpus/native-worker-terminate-loop.ts", "tests/corpus/native-worker-terminate-wait.ts", "tests/corpus/native-worker-terminate-suspended.ts", "tests/corpus/native-worker-loop-cancellation.ts"]}, {"chapter": "worker_threads", "symbols": ["worker.ref", "worker.unref"], "status": "partial", "evidence": ["tests/corpus/native-worker-references.ts"]}, {"chapter": "worker_threads", "symbols": ["port.close", "port.start", "port.ref", "port.unref", "port.hasRef"], "status": "partial", "evidence": ["tests/corpus/native-worker-port-lifetime.ts"]}, - {"chapter": "worker_threads", "parent": "Class: `Worker`", "signatures": ["Event: `'online'`", "Event: `'message'`", "Event: `'error'`", "Event: `'exit'`"], "status": "partial", "evidence": ["tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", "tests/corpus/native-worker-exit-listeners.ts"]}, + {"chapter": "worker_threads", "parent": "Class: `Worker`", "signatures": ["Event: `'online'`", "Event: `'message'`", "Event: `'error'`", "Event: `'exit'`"], "status": "partial", "evidence": ["tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", "tests/corpus/native-worker-exit-listeners.ts", "tests/corpus/5807-worker-error-values.ts", "tests/corpus/5808-worker-unhandled-rejections.ts"]}, {"chapter": "worker_threads", "parent": "Class: `MessagePort`", "signatures": ["Event: `'message'`", "Event: `'close'`"], "status": "partial", "evidence": ["tests/corpus/native-worker-port-lifetime.ts", "tests/corpus/native-worker-messages.ts"]}, - {"chapter": "worker_threads", "symbols": ["MessageChannel", "worker_threads.receiveMessageOnPort"], "status": "partial", "evidence": ["tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", "tests/corpus/5797-worker-message-port-transfer.ts"]}, + {"chapter": "worker_threads", "symbols": ["MessageChannel", "worker_threads.receiveMessageOnPort"], "status": "partial", "evidence": ["tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", "tests/corpus/5797-worker-message-port-transfer.ts", "tests/corpus/5805-worker-receive-message-parent-port.ts"]}, + {"chapter": "worker_threads", "symbols": ["worker_threads.getEnvironmentData", "worker_threads.setEnvironmentData"], "status": "partial", "evidence": ["tests/corpus/5803-worker-environment-data.ts", "tests/corpus/5804-worker-environment-data.cjs"]}, + {"chapter": "worker_threads", "symbols": ["stdout", "stderr", "stdin"], "status": "partial", "evidence": ["tests/corpus/5874-worker-stdio-streams.ts", "tests/corpus/5875-worker-stdout-pipe.cjs", "tests/corpus/5879-worker-stdin.ts"]}, + {"chapter": "worker_threads", "symbols": ["threadName", "worker_threads.markAsUntransferable", "worker_threads.isMarkedAsUntransferable"], "status": "partial", "evidence": ["tests/corpus/5870-worker-thread-names.ts", "tests/corpus/5871-worker-untransferable.cjs"]}, + {"chapter": "worker_threads", "symbols": ["resourceLimits"], "status": "partial", "evidence": ["tests/corpus/5806-worker-resource-limits.ts"]}, + {"chapter": "worker_threads", "symbols": ["BroadcastChannel extends EventTarget", "broadcastChannel.close", "broadcastChannel.postMessage", "broadcastChannel.ref", "broadcastChannel.unref", "onmessage"], "status": "partial", "evidence": ["tests/corpus/5800-broadcast-channel.ts", "tests/corpus/5801-broadcast-channel.cjs", "tests/corpus/5802-broadcast-channel-workers.ts"]}, {"chapter": "util", "symbols": ["util.types.isAnyArrayBuffer", "util.types.isArrayBuffer", "util.types.isArrayBufferView", "util.types.isDataView", "util.types.isTypedArray", "util.types.isUint8Array", "util.types.isUint8ClampedArray", "util.types.isUint16Array", "util.types.isUint32Array", "util.types.isInt8Array", "util.types.isInt16Array", "util.types.isInt32Array", "util.types.isFloat32Array", "util.types.isFloat64Array", "util.types.isMap", "util.types.isSet", "util.types.isWeakMap", "util.types.isWeakSet", "util.types.isRegExp", "util.types.isNativeError", "util.types.isPromise", "util.types.isProxy", "util.types.isAsyncFunction", "util.types.isGeneratorFunction", "util.types.isGeneratorObject"], "status": "partial", "evidence": ["tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", "tests/fixtures/node-types/util-types.ts"]}, { "chapter": "util", "symbols": ["util.styleText"], "status": "partial", "evidence": ["tests/corpus/node24-style-text.ts", "tests/corpus/node24-style-text-validation.js", "tests/corpus/node24-style-text-environment.js", "tests/corpus/node24-style-text.cjs", "tests/fixtures/node-types/style-text.ts"] }, { "chapter": "util", "symbols": ["util.isDeepStrictEqual"], "status": "partial", "evidence": ["tests/corpus/node24-deep-equality.ts", "tests/corpus/node24-deep-equality.cjs", "tests/corpus/node24-deep-equality-properties.js", "tests/fixtures/node-types/deep-equality.ts", "packages/compiler/test/deep-equality.test.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index d61d3e169..4f02cbaa1 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -699,6 +699,7 @@ interface MessageEvent extends Event { readonly data: T; readonly origin: string; readonly lastEventId: string; + readonly source: unknown; readonly ports: readonly MessagePort[]; } declare var MessageEvent: { @@ -5677,19 +5678,40 @@ declare module "worker_threads" { export const isMainThread: boolean; export const isInternalThread: boolean; export const threadId: number; + export interface ResourceLimits { + maxYoungGenerationSizeMb?: number; + maxOldGenerationSizeMb?: number; + codeRangeSizeMb?: number; + stackSizeMb?: number; + } + /* {} in the main thread */ + export const resourceLimits: ResourceLimits; + /* the Worker's name option, trimmed ("WorkerThread" by default); "" in the main thread */ + export const threadName: string | null; export interface WorkerOptions { workerData?: unknown; transferList?: readonly unknown[]; argv?: readonly unknown[]; name?: string; + resourceLimits?: ResourceLimits; + stdout?: boolean; + stderr?: boolean; + stdin?: boolean; [option: string]: unknown; } export class Worker { constructor(filename: string | URL, options?: WorkerOptions); readonly threadId: number; + readonly resourceLimits?: ResourceLimits; + readonly threadName: string | null; + /* with the stdout/stderr options: the worker's writes to those streams */ + readonly stdout: import("stream").Readable; + readonly stderr: import("stream").Readable; + /* with the stdin option: what the worker reads from process.stdin */ + readonly stdin: import("stream").Writable | null; on(event: "online", listener: () => void): this; on(event: "message", listener: (value: any) => void): this; - on(event: "error", listener: (error: Error) => void): this; + on(event: "error", listener: (error: any) => void): this; on(event: "exit", listener: (code: number) => void): this; on(event: string, listener: (...args: any[]) => void): this; once(event: string, listener: (...args: any[]) => void): this; @@ -5731,6 +5753,24 @@ declare module "worker_threads" { readonly port2: MessagePort; } export function receiveMessageOnPort(port: MessagePort): { message: any } | undefined; + /* This thread's environment data; each new Worker starts from a clone. */ + export function setEnvironmentData(key: any, value?: any): void; + export function getEnvironmentData(key: any): any; + /* A marked object cannot be listed in a transfer list. */ + export function markAsUntransferable(object: any): void; + export function isMarkedAsUntransferable(object: any): boolean; + /* Delivers each message to every other open channel with the name, in + * any thread, as a 'message' MessageEvent. */ + export class BroadcastChannel extends EventTarget { + constructor(name: string); + readonly name: string; + onmessage: ((event: MessageEvent) => void) | null; + onmessageerror: ((event: MessageEvent) => void) | null; + postMessage(message: unknown): void; + close(): void; + ref(): this; + unref(): this; + } export const parentPort: MessagePort | null; export const workerData: any; } diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 09bf4979c..bff40b27e 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1987,12 +1987,28 @@ export class LlEmitter { this.dyn.toDynHelper({ kind: "object", className: "%Writable" }), ] : null; - if (childStreamBoxes) { + // worker.stdout and worker.stderr box the stream unit's Readable the + // same way, and worker.stdin its Writable when the program has one + // (scr_worker_stdio_install, scr_worker_events.c). + const workerStdioBox = + this.mod.workers === true && usesStream && this.classMeta.has("%Readable") + ? (childStreamBoxes?.[0] ?? + this.dyn.toDynHelper({ kind: "object", className: "%Readable" })) + : null; + const workerStdinBox = + this.mod.workers === true && usesStream && this.classMeta.has("%Writable") + ? (childStreamBoxes?.[1] ?? + this.dyn.toDynHelper({ kind: "object", className: "%Writable" })) + : null; + if (childStreamBoxes || workerStdioBox || workerStdinBox) { this.declare( `@scr_stream_child_ops = external constant { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }`, ); - this.declare(`declare void @scr_child_dyn_streams_install(ptr, ptr, ptr)`); } + if (childStreamBoxes) + this.declare(`declare void @scr_child_dyn_streams_install(ptr, ptr, ptr)`); + if (workerStdioBox || workerStdinBox) + this.declare(`declare void @scr_worker_stdio_install(ptr, ptr, ptr)`); if (usesFsWatch) this.declare(`declare void @scr_watch_install()`); if (this.ffiHasForeignCallback) this.declare(`declare void @scr_ffi_install()`); if (usesStream) this.declare(`declare void @scr_stream_install()`); @@ -2582,6 +2598,11 @@ export class LlEmitter { ` call void @scr_child_dyn_streams_install(ptr @scr_stream_child_ops, ptr @${childStreamBoxes[0]}, ptr @${childStreamBoxes[1]})`, ] : []), + ...(workerStdioBox || workerStdinBox + ? [ + ` call void @scr_worker_stdio_install(ptr @scr_stream_child_ops, ptr ${workerStdioBox ? `@${workerStdioBox}` : "null"}, ptr ${workerStdinBox ? `@${workerStdinBox}` : "null"})`, + ] + : []), // fs.watch programs fill the loop's watch hooks the same way — // scr_watch.c links only when this line is emitted. ...(usesFsWatch ? [` call void @scr_watch_install()`] : []), diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 4f66eafac..5a981e5ec 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -930,8 +930,17 @@ export const LIB_FN_SYMS: Record = { "worker.root": "scr_worker_root", "worker.data": "scr_worker_data", "worker.parentPort": "scr_worker_parent_port", + "worker.resourceLimits": "scr_worker_resource_limits", + "worker.threadName": "scr_worker_thread_name_current", "worker.channel": "scr_worker_message_channel", "worker.receiveMessageOnPort": "scr_worker_receive_message_on_port", + "worker.setEnvironmentData": "scr_worker_set_environment_data", + "worker.getEnvironmentData": "scr_worker_get_environment_data", + "worker.markUntransferable": "scr_worker_mark_untransferable", + "worker.isMarkedUntransferable": "scr_worker_is_marked_untransferable", + "stream.workerStdio": "scr_stream_worker_stdio", + "worker.broadcastChannel": "scr_worker_broadcast_channel", + "event.broadcastInstall": "scr_et_broadcast_install", "process.stdinDestroy": "scr_process_stdin_destroy", "process.stdinSetRawMode": "scr_process_stdin_set_raw_mode", // node:events EventEmitter (scr_events_emitter.c): receivers borrowed, @@ -1362,6 +1371,7 @@ export const USES_TIMERS_LIB_FNS = new Set([ "worker.parentPort", "worker.channel", "worker.receiveMessageOnPort", + "worker.broadcastChannel", "process.stdio", "fetch.start", "fetch.input", diff --git a/packages/compiler/src/frontend/lowering/builtin-calls.ts b/packages/compiler/src/frontend/lowering/builtin-calls.ts index 9dafc0319..25d767da4 100644 --- a/packages/compiler/src/frontend/lowering/builtin-calls.ts +++ b/packages/compiler/src/frontend/lowering/builtin-calls.ts @@ -1,4 +1,8 @@ -import { lowerReceiveMessageOnPort } from "./builtins/workers.js"; +import { + lowerEnvironmentData, + lowerReceiveMessageOnPort, + lowerUntransferable, +} from "./builtins/workers.js"; import * as ts from "../ts7/adapter.js"; import { dynUndefinedExpr } from "../../ir/build.js"; import { DYN, type IrExpr, type SrcLoc } from "../../ir/ir.js"; @@ -92,6 +96,18 @@ export function lowerBuiltinCall( if (bi.module === "worker_threads" && bi.member === "receiveMessageOnPort") { return lowerReceiveMessageOnPort(lowerer, expr); } + if ( + bi.module === "worker_threads" && + (bi.member === "setEnvironmentData" || bi.member === "getEnvironmentData") + ) { + return lowerEnvironmentData(lowerer, expr, bi.member); + } + if ( + bi.module === "worker_threads" && + (bi.member === "markAsUntransferable" || bi.member === "isMarkedAsUntransferable") + ) { + return lowerUntransferable(lowerer, expr, bi.member); + } const builtinFn = builtinModuleFnOf(lowerer, bi.module, bi.member); if (!builtinFn) { lowerer.noLowering( diff --git a/packages/compiler/src/frontend/lowering/builtins/workers.ts b/packages/compiler/src/frontend/lowering/builtins/workers.ts index 3144f208f..1061f1389 100644 --- a/packages/compiler/src/frontend/lowering/builtins/workers.ts +++ b/packages/compiler/src/frontend/lowering/builtins/workers.ts @@ -9,6 +9,7 @@ import { F64, STRING, UNDEFINED_T, + VOID, isFfiCallbackParam, type IrExpr, type SrcLoc, @@ -27,6 +28,10 @@ export function lowerWorkerMetadata(member: string, loc: SrcLoc): IrExpr | null return { kind: "libCall", fn: "worker.parentPort", args: [], type: DYN, loc }; case "isInternalThread": return { kind: "boolLit", value: false, type: BOOL, loc }; + case "resourceLimits": + return { kind: "libCall", fn: "worker.resourceLimits", args: [], type: DYN, loc }; + case "threadName": + return { kind: "libCall", fn: "worker.threadName", args: [], type: DYN, loc }; default: return null; } @@ -76,6 +81,7 @@ export function lowerWorkerNew(lowerer: Lowerer, expression: ts.NewExpression): "native callbacks in worker executables must run on their owning script thread", ); } + refuseHeapLimits(lowerer, args[1]); lowerer.usesWorkers = true; const loc = locOf(expression); const options: IrExpr = args[1] @@ -86,7 +92,7 @@ export function lowerWorkerNew(lowerer: Lowerer, expression: ts.NewExpression): type: DYN, loc, }; - return { + const create: IrExpr = { kind: "libCall", fn: "worker.new", args: [ @@ -97,6 +103,70 @@ export function lowerWorkerNew(lowerer: Lowerer, expression: ts.NewExpression): type: DYN, loc, }; + if (!capturesStdio(args[1])) return create; + return { + kind: "seqExpr", + stmts: [ + { + kind: "exprStmt", + expr: { kind: "libCall", fn: "stream.workerStdio", args: [], type: VOID, loc }, + loc, + }, + ], + result: create, + type: DYN, + loc, + }; +} + +/** True when the options are not a literal, or a literal whose stdout, + * stderr or stdin member is not the literal false: worker.stdout, + * worker.stderr and worker.stdin then need the stream unit. */ +function capturesStdio(options: ts.Expression | undefined): boolean { + if (!options) return false; + if (!ts.isObjectLiteralExpression(options)) return true; + return options.properties.some((option) => { + if (ts.isSpreadAssignment(option)) return true; + if (!option.name) return false; + const name = propertyNameText(option.name); + if (name !== "stdout" && name !== "stderr" && name !== "stdin") return name === undefined; + return !( + ts.isPropertyAssignment(option) && option.initializer.kind === ts.SyntaxKind.FalseKeyword + ); + }); +} + +const HEAP_LIMITS = new Set([ + "maxOldGenerationSizeMb", + "maxYoungGenerationSizeMb", + "codeRangeSizeMb", +]); + +/** resourceLimits' V8 heap fields, when an options literal spells them + * with numbers (Node ignores other values; the runtime refuses the rest). */ +function refuseHeapLimits(lowerer: Lowerer, options: ts.Expression | undefined): void { + if (!options || !ts.isObjectLiteralExpression(options)) return; + for (const option of options.properties) { + if (!ts.isPropertyAssignment(option) || propertyNameText(option.name) !== "resourceLimits") + continue; + if (!ts.isObjectLiteralExpression(option.initializer)) continue; + for (const limit of option.initializer.properties) { + if (!ts.isPropertyAssignment(limit)) continue; + const name = propertyNameText(limit.name); + if (name === undefined || !HEAP_LIMITS.has(name)) continue; + const type = lowerer.checker.getTypeAtLocation(limit.initializer); + if (!(type.flags & ts.TypeFlags.NumberLike)) continue; + lowerer.noLowering( + `Worker resourceLimits.${name}`, + limit, + "worker threads have no separate V8 heap; resourceLimits supports stackSizeMb", + ); + } + } +} + +function propertyNameText(name: ts.PropertyName): string | undefined { + return ts.isIdentifier(name) || ts.isStringLiteral(name) ? name.text : undefined; } /** True when `node`'s type is worker_threads' `name` class (also reached @@ -166,3 +236,123 @@ export function lowerReceiveMessageOnPort(lowerer: Lowerer, call: ts.CallExpress loc, }; } + +/** new BroadcastChannel(name): the EventTarget unit's half installs + * first, then the channel opens (the name converts at runtime). */ +export function lowerBroadcastChannelNew( + lowerer: Lowerer, + expression: ts.NewExpression, +): IrExpr | null { + if (!isWorkerThreadsClass(lowerer, expression, "BroadcastChannel")) return null; + const args = expression.arguments ?? []; + if (args.length > 1 || args.some(ts.isSpreadElement)) { + lowerer.noLowering( + `BroadcastChannel constructor with ${args.length} arguments`, + expression, + "use new BroadcastChannel(name)", + ); + } + if (lowerer.targetPlatform === "wasi") { + lowerer.noLowering( + "BroadcastChannel in this target", + expression, + "use a native static executable", + ); + } + lowerer.usesWorkers = true; + const loc = locOf(expression); + return { + kind: "seqExpr", + stmts: [ + { + kind: "exprStmt", + expr: { kind: "libCall", fn: "event.broadcastInstall", args: [], type: VOID, loc }, + loc, + }, + ], + result: { + kind: "libCall", + fn: "worker.broadcastChannel", + args: [ + { + kind: "dynArrLit", + elems: args.map((a) => lowerer.lowerExprExpecting(a, DYN)), + type: DYN, + loc, + }, + ], + type: DYN, + loc, + }, + type: DYN, + loc, + }; +} + +/** setEnvironmentData(key, value?) and getEnvironmentData(key): this + * thread's map, cloned into each Worker it constructs. */ +export function lowerEnvironmentData( + lowerer: Lowerer, + call: ts.CallExpression, + member: "setEnvironmentData" | "getEnvironmentData", +): IrExpr { + const args = call.arguments; + const arity = member === "setEnvironmentData" ? 2 : 1; + if (args.length > arity || args.some(ts.isSpreadElement)) { + lowerer.noLowering(`${member} with ${args.length} arguments`, call); + } + if (lowerer.targetPlatform === "wasi") { + lowerer.noLowering(`${member} in this target`, call, "use a native static executable"); + } + lowerer.usesWorkers = true; + const loc = locOf(call); + const lowered: IrExpr[] = []; + for (let i = 0; i < arity; i++) { + lowered.push( + args[i] + ? lowerer.lowerExprExpecting(args[i]!, DYN) + : { + kind: "dynFrom", + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type: DYN, + loc, + }, + ); + } + return { + kind: "libCall", + fn: member === "setEnvironmentData" ? "worker.setEnvironmentData" : "worker.getEnvironmentData", + args: lowered, + type: member === "setEnvironmentData" ? VOID : DYN, + loc, + }; +} + +/** markAsUntransferable(value) and isMarkedAsUntransferable(value): marks + * kept by this thread (an ArrayBuffer's on its storage). */ +export function lowerUntransferable( + lowerer: Lowerer, + call: ts.CallExpression, + member: "markAsUntransferable" | "isMarkedAsUntransferable", +): IrExpr { + const args = call.arguments; + if (args.length > 1 || args.some(ts.isSpreadElement)) { + lowerer.noLowering(`${member} with ${args.length} arguments`, call); + } + if (lowerer.targetPlatform === "wasi") { + lowerer.noLowering(`${member} in this target`, call, "use a native static executable"); + } + lowerer.usesWorkers = true; + const loc = locOf(call); + const value: IrExpr = args[0] + ? lowerer.lowerExprExpecting(args[0], DYN) + : { + kind: "dynFrom", + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type: DYN, + loc, + }; + return member === "markAsUntransferable" + ? { kind: "libCall", fn: "worker.markUntransferable", args: [value], type: VOID, loc } + : { kind: "libCall", fn: "worker.isMarkedUntransferable", args: [value], type: BOOL, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 08367c8cd..e283e3903 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -77,7 +77,11 @@ import { bufEncoding } from "./containers/bytes.js"; import { isSafeToRepeat } from "./expressions/evaluation-safety.js"; import { lowerSearchParamsNew } from "./builtins/url.js"; import { lowerTextCodecNew } from "./builtins/text-codecs.js"; -import { lowerMessageChannelNew, lowerWorkerNew } from "./builtins/workers.js"; +import { + lowerBroadcastChannelNew, + lowerMessageChannelNew, + lowerWorkerNew, +} from "./builtins/workers.js"; import { unsupportedPackageValueDiag, unsupportedDiag, @@ -8150,7 +8154,7 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const loc = locOf(expr); const worker = lowerWorkerNew(lowerer, expr); if (worker) return worker; - const channel = lowerMessageChannelNew(lowerer, expr); + const channel = lowerMessageChannelNew(lowerer, expr) ?? lowerBroadcastChannelNew(lowerer, expr); if (channel) return channel; let intlConstructor = expr.expression; if (ts.isIdentifier(intlConstructor)) { diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index ec931350a..014425aef 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2069,7 +2069,14 @@ export const AMBIENT_SURFACE_FNS: readonly AmbientSurfaceRow[] = [ id: "node-builtin.worker_threads.metadata", kind: "node-builtin", name: "worker_threads metadata", - fns: ["worker.isMainThread", "worker.threadId", "worker.data", "worker.parentPort"], + fns: [ + "worker.isMainThread", + "worker.threadId", + "worker.data", + "worker.parentPort", + "worker.resourceLimits", + "worker.threadName", + ], note: "current-thread metadata and the worker's parent message port", }, { diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 90bf6922e..9bd8399e8 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -130,6 +130,7 @@ export const FETCH_AMBIENT_TYPES = [ "RequestInit", "Event", "CustomEvent", + "MessageEvent", "EventTarget", "AddEventListenerOptions", "EventListenerOptions", @@ -1236,7 +1237,8 @@ function isWorkerHandleSymbol( return ( (symbol?.name === "Worker" || symbol?.name === "MessagePort" || - symbol?.name === "MessageChannel") && + symbol?.name === "MessageChannel" || + symbol?.name === "BroadcastChannel") && ctx.checker .declarationsOf(symbol) .some( diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index c1a683667..acdc652e2 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -24,8 +24,12 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "worker.new", "worker.data", "worker.parentPort", + "worker.resourceLimits", "worker.channel", "worker.receiveMessageOnPort", + "worker.setEnvironmentData", + "worker.getEnvironmentData", + "worker.broadcastChannel", "process.exit", "text.encodeInto", "buffer.isAscii", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 164138e6f..ef05dbcc5 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1105,10 +1105,31 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "worker.root": { argTypes: [], result: F64 }, "worker.data": { argTypes: [], result: DYN }, "worker.parentPort": { argTypes: [], result: DYN }, + /** worker_threads.resourceLimits: {} in the main thread; a refusal in a + * worker (scr_worker_events.c). */ + "worker.resourceLimits": { argTypes: [], result: DYN }, + /** worker_threads.threadName: the Worker's name in a worker, "" in the + * main thread (scr_worker.c). */ + "worker.threadName": { argTypes: [], result: DYN }, /** new MessageChannel() ({ port1, port2 }) and receiveMessageOnPort(port) * (scr_worker_events.c; the latter may throw). */ "worker.channel": { argTypes: [], result: DYN }, "worker.receiveMessageOnPort": { argTypes: [DYN], result: DYN }, + /** setEnvironmentData(key, value) and getEnvironmentData(key) + * (scr_worker_events.c; arguments borrowed). */ + "worker.setEnvironmentData": { argTypes: [DYN, DYN], result: VOID }, + "worker.getEnvironmentData": { argTypes: [DYN], result: DYN }, + /** markAsUntransferable(value) and isMarkedAsUntransferable(value) + * (scr_worker_events.c; the value borrowed). */ + "worker.markUntransferable": { argTypes: [DYN], result: VOID }, + "worker.isMarkedUntransferable": { argTypes: [DYN], result: BOOL }, + /** before new Worker() with the stdout or stderr option: links the stream + * unit that worker.stdout and worker.stderr read through (scr_stream.c). */ + "stream.workerStdio": { argTypes: [], result: VOID }, + /** new BroadcastChannel(...args) (scr_worker_events.c; may throw), after + * event.broadcastInstall, which installs its EventTarget side. */ + "worker.broadcastChannel": { argTypes: [DYN], result: DYN }, + "event.broadcastInstall": { argTypes: [], result: VOID }, /** child_process.spawnSync (scr_child.c): posix_spawn + waitpid + piped * utf8 capture — cmd borrowed, args one borrowed string[] (the frontend * completes an omitted list to an empty literal), result an owned (+1) diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 188d0203d..8f6890335 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -265,6 +265,7 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run fn === "stream.destroy" || fn === "stream.destroyErr" || fn === "stream.prop" || + fn === "stream.workerStdio" || fn === "stream.errored" || fn === "sp.finished" || fn === "sp.pipeline" || diff --git a/packages/compiler/src/library/ir-policy.ts b/packages/compiler/src/library/ir-policy.ts index 51a5c3b9c..9fe80fdf3 100644 --- a/packages/compiler/src/library/ir-policy.ts +++ b/packages/compiler/src/library/ir-policy.ts @@ -66,6 +66,11 @@ const LIB_MODE_REFUSED_PREFIXES: readonly [string, string][] = [ ["worker.new", "native worker threads"], ["worker.channel", "native worker threads"], ["worker.receiveMessageOnPort", "native worker threads"], + ["worker.setEnvironmentData", "native worker threads"], + ["worker.getEnvironmentData", "native worker threads"], + ["worker.markUntransferable", "native worker threads"], + ["worker.isMarkedUntransferable", "native worker threads"], + ["worker.broadcastChannel", "native worker threads"], ]; /** Value/type kinds whose mere presence means an excluded unit's code (or diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5800-broadcast-channel.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5800-broadcast-channel.ts.json new file mode 100644 index 000000000..9858f853a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5800-broadcast-channel.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5800-broadcast-channel.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5801-broadcast-channel.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5801-broadcast-channel.cjs.json new file mode 100644 index 000000000..56a80c6ea --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5801-broadcast-channel.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5801-broadcast-channel.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5802-broadcast-channel-workers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5802-broadcast-channel-workers.ts.json new file mode 100644 index 000000000..5e3522da6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5802-broadcast-channel-workers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5802-broadcast-channel-workers.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5803-worker-environment-data.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5803-worker-environment-data.ts.json new file mode 100644 index 000000000..397c5afe2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5803-worker-environment-data.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5803-worker-environment-data.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5804-worker-environment-data.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5804-worker-environment-data.cjs.json new file mode 100644 index 000000000..da385edab --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5804-worker-environment-data.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5804-worker-environment-data.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5805-worker-receive-message-parent-port.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5805-worker-receive-message-parent-port.ts.json new file mode 100644 index 000000000..0976b291e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5805-worker-receive-message-parent-port.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5805-worker-receive-message-parent-port.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5806-worker-resource-limits.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5806-worker-resource-limits.ts.json new file mode 100644 index 000000000..2340ef776 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5806-worker-resource-limits.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5806-worker-resource-limits.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5807-worker-error-values.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5807-worker-error-values.ts.json new file mode 100644 index 000000000..a116df7f1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5807-worker-error-values.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5807-worker-error-values.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5808-worker-unhandled-rejections.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5808-worker-unhandled-rejections.ts.json new file mode 100644 index 000000000..ea84f1308 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5808-worker-unhandled-rejections.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5808-worker-unhandled-rejections.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5809-process-exit-and-rejections.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5809-process-exit-and-rejections.cjs.json new file mode 100644 index 000000000..21816332e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5809-process-exit-and-rejections.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5809-process-exit-and-rejections.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5870-worker-thread-names.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5870-worker-thread-names.ts.json new file mode 100644 index 000000000..2c16d66db --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5870-worker-thread-names.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5870-worker-thread-names.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5871-worker-untransferable.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5871-worker-untransferable.cjs.json new file mode 100644 index 000000000..df294877c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5871-worker-untransferable.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5871-worker-untransferable.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5874-worker-stdio-streams.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5874-worker-stdio-streams.ts.json new file mode 100644 index 000000000..12434a757 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5874-worker-stdio-streams.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5874-worker-stdio-streams.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5875-worker-stdout-pipe.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5875-worker-stdout-pipe.cjs.json new file mode 100644 index 000000000..64115b746 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5875-worker-stdout-pipe.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5875-worker-stdout-pipe.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5879-worker-stdin.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5879-worker-stdin.ts.json new file mode 100644 index 000000000..9b7dbdcd7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5879-worker-stdin.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5879-worker-stdin.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index 9bf42bb07..3b6486338 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -4400,7 +4400,9 @@ bool scr_report_unhandled_rejections(void) { #ifdef SCR_WORKERS if (scr_context_report_error) { scr_promise_rethrow(p); + scr_context_report_rejection = true; scr_exc_print_uncaught(); + scr_context_report_rejection = false; scr_promise_release(p); continue; } diff --git a/packages/runtime/src/scr_async_dyn.c b/packages/runtime/src/scr_async_dyn.c index deac50626..cdad51b7d 100644 --- a/packages/runtime/src/scr_async_dyn.c +++ b/packages/runtime/src/scr_async_dyn.c @@ -341,9 +341,100 @@ void scr_process_off_uncaught_exception(ScrDyn *fn, bool monitor) { scr_uncaught_sync_hook(); } +/* V8's side-effect-free string of a value, which Node's + * UnhandledPromiseRejection message quotes: primitives as String() gives + * them, a symbol as Symbol(description), an array as [object Array], an + * object with its own toString as [object Object], and other objects as + * #. */ +static bool scr_rejection_custom_to_string(const ScrDyn *value) { + if (value->kind == SCR_DYN_TYPED_REF) { + ScrStr *key = scr_str_new("toString", 8); + bool found = scr_dyn_typed_ref_class_has(value, key); + scr_str_release(key); + return found; + } + for (const ScrDyn *p = value; p; p = p->prototype) + if (p->kind == SCR_DYN_OBJ && scr_dyn_obj_get(p, "toString", 8)) return true; + return false; +} + +static ScrStr *scr_rejection_reason_text(const ScrDyn *reason, const ScrDyn *view) { + switch (view->kind) { + case SCR_DYN_UNDEF: return scr_str_new("undefined", 9); + case SCR_DYN_NULL: return scr_str_new("null", 4); + case SCR_DYN_SYMBOL: return reason->v.symbol.render(reason->v.symbol.value); + case SCR_DYN_ARR: return scr_str_new("[object Array]", 14); + case SCR_DYN_PROMISE: return scr_str_new("#", 10); + case SCR_DYN_OBJ: { + if (scr_rejection_custom_to_string(reason) || scr_rejection_custom_to_string(view)) + return scr_str_new("[object Object]", 15); + const char *name = reason->kind == SCR_DYN_OBJ ? scr_dyn_class_name(reason) : NULL; + const ScrStr *typed = reason->kind == SCR_DYN_TYPED_REF ? scr_dyn_typed_ref_class_name(reason) : NULL; + ScrStr *parts[3] = { + scr_str_new("#<", 2), + typed ? scr_str_new(typed->data, typed->len) : scr_str_new(name ? name : "Object", name ? strlen(name) : 6), + scr_str_new(">", 1), + }; + ScrStr *text = scr_str_concat_parts(parts, 3); + for (size_t i = 0; i < 3; i++) scr_str_release(parts[i]); + return text; + } + default: return scr_dyn_to_string(view, NULL); + } +} + +ScrDyn *scr_unhandled_rejection_error(ScrDyn *reason) { + ScrError *error = scr_errdyn_err_of(reason); + ScrDyn *view = reason->kind == SCR_DYN_TYPED_REF ? scr_dyn_typed_ref_materialize(reason) : scr_dyn_retain(reason); + if (!view || scr_exc_pending()) { + scr_error_release(error); + scr_dyn_release(view); + return NULL; + } + ScrStr *stack = scr_str_new("stack", 5); + bool error_like = error || (view->kind == SCR_DYN_OBJ && scr_dyn_has_own(view, stack)); + scr_str_release(stack); + if (error_like) { + scr_error_release(error); + scr_dyn_release(view); + return scr_dyn_retain(reason); + } + ScrStr *text = scr_rejection_reason_text(reason, view); + scr_dyn_release(view); + if (!text || scr_exc_pending()) { + scr_str_release(text); + return NULL; + } + static const char head[] = "This error originated either by throwing inside of an async function without a " + "catch block, or by rejecting a promise which was not handled with .catch(). The " + "promise rejected with the reason \""; + ScrStr *parts[3] = {scr_str_new(head, sizeof head - 1), text, scr_str_new("\".", 2)}; + ScrStr *message = scr_str_concat_parts(parts, 3); + for (size_t i = 0; i < 3; i++) scr_str_release(parts[i]); + error = scr_error_new(SCR_ERR_ERROR, message); + scr_str_release(message); + scr_str_release(error->name); + error->name = scr_str_new("UnhandledPromiseRejection", 25); + error->code = scr_str_new("ERR_UNHANDLED_REJECTION", 23); + ScrDyn *value = scr_dyn_from_error(error); + /* Node's class fields: code, then name, both own and enumerable */ + scr_dyn_obj_set(value, "name", 4, scr_dyn_new_str(error->name)); + scr_error_release(error); + return value; +} + static int scr_uncaught_dispatch(bool from_promise) { ScrCaught *caught = scr_exc_take(); ScrDyn *error = scr_caught_to_dyn(caught); + if (from_promise) { + ScrDyn *wrapped = scr_unhandled_rejection_error(error); + scr_dyn_release(error); + if (!wrapped) { + scr_caught_release(caught); + return -1; + } + error = wrapped; + } const char *origin = from_promise ? "unhandledRejection" : "uncaughtException"; ScrStr *text = scr_str_new(origin, strlen(origin)); ScrDyn *args[2] = {error, scr_dyn_new_str(text)}; diff --git a/packages/runtime/src/scr_bytes.h b/packages/runtime/src/scr_bytes.h index b56f9477d..d43102a11 100644 --- a/packages/runtime/src/scr_bytes.h +++ b/packages/runtime/src/scr_bytes.h @@ -94,6 +94,23 @@ ScrDyn *scr_worker_parent_port(void); * (scr_worker_events.c). */ ScrDyn *scr_worker_message_channel(void); ScrDyn *scr_worker_receive_message_on_port(ScrDyn *port); +/* setEnvironmentData(key, value) and getEnvironmentData(key) (+1); both + * borrow their arguments. */ +void scr_worker_set_environment_data(ScrDyn *key, ScrDyn *value); +ScrDyn *scr_worker_get_environment_data(ScrDyn *key); +ScrDyn *scr_worker_resource_limits(void); +ScrDyn *scr_worker_thread_name_current(void); +/* markAsUntransferable(value) and isMarkedAsUntransferable(value) + * (scr_worker_events.c); both borrow the value. */ +void scr_worker_mark_untransferable(ScrDyn *value); +bool scr_worker_is_marked_untransferable(ScrDyn *value); +/* worker.stdout, worker.stderr and worker.stdin streams: main installs the + * stream unit's operations and the Readable and Writable boxes (the + * Writable one may be NULL) when the program reads them. */ +struct ScrChildStreamOps; +void scr_worker_stdio_install(const struct ScrChildStreamOps *ops, ScrDyn *(*readable_box)(void *), + ScrDyn *(*writable_box)(void *)); +void scr_worker_stdio_default(const struct ScrChildStreamOps *ops, ScrDyn *(*view)(void *)); ScrDyn *scr_worker_new(double root, ScrStr *filename, ScrDyn *options); bool scr_shared_array_buffer_is(const ScrDyn *); bool scr_buffer_storage_is(const ScrDyn *); diff --git a/packages/runtime/src/scr_console.c b/packages/runtime/src/scr_console.c index d6e4e93fb..1e031a2d0 100644 --- a/packages/runtime/src/scr_console.c +++ b/packages/runtime/src/scr_console.c @@ -204,6 +204,61 @@ void scr_init(void) { /* A real definition lets relocatable library links localize this hook; * a tentative common symbol stays externally visible on Mach-O. */ SCR_TL bool (*scr_stdio_write_hook)(int fd, const void *data, size_t len, bool wide) = NULL; +SCR_TL bool (*scr_stdio_capture)(int fd, const void *data, size_t len) = NULL; + +SCR_TL bool scr_stdin_fed = false; +SCR_TL void (*scr_stdin_fed_attach)(void) = NULL; +SCR_TL bool (*scr_stdin_fed_waiting)(void) = NULL; +static SCR_TL ScrBytes **scr_stdin_fed_q; +static SCR_TL size_t scr_stdin_fed_head, scr_stdin_fed_len, scr_stdin_fed_cap; +static SCR_TL bool scr_stdin_fed_end; + +void scr_stdin_fed_push(ScrBytes *chunk) { + if (scr_stdin_fed_end) { + if (chunk) scr_bytes_release(chunk); + return; + } + if (!chunk) { + scr_stdin_fed_end = true; + return; + } + if (scr_stdin_fed_head + scr_stdin_fed_len == scr_stdin_fed_cap) { + if (scr_stdin_fed_head > 0) { + memmove(scr_stdin_fed_q, scr_stdin_fed_q + scr_stdin_fed_head, + scr_stdin_fed_len * sizeof *scr_stdin_fed_q); + scr_stdin_fed_head = 0; + } + if (scr_stdin_fed_len == scr_stdin_fed_cap) { + scr_stdin_fed_cap = scr_stdin_fed_cap ? scr_stdin_fed_cap * 2 : 8; + scr_stdin_fed_q = realloc(scr_stdin_fed_q, scr_stdin_fed_cap * sizeof *scr_stdin_fed_q); + if (!scr_stdin_fed_q) scr_trap("scriptc: out of memory\n"); + } + } + scr_stdin_fed_q[scr_stdin_fed_head + scr_stdin_fed_len++] = chunk; +} + +ScrBytes *scr_stdin_fed_take(bool *ended) { + if (scr_stdin_fed_len == 0) { + *ended = scr_stdin_fed_end; + return NULL; + } + *ended = false; + ScrBytes *chunk = scr_stdin_fed_q[scr_stdin_fed_head++]; + if (--scr_stdin_fed_len == 0) scr_stdin_fed_head = 0; + return chunk; +} + +void scr_stdin_fed_clear(void) { + for (size_t i = 0; i < scr_stdin_fed_len; i++) + scr_bytes_release(scr_stdin_fed_q[scr_stdin_fed_head + i]); + free(scr_stdin_fed_q); + scr_stdin_fed_q = NULL; + scr_stdin_fed_head = scr_stdin_fed_len = scr_stdin_fed_cap = 0; + scr_stdin_fed_end = false; + scr_stdin_fed = false; + scr_stdin_fed_attach = NULL; + scr_stdin_fed_waiting = NULL; +} /* Lines up to this size render on the C stack (fiber stacks are 256 KiB). */ #define SCR_CONSOLE_STACK_LINE 2048 @@ -338,7 +393,7 @@ static void scr_console_write(int fd, size_t n, const ScrLogArg *args, bool glob #if SCR_STDIO_DIRECT /* A large single string goes out without a copy: string + newline in one * vectored write. */ - if (!scr_stdio_write_hook && !(global && scr_console_indenter) && n == 1 && + if (!scr_stdio_write_hook && !scr_stdio_capture && !(global && scr_console_indenter) && n == 1 && (args[0].tag & SCR_ARG_KIND) == SCR_ARG_STR && args[0].v.s->len >= SCR_CONSOLE_STACK_LINE) { char *owned; @@ -409,6 +464,7 @@ void scr_console_write_fd(int fd, size_t n, const ScrLogArg *args) { * Buffered runtime-internal stdout bytes go out first (for both streams) to * preserve stdout order and the merged-fd ordering convention. */ int scr_stdio_write_raw(int fd, const void *data, size_t len) { + if (__builtin_expect(scr_stdio_capture != NULL, 0) && scr_stdio_capture(fd == 2 ? 2 : 1, data, len)) return 0; #if SCR_STDIO_DIRECT FILE *locked = scr_fd_stream_lock(fd == 2 ? 2 : 1); if (scr_stdout_pending()) fflush(stdout); diff --git a/packages/runtime/src/scr_context.c b/packages/runtime/src/scr_context.c index fc2686374..d5bb78957 100644 --- a/packages/runtime/src/scr_context.c +++ b/packages/runtime/src/scr_context.c @@ -23,6 +23,7 @@ static const atomic_bool scr_context_raised = true; static SCR_TL const atomic_bool *scr_context_signal = &scr_context_unsignaled; static SCR_TL bool scr_context_stopped; SCR_TL void (*scr_context_report_error)(void); +SCR_TL bool scr_context_report_rejection; typedef struct { char *name; char *value; } ScrContextEnvEntry; struct ScrContextEnv { size_t count; ScrContextEnvEntry *entries; }; @@ -196,6 +197,13 @@ double scr_context_thread_number(void) { return 0; } double scr_worker_root(void) { return -1; } ScrDyn *scr_worker_data(void) { return scr_dyn_new_null(); } ScrDyn *scr_worker_parent_port(void) { return scr_dyn_new_null(); } +ScrDyn *scr_worker_resource_limits(void) { return scr_dyn_new_obj(); } +ScrDyn *scr_worker_thread_name_current(void) { + ScrStr *empty = scr_str_new("", 0); + ScrDyn *name = scr_dyn_new_str(empty); + scr_str_release(empty); + return name; +} #endif /* ── native stack guard ───────────────────────────────────────────────── diff --git a/packages/runtime/src/scr_core.h b/packages/runtime/src/scr_core.h index a640169fa..ac9e732b2 100644 --- a/packages/runtime/src/scr_core.h +++ b/packages/runtime/src/scr_core.h @@ -332,6 +332,8 @@ void scr_exc_alert_add(int delta); /* worker.terminate() references */ void scr_exc_alert_thread_exit(void); void scr_loop_context_shutdown(void); extern SCR_TL void (*scr_context_report_error)(void); +/* Set while scr_context_report_error reports an unhandled rejection. */ +extern SCR_TL bool scr_context_report_rejection; typedef struct ScrContextEnv ScrContextEnv; ScrContextEnv *scr_context_env_capture(void); void scr_context_env_free(ScrContextEnv *environment); diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 2895487d9..983ea40fe 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -166,6 +166,8 @@ typedef enum { SCR_DYNH_DIR, /* fs.Dir (scr_lib.c) */ SCR_DYNH_CIPHER, /* node:crypto Cipheriv (scr_cipher.c) */ SCR_DYNH_DECIPHER, /* node:crypto Decipheriv (scr_cipher.c) */ + SCR_DYNH_MESSAGE_EVENT, /* ScrEvent with data — BroadcastChannel's 'message' */ + SCR_DYNH_BROADCAST_CHANNEL, /* worker_threads BroadcastChannel (scr_worker_events.c) */ SCR_DYNH_COUNT, } ScrDynHandleTag; diff --git a/packages/runtime/src/scr_event_target.c b/packages/runtime/src/scr_event_target.c index 722d7e5bf..59f7ca9f2 100644 --- a/packages/runtime/src/scr_event_target.c +++ b/packages/runtime/src/scr_event_target.c @@ -785,7 +785,8 @@ static ScrEventObj *scr_event_obj_of(const ScrDyn *d); static ScrEvent *scr_event_of(const ScrDyn *d) { if (d && d->kind == SCR_DYN_HANDLE && - (d->v.handle.tag == SCR_DYNH_EVENT || d->v.handle.tag == SCR_DYNH_CUSTOM_EVENT)) { + (d->v.handle.tag == SCR_DYNH_EVENT || d->v.handle.tag == SCR_DYNH_CUSTOM_EVENT || + d->v.handle.tag == SCR_DYNH_MESSAGE_EVENT)) { return (ScrEvent *)d->v.handle.ptr; } ScrEventObj *obj = scr_event_obj_of(d); @@ -1079,6 +1080,17 @@ static ScrDyn *scr_event_get(void *ptr, const char *key, size_t len) { if (scr_et_key(key, len, "isTrusted")) return scr_dyn_new_bool(ev->trusted); if (ev->custom && scr_et_key(key, len, "detail")) return ev->detail ? scr_dyn_retain(ev->detail) : scr_dyn_new_null(); + if (ev->message) { + if (scr_et_key(key, len, "data")) return ev->detail ? scr_dyn_retain(ev->detail) : scr_dyn_new_null(); + if (scr_et_key(key, len, "origin") || scr_et_key(key, len, "lastEventId")) { + ScrStr *empty = scr_str_new("", 0); + ScrDyn *value = scr_dyn_new_str(empty); + scr_str_release(empty); + return value; + } + if (scr_et_key(key, len, "source")) return scr_dyn_new_null(); + if (scr_et_key(key, len, "ports")) return scr_dyn_new_arr(); + } return scr_et_method_value(key, len, false); } @@ -1172,6 +1184,16 @@ static const ScrDynHandleOps scr_event_ops = { .inspect_view = scr_event_inspect_view, }; +static const ScrDynHandleOps scr_message_event_ops = { + .cls = "MessageEvent", + .retain = scr_event_retain_v, + .release = scr_event_release_v, + .invoke = scr_event_invoke, + .get = scr_event_get, + .set = scr_event_set, + .inspect_view = scr_event_inspect_view, +}; + static const ScrDynHandleOps scr_custom_event_ops = { .cls = "CustomEvent", .retain = scr_event_retain_v, @@ -1493,6 +1515,7 @@ static void scr_et_install(void) { installed = true; scr_dyn_handle_install(SCR_DYNH_EVENT, &scr_event_ops); scr_dyn_handle_install(SCR_DYNH_CUSTOM_EVENT, &scr_custom_event_ops); + scr_dyn_handle_install(SCR_DYNH_MESSAGE_EVENT, &scr_message_event_ops); scr_dyn_handle_install(SCR_DYNH_EVENT_TARGET, &scr_event_target_ops); scr_event_ref_hooks = &scr_event_obj_ref_hooks; scr_et_register_teardown(); @@ -1592,6 +1615,46 @@ ScrDyn *scr_custom_event_new(ScrDyn *args) { return out; } +/* ── BroadcastChannel's EventTarget side ───────────────────────────── */ + +static ScrEventTargetCore *scr_et_broadcast_core_new(const char *cls) { + ScrEventTargetCore *core = scr_et_calloc(sizeof *core); + scr_et_core_init(core, 10, cls); + return core; +} + +static void scr_et_broadcast_core_free(ScrEventTargetCore *core) { + scr_et_core_drop(core); + free(core); +} + +/* the 'message' MessageEvent (not trusted, as in Node) with the data */ +static void scr_et_broadcast_dispatch(ScrEventTargetCore *core, ScrDyn *self, ScrDyn *data) { + ScrEvent *ev = scr_event_alloc(scr_str_new("message", 7), false); + ev->message = true; + ev->detail = scr_dyn_retain(data); + scr_event_track(ev); + ScrDyn *event = scr_dyn_new_handle(ev, SCR_DYNH_MESSAGE_EVENT); + scr_event_release_v(ev); + scr_et_dispatch(core, self, event); + scr_dyn_release(event); +} + +static ScrDyn *scr_et_broadcast_method_value(const char *name, size_t length) { + return scr_et_method_value(name, length, true); +} + +static const ScrEtBroadcastOps scr_et_broadcast_table = { + &scr_et_broadcast_core_new, &scr_et_broadcast_core_free, &scr_et_broadcast_dispatch, + &scr_et_target_method, &scr_et_broadcast_method_value, + &scr_et_handler_get, &scr_et_handler_set, +}; + +void scr_et_broadcast_install(void) { + scr_et_install(); + scr_et_broadcast_ops = &scr_et_broadcast_table; +} + bool scr_event_is(const ScrDyn *v, double kind) { if (v->kind == SCR_DYN_TYPED_REF) { /* Compiled subclasses extend Event or EventTarget (never CustomEvent). */ @@ -1600,7 +1663,8 @@ bool scr_event_is(const ScrDyn *v, double kind) { } if (v->kind != SCR_DYN_HANDLE) return false; ScrDynHandleTag tag = v->v.handle.tag; - if (kind == 0) return tag == SCR_DYNH_EVENT || tag == SCR_DYNH_CUSTOM_EVENT; + if (kind == 0) + return tag == SCR_DYNH_EVENT || tag == SCR_DYNH_CUSTOM_EVENT || tag == SCR_DYNH_MESSAGE_EVENT; if (kind == 1) return tag == SCR_DYNH_CUSTOM_EVENT; return tag == SCR_DYNH_EVENT_TARGET || (scr_et_signal_core_fn != NULL && tag == SCR_DYNH_ABORT_SIGNAL); diff --git a/packages/runtime/src/scr_event_target.h b/packages/runtime/src/scr_event_target.h index f218bbc9f..d93f075f1 100644 --- a/packages/runtime/src/scr_event_target.h +++ b/packages/runtime/src/scr_event_target.h @@ -39,9 +39,9 @@ typedef struct ScrEvent { size_t rc; ScrStr *type; ScrDyn *target; /* +1, NULL until dispatched */ - ScrDyn *detail; /* CustomEvent's detail (+1); NULL for Event */ + ScrDyn *detail; /* CustomEvent's detail, MessageEvent's data (+1); NULL for Event */ double time_stamp; - bool custom, bubbles, cancelable, composed, trusted; + bool custom, message, bubbles, cancelable, composed, trusted; bool default_prevented, propagation_stopped, stop, dispatching, in_passive; bool tracked; struct ScrEvent *tracked_prev, *tracked_next; @@ -82,6 +82,25 @@ extern SCR_TL ScrEventTargetCore *(*scr_et_signal_core_fn)(const ScrDyn *d, bool * which reaches the class's compiled methods. Without it a capsule's own * view answers. */ void scr_event_handle_event_reader(ScrDyn *reader); +/* BroadcastChannel's EventTarget side, which the worker events unit + * reaches through this table (that unit links without this one): a core + * of its own, dispatching a 'message' MessageEvent with the data, the + * EventTarget methods (false: not one of them), and the on + * attributes. scr_et_broadcast_install sets the table (defined in + * scr_json.c, which every program links). */ +typedef struct { + ScrEventTargetCore *(*core_new)(const char *cls); + void (*core_free)(ScrEventTargetCore *core); + void (*dispatch_message)(ScrEventTargetCore *core, ScrDyn *self, ScrDyn *data); + bool (*method)(ScrEventTargetCore *core, ScrDyn *self, const char *method, ScrDyn *const *args, + size_t argc, ScrDyn **out); + ScrDyn *(*method_value)(const char *name, size_t length); + ScrDyn *(*handler_get)(ScrEventTargetCore *core, const char *type); + void (*handler_set)(ScrEventTargetCore *core, const char *type, const ScrDyn *value); +} ScrEtBroadcastOps; +extern SCR_TL const ScrEtBroadcastOps *scr_et_broadcast_ops; +void scr_et_broadcast_install(void); + /* events.addAbortListener(signal, listener): +1 disposable, or NULL. */ ScrDyn *scr_events_add_abort_listener(ScrDyn *signal, ScrDyn *listener); diff --git a/packages/runtime/src/scr_events.c b/packages/runtime/src/scr_events.c index 02cbed7b6..6e809824a 100644 --- a/packages/runtime/src/scr_events.c +++ b/packages/runtime/src/scr_events.c @@ -544,6 +544,25 @@ ScrPromise *scr_stdin_next_chunk(void) { * consumer, so the pipe itself is the buffer (backpressure, not loss). */ static void scr_stdin_deliver(ScrBytes *chunk); +/* A chunk that arrived (moves): delivered, or buffered while paused or + * without a consumer. */ +static void scr_stdin_arrived(ScrBytes *chunk) { + if (scr_stdin_paused || (!scr_stdin_ndata && !scr_stdin_resumed && !scr_stdin_waiter)) { + if (scr_stdin_buffer) { + size_t before = scr_stdin_buffer->len; + ScrBytes *joined = scr_bytes_new(SCR_BYTES_U8, (double)(before + chunk->len)); + memcpy(joined->data, scr_stdin_buffer->data, before); + memcpy(joined->data + before, chunk->data, chunk->len); + scr_bytes_release(scr_stdin_buffer); + scr_bytes_release(chunk); + scr_stdin_buffer = joined; + } else scr_stdin_buffer = chunk; + return; + } + scr_stdin_deliver(chunk); + scr_bytes_release(chunk); +} + static void scr_stdin_service(void) { if (!scr_stdin_watching()) return; if (!scr_stdin_paused && scr_stdin_buffer) { @@ -557,6 +576,18 @@ static void scr_stdin_service(void) { if (!scr_stdin_buffer) scr_stdin_finish(true); return; } + if (scr_stdin_fed) { + /* the chunks the parent wrote to worker.stdin, one per pass like a + * read(2) */ + bool ended = false; + ScrBytes *chunk = scr_stdin_fed_take(&ended); + if (chunk) scr_stdin_arrived(chunk); + else if (ended) { + scr_stdin_read_eof = true; + if (!scr_stdin_buffer) scr_stdin_finish(true); + } + return; + } #ifdef _WIN32 /* The poll(2)-probe's win32 spelling, by handle type: a PIPE (the * harness/ssh shape) answers PeekNamedPipe — bytes available, or a @@ -622,20 +653,7 @@ static void scr_stdin_service(void) { } ScrBytes *chunk = scr_bytes_new(SCR_BYTES_U8, (double)n); memcpy(chunk->data, buf, (size_t)n); - if (scr_stdin_paused || (!scr_stdin_ndata && !scr_stdin_resumed && !scr_stdin_waiter)) { - if (scr_stdin_buffer) { - size_t before = scr_stdin_buffer->len; - ScrBytes *joined = scr_bytes_new(SCR_BYTES_U8, (double)(before + (size_t)n)); - memcpy(joined->data, scr_stdin_buffer->data, before); - memcpy(joined->data + before, buf, (size_t)n); - scr_bytes_release(scr_stdin_buffer); - scr_bytes_release(chunk); - scr_stdin_buffer = joined; - } else scr_stdin_buffer = chunk; - return; - } - scr_stdin_deliver(chunk); - scr_bytes_release(chunk); + scr_stdin_arrived(chunk); } static void scr_stdin_deliver(ScrBytes *chunk) { @@ -1200,8 +1218,11 @@ void scr_stdin_data_thunk_bytes(ScrClosure *cb, ScrBytes *chunk) { static bool scr_events_pending(void) { return scr_stdin_pending(); } +/* A worker's fed stdin has no descriptor to poll: its chunks arrive in + * the worker's mailbox, which the worker unit waits on while + * scr_stdin_fed_waiting answers true. */ static bool scr_events_watching(void) { - return (scr_context_is_main() && scr_sig_watched > 0) || scr_stdin_pending(); + return (scr_context_is_main() && scr_sig_watched > 0) || (!scr_stdin_fed && scr_stdin_pending()); } /* One dispatch pass at a loop turn: wake-pipe bytes are consumed (safe @@ -1249,7 +1270,12 @@ void scr_events_install(void) { static SCR_TL bool installed = false; if (installed) return; installed = true; - if (!scr_context_is_main()) scr_stdin_read_eof = true; + if (scr_stdin_fed) { + scr_stdin_fed_waiting = scr_stdin_pending; + if (scr_stdin_fed_attach) scr_stdin_fed_attach(); + } else if (!scr_context_is_main()) { + scr_stdin_read_eof = true; + } #ifdef __wasi__ int stdin_flags = fcntl(0, F_GETFL, 0); if (stdin_flags >= 0) (void)fcntl(0, F_SETFL, stdin_flags | O_NONBLOCK); diff --git a/packages/runtime/src/scr_exception.h b/packages/runtime/src/scr_exception.h index c9622ceb3..80fb98957 100644 --- a/packages/runtime/src/scr_exception.h +++ b/packages/runtime/src/scr_exception.h @@ -213,5 +213,10 @@ extern SCR_TL int (*scr_uncaught_exception_hook)(bool from_promise); bool scr_exc_handle_uncaught(bool from_promise); void scr_process_on_uncaught_exception(ScrDyn *fn, bool once, bool monitor); void scr_process_off_uncaught_exception(ScrDyn *fn, bool monitor); +/* The value Node reports for an unhandled rejection (scr_async_dyn.c): an + * error-like reason itself, otherwise an UnhandledPromiseRejection Error + * (code ERR_UNHANDLED_REJECTION) quoting the reason. Borrows; +1, NULL + * after a throw. */ +ScrDyn *scr_unhandled_rejection_error(ScrDyn *reason); #endif /* SCR_EXCEPTION_H */ diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 355165333..987fffde2 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -3505,6 +3505,9 @@ ScrDyn *scr_dyn_bind(ScrDyn *target, ScrDyn *const *args, size_t argc) { * they can box its handles. */ static SCR_TL const ScrDynHandleOps *scr_dynh_ops[SCR_DYNH_COUNT]; +/* BroadcastChannel's EventTarget table (scr_et_broadcast_install). */ +SCR_TL const ScrEtBroadcastOps *scr_et_broadcast_ops = NULL; + void scr_dyn_handle_install(ScrDynHandleTag tag, const ScrDynHandleOps *ops) { scr_dynh_ops[tag] = ops; } diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index d5b581ede..53f3e9181 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -1944,14 +1944,17 @@ SCR_TL void (*scr_process_exit_hook)(double code) = NULL; SCR_TL void (*scr_warning_emit_hook)(const char *name, const char *code, ScrStr *message) = NULL; SCR_TL void (*scr_stdin_destroy_hook)(void) = NULL; -void scr_process_set_exit_code(double code) { +/* process.exitCode's validation: a safe integer, or a RangeError + * (ERR_OUT_OF_RANGE). Node converts valid codes to signed int32 for + * exitCode and exit listeners; the OS observes the low eight bits. */ +static bool scr_process_exit_code_of(double code, int *out) { if (!isfinite(code) || trunc(code) != code) { char recv[48], msg[160]; scr_num_received(code, recv); int len = snprintf(msg, sizeof msg, "The value of \"code\" is out of range. It must be an integer. Received %s", recv); scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE"); - return; + return false; } if (fabs(code) > 9007199254740991.0) { char recv[48], msg[192]; @@ -1959,15 +1962,19 @@ void scr_process_set_exit_code(double code) { int len = snprintf(msg, sizeof msg, "The value of \"code\" is out of range. It must be >= -9007199254740991 && <= 9007199254740991. Received %s", recv); scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE"); - return; + return false; } - /* Node converts valid safe integers to signed int32 for exitCode and - * exit listeners. The OS subsequently observes the low eight bits. */ double low = fmod(code, 4294967296.0); if (low < 0) low += 4294967296.0; int64_t signed_code = (int64_t)low; if (signed_code > INT_MAX) signed_code -= 4294967296LL; - scr_exit_code_note((int)signed_code); + *out = (int)signed_code; + return true; +} + +void scr_process_set_exit_code(double code) { + int converted; + if (scr_process_exit_code_of(code, &converted)) scr_exit_code_note(converted); } double scr_process_exit_code_or_zero(void) { @@ -2025,6 +2032,11 @@ static void scr_detach_teardown(void) { #endif void scr_process_exit(double code) { + /* process.exit(code) assigns process.exitCode first, so a code that is + * not a safe integer throws its RangeError and the program continues. */ + int converted; + if (!scr_process_exit_code_of(code, &converted)) return; + code = converted; /* Node runs 'exit' listeners on explicit process.exit() too — they run * HERE, synchronously, before the teardown-free exit below. The hook is * non-NULL only when the events unit is linked (scr_events.c). */ diff --git a/packages/runtime/src/scr_lib.h b/packages/runtime/src/scr_lib.h index 64f3e77a5..d240aadbd 100644 --- a/packages/runtime/src/scr_lib.h +++ b/packages/runtime/src/scr_lib.h @@ -64,6 +64,23 @@ int scr_stdio_write_raw(int fd, const void *data, size_t len); /* `wide` marks string bytes that may hold lone surrogates, which become * U+FFFD when they reach the stream itself. */ extern SCR_TL bool (*scr_stdio_write_hook)(int fd, const void *data, size_t len, bool wide); +/* A worker created with the stdout or stderr option: answers true when it + * took the bytes for fd 1 or 2 instead of the process descriptor. */ +extern SCR_TL bool (*scr_stdio_capture)(int fd, const void *data, size_t len); +/* A worker created with the stdin option: process.stdin reads the chunks + * the parent writes to worker.stdin instead of fd 0. The worker's event + * dispatch queues them (scr_stdin_fed_push; NULL ends the input) and the + * stdin service takes them (+1, or NULL with *ended set once the input + * ended). scr_stdin_fed_attach (the worker unit) starts that dispatch + * when process.stdin is first used; scr_stdin_fed_waiting (the events + * unit) says whether process.stdin still wants data, which keeps the + * worker's loop waiting on its mailbox. */ +extern SCR_TL bool scr_stdin_fed; +extern SCR_TL void (*scr_stdin_fed_attach)(void); +extern SCR_TL bool (*scr_stdin_fed_waiting)(void); +void scr_stdin_fed_push(struct ScrBytes *chunk /* moves; NULL ends the input */); +struct ScrBytes *scr_stdin_fed_take(bool *ended); +void scr_stdin_fed_clear(void); /* process.stdout/.stderr .write — raw bytes (no newline or formatting; data * borrowed), promptly visible and ordered with console output. Constantly * true (the synchronous runtime never queues backpressure). */ diff --git a/packages/runtime/src/scr_mailbox.c b/packages/runtime/src/scr_mailbox.c index 89cb6ce83..f983bd289 100644 --- a/packages/runtime/src/scr_mailbox.c +++ b/packages/runtime/src/scr_mailbox.c @@ -128,6 +128,7 @@ ScrMailbox *scr_mailbox_retain(ScrMailbox *mailbox) { void scr_mail_event_free(ScrMailEvent *event) { if (!event) return; scr_message_free(event->message); + free(event->data); free(event); } @@ -177,6 +178,24 @@ ScrMailEvent *scr_mailbox_take(ScrMailbox *mailbox) { return event; } +ScrMailEvent *scr_mailbox_take_kind(ScrMailbox *mailbox, unsigned kind, uint64_t source) { + scr_mailbox_lock(mailbox); + ScrMailEvent **slot = &mailbox->head; + while (*slot && ((*slot)->kind != kind || (*slot)->source != source)) slot = &(*slot)->next; + ScrMailEvent *event = *slot; + if (event) { + *slot = event->next; + if (mailbox->tail == &event->next) mailbox->tail = slot; + event->next = NULL; + } + if (!mailbox->head) { + mailbox->tail = &mailbox->head; + scr_mailbox_drain(mailbox); + } + scr_mailbox_unlock(mailbox); + return event; +} + void scr_mailbox_close(ScrMailbox *mailbox) { scr_mailbox_lock(mailbox); mailbox->closed = true; @@ -420,3 +439,80 @@ void scr_channel_drop(ScrChannel *channel, int side) { scr_mail_event_free(event); } } + +/* ── BroadcastChannel registry ───────────────────────────────────────── */ + +/* Every open BroadcastChannel in the process, by name: each has a channel + * whose end 0 queues its incoming messages. */ +typedef struct ScrBroadcastEntry { + char *name; + size_t length; + ScrChannel *channel; /* +1 */ + struct ScrBroadcastEntry *next; +} ScrBroadcastEntry; + +static ScrBroadcastEntry *scr_broadcast_entries; +#ifdef _WIN32 +static SRWLOCK scr_broadcast_lock = SRWLOCK_INIT; +#define SCR_BROADCAST_LOCK() AcquireSRWLockExclusive(&scr_broadcast_lock) +#define SCR_BROADCAST_UNLOCK() ReleaseSRWLockExclusive(&scr_broadcast_lock) +#else +static pthread_mutex_t scr_broadcast_lock = PTHREAD_MUTEX_INITIALIZER; +#define SCR_BROADCAST_LOCK() (void)pthread_mutex_lock(&scr_broadcast_lock) +#define SCR_BROADCAST_UNLOCK() (void)pthread_mutex_unlock(&scr_broadcast_lock) +#endif + +void scr_broadcast_join(const char *name, size_t length, ScrChannel *channel) { + ScrBroadcastEntry *entry = calloc(1, sizeof(*entry)); + if (!entry) scr_trap("scriptc: out of memory\n"); + entry->name = malloc(length ? length : 1); + if (!entry->name) scr_trap("scriptc: out of memory\n"); + memcpy(entry->name, name, length); + entry->length = length; + entry->channel = scr_channel_retain(channel); + SCR_BROADCAST_LOCK(); + /* registration order is delivery order to the subscribers */ + ScrBroadcastEntry **tail = &scr_broadcast_entries; + while (*tail) tail = &(*tail)->next; + *tail = entry; + SCR_BROADCAST_UNLOCK(); +} + +void scr_broadcast_leave(ScrChannel *channel) { + ScrBroadcastEntry *gone = NULL; + SCR_BROADCAST_LOCK(); + for (ScrBroadcastEntry **at = &scr_broadcast_entries; *at; at = &(*at)->next) { + if ((*at)->channel != channel) continue; + gone = *at; + *at = gone->next; + break; + } + SCR_BROADCAST_UNLOCK(); + if (!gone) return; + scr_channel_release(gone->channel); + free(gone->name); + free(gone); +} + +/* The other open channels named `name` (+1 each, in registration order); + * the caller frees the array. */ +size_t scr_broadcast_peers(const char *name, size_t length, ScrChannel *self, ScrChannel ***out) { + size_t n = 0, cap = 0; + ScrChannel **peers = NULL; + SCR_BROADCAST_LOCK(); + for (ScrBroadcastEntry *entry = scr_broadcast_entries; entry; entry = entry->next) { + if (entry->channel == self || entry->length != length || + (length && memcmp(entry->name, name, length) != 0)) + continue; + if (n == cap) { + cap = cap ? cap * 2 : 4; + ScrChannel **grown = realloc(peers, cap * sizeof *grown); + if (!grown) scr_trap("scriptc: out of memory\n"); + peers = grown; + } + peers[n++] = scr_channel_retain(entry->channel); + } + SCR_BROADCAST_UNLOCK(); + *out = peers; + return n; +} diff --git a/packages/runtime/src/scr_mailbox.h b/packages/runtime/src/scr_mailbox.h index 75d99bbc8..678d17723 100644 --- a/packages/runtime/src/scr_mailbox.h +++ b/packages/runtime/src/scr_mailbox.h @@ -9,6 +9,8 @@ typedef struct ScrMailEvent { uint64_t source; int code; ScrMessage *message; + unsigned char *data; /* raw bytes (a worker's captured stdout or stderr), owned */ + size_t length; struct ScrMailEvent *next; } ScrMailEvent; @@ -19,6 +21,8 @@ void scr_mailbox_release(ScrMailbox *mailbox); * closed. Taking returns an owned event; no runtime object crosses a queue. */ bool scr_mailbox_post(ScrMailbox *mailbox, ScrMailEvent *event); ScrMailEvent *scr_mailbox_take(ScrMailbox *mailbox); +/* The first queued event with this kind and source, or NULL. */ +ScrMailEvent *scr_mailbox_take_kind(ScrMailbox *mailbox, unsigned kind, uint64_t source); void scr_mail_event_free(ScrMailEvent *event); void scr_mailbox_close(ScrMailbox *mailbox); bool scr_mailbox_pending(ScrMailbox *mailbox); @@ -46,4 +50,12 @@ size_t scr_channel_count(ScrChannel *channel, int side); uint64_t scr_channel_peer_closed(ScrChannel *channel, int side); /* the notice's order, 0: none */ void scr_channel_drop(ScrChannel *channel, int side); +/* BroadcastChannel: the process-wide registry of open channels by name. + * Each instance's channel queues its messages on end 0 (posts go through + * side 1). peers answers the others with the name (+1 each, array + * malloc'd). */ +void scr_broadcast_join(const char *name, size_t length, ScrChannel *channel); +void scr_broadcast_leave(ScrChannel *channel); +size_t scr_broadcast_peers(const char *name, size_t length, ScrChannel *self, ScrChannel ***out); + #endif diff --git a/packages/runtime/src/scr_message.c b/packages/runtime/src/scr_message.c index a0b3b8d4e..8268ee4d0 100644 --- a/packages/runtime/src/scr_message.c +++ b/packages/runtime/src/scr_message.c @@ -31,6 +31,7 @@ typedef struct { char *key; size_t length; size_t value; + bool hidden; /* an Error's non-enumerable or inherited property */ } ScrMessageProperty; typedef struct { @@ -73,6 +74,7 @@ typedef struct { ScrDyn *view; ScrDyn *keys; size_t cursor; + bool uncaught; /* an Error encoded as an uncaught exception */ } ScrMessageVisit; typedef struct { @@ -91,6 +93,7 @@ typedef struct { size_t depth; size_t stack_capacity; const ScrDyn *transfer; /* the transfer list (a dyn array), or NULL */ + bool uncaught; /* the next value is an uncaught exception or its cause */ } ScrMessageEncoder; static bool scr_message_listed(const ScrMessageEncoder *encoder, const ScrDyn *value) { @@ -211,7 +214,44 @@ static size_t scr_message_storage(ScrMessageEncoder *encoder, const ScrBytes *by return node; } +/* The nearest built-in constructor an uncaught Error keeps: Node's + * serializer knows Error and its six native subclasses. */ +static int scr_message_error_kind(const ScrError *error) { + static const int kinds[] = { + SCR_ERR_TYPE, SCR_ERR_RANGE, SCR_ERR_SYNTAX, SCR_ERR_REFERENCE, SCR_ERR_EVAL, SCR_ERR_URI, + }; + for (size_t i = 0; i < sizeof kinds / sizeof kinds[0]; i++) + if (scr_error_vts[kinds[i]].pre <= error->vt->pre && error->vt->pre <= scr_error_vts[kinds[i]].post) + return kinds[i]; + return SCR_ERR_ERROR; +} + +/* An uncaught Error's keys: name and message, which it may inherit, then + * its other own properties in order. */ +static ScrDyn *scr_message_uncaught_keys(const ScrDyn *view) { + ScrDyn *own = scr_dyn_get_own_property_names(view); + if (!own) return NULL; + ScrDyn *keys = scr_dyn_new_arr(); + static const char *const first[] = {"name", "message"}; + for (size_t i = 0; i < 2; i++) { + ScrStr *key = scr_str_new(first[i], strlen(first[i])); + scr_dyn_arr_push(keys, scr_dyn_new_str(key)); + scr_str_release(key); + } + for (size_t i = 0; i < own->v.arr.len; i++) { + const ScrStr *key = own->v.arr.items[i]->v.str; + if ((key->len == 4 && !memcmp(key->data, "name", 4)) || (key->len == 7 && !memcmp(key->data, "message", 7)) || + (key->len && key->data[0] == '%')) + continue; + scr_dyn_arr_push(keys, scr_dyn_retain(own->v.arr.items[i])); + } + scr_dyn_release(own); + return keys; +} + static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) { + bool uncaught = encoder->uncaught; + encoder->uncaught = false; const void *identity = NULL; unsigned domain = 0; switch (input->kind) { @@ -264,6 +304,16 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) ScrMessageNode *node = &encoder->message->nodes[id]; ScrError *error = scr_errdyn_err_of(input); if (!error && value != input) error = scr_errdyn_err_of(value); + if (error && uncaught && error->vt != &scr_error_vts[SCR_ERR_DOMEX]) { + node->kind = SCR_MESSAGE_ERROR; + node->number = scr_message_error_kind(error); + scr_error_release(error); + encoder->visits[id].uncaught = true; + encoder->visits[id].keys = scr_message_uncaught_keys(value); + if (!encoder->visits[id].keys) return SIZE_MAX; + scr_message_push(encoder, id); + return id; + } if (error) { node->kind = SCR_MESSAGE_ERROR; node->number = SCR_ERR_ERROR; @@ -355,7 +405,7 @@ unsupported: } static void scr_message_property(ScrMessageEncoder *encoder, size_t id, - const ScrStr *key, size_t value) { + const ScrStr *key, size_t value, bool hidden) { ScrMessageNode *node = &encoder->message->nodes[id]; if (node->count == node->capacity) { size_t capacity = scr_message_grow(node->capacity); @@ -366,7 +416,7 @@ static void scr_message_property(ScrMessageEncoder *encoder, size_t id, node->capacity = capacity; } node->properties[node->count++] = (ScrMessageProperty){ - (char *)scr_message_copy(key->data, key->len), key->len, value, + (char *)scr_message_copy(key->data, key->len), key->len, value, hidden, }; } @@ -521,9 +571,15 @@ static ScrMessage *scr_message_try_publish(const ScrDyn *value) { } static ScrMessage *scr_message_encode_with(const ScrDyn *value, const ScrDyn *transfer); +static ScrMessage *scr_message_encode_run(ScrMessageEncoder encoder, const ScrDyn *value); ScrMessage *scr_message_encode(const ScrDyn *value) { return scr_message_encode_with(value, NULL); } +ScrMessage *scr_message_encode_uncaught(const ScrDyn *value) { + ScrMessage *message = scr_message_alloc(1, sizeof(*message)); + return scr_message_encode_run((ScrMessageEncoder){.message = message, .uncaught = true}, value); +} + ScrMessage *scr_message_encode_transfer(const ScrDyn *value, const ScrDyn *transfer) { if (!transfer || transfer->kind != SCR_DYN_ARR || transfer->v.arr.len == 0) return scr_message_encode_with(value, NULL); @@ -552,21 +608,33 @@ static ScrMessage *scr_message_encode_with(const ScrDyn *value, const ScrDyn *tr ScrMessage *published = transfer ? NULL : scr_message_try_publish(value); if (published) return published; ScrMessage *message = scr_message_alloc(1, sizeof(*message)); - ScrMessageEncoder encoder = {.message = message, .transfer = transfer}; + return scr_message_encode_run((ScrMessageEncoder){.message = message, .transfer = transfer}, value); +} + +static ScrMessage *scr_message_encode_run(ScrMessageEncoder encoder, const ScrDyn *value) { + ScrMessage *message = encoder.message; if (scr_message_value(&encoder, value) == SIZE_MAX) goto done; while (encoder.depth && !scr_exc_pending()) { size_t id = encoder.stack[encoder.depth - 1]; ScrMessageVisit *visit = &encoder.visits[id]; if (visit->cursor == visit->keys->v.arr.len) { encoder.depth--; continue; } ScrDyn *key = visit->keys->v.arr.items[visit->cursor++]; - if (key->kind != SCR_DYN_STR || - (message->nodes[id].kind != SCR_MESSAGE_ERROR && !scr_dyn_property_is_enumerable(visit->view, key->v.str))) continue; + bool error = message->nodes[id].kind == SCR_MESSAGE_ERROR; + if (key->kind != SCR_DYN_STR || (!error && !scr_dyn_property_is_enumerable(visit->view, key->v.str))) continue; ScrDyn *child = scr_dyn_bag_get(visit->view, key->v.str, visit->view); if (!child || scr_exc_pending()) { scr_dyn_release(child); break; } + bool hidden = error; + if (visit->uncaught) { + /* Node keeps an uncaught Error's data properties except functions + * and symbols, and serializes its cause the same way. */ + if (child->kind == SCR_DYN_FUNC || child->kind == SCR_DYN_SYMBOL) { scr_dyn_release(child); continue; } + hidden = !scr_dyn_has_own(visit->view, key->v.str) || !scr_dyn_property_is_enumerable(visit->view, key->v.str); + encoder.uncaught = key->v.str->len == 5 && !memcmp(key->v.str->data, "cause", 5); + } size_t next = scr_message_value(&encoder, child); scr_dyn_release(child); if (next == SIZE_MAX) break; - scr_message_property(&encoder, id, key->v.str, next); + scr_message_property(&encoder, id, key->v.str, next, hidden); } done: for (size_t i = 0; i < message->count; i++) { @@ -710,7 +778,15 @@ ScrDyn *scr_message_decode(const ScrMessage *message) { } else scr_dyn_obj_set(values[i], property->key, property->length, value); } if (node->kind == SCR_MESSAGE_ERROR) { - for (size_t j = 0; j < values[i]->v.obj.len; j++) values[i]->v.obj.entries[j].enumerable = false; + for (size_t j = 0; j < values[i]->v.obj.len; j++) { + ScrDynEntry *entry = &values[i]->v.obj.entries[j]; + entry->enumerable = false; + for (size_t k = 0; k < node->count; k++) { + const ScrMessageProperty *property = &node->properties[k]; + if (!property->hidden && property->length == entry->key_len && !memcmp(property->key, entry->key, entry->key_len)) + entry->enumerable = true; + } + } ScrError *error = scr_errdyn_err_of(values[i]); scr_error_commit_dyn(error, values[i]); scr_error_release(error); diff --git a/packages/runtime/src/scr_message.h b/packages/runtime/src/scr_message.h index ba0a7391c..ffd155fe6 100644 --- a/packages/runtime/src/scr_message.h +++ b/packages/runtime/src/scr_message.h @@ -12,6 +12,12 @@ ScrMessage *scr_message_encode(const ScrDyn *value); * message (a port in the value that is not listed throws DataCloneError); * transfer is NULL or a dyn array. */ ScrMessage *scr_message_encode_transfer(const ScrDyn *value, const ScrDyn *transfer); +/* A worker's uncaught exception, as Node's error serializer sends it: an + * Error keeps the nearest of Error and its six native subclasses, and its + * name, message and other data properties (functions and symbols aside) + * with their enumerability, own or inherited; its cause encodes the same + * way. Other values encode as scr_message_encode encodes them. */ +ScrMessage *scr_message_encode_uncaught(const ScrDyn *value); /* MessagePort transfer, installed by the worker events unit: channel_of * answers a channel port's end (+1 channel; NULL for other values, side diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 153e6b36e..3fc0be120 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6314,6 +6314,15 @@ const ScrChildStreamOps scr_stream_child_ops = { scr_stream_write_done, scr_stream_final_done, }; +static ScrDyn *scr_stream_dyn_view_v(void *stream) { return scr_stream_dyn_view(stream); } + +/* new Worker() with the stdout or stderr option (readable.workerStdio) */ +void scr_stream_worker_stdio(void) { +#ifdef SCR_WORKERS + scr_worker_stdio_default(&scr_stream_child_ops, scr_stream_dyn_view_v); +#endif +} + static ScrStream *scr_stream_view_receiver(const ScrDyn *value) { if (value->kind == SCR_DYN_TYPED_REF && value->v.typed_ref.type_key_len > 7 && !memcmp(value->v.typed_ref.type_key, "object:", 7)) { diff --git a/packages/runtime/src/scr_stream.h b/packages/runtime/src/scr_stream.h index 1836c206d..82727c1dc 100644 --- a/packages/runtime/src/scr_stream.h +++ b/packages/runtime/src/scr_stream.h @@ -123,6 +123,7 @@ void scr_stream_init_passthrough(ScrStream *s, double rhwm, double whwm, bool au * (a subclass's overridden underscore-method wrappers, shadowed by * options callbacks per Node's instance-property rule) MOVE. */ ScrStream *scr_stream_new_readable_dyn(struct ScrDyn *opts); +void scr_stream_worker_stdio(void); ScrStream *scr_stream_new_writable_dyn(struct ScrDyn *opts); ScrStream *scr_stream_new_duplex_dyn(struct ScrDyn *opts); ScrStream *scr_stream_new_transform_dyn(struct ScrDyn *opts); diff --git a/packages/runtime/src/scr_worker.c b/packages/runtime/src/scr_worker.c index 9a57596f7..0c9a2d903 100644 --- a/packages/runtime/src/scr_worker.c +++ b/packages/runtime/src/scr_worker.c @@ -10,6 +10,7 @@ #include #else #include +#include #endif #if defined(__linux__) @@ -60,7 +61,11 @@ struct ScrWorkerThread { ScrMailbox *inbox; ScrMailbox *parent; ScrMessage *data; + /* data is [workerData, entries] when the parent had environment data */ + bool environment_data; ScrContextEnv *environment; + ScrStr *name; /* threadName: immortal copy shared by both threads */ + unsigned capture; /* 1 stdout, 2 stderr: writes go to the parent as events */ int argc; char **argv; bool joined; @@ -75,6 +80,7 @@ struct ScrWorkerThread { static atomic_uint_fast64_t scr_worker_next_id = 1; static SCR_TL ScrWorkerThread *scr_worker_current; static SCR_TL ScrDyn *scr_worker_local_data; +static SCR_TL ScrDyn *scr_worker_local_environment; /* SCRIPTC_WORKER_STATS=1 reports, as each worker thread exits, how long it * took to start, to run its script (runtime and module initialization @@ -115,6 +121,7 @@ void scr_worker_thread_release(ScrWorkerThread *worker) { scr_mailbox_release(worker->parent); scr_message_free(worker->data); scr_context_env_free(worker->environment); + free(worker->name); for (int i = 0; i < worker->argc; i++) free(worker->argv[i]); free(worker->argv); #ifdef SCR_EXC_FLAG @@ -125,23 +132,46 @@ void scr_worker_thread_release(ScrWorkerThread *worker) { static void scr_worker_data_cleanup(void) { ScrDyn *data = scr_worker_local_data; + ScrDyn *environment = scr_worker_local_environment; scr_worker_local_data = NULL; + scr_worker_local_environment = NULL; scr_dyn_release(data); + scr_dyn_release(environment); +} + +/* Decodes the start message once: workerData and, when the parent had + * environment data, its entries. */ +static bool scr_worker_decode_start(void) { + if (scr_worker_local_data) return true; + ScrDyn *data = scr_message_decode(scr_worker_current->data); + if (!data) return false; + if (scr_worker_current->environment_data) { + scr_worker_local_environment = scr_dyn_arr_at(data, 1); + ScrDyn *value = scr_dyn_arr_at(data, 0); + scr_dyn_release(data); + data = value; + } + scr_worker_local_data = data; + if (scr_context_atexit(scr_worker_data_cleanup) != 0) scr_trap("scriptc: out of memory\n"); + scr_message_free(scr_worker_current->data); + scr_worker_current->data = NULL; + return true; } ScrDyn *scr_worker_data(void) { if (!scr_worker_current) return scr_dyn_new_null(); - if (!scr_worker_local_data) { - ScrDyn *data = scr_message_decode(scr_worker_current->data); - if (!data) return NULL; - scr_worker_local_data = data; - if (scr_context_atexit(scr_worker_data_cleanup) != 0) scr_trap("scriptc: out of memory\n"); - scr_message_free(scr_worker_current->data); - scr_worker_current->data = NULL; - } + if (!scr_worker_decode_start()) return NULL; return scr_dyn_retain(scr_worker_local_data); } +ScrDyn *scr_worker_take_environment(void) { + if (!scr_worker_current || !scr_worker_current->environment_data) return NULL; + if (!scr_worker_decode_start()) return NULL; + ScrDyn *entries = scr_worker_local_environment; + scr_worker_local_environment = NULL; + return entries; +} + ScrMailbox *scr_worker_inbox(void) { return scr_worker_current ? scr_worker_current->inbox : NULL; } @@ -152,6 +182,18 @@ char **scr_worker_argv(void) { return scr_worker_current ? scr_worker_current->a uint64_t scr_worker_thread_id(const ScrWorkerThread *worker) { return worker->id; } +const ScrStr *scr_worker_thread_name(const ScrWorkerThread *worker) { return worker->name; } + +ScrDyn *scr_worker_thread_name_current(void) { + if (!scr_worker_current) { + ScrStr *empty = scr_str_new("", 0); + ScrDyn *name = scr_dyn_new_str(empty); + scr_str_release(empty); + return name; + } + return scr_dyn_new_str(scr_worker_current->name); +} + void scr_worker_thread_terminate(ScrWorkerThread *worker) { atomic_store_explicit(&worker->cancel, true, memory_order_relaxed); #ifdef SCR_EXC_FLAG @@ -187,16 +229,59 @@ void scr_worker_port_close(void) { atomic_store_explicit(&scr_worker_current->port_closed, true, memory_order_relaxed); } +static _Atomic(void (*)(void)) scr_worker_stdin_attach; + +void scr_worker_set_stdin_attach(void (*attach)(void)) { + atomic_store_explicit(&scr_worker_stdin_attach, attach, memory_order_relaxed); +} + +bool scr_worker_thread_post_stdin(ScrWorkerThread *worker, const void *data, size_t len, bool end) { + ScrMailEvent *event = scr_worker_event(SCR_WORKER_STDIN, 0, 0, NULL); + if (!end) { + event->data = malloc(len ? len : 1); + if (!event->data) scr_trap("scriptc: out of memory\n"); + memcpy(event->data, data, len); + event->length = len; + } + return scr_mailbox_post(worker->inbox, event); +} + bool scr_worker_post_parent(ScrMessage *message) { if (!scr_worker_current) { scr_message_free(message); return false; } return scr_mailbox_post(scr_worker_current->parent, scr_worker_event(SCR_WORKER_MESSAGE, scr_worker_current->id, 0, message)); } +/* The stdout and stderr options: a captured write reaches the parent's + * worker.stdout or worker.stderr in order with the worker's other events. */ +static bool scr_worker_capture(int fd, const void *data, size_t len) { + unsigned bit = fd == 2 ? 2 : 1; + if (!scr_worker_current || !(scr_worker_current->capture & bit)) return false; + if (!len) return true; + ScrMailEvent *event = scr_worker_event(bit == 2 ? SCR_WORKER_STDERR : SCR_WORKER_STDOUT, + scr_worker_current->id, 0, NULL); + event->data = malloc(len); + if (!event->data) scr_trap("scriptc: out of memory\n"); + memcpy(event->data, data, len); + event->length = len; + scr_mailbox_post(scr_worker_current->parent, event); + return true; +} + static void scr_worker_report_error(void) { ScrCaught *caught = scr_exc_take(); ScrDyn *value = scr_caught_to_dyn(caught); - ScrMessage *message = scr_message_encode(value); + if (scr_context_report_rejection) { + ScrDyn *error = scr_unhandled_rejection_error(value); + scr_dyn_release(value); + value = error; + } + ScrMessage *message = value ? scr_message_encode_uncaught(value) : NULL; + if (!message && value) { + /* Node falls back to the plain clone when a property does not clone. */ + scr_exc_clear(); + message = scr_message_encode(value); + } scr_dyn_release(value); scr_caught_release(caught); if (!message) { @@ -230,10 +315,16 @@ static void scr_worker_thread_run(ScrWorkerThread *worker) { worker->environment = NULL; scr_worker_current = worker; scr_context_report_error = scr_worker_report_error; + if (worker->capture & 3) scr_stdio_capture = scr_worker_capture; + if (worker->capture & 4) { + scr_stdin_fed = true; + scr_stdin_fed_attach = atomic_load_explicit(&scr_worker_stdin_attach, memory_order_relaxed); + } scr_mailbox_post(worker->parent, scr_worker_event(SCR_WORKER_ONLINE, worker->id, 0, NULL)); int code = worker->entry(worker->root); scr_context_note_script_end(); /* when the program frees nothing at exit */ scr_mailbox_close(worker->inbox); + scr_stdin_fed_clear(); /* chunks the worker never read */ scr_context_cleanup(); if (stats) { uint64_t now = scr_hrtime_ns(); @@ -241,6 +332,7 @@ static void scr_worker_thread_run(ScrWorkerThread *worker) { (unsigned long long)worker->id, (double)(started_ns - worker->spawned_ns) / 1e6, (double)(scr_context_script_end_ns() - started_ns) / 1e6, (double)(now - scr_context_script_end_ns()) / 1e6); } + scr_stdio_capture = NULL; scr_worker_current = NULL; scr_exc_alert_thread_exit(); #ifdef SCR_EXC_FLAG @@ -273,8 +365,10 @@ static void *scr_worker_thread_main(void *data) { #endif ScrWorkerThread *scr_worker_thread_start(ScrWorkerEntry entry, uint32_t root, - ScrMessage *data, ScrMailbox *parent, - ScrArr *arguments) { + ScrMessage *data, bool environment_data, + ScrMailbox *parent, ScrArr *arguments, + size_t stack_size, const ScrStr *name, + unsigned capture) { ScrWorkerThread *worker = calloc(1, sizeof(*worker)); if (!worker) scr_trap("scriptc: out of memory\n"); atomic_init(&worker->references, 2); /* owner and native thread */ @@ -290,7 +384,13 @@ ScrWorkerThread *scr_worker_thread_start(ScrWorkerEntry entry, uint32_t root, worker->entry = entry; worker->root = root; worker->data = data; + worker->environment_data = environment_data; + worker->capture = capture; worker->environment = scr_context_env_capture(); + worker->name = malloc(sizeof(ScrStr) + name->len + 1); + if (!worker->name) scr_trap("scriptc: out of memory\n"); + memcpy(worker->name, name, sizeof(ScrStr) + name->len + 1); + worker->name->rc = SIZE_MAX; worker->parent = scr_mailbox_retain(parent); if (arguments) { if (arguments->len > INT_MAX) scr_trap("scriptc: too many worker arguments\n"); @@ -309,16 +409,24 @@ ScrWorkerThread *scr_worker_thread_start(ScrWorkerEntry entry, uint32_t root, if (!worker->inbox) goto failed; if (scr_worker_stats()) worker->spawned_ns = scr_hrtime_ns(); #ifdef _WIN32 - worker->thread = (HANDLE)_beginthreadex(NULL, 0, scr_worker_thread_main, worker, 0, NULL); + worker->thread = (HANDLE)_beginthreadex(NULL, stack_size > UINT_MAX ? UINT_MAX : (unsigned)stack_size, + scr_worker_thread_main, worker, 0, NULL); if (!worker->thread) goto failed; #else /* An explicit size keeps recursion depth independent of the C library's * default thread stack (as small as 128 KiB with musl and 512 KiB on - * macOS): workers get the 8 MiB a main thread usually has. Pages are - * committed only as the stack grows. */ + * macOS): workers get the 8 MiB a main thread usually has, or + * resourceLimits.stackSizeMb. Pages are committed only as the stack + * grows. */ pthread_attr_t attr; if (pthread_attr_init(&attr) != 0) goto failed; - (void)pthread_attr_setstacksize(&attr, (size_t)8 << 20); + if (!stack_size) stack_size = (size_t)8 << 20; + long page = sysconf(_SC_PAGESIZE); + if (page > 0 && stack_size % (size_t)page) stack_size += (size_t)page - stack_size % (size_t)page; + if (pthread_attr_setstacksize(&attr, stack_size) != 0) { + pthread_attr_destroy(&attr); + goto failed; + } int started = pthread_create(&worker->thread, &attr, scr_worker_thread_main, worker); pthread_attr_destroy(&attr); if (started != 0) goto failed; @@ -327,6 +435,7 @@ ScrWorkerThread *scr_worker_thread_start(ScrWorkerEntry entry, uint32_t root, failed: for (int i = 0; i < worker->argc; i++) free(worker->argv[i]); free(worker->argv); + free(worker->name); scr_context_env_free(worker->environment); scr_mailbox_release(worker->inbox); scr_mailbox_release(worker->parent); diff --git a/packages/runtime/src/scr_worker.h b/packages/runtime/src/scr_worker.h index 008159fa2..fa2d58efa 100644 --- a/packages/runtime/src/scr_worker.h +++ b/packages/runtime/src/scr_worker.h @@ -18,24 +18,46 @@ enum { SCR_WORKER_WAKE, SCR_WORKER_STDOUT, SCR_WORKER_STDERR, + SCR_WORKER_STDIN, /* parent to worker: a worker.stdin chunk, or its end (no data) */ }; -/* Consumes data, including on failure. Borrows the parent's mailbox. */ +/* Consumes data, including on failure. Borrows the parent's mailbox. With + * environment_data, data encodes [workerData, environment entries]. A + * stack_size of 0 selects the default 8 MiB thread stack. capture (1 + * stdout, 2 stderr) posts the worker's writes to those descriptors to the + * parent as SCR_WORKER_STDOUT/STDERR events; 4 (stdin) has the worker's + * process.stdin read what scr_worker_thread_post_stdin sends. */ ScrWorkerThread *scr_worker_thread_start(ScrWorkerEntry entry, uint32_t root, - ScrMessage *data, ScrMailbox *parent, - ScrArr *arguments); + ScrMessage *data, bool environment_data, + ScrMailbox *parent, ScrArr *arguments, + size_t stack_size, const ScrStr *name, + unsigned capture); ScrWorkerThread *scr_worker_thread_retain(ScrWorkerThread *worker); void scr_worker_thread_release(ScrWorkerThread *worker); /* Join is owner-only and idempotent. The caller holds a reference. */ void scr_worker_thread_join(ScrWorkerThread *worker); void scr_worker_thread_terminate(ScrWorkerThread *worker); uint64_t scr_worker_thread_id(const ScrWorkerThread *worker); +/* The Worker's threadName (immortal, owned by the thread record). */ +const ScrStr *scr_worker_thread_name(const ScrWorkerThread *worker); /* Posting consumes the message even after the destination has closed. */ bool scr_worker_thread_post(ScrWorkerThread *worker, ScrMessage *message); +/* A worker.stdin chunk (data copied), or with end the end of the input. + * False once the worker's inbox has closed. */ +bool scr_worker_thread_post_stdin(ScrWorkerThread *worker, const void *data, size_t len, bool end); +/* The worker event unit's function that starts a worker's event dispatch, + * which queues the stdin chunks. The unit stores it before it starts a + * worker with the stdin option; that worker installs it as + * scr_stdin_fed_attach. */ +void scr_worker_set_stdin_attach(void (*attach)(void)); bool scr_worker_post_parent(ScrMessage *message); void scr_worker_port_close(void); /* Current-thread access: inbox is borrowed, data is a retained local value. */ ScrMailbox *scr_worker_inbox(void); +/* The parent's environment data entries ([key, value, ...], +1) on the + * first call in a worker; NULL afterwards, in the main thread, when the + * parent had none, and after a throw. */ +ScrDyn *scr_worker_take_environment(void); void scr_loop_set_workers(bool (*pending)(void), bool (*ready)(void), void (*dispatch)(void), int (*pollfd)(void), void (*wait)(double)); /* After a dispatch: true keeps the loop pass delivering (a MessagePort poll diff --git a/packages/runtime/src/scr_worker.test.c b/packages/runtime/src/scr_worker.test.c index 12065b43d..a50fd2fe2 100644 --- a/packages/runtime/src/scr_worker.test.c +++ b/packages/runtime/src/scr_worker.test.c @@ -95,7 +95,9 @@ int main(void) { ScrMessage *wire = scr_message_encode(input); scr_dyn_release(input); assert(wire && !scr_exc_pending()); - workers[i] = scr_worker_thread_start(entry, i, wire, mailbox, NULL); + ScrStr *name = scr_str_new("WorkerThread", 12); + workers[i] = scr_worker_thread_start(entry, i, wire, false, mailbox, NULL, 0, name, 0); + scr_str_release(name); assert(workers[i] && !scr_exc_pending()); assert(scr_worker_thread_id(workers[i]) != 0); } diff --git a/packages/runtime/src/scr_worker.test.ts b/packages/runtime/src/scr_worker.test.ts index edcca4eaa..2d2cbcae2 100644 --- a/packages/runtime/src/scr_worker.test.ts +++ b/packages/runtime/src/scr_worker.test.ts @@ -28,6 +28,7 @@ test.skipIf(process.platform === "win32")( "scr_worker.c", "scr_mailbox.c", "scr_message.c", + "scr_async_dyn.c", ...EXECUTABLE_RUNTIME_SOURCES, ].map((name) => join(import.meta.dirname, name)), ...(process.platform === "linux" ? ["-lm"] : []), diff --git a/packages/runtime/src/scr_worker_events.c b/packages/runtime/src/scr_worker_events.c index 51fbce59f..6ad62802e 100644 --- a/packages/runtime/src/scr_worker_events.c +++ b/packages/runtime/src/scr_worker_events.c @@ -25,6 +25,21 @@ typedef struct ScrWorkerView { uint64_t close_gen; /* the poll generation close() ran in */ size_t phase_left; /* messages this poll phase still delivers */ bool phase_close; /* the other end's close, delivered this phase */ + /* A BroadcastChannel: its name and EventTarget core; its channel's end 0 + * queues what the other instances with the name post. */ + bool broadcast; + ScrStr *name; + ScrEventTargetCore *et; + /* A Worker's stdout/stderr streams (the stdout and stderr options) and + * their checked-dynamic boxes, made on first read */ + ScrStream *stdio[2]; + ScrDyn *stdio_box[2]; + bool stdio_captured[2]; + /* worker.stdin (the stdin option): a Writable whose chunks go to the + * worker's process.stdin, and its box */ + ScrStream *stdin_stream; + ScrDyn *stdin_box; + bool stdin_captured; struct ScrWorkerView *next; } ScrWorkerView; @@ -47,16 +62,89 @@ static const char *const scr_worker_method_names[] = { "listenerCount", "close", "start", }; static SCR_TL ScrDyn *scr_worker_methods[sizeof scr_worker_method_names / sizeof scr_worker_method_names[0]]; +static const char *const scr_broadcast_method_names[] = { + "postMessage", "close", "ref", "unref", "addEventListener", "removeEventListener", "dispatchEvent", +}; +static SCR_TL ScrDyn *scr_broadcast_methods[sizeof scr_broadcast_method_names / sizeof scr_broadcast_method_names[0]]; + + +/* The stream unit's half of worker.stdout, worker.stderr and + * worker.stdin, installed by main when the program reads them as streams + * (scr_worker_stdio_install; a box the program has no type for is NULL). */ +static SCR_TL const ScrChildStreamOps *scr_worker_stdio_ops; +static SCR_TL ScrDyn *(*scr_worker_stdio_box)(void *); +static SCR_TL ScrDyn *(*scr_worker_stdin_box)(void *); + +void scr_worker_stdio_install(const ScrChildStreamOps *ops, ScrDyn *(*readable_box)(void *), + ScrDyn *(*writable_box)(void *)) { + scr_worker_stdio_ops = ops; + scr_worker_stdio_box = readable_box; + scr_worker_stdin_box = writable_box; +} + +/* A Worker with the stdout, stderr or stdin option in a program that has + * no typed Readable or Writable box: the streams go through the stream + * unit's live view. */ +void scr_worker_stdio_default(const ScrChildStreamOps *ops, ScrDyn *(*view)(void *)) { + if (!scr_worker_stdio_ops) scr_worker_stdio_ops = ops; + if (!scr_worker_stdio_box) scr_worker_stdio_box = view; + if (!scr_worker_stdin_box) scr_worker_stdin_box = view; +} + +/* worker.stdin: each chunk written goes to the worker as an + * SCR_WORKER_STDIN event, and end() sends the end of the input. The + * callbacks hold the thread record, not the view (the view owns the + * stream). Writes after the worker exited are dropped. */ +static void *scr_worker_thread_retain_v(void *thread) { return scr_worker_thread_retain(thread); } +static void scr_worker_thread_release_v(void *thread) { scr_worker_thread_release(thread); } + +static void scr_worker_stdin_write(ScrClosure *cb, ScrStream *stream, ScrBytes *chunk) { + ScrWorkerThread *thread = scr_box_get_ref(cb->caps[0]); /* +1 */ + /* an empty chunk pushes nothing in Node's process.stdin */ + if (chunk->len) scr_worker_thread_post_stdin(thread, chunk->data, chunk->len, false); + scr_worker_thread_release(thread); + scr_worker_stdio_ops->write_done(stream, NULL); +} + +static void scr_worker_stdin_final(ScrClosure *cb, ScrStream *stream) { + ScrWorkerThread *thread = scr_box_get_ref(cb->caps[0]); /* +1 */ + scr_worker_thread_post_stdin(thread, NULL, 0, true); + scr_worker_thread_release(thread); + scr_worker_stdio_ops->final_done(stream, NULL); +} + +static ScrClosure *scr_worker_stdin_callback(ScrWorkerThread *thread, void *fire) { + ScrClosure *cb = scr_closure_new(fire, 1); + cb->caps[0] = scr_box_new_obj(scr_worker_thread_retain_v, scr_worker_thread_release_v, NULL); + scr_box_set_ref(cb->caps[0], scr_worker_thread_retain(thread)); + return cb; +} + +static ScrStream *scr_worker_stdin_new(ScrWorkerThread *thread) { + return scr_worker_stdio_ops->writable( + scr_worker_stdin_callback(thread, (void *)scr_worker_stdin_write), scr_worker_stdin_write, + scr_worker_stdin_callback(thread, (void *)scr_worker_stdin_final), scr_worker_stdin_final); +} static void scr_worker_view_trace(void *ptr, ScrTraceVisit visit, void *ctx) { - visit(((ScrWorkerView *)ptr)->events, ctx); - visit(((ScrWorkerView *)ptr)->termination, ctx); + ScrWorkerView *view = ptr; + visit(view->events, ctx); + visit(view->termination, ctx); + for (int i = 0; i < 2; i++) { + visit(view->stdio[i], ctx); + visit(view->stdio_box[i], ctx); + } + visit(view->stdin_stream, ctx); + visit(view->stdin_box, ctx); } static void scr_worker_view_gcfree(void *ptr) { ScrWorkerView *view = ptr; scr_worker_thread_release(view->thread); + if (view->broadcast && view->channel && !view->closed) scr_broadcast_leave(view->channel); scr_channel_release(view->channel); + if (view->name) scr_str_release(view->name); + if (view->et) scr_et_broadcast_ops->core_free(view->et); while (view->queued_head) { ScrMailEvent *event = view->queued_head; view->queued_head = event->next; @@ -70,6 +158,12 @@ static void scr_worker_view_destroy(void *ptr) { ScrWorkerView *view = ptr; scr_emitter_release(view->events); scr_promise_release(view->termination); + for (int i = 0; i < 2; i++) { + if (view->stdio[i]) scr_worker_stdio_ops->release(view->stdio[i]); + scr_dyn_release(view->stdio_box[i]); + } + if (view->stdin_stream) scr_worker_stdio_ops->release(view->stdin_stream); + scr_dyn_release(view->stdin_box); scr_worker_view_gcfree(ptr); } @@ -125,6 +219,70 @@ static bool scr_worker_empty_transfer(const ScrDyn *value) { return value->kind == SCR_DYN_UNDEF || (value->kind == SCR_DYN_ARR && value->v.arr.len == 0); } +/* ── markAsUntransferable ─────────────────────────────────────────────── */ + +/* An ArrayBuffer's mark lives on its storage (Buffer pool slabs carry it + * from creation, as in Node); other marked objects stay listed, retained, + * for this thread's lifetime. A typed array shares its owner's storage with + * its ArrayBuffer, so views are listed by their own identity. */ +static SCR_TL ScrDyn **scr_untransferable; +static SCR_TL size_t scr_untransferable_count; +static SCR_TL size_t scr_untransferable_capacity; + +static void scr_untransferable_cleanup(void) { + for (size_t i = 0; i < scr_untransferable_count; i++) scr_dyn_release(scr_untransferable[i]); + free(scr_untransferable); + scr_untransferable = NULL; + scr_untransferable_count = scr_untransferable_capacity = 0; +} + +static bool scr_untransferable_same(const ScrDyn *a, const ScrDyn *b) { + if (a->kind != b->kind) return false; + switch (a->kind) { + case SCR_DYN_BYTES: return a->v.bytes == b->v.bytes; + case SCR_DYN_HANDLE: return a->v.handle.ptr == b->v.handle.ptr; + case SCR_DYN_TYPED_REF: return a->v.typed_ref.ptr == b->v.typed_ref.ptr; + default: return scr_dyn_strict_eq(a, b); + } +} + +/* typeof value is "object" or "function", and value is not null */ +static bool scr_untransferable_object(const ScrDyn *value) { + switch (value->kind) { + case SCR_DYN_UNDEF: case SCR_DYN_NULL: case SCR_DYN_BOOL: case SCR_DYN_NUM: + case SCR_DYN_STR: case SCR_DYN_BIGINT: case SCR_DYN_SYMBOL: return false; + default: return true; + } +} + +bool scr_worker_is_marked_untransferable(ScrDyn *value) { + if (!scr_untransferable_object(value)) return false; + if (scr_array_buffer_is(value) || scr_shared_array_buffer_is(value)) + return ((ScrBytes *)value->v.handle.ptr)->untransferable; + for (size_t i = 0; i < scr_untransferable_count; i++) + if (scr_untransferable_same(scr_untransferable[i], value)) return true; + return false; +} + +/* markAsUntransferable(value): primitives are left as they are */ +void scr_worker_mark_untransferable(ScrDyn *value) { + if (!scr_untransferable_object(value) || scr_worker_is_marked_untransferable(value)) return; + if (scr_array_buffer_is(value) || scr_shared_array_buffer_is(value)) { + ((ScrBytes *)value->v.handle.ptr)->untransferable = true; + return; + } + if (scr_untransferable_count == scr_untransferable_capacity) { + if (!scr_untransferable_capacity && scr_context_atexit(scr_untransferable_cleanup) != 0) + scr_trap("scriptc: out of memory\n"); + size_t capacity = scr_untransferable_capacity ? scr_untransferable_capacity * 2 : 8; + ScrDyn **values = realloc(scr_untransferable, capacity * sizeof *values); + if (!values) scr_trap("scriptc: out of memory\n"); + scr_untransferable = values; + scr_untransferable_capacity = capacity; + } + scr_untransferable[scr_untransferable_count++] = scr_dyn_retain(value); +} + /* postMessage's transfer argument: an array, or { transfer } (+1, or NULL * when empty) */ static ScrDyn *scr_worker_transfer_list(ScrDyn *arg) { @@ -145,6 +303,14 @@ static ScrDyn *scr_worker_transfer_list(ScrDyn *arg) { return result; } if (value->kind == SCR_DYN_ARR && value->v.arr.len > 0) { + for (size_t i = 0; i < value->v.arr.len; i++) { + ScrDyn *item = value->v.arr.items[i]; + if (item && scr_worker_is_marked_untransferable(item)) { + scr_dyn_release(own); + scr_throw_domex("DataCloneError", "Cannot transfer object of unsupported type."); + return NULL; + } + } ScrDyn *result = scr_dyn_retain(value); scr_dyn_release(own); return result; @@ -295,6 +461,26 @@ static ScrDyn *scr_worker_view_get(void *ptr, const char *key, size_t length) { ScrWorkerView *view = ptr; if (!view->port && length == 8 && !memcmp(key, "threadId", 8)) return scr_dyn_new_num(view->closed ? -1 : (double)scr_worker_thread_id(view->thread)); + /* Node reports the running worker's V8 heap configuration; an exited + * worker answers {}. */ + if (!view->port && length == 5 && !memcmp(key, "stdin", 5)) { + if (!view->stdin_stream) return scr_dyn_new_null(); + if (!view->stdin_box) view->stdin_box = scr_worker_stdin_box(view->stdin_stream); + return scr_dyn_retain(view->stdin_box); + } + if (!view->port && length == 6 && (!memcmp(key, "stdout", 6) || !memcmp(key, "stderr", 6))) { + int i = key[3] == 'e' ? 1 : 0; + if (!view->stdio_captured[i]) + return scr_worker_refusal(i ? "worker.stderr without the stderr option is not supported yet" + : "worker.stdout without the stdout option is not supported yet"); + if (!view->stdio[i]) return scr_dyn_new_null(); + if (!view->stdio_box[i]) view->stdio_box[i] = scr_worker_stdio_box(view->stdio[i]); + return scr_dyn_retain(view->stdio_box[i]); + } + if (!view->port && length == 10 && !memcmp(key, "threadName", 10)) + return view->closed ? scr_dyn_new_null() : scr_dyn_new_str((ScrStr *)scr_worker_thread_name(view->thread)); + if (!view->port && length == 14 && !memcmp(key, "resourceLimits", 14)) + return view->closed ? scr_dyn_new_obj() : scr_worker_refusal("worker.resourceLimits is not supported yet"); for (size_t i = 0; i < sizeof scr_worker_methods / sizeof scr_worker_methods[0]; i++) { const char *name = scr_worker_method_names[i]; if (strlen(name) != length || memcmp(name, key, length)) continue; @@ -312,6 +498,8 @@ static ScrDyn *scr_worker_view_get(void *ptr, const char *key, size_t length) { } static bool scr_workers_pending(void) { + /* a worker's process.stdin waiting for worker.stdin chunks */ + if (scr_stdin_fed && scr_stdin_fed_waiting && scr_stdin_fed_waiting()) return true; for (ScrWorkerView *view = scr_worker_views; view; view = view->next) if (view->referenced) return true; for (ScrWorkerView *view = scr_channel_ports; view; view = view->next) @@ -412,7 +600,13 @@ static bool scr_channel_dispatch(void) { } scr_worker_view_retain(view); ScrDyn *argument = event->message ? scr_message_decode(event->message) : NULL; - if (argument) scr_worker_port_emit(view, "message", argument); + if (argument && view->broadcast) { + ScrDyn *self = scr_dyn_new_handle(view, SCR_DYNH_BROADCAST_CHANNEL); + scr_et_broadcast_ops->dispatch_message(view->et, self, argument); + scr_dyn_release(self); + } else if (argument) { + scr_worker_port_emit(view, "message", argument); + } scr_dyn_release(argument); scr_mail_event_free(event); scr_worker_view_release(view); @@ -483,6 +677,31 @@ static void scr_worker_dispatch(void) { } else event = scr_mailbox_take(scr_worker_events); if (!event) return; if (event->kind == SCR_WORKER_WAKE) { scr_mail_event_free(event); return; } + if (event->kind == SCR_WORKER_STDIN) { + ScrBytes *chunk = NULL; + if (event->data) { + chunk = scr_bytes_new(SCR_BYTES_U8, (double)event->length); + memcpy(chunk->data, event->data, event->length); + chunk->is_buffer = true; + } + scr_stdin_fed_push(chunk); + scr_mail_event_free(event); + return; + } + if (event->kind == SCR_WORKER_STDOUT || event->kind == SCR_WORKER_STDERR) { + ScrWorkerView *source = scr_worker_views; + while (source && scr_worker_thread_id(source->thread) != event->source) source = source->next; + ScrStream *stream = source ? source->stdio[event->kind == SCR_WORKER_STDERR] : NULL; + if (stream) { + ScrBytes *chunk = scr_bytes_new(SCR_BYTES_U8, (double)event->length); + memcpy(chunk->data, event->data, event->length); + chunk->is_buffer = true; + scr_worker_stdio_ops->push(stream, chunk); + scr_bytes_release(chunk); + } + scr_mail_event_free(event); + return; + } ScrWorkerView *view = scr_worker_port; if (event->source) { view = scr_worker_views; @@ -522,6 +741,11 @@ static void scr_worker_dispatch(void) { scr_dyn_this_pop(); scr_str_release(name); } + /* Node ends worker.stdout and worker.stderr as the worker exits: their + * 'end' events follow 'exit'. */ + if (event->kind == SCR_WORKER_EXIT) + for (int i = 0; i < 2; i++) + if (view->stdio[i]) scr_worker_stdio_ops->end(view->stdio[i]); scr_dyn_release(argument); scr_worker_view_release(view); scr_mail_event_free(event); @@ -547,17 +771,36 @@ static void scr_worker_events_cleanup(void) { scr_channel_ports = view->next; view->next = NULL; if (view->channel) scr_channel_set_owner(view->channel, view->side, NULL, SCR_WORKER_WAKE); + /* a BroadcastChannel's name and listeners go now: program values + * may still hold the handle past this teardown */ + if (view->broadcast) { + if (!view->closed) { + view->closed = true; + scr_broadcast_leave(view->channel); + } + if (view->name) scr_str_release(view->name); + view->name = NULL; + if (view->et) scr_et_broadcast_ops->core_free(view->et); + view->et = NULL; + } scr_worker_view_release(view); } for (size_t i = 0; i < sizeof scr_worker_methods / sizeof scr_worker_methods[0]; i++) { scr_dyn_release(scr_worker_methods[i]); scr_worker_methods[i] = NULL; } + for (size_t i = 0; i < sizeof scr_broadcast_methods / sizeof scr_broadcast_methods[0]; i++) { + scr_dyn_release(scr_broadcast_methods[i]); + scr_broadcast_methods[i] = NULL; + } scr_mailbox_release(scr_worker_events); scr_worker_events = NULL; } static void scr_port_ops_install(void); +static bool scr_worker_events_install(void); + +static void scr_worker_stdin_attach(void) { (void)scr_worker_events_install(); } static bool scr_worker_events_install(void) { if (scr_worker_events) return true; @@ -647,6 +890,151 @@ ScrDyn *scr_worker_message_channel(void) { return object; } +/* ── BroadcastChannel ───────────────────────────────────────────────── */ + + +static ScrDyn *scr_broadcast_invoke(void *ptr, ScrDyn *self, const char *method, + ScrDyn *const *args, size_t argc, const char *what) { + (void)what; + ScrWorkerView *view = ptr; + if (!strcmp(method, "postMessage")) { + if (view->closed) { + scr_throw_domex("InvalidStateError", "BroadcastChannel is closed."); + return NULL; + } + if (!argc) { + static const char message[] = "The \"message\" argument must be specified"; + scr_throw_error_msg_code(SCR_ERR_TYPE, message, sizeof message - 1, "ERR_MISSING_ARGS"); + return NULL; + } + ScrMessage *first = scr_message_encode(args[0]); + if (!first) return NULL; + ScrChannel **peers = NULL; + size_t n = scr_broadcast_peers(view->name->data, view->name->len, view->channel, &peers); + for (size_t i = 0; i < n; i++) { + ScrMessage *message = i == 0 ? first : scr_message_encode(args[0]); + if (i == 0) first = NULL; + if (message) scr_channel_post(peers[i], 1, message, SCR_WORKER_MESSAGE, SCR_WORKER_WAKE); + scr_channel_release(peers[i]); + } + free(peers); + scr_message_free(first); + return scr_exc_pending() ? NULL : scr_dyn_retain(scr_dyn_undefined()); + } + if (!strcmp(method, "close")) { + if (!view->closed) { + view->closed = true; + scr_broadcast_leave(view->channel); + scr_channel_drop(view->channel, 0); + } + return scr_dyn_retain(scr_dyn_undefined()); + } + if (!strcmp(method, "ref") || !strcmp(method, "unref")) { + view->referenced = !strcmp(method, "ref"); + return scr_dyn_retain(self); + } + ScrDyn *out = NULL; + if (scr_et_broadcast_ops->method(view->et, self, method, args, argc, &out)) return out; + return scr_worker_refusal("This BroadcastChannel method is not supported yet"); +} + +static ScrDyn *scr_broadcast_method_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + ScrDyn *self = scr_dyn_this_get(); + ScrDyn *result = NULL; + if (self->kind != SCR_DYN_HANDLE || self->v.handle.tag != SCR_DYNH_BROADCAST_CHANNEL) { + static const char message[] = "Illegal invocation"; + scr_throw_error_msg_code(SCR_ERR_TYPE, message, sizeof message - 1, "ERR_INVALID_THIS"); + } else { + size_t method = (size_t)scr_box_get_f64(closure->caps[0]); + result = scr_broadcast_invoke(self->v.handle.ptr, self, scr_broadcast_method_names[method], args, + argc, "BroadcastChannel method"); + } + scr_dyn_release(self); + return result; +} + +static ScrDyn *scr_broadcast_get(void *ptr, const char *key, size_t length) { + ScrWorkerView *view = ptr; + if (length == 4 && !memcmp(key, "name", 4)) return scr_dyn_new_str(view->name); + if ((length == 9 && !memcmp(key, "onmessage", 9)) || + (length == 14 && !memcmp(key, "onmessageerror", 14))) { + char type[16]; + memcpy(type, key + 2, length - 2); + type[length - 2] = '\0'; + return scr_et_broadcast_ops->handler_get(view->et, type); + } + for (size_t i = 0; i < sizeof scr_broadcast_methods / sizeof scr_broadcast_methods[0]; i++) { + const char *name = scr_broadcast_method_names[i]; + if (strlen(name) != length || memcmp(name, key, length)) continue; + if (!scr_broadcast_methods[i]) { + ScrClosure *closure = scr_closure_new(NULL, 1); + closure->caps[0] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(closure->caps[0], (double)i); + scr_broadcast_methods[i] = scr_dyn_new_func(closure, scr_broadcast_method_call, 0, "", name); + } + return scr_dyn_retain(scr_broadcast_methods[i]); + } + return NULL; +} + +static bool scr_broadcast_set(void *ptr, const char *key, size_t length, const ScrDyn *value) { + ScrWorkerView *view = ptr; + if ((length == 9 && !memcmp(key, "onmessage", 9)) || + (length == 14 && !memcmp(key, "onmessageerror", 14))) { + char type[16]; + memcpy(type, key + 2, length - 2); + type[length - 2] = '\0'; + scr_et_broadcast_ops->handler_set(view->et, type, value); + return true; + } + return false; +} + +/* new BroadcastChannel(name): open and referenced until close() or + * unref(); args is the argument vector as one dyn array */ +ScrDyn *scr_worker_broadcast_channel(ScrDyn *args) { + if (!scr_worker_events_install()) return NULL; + if (args->kind != SCR_DYN_ARR || args->v.arr.len == 0) { + static const char message[] = "The \"name\" argument must be specified"; + scr_throw_error_msg_code(SCR_ERR_TYPE, message, sizeof message - 1, "ERR_MISSING_ARGS"); + return NULL; + } + ScrStr *name = scr_dyn_string_coerce_js(args->v.arr.items[0]); + if (!name) return NULL; + static SCR_TL bool installed = false; + if (!installed) { + installed = true; + static const ScrDynHandleOps broadcast_ops = { + .cls = "BroadcastChannel", .retain = scr_worker_view_retain, .release = scr_worker_view_release, + .invoke = scr_broadcast_invoke, .get = scr_broadcast_get, .set = scr_broadcast_set, + }; + scr_dyn_handle_install(SCR_DYNH_BROADCAST_CHANNEL, &broadcast_ops); + } + ScrChannel *channel = scr_channel_new(); + ScrWorkerView *view = scr_channel_port_new(channel, 0); + scr_channel_release(channel); + view->broadcast = true; + view->name = name; + view->et = scr_et_broadcast_ops->core_new("BroadcastChannel"); + view->started = true; + view->referenced = true; + scr_broadcast_join(name->data, name->len, view->channel); + return scr_dyn_new_handle(view, SCR_DYNH_BROADCAST_CHANNEL); +} + +/* A port's next queued message. For parentPort: the messages held until + * start(), then the inbox's next message from the parent (events from this + * thread's own workers stay queued). */ +static ScrMailEvent *scr_port_take(ScrWorkerView *view) { + if (view->channel) return scr_channel_take(view->channel, view->side); + ScrMailEvent *event = view->queued_head; + if (!event) return scr_mailbox_take_kind(scr_worker_events, SCR_WORKER_MESSAGE, 0); + view->queued_head = event->next; + if (!view->queued_head) view->queued_tail = NULL; + event->next = NULL; + return event; +} + /* receiveMessageOnPort(port): { message } of the next queued message, or * undefined */ ScrDyn *scr_worker_receive_message_on_port(ScrDyn *port) { @@ -656,8 +1044,7 @@ ScrDyn *scr_worker_receive_message_on_port(ScrDyn *port) { scr_throw_error_msg_code(SCR_ERR_TYPE, message, sizeof message - 1, "ERR_INVALID_ARG_TYPE"); return NULL; } - if (!view->channel) return scr_worker_refusal("receiveMessageOnPort on parentPort is not supported yet"); - ScrMailEvent *event = view->closed || view->detached ? NULL : scr_channel_take(view->channel, view->side); + ScrMailEvent *event = view->closed || view->detached ? NULL : scr_port_take(view); if (!event) return scr_dyn_retain(scr_dyn_undefined()); ScrDyn *value = event->message ? scr_message_decode(event->message) : NULL; scr_mail_event_free(event); @@ -667,6 +1054,124 @@ ScrDyn *scr_worker_receive_message_on_port(ScrDyn *port) { return object; } +/* ── environment data ─────────────────────────────────────────────────── */ + +/* setEnvironmentData's map for this thread: keys compare with + * SameValueZero, and a deleted key re-added goes last. A worker starts + * from a clone of its parent's entries taken by new Worker(). */ +typedef struct { + ScrDyn *key; + ScrDyn *value; +} ScrEnvironmentEntry; +static SCR_TL ScrEnvironmentEntry *scr_environment; +static SCR_TL size_t scr_environment_count; +static SCR_TL size_t scr_environment_capacity; +static SCR_TL bool scr_environment_ready; + +static void scr_environment_cleanup(void) { + for (size_t i = 0; i < scr_environment_count; i++) { + scr_dyn_release(scr_environment[i].key); + scr_dyn_release(scr_environment[i].value); + } + free(scr_environment); + scr_environment = NULL; + scr_environment_count = scr_environment_capacity = 0; + scr_environment_ready = false; +} + +static void scr_environment_append(ScrDyn *key, ScrDyn *value) { + if (scr_environment_count == scr_environment_capacity) { + size_t capacity = scr_environment_capacity ? scr_environment_capacity * 2 : 4; + ScrEnvironmentEntry *entries = realloc(scr_environment, capacity * sizeof *entries); + if (!entries) scr_trap("scriptc: out of memory\n"); + scr_environment = entries; + scr_environment_capacity = capacity; + } + scr_environment[scr_environment_count++] = (ScrEnvironmentEntry){key, value}; +} + +/* This thread's entries, the inherited ones decoded on first use. */ +static bool scr_environment_load(void) { + if (scr_environment_ready) return true; + ScrDyn *inherited = scr_worker_take_environment(); + if (scr_exc_pending()) return false; + scr_environment_ready = true; + if (scr_context_atexit(scr_environment_cleanup) != 0) scr_trap("scriptc: out of memory\n"); + for (size_t i = 0; inherited && i + 1 < inherited->v.arr.len; i += 2) + scr_environment_append(scr_dyn_arr_at(inherited, (double)i), scr_dyn_arr_at(inherited, (double)i + 1)); + scr_dyn_release(inherited); + return true; +} + +static bool scr_environment_key_eq(const ScrDyn *a, const ScrDyn *b) { + if (a->kind == SCR_DYN_NUM && b->kind == SCR_DYN_NUM) + return a->v.num == b->v.num || (a->v.num != a->v.num && b->v.num != b->v.num); + if (a->kind == SCR_DYN_TYPED_REF && b->kind == SCR_DYN_TYPED_REF) + return a->v.typed_ref.ptr == b->v.typed_ref.ptr; + return scr_dyn_strict_eq(a, b); +} + +static size_t scr_environment_find(const ScrDyn *key) { + for (size_t i = 0; i < scr_environment_count; i++) + if (scr_environment_key_eq(scr_environment[i].key, key)) return i; + return SIZE_MAX; +} + +/* setEnvironmentData(key, value): undefined deletes the key. */ +void scr_worker_set_environment_data(ScrDyn *key, ScrDyn *value) { + if (!scr_environment_load()) return; + size_t index = scr_environment_find(key); + if (value->kind == SCR_DYN_UNDEF) { + if (index == SIZE_MAX) return; + scr_dyn_release(scr_environment[index].key); + scr_dyn_release(scr_environment[index].value); + memmove(&scr_environment[index], &scr_environment[index + 1], + (scr_environment_count - index - 1) * sizeof *scr_environment); + scr_environment_count--; + return; + } + if (index != SIZE_MAX) { + scr_dyn_release(scr_environment[index].value); + scr_environment[index].value = scr_dyn_retain(value); + return; + } + scr_environment_append(scr_dyn_retain(key), scr_dyn_retain(value)); +} + +ScrDyn *scr_worker_get_environment_data(ScrDyn *key) { + if (!scr_environment_load()) return NULL; + size_t index = scr_environment_find(key); + return scr_dyn_retain(index == SIZE_MAX ? scr_dyn_undefined() : scr_environment[index].value); +} + +/* new Worker()'s start message: workerData alone, or [workerData, + * [key, value, ...]] when this thread has environment data, cloned in one + * message as Node clones both in one postMessage. */ +static ScrMessage *scr_worker_start_message(ScrDyn *data, ScrDyn *transfer, bool *environment_data) { + *environment_data = false; + if (!scr_environment_load()) return NULL; + if (!scr_environment_count) return scr_message_encode_transfer(data, transfer); + ScrDyn *entries = scr_dyn_new_arr(); + for (size_t i = 0; i < scr_environment_count; i++) { + scr_dyn_arr_push(entries, scr_dyn_retain(scr_environment[i].key)); + scr_dyn_arr_push(entries, scr_dyn_retain(scr_environment[i].value)); + } + ScrDyn *start = scr_dyn_new_arr(); + scr_dyn_arr_push(start, scr_dyn_retain(data)); + scr_dyn_arr_push(start, entries); + ScrMessage *message = scr_message_encode_transfer(start, transfer); + scr_dyn_release(start); + *environment_data = message != NULL; + return message; +} + +/* worker_threads.resourceLimits: {} in the main thread, as Node; a worker's + * values are its V8 heap configuration. */ +ScrDyn *scr_worker_resource_limits(void) { + if (scr_context_is_main()) return scr_dyn_new_obj(); + return scr_worker_refusal("resourceLimits in a worker is not supported yet"); +} + ScrDyn *scr_worker_parent_port(void) { if (scr_context_is_main()) return scr_dyn_new_null(); if (!scr_worker_events_install()) return NULL; @@ -709,11 +1214,42 @@ static ScrArr *scr_worker_arguments(ScrStr *filename, ScrDyn *argv) { return arguments; } +/* resourceLimits: Node reads the four numbers when the option is an object + * and ignores other values. stackSizeMb sizes the thread's stack (at least + * 192 KiB, as Node); the V8 heap limits are refused. */ +static bool scr_worker_stack_size(ScrDyn *limits, size_t *stack_size) { + if (limits->kind == SCR_DYN_TYPED_REF) { + ScrDyn *view = scr_dyn_typed_ref_materialize(limits); + bool ok = view && !scr_exc_pending() && scr_worker_stack_size(view, stack_size); + scr_dyn_release(view); + return ok; + } + if (limits->kind != SCR_DYN_OBJ) return true; + static const char *const heap[] = {"maxOldGenerationSizeMb", "maxYoungGenerationSizeMb", "codeRangeSizeMb"}; + for (size_t i = 0; i < sizeof heap / sizeof heap[0]; i++) { + const ScrDyn *value = scr_dyn_obj_get(limits, heap[i], strlen(heap[i])); + if (value && value->kind == SCR_DYN_NUM) { + scr_worker_refusal("Worker resourceLimits heap limits are not supported yet"); + return false; + } + } + const ScrDyn *megabytes = scr_dyn_obj_get(limits, "stackSizeMb", 11); + if (megabytes && megabytes->kind == SCR_DYN_NUM && megabytes->v.num > 0) { + double bytes = megabytes->v.num * 1048576.0; + if (bytes < 192.0 * 1024) bytes = 192.0 * 1024; + *stack_size = bytes >= (double)(SIZE_MAX / 2) ? SIZE_MAX / 2 : (size_t)bytes; + } + return true; +} + static ScrDyn *scr_worker_new_options(double root, ScrStr *filename, ScrDyn *options) { if (!scr_worker_events_install()) return NULL; ScrDyn *data = scr_dyn_undefined(); ScrDyn *argv = scr_dyn_undefined(); ScrDyn *transfer_list = scr_dyn_undefined(); + ScrDyn *limits = scr_dyn_undefined(); + ScrDyn *name = scr_dyn_undefined(); + unsigned capture = 0; if (options->kind != SCR_DYN_UNDEF) { if (options->kind != SCR_DYN_OBJ) { scr_dyn_arg_type_fail("options", "object", options); @@ -725,21 +1261,52 @@ static ScrDyn *scr_worker_new_options(double root, ScrStr *filename, ScrDyn *opt if (entry->key_len == 10 && !memcmp(entry->key, "workerData", 10)) data = entry->value; else if (entry->key_len == 4 && !memcmp(entry->key, "argv", 4)) argv = entry->value; else if (entry->key_len == 12 && !memcmp(entry->key, "transferList", 12)) transfer_list = entry->value; + else if (entry->key_len == 14 && !memcmp(entry->key, "resourceLimits", 14)) limits = entry->value; + else if (entry->key_len == 4 && !memcmp(entry->key, "name", 4)) name = entry->value; + else if (entry->key_len == 6 && !memcmp(entry->key, "stdout", 6)) capture |= scr_dyn_truthy(entry->value) ? 1 : 0; + else if (entry->key_len == 6 && !memcmp(entry->key, "stderr", 6)) capture |= scr_dyn_truthy(entry->value) ? 2 : 0; + else if (entry->key_len == 5 && !memcmp(entry->key, "stdin", 5)) capture |= scr_dyn_truthy(entry->value) ? 4 : 0; else return scr_worker_refusal("This Worker constructor option is not supported yet"); } } + size_t stack_size = 0; + if (!scr_worker_stack_size(limits, &stack_size)) return NULL; ScrArr *arguments = scr_worker_arguments(filename, argv); if (!arguments) return NULL; + /* Node: a truthy name must be a string, trimmed; otherwise WorkerThread */ + ScrStr *thread_name; + if (scr_dyn_truthy(name)) { + if (name->kind != SCR_DYN_STR) { + scr_arr_release(arguments); + scr_dyn_prop_type_fail("options.name", "of type string", name); + return NULL; + } + thread_name = scr_str_trim(name->v.str); + } else { + thread_name = scr_str_new("WorkerThread", 12); + } ScrDyn *transfer = scr_worker_transfer_list(transfer_list); - if (scr_exc_pending()) { scr_arr_release(arguments); return NULL; } - ScrMessage *wire = scr_message_encode_transfer(data, transfer); + if (scr_exc_pending()) { scr_arr_release(arguments); scr_str_release(thread_name); return NULL; } + bool environment_data; + ScrMessage *wire = scr_worker_start_message(data, transfer, &environment_data); + if (capture & 4) scr_worker_set_stdin_attach(scr_worker_stdin_attach); scr_dyn_release(transfer); - if (!wire) { scr_arr_release(arguments); return NULL; } - ScrWorkerThread *thread = scr_worker_thread_start(sc_worker_entry, (uint32_t)root, wire, scr_worker_events, arguments); + if (!wire) { scr_arr_release(arguments); scr_str_release(thread_name); return NULL; } + ScrWorkerThread *thread = scr_worker_thread_start(sc_worker_entry, (uint32_t)root, wire, environment_data, + scr_worker_events, arguments, stack_size, thread_name, + capture); + scr_str_release(thread_name); scr_arr_release(arguments); if (!thread) return NULL; ScrWorkerView *view = scr_worker_view_new(false); view->thread = thread; + for (int i = 0; i < 2; i++) { + view->stdio_captured[i] = (capture >> i) & 1; + /* without the stream unit nothing can read the stream: the output is dropped */ + if (view->stdio_captured[i] && scr_worker_stdio_ops) view->stdio[i] = scr_worker_stdio_ops->readable(); + } + view->stdin_captured = capture & 4; + if (view->stdin_captured && scr_worker_stdio_ops) view->stdin_stream = scr_worker_stdin_new(thread); view->next = scr_worker_views; scr_worker_views = view; return scr_dyn_new_handle(view, SCR_DYNH_WORKER); diff --git a/tests/corpus/5800-broadcast-channel.ts b/tests/corpus/5800-broadcast-channel.ts new file mode 100644 index 000000000..648d2caed --- /dev/null +++ b/tests/corpus/5800-broadcast-channel.ts @@ -0,0 +1,35 @@ +import { BroadcastChannel } from "node:worker_threads"; + +// BroadcastChannel within one thread: delivery to every other channel with +// the name (not the sender), per channel in creation order before +// setImmediate, MessageEvent fields, listeners, and the errors. +const a = new BroadcastChannel("o"); +const b = new BroadcastChannel("o"); +const c = new BroadcastChannel("o"); +const other = new BroadcastChannel("p"); +const log = (n: string) => (e: MessageEvent) => + console.log(n, JSON.stringify(e.data), e.type, e.origin === "", e.lastEventId === "", e.source, e.isTrusted, e.target === (n === "a" ? a : n === "b" ? b : c)); +a.onmessage = log("a"); +b.onmessage = log("b"); +c.onmessage = log("c"); +c.addEventListener("message", (e: Event) => console.log("c listener", JSON.stringify((e as MessageEvent).data))); +other.onmessage = () => console.log("other got (should not)"); +a.postMessage("from a"); +b.postMessage({ from: "b" }); +console.log("name", a.name, typeof b.onmessage, b.onmessageerror); +const named = new BroadcastChannel(String(42)); +console.log("coerced", named.name); +named.close(); +try { + named.postMessage(1); +} catch (err) { + const e = err as Error; + console.log(e.name, e.message); +} +setImmediate(() => { + console.log("immediate"); + a.close(); + b.close(); + c.close(); + other.close(); +}); diff --git a/tests/corpus/5801-broadcast-channel.cjs b/tests/corpus/5801-broadcast-channel.cjs new file mode 100644 index 000000000..9fd8c759c --- /dev/null +++ b/tests/corpus/5801-broadcast-channel.cjs @@ -0,0 +1,30 @@ +'use strict'; +// BroadcastChannel in JavaScript: error codes, the MessageEvent's ports, +// once and removed listeners, ref()/unref() returning the channel, and an +// unref'd channel that does not keep the process alive. +const { BroadcastChannel } = require('node:worker_threads'); + +for (const f of [ + () => new BroadcastChannel(), + () => { const c = new BroadcastChannel('x'); try { c.postMessage(); } finally { c.close(); } }, + () => { const c = new BroadcastChannel('x'); c.close(); c.close(); c.postMessage(1); }, +]) { + try { + f(); + console.log('ok'); + } catch (e) { + console.log(e.name, e.code, e.message); + } +} +const a = new BroadcastChannel('n'); +const b = new BroadcastChannel('n'); +const removed = () => console.log('removed listener ran'); +b.addEventListener('message', (e) => console.log('once', e.data, Array.isArray(e.ports), e.ports.length), { once: true }); +b.addEventListener('message', removed); +b.removeEventListener('message', removed); +b.onmessage = (e) => console.log('onmessage', e.data, e.target === b, this === undefined); +console.log('ref returns', a.ref() === a, a.unref() === a, b.unref() === b); +a.postMessage(1); +a.postMessage(2); +setTimeout(() => console.log('never: unref channels do not hold the loop'), 10000).unref(); +setImmediate(() => console.log('immediate')); diff --git a/tests/corpus/5802-broadcast-channel-workers.ts b/tests/corpus/5802-broadcast-channel-workers.ts new file mode 100644 index 000000000..2d6673537 --- /dev/null +++ b/tests/corpus/5802-broadcast-channel-workers.ts @@ -0,0 +1,25 @@ +import { BroadcastChannel, Worker, isMainThread } from "node:worker_threads"; + +// BroadcastChannel across threads: the main thread's channel and a +// worker's channel with the same name hear each other, a sender never +// hears its own message, and closing both lets the worker exit. +if (isMainThread) { + const bc = new BroadcastChannel("jobs"); + bc.onmessage = (e: MessageEvent) => { + console.log("main got", JSON.stringify(e.data)); + if (e.data === "ready") bc.postMessage("work"); + if (e.data === "done:work") { + bc.postMessage("bye"); + bc.close(); + } + }; + const worker = new Worker(new URL(import.meta.url)); + worker.on("exit", (code: number) => console.log("exit", code)); +} else { + const bc = new BroadcastChannel("jobs"); + bc.onmessage = (e: MessageEvent) => { + if (e.data === "work") bc.postMessage("done:" + e.data); + if (e.data === "bye") bc.close(); + }; + bc.postMessage("ready"); +} diff --git a/tests/corpus/5803-worker-environment-data.ts b/tests/corpus/5803-worker-environment-data.ts new file mode 100644 index 000000000..4debbbe3e --- /dev/null +++ b/tests/corpus/5803-worker-environment-data.ts @@ -0,0 +1,53 @@ +import { Worker, getEnvironmentData, isMainThread, parentPort, setEnvironmentData, workerData } from "node:worker_threads"; + +// setEnvironmentData/getEnvironmentData: keys compare with SameValueZero, +// undefined deletes, and each new Worker starts from a clone of its +// parent's entries taken at construction, which it passes on to its own +// workers. +if (isMainThread) { + console.log("missing", getEnvironmentData("missing")); + setEnvironmentData("a", 1); + setEnvironmentData("config", { list: [1, 2], name: "x" }); + setEnvironmentData(42, "number key"); + setEnvironmentData(NaN, "nan key"); + setEnvironmentData(-0, "zero key"); + const key = { k: 1 }; + setEnvironmentData(key, "object key"); + const shared = { v: 1 }; + setEnvironmentData("shared", shared); + console.log(getEnvironmentData("a"), getEnvironmentData(42), getEnvironmentData(NaN), getEnvironmentData(0)); + console.log("object key", getEnvironmentData(key), getEnvironmentData({ k: 1 })); + console.log("same value", getEnvironmentData("shared") === shared); + setEnvironmentData("gone", 5); + setEnvironmentData("gone", undefined); + setEnvironmentData("gone too", 5); + setEnvironmentData("gone too"); + console.log("deleted", getEnvironmentData("gone"), getEnvironmentData("gone too")); + + const first = new Worker(new URL(import.meta.url), { workerData: "first" }); + setEnvironmentData("a", 2); + first.on("message", (m: unknown) => console.log("first", JSON.stringify(m))); + first.on("exit", (code: number) => { + console.log("first exit", code, getEnvironmentData("a"), getEnvironmentData("set by worker")); + const second = new Worker(new URL(import.meta.url), { workerData: "second" }); + second.on("message", (m: unknown) => console.log("second", JSON.stringify(m))); + second.on("exit", (c: number) => console.log("second exit", c)); + }); +} else if (workerData === "first" || workerData === "second") { + parentPort!.postMessage([ + getEnvironmentData("a"), + getEnvironmentData("config"), + getEnvironmentData(42), + getEnvironmentData(NaN), + getEnvironmentData(0), + getEnvironmentData("gone"), + ]); + setEnvironmentData("set by worker", true); + setEnvironmentData("a", 10); + if (workerData === "second") { + const nested = new Worker(new URL(import.meta.url), { workerData: "nested" }); + nested.on("message", (m: unknown) => parentPort!.postMessage({ nested: m })); + } +} else { + parentPort!.postMessage([getEnvironmentData("set by worker"), getEnvironmentData("a"), getEnvironmentData("shared")]); +} diff --git a/tests/corpus/5804-worker-environment-data.cjs b/tests/corpus/5804-worker-environment-data.cjs new file mode 100644 index 000000000..e16fe248d --- /dev/null +++ b/tests/corpus/5804-worker-environment-data.cjs @@ -0,0 +1,26 @@ +'use strict'; +// Environment data in CommonJS: a worker sees its parent's entries, a +// value that cannot be cloned makes new Worker() throw DataCloneError, +// and the thread keeps its own entries after that failure. +const { Worker, getEnvironmentData, isMainThread, parentPort, setEnvironmentData } = require('node:worker_threads'); + +if (isMainThread) { + setEnvironmentData('greeting', 'hello'); + setEnvironmentData('list', [1, [2, 3]]); + const worker = new Worker(__filename); + worker.on('message', (m) => console.log('worker saw', JSON.stringify(m))); + worker.on('exit', (code) => { + console.log('exit', code); + setEnvironmentData('callback', () => 1); + try { + new Worker(__filename); + console.log('constructed'); + } catch (err) { + console.log('caught', err.name); + } + setEnvironmentData('callback'); + console.log('kept', getEnvironmentData('greeting'), typeof getEnvironmentData('callback')); + }); +} else { + parentPort.postMessage({ greeting: getEnvironmentData('greeting'), list: getEnvironmentData('list') }); +} diff --git a/tests/corpus/5805-worker-receive-message-parent-port.ts b/tests/corpus/5805-worker-receive-message-parent-port.ts new file mode 100644 index 000000000..99d429169 --- /dev/null +++ b/tests/corpus/5805-worker-receive-message-parent-port.ts @@ -0,0 +1,43 @@ +import { Worker, isMainThread, parentPort, receiveMessageOnPort, workerData } from "node:worker_threads"; + +// receiveMessageOnPort(parentPort) in a worker takes the parent's messages +// one at a time, before and between 'message' listener deliveries, and +// answers undefined once the queue is empty. +if (isMainThread) { + const flag = new Int32Array(new SharedArrayBuffer(4)); + const worker = new Worker(new URL(import.meta.url), { workerData: flag }); + worker.postMessage("a"); + worker.postMessage({ b: 2 }); + worker.postMessage("c"); + worker.on("message", (m: unknown) => { + console.log("main got", JSON.stringify(m)); + if (m === "ready") { + worker.postMessage("d"); + worker.postMessage("e"); + Atomics.store(flag, 0, 1); + Atomics.notify(flag, 0); + } + }); + worker.on("exit", (code: number) => console.log("exit", code)); +} else { + const flag = workerData as Int32Array; + const port = parentPort!; + let first = receiveMessageOnPort(port); + while (first === undefined) first = receiveMessageOnPort(port); + port.postMessage(["first", first]); + port.postMessage(["second", receiveMessageOnPort(port)]); + port.on("message", (v: unknown) => { + port.postMessage(["listener", v]); + if (v === "c") { + port.postMessage("ready"); + Atomics.wait(flag, 0, 0); + let next = receiveMessageOnPort(port); + while (next === undefined) next = receiveMessageOnPort(port); + port.postMessage(["sync", next]); + } + if (v === "e") { + port.postMessage(["empty", receiveMessageOnPort(port) === undefined]); + port.close(); + } + }); +} diff --git a/tests/corpus/5806-worker-resource-limits.ts b/tests/corpus/5806-worker-resource-limits.ts new file mode 100644 index 000000000..a4f5f7390 --- /dev/null +++ b/tests/corpus/5806-worker-resource-limits.ts @@ -0,0 +1,38 @@ +import { Worker, isMainThread, parentPort, resourceLimits, workerData } from "node:worker_threads"; + +// resourceLimits is {} in the main thread and after a worker exits. A +// worker's resourceLimits.stackSizeMb sets its thread's stack size: deep +// recursion still ends in a catchable RangeError. A stackSizeMb of 0 keeps +// the default stack. +function depth(n: number, path: number[]): number { + path.push(n); + const result = n === 0 ? 0 : 1 + depth(n - 1, path); + path.pop(); + return result; +} + +if (isMainThread) { + console.log("main", JSON.stringify(resourceLimits), Object.keys(resourceLimits).length); + const worker = new Worker(new URL(import.meta.url), { + workerData: "small", + resourceLimits: { stackSizeMb: 1 }, + }); + worker.on("message", (m: unknown) => console.log("small stack", JSON.stringify(m))); + worker.on("exit", (code: number) => { + console.log("exit", code, JSON.stringify(worker.resourceLimits)); + const other = new Worker(new URL(import.meta.url), { + workerData: "default", + resourceLimits: { stackSizeMb: 0 }, + }); + other.on("message", (m: unknown) => console.log("default stack", JSON.stringify(m))); + other.on("exit", (c: number) => console.log("exit", c)); + }); +} else { + let overflow = "none"; + try { + depth(1e7, []); + } catch (error) { + if (error instanceof RangeError) overflow = error.name; + } + parentPort!.postMessage({ data: workerData, overflow, shallow: depth(1000, []) }); +} diff --git a/tests/corpus/5807-worker-error-values.ts b/tests/corpus/5807-worker-error-values.ts new file mode 100644 index 000000000..e2edabfee --- /dev/null +++ b/tests/corpus/5807-worker-error-values.ts @@ -0,0 +1,68 @@ +import { Worker, isMainThread, workerData } from "node:worker_threads"; + +// A worker's uncaught exception reaches the 'error' listener as Node's +// error serializer sends it: an Error keeps the nearest built-in +// constructor, its name (own or inherited), message, cause and other data +// properties with their enumerability; other values clone as messages do. +class ConfigError extends RangeError { + setting: string; + constructor(message: string, setting: string) { + super(message); + this.name = "ConfigError"; + this.setting = setting; + } +} + +const cases = ["props", "subclass", "aggregate", "cause", "string", "null", "number", "object", "runtime"]; + +if (isMainThread) { + let next = 0; + const run = (): void => { + const name = cases[next++]; + if (name === undefined) return; + const worker = new Worker(new URL(import.meta.url), { workerData: name }); + worker.on("error", (e: any) => { + if (typeof e !== "object" || e === null) { + console.log(name, typeof e, e); + return; + } + console.log(name, e instanceof Error, e instanceof RangeError, e instanceof TypeError, e.name, e.message); + console.log(" ", JSON.stringify(e), e.code, e.setting, e.errors?.length, e.cause?.message, e.cause?.detail); + }); + worker.on("exit", (code: number) => { + console.log(" ", "exit", code); + run(); + }); + }; + run(); +} else { + switch (workerData) { + case "props": { + const e: any = new Error("with props"); + e.code = "E_PROPS"; + e.extra = { y: 2 }; + throw e; + } + case "subclass": + throw new ConfigError("bad setting", "port"); + case "aggregate": + throw new AggregateError([new Error("a"), new TypeError("b")], "several"); + case "cause": { + const inner: any = new Error("inner"); + inner.detail = 7; + throw new Error("outer", { cause: inner }); + } + case "string": + throw "plain string"; + case "null": + throw null; + case "number": + throw 42; + case "object": + throw { a: 1, b: "x" }; + case "runtime": { + const value: any = JSON.parse("null"); + console.log(value.missing); + } + } +} diff --git a/tests/corpus/5808-worker-unhandled-rejections.ts b/tests/corpus/5808-worker-unhandled-rejections.ts new file mode 100644 index 000000000..d13369671 --- /dev/null +++ b/tests/corpus/5808-worker-unhandled-rejections.ts @@ -0,0 +1,39 @@ +import { Worker, isMainThread, workerData } from "node:worker_threads"; + +// An unhandled rejection ends a worker with an 'error' event: an +// error-like reason as itself, any other reason as Node's +// UnhandledPromiseRejection Error quoting the reason. +const reasons = ["string", "number", "undefined", "null", "object", "array", "symbol", "bigint", "errorLike", "error"]; + +if (isMainThread) { + let next = 0; + const run = (): void => { + const reason = reasons[next++]; + if (reason === undefined) return; + const worker = new Worker(new URL(import.meta.url), { workerData: reason }); + worker.on("error", (e: any) => { + const at = typeof e.message === "string" ? e.message.indexOf("The promise") : -1; + const message = at < 0 ? e.message : e.message.slice(at); + console.log(reason, e instanceof Error, e.name, e.code, message, JSON.stringify(e)); + }); + worker.on("exit", (code: number) => { + console.log(" ", "exit", code); + run(); + }); + }; + run(); +} else { + const values: Record = { + string: "rejected", + number: 1.5, + undefined: undefined, + null: null, + object: { a: 1 }, + array: [1, [2, 3]], + symbol: Symbol("why"), + bigint: 10n, + errorLike: { stack: "custom stack", message: "like an error" }, + error: new RangeError("real error"), + }; + void Promise.reject(values[workerData as string]); +} diff --git a/tests/corpus/5809-process-exit-and-rejections.cjs b/tests/corpus/5809-process-exit-and-rejections.cjs new file mode 100644 index 000000000..77b2a3609 --- /dev/null +++ b/tests/corpus/5809-process-exit-and-rejections.cjs @@ -0,0 +1,46 @@ +// @exit: 3 +'use strict'; +// process.exit(code) assigns process.exitCode first: a code that is not a +// safe integer throws a RangeError and execution continues. Valid codes +// convert to int32, which a worker's 'exit' event reports in full. An +// 'uncaughtException' listener receives an unhandled rejection with origin +// 'unhandledRejection': an Error reason as itself, any other reason as +// Node's UnhandledPromiseRejection Error quoting the reason. +const { Worker, isMainThread, workerData } = require('node:worker_threads'); + +const codes = [1.5, -1, 261, 2 ** 32 + 5]; + +if (isMainThread) { + process.on('uncaughtException', (err, origin) => { + const at = typeof err.message === 'string' ? err.message.indexOf('The promise') : -1; + console.log(origin, err instanceof Error, err.name, err.code, at < 0 ? err.message : err.message.slice(at)); + console.log(' ', JSON.stringify(err), typeof err === 'object' ? Object.keys(err).join(',') : typeof err); + }); + for (const code of [3.7, 2 ** 53, NaN]) { + try { + process.exit(code); + } catch (error) { + if (error instanceof RangeError) console.log(error.name, error.message); + } + } + void Promise.reject('main reason'); + setTimeout(() => void Promise.reject({ a: 1 }), 1); + setTimeout(() => void Promise.reject(new TypeError('typed reason')), 2); + setTimeout(() => { + throw 'thrown string'; + }, 3); + let next = 0; + const run = () => { + const code = codes[next++]; + if (code === undefined) process.exit(256 + 3); + const worker = new Worker(__filename, { workerData: code }); + worker.on('error', (e) => console.log(code, 'error', e.name, e.code)); + worker.on('exit', (exitCode) => { + console.log(code, 'exit', exitCode); + run(); + }); + }; + setTimeout(run, 20); +} else { + process.exit(workerData); +} diff --git a/tests/corpus/5870-worker-thread-names.ts b/tests/corpus/5870-worker-thread-names.ts new file mode 100644 index 000000000..ce5d98cca --- /dev/null +++ b/tests/corpus/5870-worker-thread-names.ts @@ -0,0 +1,35 @@ +import { Worker, isMainThread, parentPort, threadId, threadName, workerData } from "node:worker_threads"; + +// The Worker name option: a truthy name must be a string and is trimmed, +// any other value selects "WorkerThread"; threadName reports it inside the +// worker and on the Worker until exit (null afterwards), and is "" in the +// main thread. +if (isMainThread) { + console.log("main", threadId, JSON.stringify(threadName)); + for (const name of [5, true, {}] as unknown[]) { + try { + const options: Record = { name }; + new Worker(new URL(import.meta.url), options); + } catch (e) { + const err = e as Error & { code?: string }; + console.log(JSON.stringify(name), err.name, err.code, err.message); + } + } + const names: unknown[] = [" reader one ", "", " ", 0, null, undefined, "a\tb "]; + let next = 0; + const run = (): void => { + if (next >= names.length) return; + const name = names[next++]; + const options: Record = { name, workerData: next }; + const worker = new Worker(new URL(import.meta.url), options); + console.log(JSON.stringify(name), "threadName", JSON.stringify(worker.threadName)); + worker.on("message", (m: unknown) => console.log(" worker saw", JSON.stringify(m))); + worker.on("exit", (code: number) => { + console.log(" exit", code, JSON.stringify(worker.threadName)); + run(); + }); + }; + run(); +} else { + parentPort!.postMessage([workerData, threadName, threadId > 0]); +} diff --git a/tests/corpus/5871-worker-untransferable.cjs b/tests/corpus/5871-worker-untransferable.cjs new file mode 100644 index 000000000..b79482dde --- /dev/null +++ b/tests/corpus/5871-worker-untransferable.cjs @@ -0,0 +1,56 @@ +'use strict'; +// markAsUntransferable and isMarkedAsUntransferable: marks on objects, +// ArrayBuffers (a typed array and its ArrayBuffer are marked separately), +// functions and MessagePorts; primitives are never marked. A marked +// ArrayBuffer or port in a transfer list throws DataCloneError, and so does +// the ArrayBuffer of a pooled Buffer, which Node marks. Cloning a marked +// value is unaffected. +const { MessageChannel, isMarkedAsUntransferable, markAsUntransferable } = require('node:worker_threads'); + +const ab = new ArrayBuffer(8); +const before = isMarkedAsUntransferable(ab); +markAsUntransferable(ab); +console.log('arraybuffer', before, isMarkedAsUntransferable(ab)); +const obj = { a: 1 }; +const objectBefore = isMarkedAsUntransferable(obj); +markAsUntransferable(obj); +console.log('object', objectBefore, isMarkedAsUntransferable(obj), isMarkedAsUntransferable({ a: 1 })); +const fn = () => 1; +markAsUntransferable(fn); +console.log('function', isMarkedAsUntransferable(fn)); +markAsUntransferable(5); +console.log('primitives', isMarkedAsUntransferable(5), isMarkedAsUntransferable('s'), isMarkedAsUntransferable(null), isMarkedAsUntransferable(undefined), isMarkedAsUntransferable()); +const view = new Uint8Array(4); +markAsUntransferable(view.buffer); +console.log('view buffer', isMarkedAsUntransferable(view), isMarkedAsUntransferable(view.buffer)); +const other = new Uint8Array(4); +markAsUntransferable(other); +console.log('view itself', isMarkedAsUntransferable(other), isMarkedAsUntransferable(other.buffer)); +console.log('pooled buffer', isMarkedAsUntransferable(Buffer.from('x').buffer), isMarkedAsUntransferable(Buffer.alloc(10).buffer), isMarkedAsUntransferable(Buffer.from('x'))); +const sab = new SharedArrayBuffer(4); +markAsUntransferable(sab); +console.log('shared', isMarkedAsUntransferable(sab)); + +const { port1, port2 } = new MessageChannel(); +const spare = new MessageChannel(); +markAsUntransferable(spare.port1); +console.log('port', isMarkedAsUntransferable(spare.port1), isMarkedAsUntransferable(spare.port2)); +for (const [label, value] of [['marked arraybuffer', ab], ['pooled arraybuffer', Buffer.from('ab').buffer], ['marked port', spare.port1]]) { + try { + port1.postMessage(value, [value]); + console.log(label, 'posted'); + } catch (e) { + console.log(label, e.name, e.message); + } +} +try { + port1.postMessage('options form', { transfer: [spare.port1] }); +} catch (e) { + console.log('options form', e.name, e.message); +} +port1.postMessage({ ab, obj }); +port2.on('message', (m) => { + console.log('cloned', m.ab.byteLength, JSON.stringify(m.obj), isMarkedAsUntransferable(m.ab), isMarkedAsUntransferable(m.obj)); + port1.close(); + spare.port1.close(); +}); diff --git a/tests/corpus/5874-worker-stdio-streams.ts b/tests/corpus/5874-worker-stdio-streams.ts new file mode 100644 index 000000000..28d2ff4a2 --- /dev/null +++ b/tests/corpus/5874-worker-stdio-streams.ts @@ -0,0 +1,28 @@ +import { Worker, isMainThread } from "node:worker_threads"; + +// The stdout and stderr options: the worker's console and process.stdout/ +// process.stderr writes reach worker.stdout and worker.stderr instead of +// the process output, as Readable streams that end after the worker's +// 'exit' event. worker.stdin is null without the stdin option. +if (isMainThread) { + const worker = new Worker(new URL(import.meta.url), { stdout: true, stderr: true }); + let out = ""; + let err = ""; + worker.stdout.setEncoding("utf8"); + worker.stdout.on("data", (chunk: string) => { + out += chunk; + }); + worker.stdout.on("end", () => console.log("stdout end", JSON.stringify(out))); + worker.stderr.on("data", (chunk: Buffer) => { + err += chunk.toString(); + }); + worker.stderr.on("end", () => console.log("stderr end", JSON.stringify(err))); + worker.on("exit", (code: number) => console.log("exit", code)); + console.log("stdin", worker.stdin); +} else { + console.log("hello from the worker"); + process.stdout.write("raw write\n"); + process.stdout.write(Buffer.from("bytes\n")); + console.error("an error line"); + process.stderr.write("err bytes\n"); +} diff --git a/tests/corpus/5875-worker-stdout-pipe.cjs b/tests/corpus/5875-worker-stdout-pipe.cjs new file mode 100644 index 000000000..8a9551a12 --- /dev/null +++ b/tests/corpus/5875-worker-stdout-pipe.cjs @@ -0,0 +1,24 @@ +'use strict'; +// worker.stdout as a pipe source: with only the stdout option, the +// worker's stdout writes reach the parent's Writable while its stderr +// output goes to the process's stderr as before. +const { Worker, isMainThread } = require('node:worker_threads'); +const { Writable } = require('node:stream'); + +if (isMainThread) { + const worker = new Worker(__filename, { stdout: true }); + const chunks = []; + const sink = new Writable({ + write(chunk, encoding, callback) { + chunks.push(chunk.toString().toUpperCase()); + callback(); + }, + }); + sink.on('finish', () => console.log('piped', JSON.stringify(chunks.join('')))); + worker.stdout.pipe(sink); + worker.on('exit', (code) => console.log('exit', code)); +} else { + console.log('first line'); + console.error('to stderr'); + console.log('second line'); +} diff --git a/tests/corpus/5879-worker-stdin.ts b/tests/corpus/5879-worker-stdin.ts new file mode 100644 index 000000000..197ee719c --- /dev/null +++ b/tests/corpus/5879-worker-stdin.ts @@ -0,0 +1,42 @@ +// The Worker stdin option: worker.stdin is a Writable whose chunks the +// worker reads from process.stdin, which ends when worker.stdin ends. +// Without the option worker.stdin is null and the worker's process.stdin +// ends without data. +import { Worker, isMainThread, parentPort } from "node:worker_threads"; +import { Writable } from "node:stream"; +import * as readline from "node:readline"; + +function run(mode: string, stdin: boolean, feed: (sink: Writable) => void, next: () => void): void { + const worker = new Worker(new URL(import.meta.url), { argv: [mode], stdin }); + const messages: string[] = []; + worker.on("message", (m: string) => messages.push(m)); + worker.on("exit", (code: number) => { + console.log(mode, "exit", code, JSON.stringify(messages)); + next(); + }); + if (worker.stdin === null) console.log(mode, "stdin", null); + else feed(worker.stdin); +} + +if (isMainThread) { + run("plain", false, () => {}, () => + run("chunks", true, (sink) => { + sink.write("first line\n"); + sink.write(Buffer.from("second ")); + sink.end("line\n", () => console.log("chunks end callback")); + }, () => + run("lines", true, (sink) => { + sink.write("alpha\nbeta"); + sink.end("\ngamma\n"); + }, () => console.log("done")))); +} else if (process.argv[2] === "lines") { + const rl = readline.createInterface({ input: process.stdin }); + rl.on("line", (line) => parentPort!.postMessage(line.toUpperCase())); + rl.on("close", () => parentPort!.postMessage("closed")); +} else { + const chunks: string[] = []; + process.stdin.on("data", (d: Uint8Array) => { + chunks.push(Buffer.from(d).toString()); + }); + process.stdin.on("end", () => parentPort!.postMessage(`${chunks.length} ${JSON.stringify(chunks.join(""))}`)); +} From 69320be4f32eb4959c7596217452bcdcf89827ae Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 11:40:07 -0500 Subject: [PATCH 002/117] Declare scr_worker_broadcast_channel in the runtime header The LLVM backend can emit calls to scr_worker_broadcast_channel (new BroadcastChannel), so llvm-runtime-abi.test.ts requires a prototype in a header scr_runtime.h includes; it now sits next to scr_worker_message_channel in scr_bytes.h. --- packages/runtime/src/scr_bytes.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/runtime/src/scr_bytes.h b/packages/runtime/src/scr_bytes.h index d43102a11..cdf7cef9f 100644 --- a/packages/runtime/src/scr_bytes.h +++ b/packages/runtime/src/scr_bytes.h @@ -94,6 +94,9 @@ ScrDyn *scr_worker_parent_port(void); * (scr_worker_events.c). */ ScrDyn *scr_worker_message_channel(void); ScrDyn *scr_worker_receive_message_on_port(ScrDyn *port); +/* new BroadcastChannel(...args) (scr_worker_events.c): args is the argument + * vector as one array (borrowed); may throw. */ +ScrDyn *scr_worker_broadcast_channel(ScrDyn *args); /* setEnvironmentData(key, value) and getEnvironmentData(key) (+1); both * borrow their arguments. */ void scr_worker_set_environment_data(ScrDyn *key, ScrDyn *value); From 4530547f010c954114fd5bfdf27c6ca7441f5df5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 12:36:51 -0500 Subject: [PATCH 003/117] Return owned copies of the worker thread name The thread record keeps the Worker's name as an immortal string and frees it with the record. worker.threadName and the in-thread threadName returned that buffer as a string value, whose retains do not extend an immortal string's lifetime, so a name read before the Worker was released pointed at freed memory once the record was destroyed. Both getters now copy the name into a new string. Corpus 5992 keeps worker.threadName past the worker's exit and the Worker's release and then uses it; it matches Node, plain and with SCRIPTC_SAN=1, and fails under ASan without this change. --- .../5992-worker-thread-name-lifetime.mjs.json | 6 ++++ packages/runtime/src/scr_worker.c | 6 +++- packages/runtime/src/scr_worker.h | 3 +- packages/runtime/src/scr_worker_events.c | 12 +++++-- .../5992-worker-thread-name-lifetime.mjs | 33 +++++++++++++++++++ 5 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5992-worker-thread-name-lifetime.mjs.json create mode 100644 tests/corpus/5992-worker-thread-name-lifetime.mjs diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5992-worker-thread-name-lifetime.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5992-worker-thread-name-lifetime.mjs.json new file mode 100644 index 000000000..20ef55142 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5992-worker-thread-name-lifetime.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5992-worker-thread-name-lifetime.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_worker.c b/packages/runtime/src/scr_worker.c index 0c9a2d903..419d6b79f 100644 --- a/packages/runtime/src/scr_worker.c +++ b/packages/runtime/src/scr_worker.c @@ -191,7 +191,11 @@ ScrDyn *scr_worker_thread_name_current(void) { scr_str_release(empty); return name; } - return scr_dyn_new_str(scr_worker_current->name); + /* a copy: the thread record's name is freed with the record */ + ScrStr *copy = scr_str_new(scr_worker_current->name->data, scr_worker_current->name->len); + ScrDyn *name = scr_dyn_new_str(copy); + scr_str_release(copy); + return name; } void scr_worker_thread_terminate(ScrWorkerThread *worker) { diff --git a/packages/runtime/src/scr_worker.h b/packages/runtime/src/scr_worker.h index fa2d58efa..ba27f69af 100644 --- a/packages/runtime/src/scr_worker.h +++ b/packages/runtime/src/scr_worker.h @@ -38,7 +38,8 @@ void scr_worker_thread_release(ScrWorkerThread *worker); void scr_worker_thread_join(ScrWorkerThread *worker); void scr_worker_thread_terminate(ScrWorkerThread *worker); uint64_t scr_worker_thread_id(const ScrWorkerThread *worker); -/* The Worker's threadName (immortal, owned by the thread record). */ +/* The Worker's threadName, owned by the thread record and freed with it: + * callers copy it into the strings they return. */ const ScrStr *scr_worker_thread_name(const ScrWorkerThread *worker); /* Posting consumes the message even after the destination has closed. */ bool scr_worker_thread_post(ScrWorkerThread *worker, ScrMessage *message); diff --git a/packages/runtime/src/scr_worker_events.c b/packages/runtime/src/scr_worker_events.c index 6ad62802e..a4a10b3b8 100644 --- a/packages/runtime/src/scr_worker_events.c +++ b/packages/runtime/src/scr_worker_events.c @@ -477,8 +477,16 @@ static ScrDyn *scr_worker_view_get(void *ptr, const char *key, size_t length) { if (!view->stdio_box[i]) view->stdio_box[i] = scr_worker_stdio_box(view->stdio[i]); return scr_dyn_retain(view->stdio_box[i]); } - if (!view->port && length == 10 && !memcmp(key, "threadName", 10)) - return view->closed ? scr_dyn_new_null() : scr_dyn_new_str((ScrStr *)scr_worker_thread_name(view->thread)); + if (!view->port && length == 10 && !memcmp(key, "threadName", 10)) { + if (view->closed) return scr_dyn_new_null(); + /* a copy: the thread record's name is freed with the record, which + * a string value can outlive */ + const ScrStr *name = scr_worker_thread_name(view->thread); + ScrStr *copy = scr_str_new(name->data, name->len); + ScrDyn *value = scr_dyn_new_str(copy); + scr_str_release(copy); + return value; + } if (!view->port && length == 14 && !memcmp(key, "resourceLimits", 14)) return view->closed ? scr_dyn_new_obj() : scr_worker_refusal("worker.resourceLimits is not supported yet"); for (size_t i = 0; i < sizeof scr_worker_methods / sizeof scr_worker_methods[0]; i++) { diff --git a/tests/corpus/5992-worker-thread-name-lifetime.mjs b/tests/corpus/5992-worker-thread-name-lifetime.mjs new file mode 100644 index 000000000..455ccec4b --- /dev/null +++ b/tests/corpus/5992-worker-thread-name-lifetime.mjs @@ -0,0 +1,33 @@ +// worker.threadName read while the worker runs stays a usable string after +// the worker exits and the Worker object is released. +import { Worker, isMainThread, parentPort, threadName } from "node:worker_threads"; + +async function run(name) { + const worker = new Worker(new URL(import.meta.url), { name }); + const kept = worker.threadName; + await new Promise((resolve) => worker.once("exit", resolve)); + return kept; +} + +if (isMainThread) { + const fromFunction = await run("function worker"); + const names = []; + for (const name of ["first worker", " second "]) { + let worker = new Worker(new URL(import.meta.url), { name }); + names.push(worker.threadName); + const exited = new Promise((resolve) => worker.once("exit", resolve)); + const inner = await new Promise((resolve) => worker.once("message", resolve)); + await exited; + console.log("after exit", JSON.stringify(worker.threadName), JSON.stringify(inner)); + worker = null; + } + // allocations that would reuse the released names' storage + const filler = []; + for (let i = 0; i < 1000; i++) filler.push("x".repeat(i % 64)); + console.log("kept", filler.length, JSON.stringify(names), names.map((n) => n.length).join(",")); + console.log("joined", names.join("|").toUpperCase()); + console.log("from function", JSON.stringify(fromFunction), fromFunction.length, fromFunction.toUpperCase()); +} else { + const own = threadName; + parentPort.postMessage(`${own}:${own.length}`); +} From 3fcef83d38c292fa29c45f8f2e699c2b701c706a Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 11:26:12 -0700 Subject: [PATCH 004/117] Carry lifetime regions across await and reuse freed region chunks An async function called inside LifetimeRegion.run now keeps its region after every await: its fiber records the region that was current at spawn, and the event loop makes that region current while it resumes the fiber. A region is not freed (or attempted) while a fiber that carries it exists, so a region released while its async work is pending keeps taking that work's objects and is freed once the work ends. Before, objects created after an await went to the default region, which is never freed, and kept the request's region allocated for good, so per-request regions in async servers grew without bound. Freed region chunks now go to a per-thread cache (at most 8 MiB resident, the first 256 KiB of each kept cleared, fresh pages past it, no huge-page chunks) instead of being unmapped, so a region per request or per batch no longer maps and faults in new memory every time. Adds the requests.ts region benchmark (concurrent async handlers), corpus 5023 and its region-stats checks, and a chunk-reuse runtime unit check. Co-Authored-By: Claude Opus 5.5 --- benchmarks/regions/README.md | 1 + benchmarks/regions/emit.ts | 2 +- benchmarks/regions/requests.ts | 221 ++++++++++++++++++ benchmarks/regions/run.mjs | 4 +- docs/content/docs/experimental.mdx | 63 ++++- docs/test/fixtures/migration-baseline.json | 4 + .../corpus/5023-lifetime-region-await.ts.json | 6 + packages/experimental/README.md | 2 +- packages/experimental/index.d.ts | 11 +- packages/runtime/src/scr_async.c | 20 ++ packages/runtime/src/scr_region.c | 162 +++++++++++-- packages/runtime/src/scr_region.h | 21 ++ packages/runtime/src/scr_region.test.c | 25 ++ packages/runtime/src/scr_region.test.ts | 11 +- tests/corpus/5013-lifetime-region-async.ts | 9 +- tests/corpus/5023-lifetime-region-await.ts | 200 ++++++++++++++++ tests/harness/lifetime-regions.test.ts | 23 +- 17 files changed, 748 insertions(+), 37 deletions(-) create mode 100644 benchmarks/regions/requests.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5023-lifetime-region-await.ts.json create mode 100644 tests/corpus/5023-lifetime-region-await.ts diff --git a/benchmarks/regions/README.md b/benchmarks/regions/README.md index 457f059be..0cc450abc 100644 --- a/benchmarks/regions/README.md +++ b/benchmarks/regions/README.md @@ -7,6 +7,7 @@ Programs that build generations of `ProgramLifetime` objects and free each gener | `generations.ts` | Per-file syntax trees and binder symbols in one region per file, checker state (types, signatures, node and symbol links in paged tables, literal and union caches) in one region per generation. `edit` re-parses one file per generation, `all` re-parses every file. | | `compiler.ts` | A tokenizer, recursive-descent parser, binder and checker over generated sources, rebuilt from scratch in one region per build, like a watch mode that does not reuse syntax trees. | | `emit.ts` | A large live graph of ordinary objects with parent links, standing in for a type checker, and a per-file emit that builds its output in a region released right after. | +| `requests.ts` | Batches of concurrent async request handlers, each in its own region across its awaits: tokenize a JSON body, parse it into a syntax tree that points at its tokens, validate it into issues and an index, render a response, release the region. | ```console $ node benchmarks/regions/run.mjs --baseline=../scriptc-main --runs=7 diff --git a/benchmarks/regions/emit.ts b/benchmarks/regions/emit.ts index 630708361..9fd15b860 100644 --- a/benchmarks/regions/emit.ts +++ b/benchmarks/regions/emit.ts @@ -54,7 +54,7 @@ let level: Type[] = [new Type(id++, undefined)]; while (id < typeCount) { const next: Type[] = []; for (const t of level) for (let k = 0; k < 4 && id < typeCount; k++) next.push(new Type(id++, t)); - roots.push(...next); + for (const t of next) roots.push(t); level = next; } diff --git a/benchmarks/regions/requests.ts b/benchmarks/regions/requests.ts new file mode 100644 index 000000000..6148eb25d --- /dev/null +++ b/benchmarks/regions/requests.ts @@ -0,0 +1,221 @@ +// An async request handler: each request tokenizes a JSON body, awaits (as +// if reading more of it), parses the tokens into a syntax tree whose nodes +// point back at their tokens, awaits again (as if loading reference data), +// validates the tree into issues held in an index, and renders a response. +// Requests run in batches of concurrent handlers, so the handlers of one +// batch interleave at every await. +// +// requests [plain] +// +// Each request runs in its own LifetimeRegion, released when its response +// is rendered; `plain` never constructs a region. +import { readFileSync } from "node:fs"; +import type { ProgramLifetime } from "@scriptc/types"; +import { LifetimeRegion } from "@scriptc/experimental"; + +const T_PUNCT = 0; +const T_STR = 1; +const T_NUM = 2; +const T_WORD = 3; + +class Token implements ProgramLifetime { + readonly kind: number; + readonly text: string; + readonly pos: number; + constructor(kind: number, text: string, pos: number) { + this.kind = kind; + this.text = text; + this.pos = pos; + } +} + +const N_OBJECT = 0; +const N_ARRAY = 1; +const N_STRING = 2; +const N_NUMBER = 3; +const N_LITERAL = 4; + +class JsonNode implements ProgramLifetime { + readonly kind: number; + readonly token: Token; + parent: JsonNode | undefined = undefined; + readonly keys: string[] = []; + readonly children: JsonNode[] = []; + constructor(kind: number, token: Token) { + this.kind = kind; + this.token = token; + } +} + +class Issue implements ProgramLifetime { + readonly path: string; + readonly node: JsonNode; + readonly message: string; + constructor(path: string, node: JsonNode, message: string) { + this.path = path; + this.node = node; + this.message = message; + } +} + +// ---- request bodies (deterministic) ---- + +function body(id: number, items: number): string { + let seed = 7 + id * 7919; + const rand = (n: number): number => { + seed = (seed * 1103515245 + 12345) % 2147483648; + return seed % n; + }; + const parts: string[] = []; + for (let i = 0; i < items; i++) { + const qty = rand(12) - 1; + const sku = rand(9) === 0 ? "" : `sku-${rand(5000)}`; + const tags = Array.from({ length: rand(4) }, (_, k) => `"t${k}${rand(10)}"`).join(","); + parts.push(`{"sku":"${sku}","qty":${qty},"price":${rand(10000) / 100},"gift":${rand(2) === 0},"tags":[${tags}]}`); + } + return `{"order":${id},"customer":"c${id % 97}","items":[${parts.join(",")}]}`; +} + +// ---- handler ---- + +function tokenize(text: string): Token[] { + const tokens: Token[] = []; + let i = 0; + while (i < text.length) { + const c = text.charCodeAt(i); + const start = i; + if (c === 34) { + i++; + while (text.charCodeAt(i) !== 34) i++; + i++; + tokens.push(new Token(T_STR, text.slice(start + 1, i - 1), start)); + } else if (c === 45 || (c >= 48 && c <= 57)) { + i++; + while (i < text.length && (text.charCodeAt(i) === 46 || (text.charCodeAt(i) >= 48 && text.charCodeAt(i) <= 57))) i++; + tokens.push(new Token(T_NUM, text.slice(start, i), start)); + } else if (c >= 97 && c <= 122) { + while (i < text.length && text.charCodeAt(i) >= 97 && text.charCodeAt(i) <= 122) i++; + tokens.push(new Token(T_WORD, text.slice(start, i), start)); + } else { + i++; + tokens.push(new Token(T_PUNCT, text[start]!, start)); + } + } + return tokens; +} + +class Parser { + private at = 0; + private readonly tokens: Token[]; + constructor(tokens: Token[]) { + this.tokens = tokens; + } + value(): JsonNode { + const token = this.tokens[this.at++]!; + if (token.kind === T_STR) return new JsonNode(N_STRING, token); + if (token.kind === T_NUM) return new JsonNode(N_NUMBER, token); + if (token.kind === T_WORD) return new JsonNode(N_LITERAL, token); + const node = new JsonNode(token.text === "{" ? N_OBJECT : N_ARRAY, token); + const close = token.text === "{" ? "}" : "]"; + while (this.tokens[this.at]!.text !== close) { + if (node.kind === N_OBJECT) { + node.keys.push(this.tokens[this.at]!.text); + this.at += 2; // the key and the colon + } + const child = this.value(); + child.parent = node; + node.children.push(child); + if (this.tokens[this.at]!.text === ",") this.at++; + } + this.at++; + return node; + } +} + +function member(node: JsonNode, key: string): JsonNode | undefined { + const i = node.keys.indexOf(key); + return i < 0 ? undefined : node.children[i]; +} + +function validate(root: JsonNode, issues: Issue[], index: Map): number { + let total = 0; + const items = member(root, "items")!; + for (let i = 0; i < items.children.length; i++) { + const item = items.children[i]!; + const path = `items[${i}]`; + const sku = member(item, "sku")!; + if (sku.token.text === "") issues.push(new Issue(`${path}.sku`, sku, "empty sku")); + else if (index.has(sku.token.text)) issues.push(new Issue(`${path}.sku`, sku, `duplicate of ${index.get(sku.token.text)!.token.pos}`)); + else index.set(sku.token.text, item); + const qty = Number(member(item, "qty")!.token.text); + if (qty <= 0) issues.push(new Issue(`${path}.qty`, member(item, "qty")!, "quantity must be positive")); + else total += qty * Number(member(item, "price")!.token.text); + const tags = member(item, "tags")!; + for (const tag of tags.children) if (tag.token.text.endsWith("0")) issues.push(new Issue(`${path}.tags`, tag, "reserved tag")); + } + return total; +} + +const hop = (): Promise => new Promise((resolve) => setImmediate(resolve)); + +async function handle(text: string): Promise { + const tokens = tokenize(text); + await hop(); + const root = new Parser(tokens).value(); + await hop(); + const issues: Issue[] = []; + const index = new Map(); + const total = validate(root, issues, index); + await hop(); + const first = issues[0]; + return `${member(root, "order")!.token.text} ${tokens.length} ${index.size} ${issues.length} ${total.toFixed(2)}` + + (first === undefined ? "" : ` ${first.path}@${first.node.token.pos}`); +} + +// ---- driver ---- + +function rssMb(key: string): number { + const m = new RegExp(`${key}:\\s*(\\d+) kB`).exec(readFileSync("/proc/self/status", "utf8")); + return m === null ? 0 : Number(m[1]) / 1024; +} + +const args = process.argv.slice(2); +const requests = Number(args[0] ?? "4000"); +const concurrency = Number(args[1] ?? "16"); +const items = Number(args[2] ?? "100"); +const useRegions = args[3] !== "plain"; + +async function serve(id: number): Promise { + const text = body(id, items); + if (!useRegions) return await handle(text); + const region = new LifetimeRegion(); + const response = await region.run(() => handle(text)); + region.release(); + return response; +} + +async function main(): Promise { + let hash = 0; + let lines = 0; + let sample = ""; + let rssFirst = 0; + const t0 = performance.now(); + for (let next = 0; next < requests; next += concurrency) { + const batch: Promise[] = []; + for (let k = next; k < next + concurrency && k < requests; k++) batch.push(serve(k)); + for (const response of await Promise.all(batch)) { + for (let i = 0; i < response.length; i++) hash = (hash * 31 + response.charCodeAt(i)) % 1000000007; + lines++; + if (lines === 1) sample = response; + } + if (next === 0) rssFirst = rssMb("VmRSS"); + } + const ms = performance.now() - t0; + console.log(`${lines} responses, hash ${hash}, first ${sample}`); + console.log( + `total ${ms.toFixed(1)} ms per-request ${((ms * 1000) / requests).toFixed(1)} us` + + ` rss-first ${rssFirst.toFixed(1)} MB rss-last ${rssMb("VmRSS").toFixed(1)} MB peak ${rssMb("VmHWM").toFixed(1)} MB`, + ); +} + +main(); diff --git a/benchmarks/regions/run.mjs b/benchmarks/regions/run.mjs index 1f1c4609f..e698dc47d 100644 --- a/benchmarks/regions/run.mjs +++ b/benchmarks/regions/run.mjs @@ -39,6 +39,8 @@ const CONFIGS = [ { name: "compiler-one-shot", program: "compiler.ts", args: ["400", "60", "1"] }, // Per-file emit regions next to a large live heap of ordinary objects. { name: "emit-files", program: "emit.ts", args: ["400000", "200", "2000"] }, + // Concurrent async request handlers, one region per request across its awaits. + { name: "requests-async", program: "requests.ts", args: ["4000", "16", "100"] }, ]; const work = join(tmpdir(), `scriptc-region-bench-${process.pid}`); @@ -93,7 +95,7 @@ for (const config of CONFIGS) { const lines = r.stdout.trim().split("\n"); outputs.set(name, lines[0].replace(/ gen0 .*/, "")); const metrics = {}; - for (const [, key, value] of lines.at(-1).matchAll(/([a-z0-9-]+) ([0-9.]+) (?:ms|MB)/g)) + for (const [, key, value] of lines.at(-1).matchAll(/([a-z0-9-]+) ([0-9.]+) (?:ms|us|MB)/g)) metrics[key] = Number(value); samples[name].push(metrics); } diff --git a/docs/content/docs/experimental.mdx b/docs/content/docs/experimental.mdx index ac5891ec9..6a0fb53ef 100644 --- a/docs/content/docs/experimental.mdx +++ b/docs/content/docs/experimental.mdx @@ -73,9 +73,9 @@ scriptc region heap passes: 0
new LifetimeRegion()
Creates a region. Creating a region also retries the released regions that could not be freed yet.
region.run(fn)
-
Calls fn with the region as the current region and returns its result. ProgramLifetime instances created during the call belong to the region. Calls nest: a run inside the callback makes another region current until it returns, and the previous region is current again however the callback finishes, including when it throws.
+
Calls fn with the region as the current region and returns its result. ProgramLifetime instances created during the call belong to the region, and so do those that async functions called during it create after an await (see Async work). Calls nest: a run inside the callback makes another region current until it returns, and the previous region is current again however the callback finishes, including when it throws.
region.release()
-
Requests that the region be freed. scriptc frees it as soon as nothing outside the region refers to any of its instances, which may be at once, at a later release or region creation, or never. A region is never freed while a run call on it is active. After release(), run still calls its callback, and the instances it creates belong to the default region.
+
Requests that the region be freed. scriptc frees it as soon as nothing outside the region refers to any of its instances, which may be at once, at a later release or region creation, or never. A region is never freed while a run call on it is active, or while async work started inside it has not finished. After release(), run still calls its callback, and the instances it creates belong to the default region.
`ProgramLifetime` instances created outside every `run` call belong to the default region, which is never freed. Ordinary objects (instances of classes without the contract, arrays, maps, closures) are reference counted as always; a region frees the ones that only its instances refer to. @@ -92,7 +92,62 @@ A released region stays allocated, and its instances stay usable, while anything - an instance of the default region, which is never freed; - a promise, generator or `Error` that holds an instance, until it is no longer referenced. -Work that resumes after an `await` inside the callback runs outside the region, so the instances it creates belong to the default region and keep the instances they refer to allocated. +### Async work + +An async function called inside `run` keeps the region for its whole run: the instances it creates after each `await` belong to the region too, as do those of the async functions it calls. A server can give every request its own region, even while requests interleave at their awaits: + +```ts:requests.ts +import type { ProgramLifetime } from "@scriptc/types"; +import { LifetimeRegion } from "@scriptc/experimental"; + +class Part implements ProgramLifetime { + readonly text: string; + previous: Part | undefined = undefined; + constructor(text: string) { + this.text = text; + } +} + +const read = (): Promise => new Promise((resolve) => setImmediate(resolve)); + +async function handle(id: number): Promise { + let last: Part | undefined; + for (let i = 0; i < 1000; i++) { + if (i % 100 === 0) await read(); // the next chunk of the request body + const part = new Part(`${id}.${i}`); + part.previous = last; + last = part; + } + return `request ${id}: last part ${last!.text}`; +} + +async function serve(id: number): Promise { + const region = new LifetimeRegion(); + try { + return await region.run(() => handle(id)); + } finally { + region.release(); + } +} + +Promise.all([1, 2, 3].map(serve)).then((responses) => { + for (const response of responses) console.log(response); +}); +``` + +Each request's 1000 parts are freed when the request releases its region: + +```console +$ scriptc build requests.ts -o requests >/dev/null +$ SCRIPTC_REGION_STATS=1 ./requests >/dev/null +scriptc region 1: freed 1000 objects, 0 owned objects, 1 chunks (2.0 MiB); cycles 0.0 ms, walk 0.0 ms, free 0.0 ms +scriptc region 2: freed 1000 objects, 0 owned objects, 1 chunks (2.0 MiB); cycles 0.0 ms, walk 0.0 ms, free 0.0 ms +scriptc region 3: freed 1000 objects, 0 owned objects, 1 chunks (2.0 MiB); cycles 0.0 ms, walk 0.0 ms, free 0.0 ms +scriptc regions: 3 created, 3 released, 3 freed, 0 pinned, 0 kept +scriptc region heap passes: 0 +``` + +A region released while async work started inside it is still pending stays allocated until that work has finished, and the work keeps creating its instances in the region. Callbacks that the event loop calls (timers, `queueMicrotask`, event listeners) and the bodies of async generators run outside the region; synchronous generators run in the region of the code that resumes them. ### Threads @@ -102,7 +157,7 @@ Each thread has its own regions and its own default region. A region belongs to Programs that never construct a `LifetimeRegion` compile exactly as they would without the package. In programs that do, every retain and release of a `ProgramLifetime` instance that belongs to a region updates a count of the region chunk that holds it. Instances of the default region are not counted, and until the program creates its first region, a retain or release only tests whether counting has started. -Freeing a region visits each of its instances and the ordinary objects they own. A region that the check would keep may be kept only by unreachable cycles of ordinary objects that refer into it, so before keeping it scriptc runs the cycle collector over the thread's heap and checks again. +Freeing a region visits each of its instances and the ordinary objects they own. Each thread keeps up to 8 MiB of the memory of freed regions for its next regions, so a program that frees a region per request or per batch does not map and fault in new pages every time. A region that the check would keep may be kept only by unreachable cycles of ordinary objects that refer into it, so before keeping it scriptc runs the cycle collector over the thread's heap and checks again. `SCRIPTC_REGION_STATS=1` prints one line per release attempt, freed, `kept` (with the number of references the check could not explain) or `pinned` (published), and at exit a summary per thread and the number of those cycle-collector passes over the thread's heap. diff --git a/docs/test/fixtures/migration-baseline.json b/docs/test/fixtures/migration-baseline.json index 6aaab5f70..dd4320e03 100644 --- a/docs/test/fixtures/migration-baseline.json +++ b/docs/test/fixtures/migration-baseline.json @@ -273,6 +273,10 @@ "text": "When a region is freed", "id": "when-a-region-is-freed" }, + { + "text": "Async work", + "id": "async-work" + }, { "text": "Threads", "id": "threads" diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5023-lifetime-region-await.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5023-lifetime-region-await.ts.json new file mode 100644 index 000000000..9e7d48130 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5023-lifetime-region-await.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5023-lifetime-region-await.ts" + ], + "diags": [] +} diff --git a/packages/experimental/README.md b/packages/experimental/README.md index 413deeff2..8a44053b0 100644 --- a/packages/experimental/README.md +++ b/packages/experimental/README.md @@ -21,7 +21,7 @@ function rebuild(): Program { - `run(fn)` calls `fn` with the region as the current region and returns its result. `ProgramLifetime` instances created during the call belong to the region; calls nest. - Instances created outside every `run` call belong to the default region, which is never freed. -- Work that resumes after an `await` inside `fn` runs outside the region. +- Async work started inside `fn` keeps its region: what it creates after an `await` belongs to the region too, and the region is not freed before that work has finished. - `release()` requests that the region be freed. scriptc frees it once nothing outside the region refers to any of its instances; until then the region stays allocated. Later `run` calls on a released region allocate in the default region. - A region that holds a published object (`@scriptc/threads`) is never freed. diff --git a/packages/experimental/index.d.ts b/packages/experimental/index.d.ts index d831cbff9..057dcde09 100644 --- a/packages/experimental/index.d.ts +++ b/packages/experimental/index.d.ts @@ -7,13 +7,14 @@ export declare class LifetimeRegion { constructor(); /** Calls `fn` with this region as the current region and returns its * result. ProgramLifetime instances created during the call, outside - * nested `run` calls of other regions, belong to this region. Work that - * resumes after an `await` inside `fn` runs outside the region. */ + * nested `run` calls of other regions, belong to this region, and so do + * those that async functions called during it create after an `await`. */ run(fn: () => T): T; /** Requests that the region be freed. Its instances are freed once - * nothing outside the region refers to any of them; until then the - * region stays allocated. Later `run` calls allocate outside the region. - * Never observable except through memory use. */ + * nothing outside the region refers to any of them and the async work + * started inside it has finished; until then the region stays allocated. + * Later `run` calls allocate outside the region. Never observable except + * through memory use. */ release(): void; } diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index 9bf42bb07..d8ff98154 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -594,6 +595,11 @@ struct ScrFiber { * SPAWNER at spawn (Node's init-time capture), swapped active with the * fiber (the exc-cell pattern) so run()'s window rides awaits. */ ScrAlsCtx *als; + /* The lifetime region the body was spawned in (scr_region_fiber_hooks; + * NULL = the default region): the loop makes it current again whenever + * it resumes the fiber. Async bodies only; generators run in their + * resumer's region. */ + void *region; bool done; /* A native synchronous generator compiled as an LLVM coroutine (see coro * above): no stack or saved context; resumes call into the frame on the @@ -676,6 +682,12 @@ void scr_als_ctx_release(ScrAlsCtx *c) { free(c); } +/* The lifetime region a new async fiber carries (ScrFiber.region). */ +static inline void *scr_fiber_region_capture(void) { + const ScrRgnFiberHooks *regions = atomic_load_explicit(&scr_region_fiber_hooks, memory_order_relaxed); + return regions != NULL ? regions->capture() : NULL; +} + static SCR_TL ScrCtx scr_loop_ctx; /* the main stack (scheduler home) */ static SCR_TL ScrFiber *scr_current = NULL; /* A finished fiber whose last switch went to the loop (scr_resume_fiber). */ @@ -1883,6 +1895,7 @@ static void scr_fiber_destroy(ScrFiber *f) { #endif #endif scr_als_ctx_release(f->als); + if (f->region != NULL) atomic_load_explicit(&scr_region_fiber_hooks, memory_order_relaxed)->drop(f->region); #if !defined(_WIN32) && !defined(__wasi__) scr_fiber_stack_free(f->stack); #else @@ -1914,6 +1927,7 @@ static ScrPromise *scr_async_spawn_impl(void (*entry)(ScrFiber *, void *), void /* AsyncLocalStorage: the child runs in the SPAWNER's context (Node's * init-time capture); snapshots are immutable, so a retain suffices. */ f->als = scr_als_ctx_retain(*SCR_ALS_SLOT()); + f->region = scr_fiber_region_capture(); scr_fibers_live++; #ifdef _WIN32 @@ -2123,6 +2137,7 @@ ScrPromise *scr_async_spawn_after(ScrPromise *dependency, f->entry = entry; f->argpack = argpack; f->als = scr_als_ctx_retain(*SCR_ALS_SLOT()); + f->region = scr_fiber_region_capture(); scr_fibers_live++; if (dependency->state == SCR_PROM_PENDING) { @@ -3624,6 +3639,9 @@ static void scr_resume_fiber(ScrFiber *f) { (void)scr_win_self(); #endif f->return_to = &scr_loop_ctx; + /* The body continues in the lifetime region it was spawned in. */ + const ScrRgnFiberHooks *regions = atomic_load_explicit(&scr_region_fiber_hooks, memory_order_relaxed); + void *region_before = regions != NULL ? regions->resume(f->region) : NULL; #ifdef __wasi__ scr_current = f; scr_exc_swap_cell(&f->exc); @@ -3640,8 +3658,10 @@ static void scr_resume_fiber(ScrFiber *f) { scr_current = NULL; scr_exc_swap_cell(NULL); scr_als_active = &scr_als_main_slot; + if (regions != NULL) regions->suspend(region_before); #else scr_switch(&scr_loop_ctx, &f->ctx, f); + if (regions != NULL) regions->suspend(region_before); f = scr_loop_reap; if (f == NULL) return; scr_loop_reap = NULL; diff --git a/packages/runtime/src/scr_region.c b/packages/runtime/src/scr_region.c index c1a125e8b..c8906ad0f 100644 --- a/packages/runtime/src/scr_region.c +++ b/packages/runtime/src/scr_region.c @@ -70,6 +70,18 @@ void __lsan_unregister_root_region(const void *p, size_t size) __attribute__((we #define SCR_RGN_AHEAD_START ((size_t)1 << 20) /* see scr_rgn_ahead */ _Static_assert(sizeof(ScrRgnChunk) <= SCR_RGN_HDR, "the chunk header fits before the first segment"); +/* Freed chunks a thread keeps for its next regions: a program that frees + * a region per request or per batch would otherwise map, fault in and + * unmap its chunks every time. A cached chunk keeps at most its first + * SCR_RGN_CACHE_WARM bytes resident (cleared), and gets fresh pages past + * them, so a small region that reuses the chunk of a large one does not + * hold the large one's memory. The cache holds at most SCR_RGN_CACHE_BYTES + * of resident chunk memory (whole chunks where chunks are not mapped + * pages); chunks beyond it, and chunks huge pages may back, are unmapped + * as before. */ +#define SCR_RGN_CACHE_BYTES ((size_t)8 << 20) +#define SCR_RGN_CACHE_WARM ((size_t)256 << 10) + /* Regions start with small pages and switch to huge pages once they span * this many chunks (a default region at once): small regions then do not * pay a 2 MiB fault, large ones do not pay 512 small ones. */ @@ -99,6 +111,7 @@ typedef struct ScrRegion { uint64_t id; /* 0: the thread's default region */ int state; uint32_t depth; /* run() frames active on this region */ + size_t fibers; /* async fibers that carry it (scr_region_fiber_hooks) */ ScrRgnChunk *chunks; size_t nchunks; ScrRgnSeg *segs; @@ -210,7 +223,10 @@ typedef struct { size_t allocated; /* bytes of region segments this thread has allocated */ size_t checked; /* `allocated` at the last retry */ ScrRgnWalk walk; + ScrRgnChunk *cache; /* freed chunks, linked through `next` (SCR_RGN_CACHE_BYTES) */ + size_t cache_bytes; /* their resident bytes, as recorded in each one's `found` */ bool exit_registered; + bool exited; /* the exit cleanup ran: the fiber hooks do nothing */ double cycle_ms; /* the cycle pass before the next attempt (stats) */ struct { size_t created, released, freed, pinned, leaked, attempts; @@ -329,18 +345,39 @@ static bool scr_rgn_huge(const ScrRegion *r) { return r->id == 0 || r->nchunks + /* A chunk for `r`'s next one, with its page policy. */ static ScrRgnChunk *scr_rgn_chunk_reserve(const ScrRegion *r) { ScrRgnChunk *c = scr_rgn_chunk_map(); + c->huge = false; +#if SCR_RGN_MMAP + c->touched = (char *)c + SCR_RGN_HDR; +#else + c->touched = (char *)c + SCR_RGN_CHUNK; /* allocated zeroed */ +#endif #if SCR_RGN_MMAP && defined(MADV_HUGEPAGE) - if (scr_rgn_huge(r)) (void)madvise(c, SCR_RGN_CHUNK, MADV_HUGEPAGE); + if (scr_rgn_huge(r)) { + (void)madvise(c, SCR_RGN_CHUNK, MADV_HUGEPAGE); + c->huge = true; + } #else (void)r; #endif return c; } +/* Faults [from, to) of chunk `c` in ahead of use. */ +static void scr_rgn_prefault(ScrRgnChunk *c, char *from, char *to) { + if (to > c->touched) c->touched = to; + scr_mem_prefault(from, to); +} + static ScrRgnChunk *scr_rgn_chunk_new(ScrRegion *r) { - ScrRgnChunk *c = r->spare ? r->spare : scr_rgn_chunk_reserve(r); + ScrRgnChunk *c = r->spare; + if (!c && scr_rgn.cache) { + c = scr_rgn.cache; + scr_rgn.cache = c->next; + scr_rgn.cache_bytes -= (size_t)c->found; + } + if (!c) c = scr_rgn_chunk_reserve(r); r->spare = NULL; - if (r->bytes >= SCR_RGN_AHEAD_START) scr_mem_prefault(c, (char *)c + 2 * SCR_RGN_AHEAD); + if (r->bytes >= SCR_RGN_AHEAD_START) scr_rgn_prefault(c, (char *)c, (char *)c + 2 * SCR_RGN_AHEAD); #ifdef SCR_LSAN_IMMORTAL if (__lsan_register_root_region) __lsan_register_root_region(c, SCR_RGN_CHUNK); #endif @@ -369,28 +406,76 @@ static void scr_rgn_ahead(ScrRegion *r, ScrRgnChunk *c, char *from) { size_t before = (size_t)(from - (char *)c), after = (size_t)(c->bump - (char *)c); if (after / SCR_RGN_AHEAD != before / SCR_RGN_AHEAD) { char *lo = (char *)c + (after / SCR_RGN_AHEAD + 1) * SCR_RGN_AHEAD; - if (lo < (char *)c + SCR_RGN_CHUNK) scr_mem_prefault(lo, lo + SCR_RGN_AHEAD); + if (lo < (char *)c + SCR_RGN_CHUNK) scr_rgn_prefault(c, lo, lo + SCR_RGN_AHEAD); } if (!r->spare && after >= SCR_RGN_CHUNK / 2 && before < SCR_RGN_CHUNK / 2) { bool huge = scr_rgn_huge(r); r->spare = scr_rgn_chunk_reserve(r); - scr_mem_prefault(r->spare, (char *)r->spare + (huge ? SCR_RGN_CHUNK : SCR_RGN_AHEAD)); + scr_rgn_prefault(r->spare, (char *)r->spare, (char *)r->spare + (huge ? SCR_RGN_CHUNK : SCR_RGN_AHEAD)); } } +/* Returns a chunk that holds no object to the system. */ +static void scr_rgn_chunk_drop(ScrRgnChunk *c) { +#if SCR_RGN_MMAP + munmap(c, SCR_RGN_CHUNK); +#elif defined(_WIN32) + _aligned_free(c); +#else + free(c); +#endif +} + /* A spare chunk never held objects: it goes straight back. */ static void scr_rgn_spare_drop(ScrRegion *r) { if (!r->spare) return; -#if SCR_RGN_MMAP - munmap(r->spare, SCR_RGN_CHUNK); -#elif defined(_WIN32) - _aligned_free(r->spare); -#else - free(r->spare); -#endif + scr_rgn_chunk_drop(r->spare); r->spare = NULL; } +/* A freed region's chunk: kept for the thread's next regions while the + * cache has room, cleared (a fresh chunk is zero, and allocation relies on + * that), else unmapped (SCR_RGN_CACHE_BYTES). Sanitized builds never reuse + * a chunk (scr_rgn_chunk_unmap). */ +static void scr_rgn_chunk_retire(ScrRgnThread *t, ScrRgnChunk *c) { +#ifndef SCR_RGN_POISON + char *first = (char *)c + SCR_RGN_HDR; + if (c->bump > c->touched) c->touched = c->bump; +#if SCR_RGN_MMAP + char *warm = (char *)c + SCR_RGN_CACHE_WARM; + size_t resident = (size_t)((c->touched < warm ? c->touched : warm) - (char *)c); +#else + size_t resident = SCR_RGN_CHUNK; +#endif + if (!c->huge && t->cache_bytes + resident <= SCR_RGN_CACHE_BYTES) { +#if SCR_RGN_MMAP + if (c->touched > warm) { + /* Fresh zero pages past the warm part (64 KiB steps cover every + * page size). */ + size_t tail = ((size_t)(c->touched - warm) + 0xffff) & ~(size_t)0xffff; + if (tail > SCR_RGN_CHUNK - SCR_RGN_CACHE_WARM) tail = SCR_RGN_CHUNK - SCR_RGN_CACHE_WARM; + if (mmap(warm, tail, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED) { + scr_rgn_chunk_unmap(c); + return; + } + c->touched = warm; + } + memset(first, 0, (size_t)((c->bump < warm ? c->bump : warm) - first)); +#else + memset(first, 0, (size_t)(c->bump - first)); +#endif + c->found = (int64_t)resident; + c->next = t->cache; + t->cache = c; + t->cache_bytes += resident; + return; + } +#else + (void)t; +#endif + scr_rgn_chunk_unmap(c); +} + /* The instance stride: the emitted fast path rounds the size the same way. */ static inline size_t scr_rgn_stride(const ScrRgnClass *cls) { return (cls->size + 7) & ~(size_t)7; } @@ -875,7 +960,7 @@ static void scr_rgn_free_region(ScrRgnThread *t, ScrRegion *r) { scr_rgn_spare_drop(r); for (ScrRgnChunk *c = r->chunks, *next; c; c = next) { next = c->next; - scr_rgn_chunk_unmap(c); + scr_rgn_chunk_retire(t, c); } for (ScrRgnSeg *s = r->segs, *next; s; s = next) { next = s->next; @@ -1118,7 +1203,7 @@ static bool scr_rgn_try_free(ScrRgnThread *t, ScrRegion *r, bool tentative) { /* A condemned region not in use, never attempted, or kept by an attempt * whose outcome may have changed since (see SCR_RGN_RETRY_BYTES). */ static bool scr_rgn_due(const ScrRegion *r, const ScrRgnThread *t) { - if (r->state != SCR_RGN_CONDEMNED || r->depth != 0 || r == t->current) return false; + if (r->state != SCR_RGN_CONDEMNED || r->depth != 0 || r->fibers != 0 || r == t->current) return false; return !r->kept || t->allocated >= r->retry_at || scr_rgn_counted(r) != r->kept_counted; } @@ -1162,11 +1247,55 @@ static void scr_rgn_retry(ScrRgnThread *t) { scr_rgn_try_due(t, false); } +/* ── async continuations ─────────────────────────────────────────────── */ + +/* A fiber spawned while a region is current carries it: the region + * cannot be freed until the fiber is gone, so work that resumes after an + * await can keep allocating in it, condemned or not (scr_rgn_due). The + * fiber's own references to the region's objects are counted like any + * others. Fibers of the default region carry nothing. */ +static void *scr_rgn_fiber_capture(void) { + ScrRgnThread *t = &scr_rgn; + ScrRegion *r = t->current; + if (t->exited || !r || r->id == 0) return NULL; + r->fibers++; + return r; +} + +static void scr_rgn_fiber_drop(void *region) { + if (region && !scr_rgn.exited) ((ScrRegion *)region)->fibers--; +} + +/* The event loop resumes a fiber: its region becomes current until the + * fiber suspends or finishes. Run frames never span a suspension, so the + * fiber leaves the region current that it found. */ +static void *scr_rgn_fiber_resume(void *region) { + ScrRgnThread *t = &scr_rgn; + if (t->exited || !t->dflt) return NULL; /* no region on this thread yet */ + ScrRegion *previous = t->current; + scr_rgn_switch(t, region ? (ScrRegion *)region : t->dflt); + return previous; +} + +static void scr_rgn_fiber_suspend(void *previous) { + if (previous && !scr_rgn.exited) scr_rgn_switch(&scr_rgn, previous); +} + +static const ScrRgnFiberHooks scr_rgn_fiber_hooks = { + scr_rgn_fiber_capture, + scr_rgn_fiber_drop, + scr_rgn_fiber_resume, + scr_rgn_fiber_suspend, +}; + +_Atomic(const ScrRgnFiberHooks *) scr_region_fiber_hooks = NULL; + /* ── program-facing entry points ─────────────────────────────────────── */ double scr_region_create(const ScrRgnType *types) { const ScrRgnType *expected = NULL; atomic_compare_exchange_strong(&scr_rgn_types, &expected, types); + atomic_store_explicit(&scr_region_fiber_hooks, &scr_rgn_fiber_hooks, memory_order_relaxed); /* Counting starts before the region's first object exists. */ atomic_store_explicit(&scr_region_counting, 1, memory_order_relaxed); ScrRgnThread *t = scr_rgn_thread(); @@ -1230,6 +1359,10 @@ static void scr_rgn_thread_exit(void) { free(r->cur); free(r); } + for (ScrRgnChunk *c = t->cache, *next; c; c = next) { + next = c->next; + scr_rgn_chunk_drop(c); + } free(t->regions); free(t->cursors); free(t->stack); @@ -1243,4 +1376,5 @@ static void scr_rgn_thread_exit(void) { #endif memset(t, 0, sizeof *t); t->exit_registered = true; /* the cleanup ran; a late allocation keeps its memory */ + t->exited = true; /* fibers destroyed later must not touch the freed regions */ } diff --git a/packages/runtime/src/scr_region.h b/packages/runtime/src/scr_region.h index 14eae6951..69c2d3f14 100644 --- a/packages/runtime/src/scr_region.h +++ b/packages/runtime/src/scr_region.h @@ -77,6 +77,11 @@ typedef struct ScrRgnChunk { struct ScrRgnChunk *next; char *bump; /* the next free segment byte */ int64_t found; /* references the last walk saw into this chunk */ + /* What stays resident across reuse (scr_region.c's chunk cache): the + * highest byte any region carved or faulted in, and whether the chunk + * may be backed by huge pages. */ + char *touched; + bool huge; } ScrRgnChunk; _Static_assert(offsetof(ScrRgnChunk, count) == 0 && offsetof(ScrRgnChunk, owner) == sizeof(int64_t), "llvm/regions.ts addresses the chunk count at 0 and the owner at 8"); @@ -111,4 +116,20 @@ void scr_region_release(double id); void scr_region_ref(ScrRgnWalk *w, void *obj); void scr_region_slot(ScrRgnWalk *w, void *obj, void (*release)(void *)); +/* Async continuations. A fiber that runs an async function body carries + * the region that was current when it was spawned (`capture`; NULL is the + * default region), and the event loop makes that region current while the + * fiber runs after an await (`resume` answers the region to restore with + * `suspend`). A region is never freed while a fiber that carries it + * exists; `drop` ends the fiber's hold. scr_region_create installs the + * hooks (process-wide, once); until then the fiber machinery (scr_async.c) + * calls nothing. Every hook acts on the calling thread's regions. */ +typedef struct ScrRgnFiberHooks { + void *(*capture)(void); + void (*drop)(void *region); + void *(*resume)(void *region); + void (*suspend)(void *previous); +} ScrRgnFiberHooks; +extern _Atomic(const ScrRgnFiberHooks *) scr_region_fiber_hooks; + #endif /* SCR_REGION_H */ diff --git a/packages/runtime/src/scr_region.test.c b/packages/runtime/src/scr_region.test.c index b79c818cd..31e98942a 100644 --- a/packages/runtime/src/scr_region.test.c +++ b/packages/runtime/src/scr_region.test.c @@ -381,6 +381,30 @@ static void check_debug_report(void) { puts("the debug report names what keeps a region"); } +/* A freed region's chunk serves the thread's next region, cleared where + * the freed objects were. Sanitized builds never reuse a chunk. */ +static void check_chunk_reuse(void) { +#ifndef SCR_RC_AUDIT + double r = region(); + scr_region_enter(r); + Node *first = node_new(7); + first->other = node_retain(first); + scr_region_leave(); + ScrRgnChunk *chunk = scr_rgn_chunk_of(first); + node_release(first); + scr_region_release(r); + double s = region(); + scr_region_enter(s); + Node *again = node_new(8); + scr_region_leave(); + assert(scr_rgn_chunk_of(again) == chunk); + assert(again->other == NULL && again->parent == NULL && again->kids == NULL); + node_release(again); + scr_region_release(s); + puts("a freed region's chunk serves the next region, cleared"); +#endif +} + static void check_poison(void) { #if defined(SCR_RC_AUDIT) && !defined(_WIN32) double r = region(); @@ -499,6 +523,7 @@ int main(int argc, char **argv) { check_in_use(); check_cursors(); check_retry_schedule(); + check_chunk_reuse(); check_poison(); } else if (!strcmp(mode, "debug")) { check_debug_report(); diff --git a/packages/runtime/src/scr_region.test.ts b/packages/runtime/src/scr_region.test.ts index cfadac91e..28e44e09a 100644 --- a/packages/runtime/src/scr_region.test.ts +++ b/packages/runtime/src/scr_region.test.ts @@ -122,11 +122,16 @@ describe.skipIf(process.platform === "win32")("counted lifetime regions", () => const sanitized = lane === "sanitized"; expect(owned.stdout.trim().split("\n")).toEqual([ ...OWNED_STDOUT, - ...(sanitized ? ["sanitized builds fault on any access to a freed region"] : []), + sanitized + ? "sanitized builds fault on any access to a freed region" + : "a freed region's chunk serves the next region, cleared", ]); const ownedStats = attempts(owned.stderr); - expect(ownedStats.attempts).toEqual([...OWNED_ATTEMPTS, ...(sanitized ? ["18 freed"] : [])]); - const n = sanitized ? 18 : 17; + expect(ownedStats.attempts).toEqual([ + ...OWNED_ATTEMPTS, + ...(sanitized ? ["18 freed"] : ["18 freed", "19 freed"]), + ]); + const n = sanitized ? 18 : 19; expect(ownedStats.summaries).toEqual([ `scriptc regions: ${n} created, ${n} released, ${n} freed, 0 pinned, 0 kept`, ]); diff --git a/tests/corpus/5013-lifetime-region-async.ts b/tests/corpus/5013-lifetime-region-async.ts index 683d93d6d..930c6af67 100644 --- a/tests/corpus/5013-lifetime-region-async.ts +++ b/tests/corpus/5013-lifetime-region-async.ts @@ -1,10 +1,9 @@ // LifetimeRegion (@scriptc/experimental) with async callbacks: run(fn) // returns fn's promise once fn first awaits, and the work that resumes -// after an await runs outside the region (it allocates in the default -// region, which is never freed). Releasing the region while the async work -// is still pending is safe: everything the pending work refers to stays -// allocated, and objects of the default region that refer into a released -// region keep it allocated for good. Node.js prints the same. +// after an await still allocates in the region. Releasing the region while +// the async work is still pending is safe: the region is not freed before +// that work has finished and nothing outside refers to its objects. +// Node.js prints the same. import type { ProgramLifetime } from "@scriptc/types"; import { LifetimeRegion } from "@scriptc/experimental"; diff --git a/tests/corpus/5023-lifetime-region-await.ts b/tests/corpus/5023-lifetime-region-await.ts new file mode 100644 index 000000000..b17ef07aa --- /dev/null +++ b/tests/corpus/5023-lifetime-region-await.ts @@ -0,0 +1,200 @@ +// LifetimeRegion (@scriptc/experimental) across await: an async callback +// keeps allocating in its region after it resumes, so a region per request +// holds the whole request's graph and frees it once released. Requests run +// concurrently and interleave at every await; continuations nest other +// regions, reject, release their region while still pending, spawn work +// that outlives the request, and return objects that escape into a cache. +// Node.js prints the same. +import type { ProgramLifetime } from "@scriptc/types"; +import { LifetimeRegion } from "@scriptc/experimental"; + +class Token implements ProgramLifetime { + readonly text: string; + readonly pos: number; + constructor(text: string, pos: number) { + this.text = text; + this.pos = pos; + } +} + +class Node implements ProgramLifetime { + readonly token: Token; + readonly kids: Node[] = []; + parent: Node | undefined = undefined; + readonly attrs = new Map(); + constructor(token: Token) { + this.token = token; + } +} + +const tick = (): Promise => new Promise((resolve) => setTimeout(resolve, 1)); +const turn = (): Promise => new Promise((resolve) => setImmediate(resolve)); + +function tokenize(source: string): Token[] { + return source.split(" ").map((text, i) => new Token(text, i)); +} + +async function parse(tokens: Token[]): Promise { + const root = new Node(tokens[0]!); + for (let i = 1; i < tokens.length; i++) { + if (i % 3 === 0) await turn(); + const node = new Node(tokens[i]!); + node.parent = root; + node.attrs.set("pos", `${tokens[i]!.pos}`); + root.kids.push(node); + } + return root; +} + +function render(root: Node): string { + return `${root.token.text}(${root.kids.map((k) => `${k.token.text}@${k.attrs.get("pos")}`).join(" ")})`; +} + +async function handle(id: number, source: string): Promise { + const tokens = tokenize(source); + await tick(); + const root = await parse(tokens); + await Promise.resolve(); + // Children spawned after a resume run in the region too. + const sizes = await Promise.all(root.kids.map(async (kid) => { + await turn(); + const copy = new Node(kid.token); + copy.parent = kid; + return copy.token.text.length; + })); + return `#${id} ${render(root)} sizes=${sizes.join(",")}`; +} + +async function serve(id: number, source: string): Promise { + const region = new LifetimeRegion(); + try { + return await region.run(() => handle(id, source)); + } finally { + region.release(); + } +} + +// A sync generator driven by a resumed continuation. +function* chain(tokens: Token[]): Generator { + let prev: Node | undefined; + for (const token of tokens) { + const node = new Node(token); + node.parent = prev; + prev = node; + yield node; + } +} + +async function nested(): Promise { + const outer = new LifetimeRegion(); + const inner = new LifetimeRegion(); + const result = await outer.run(async () => { + const before = new Node(new Token("outer", 0)); + await tick(); + const local = inner.run(() => new Node(new Token("inner-sync", 1))); + const later = await inner.run(async () => { + await turn(); + const n = new Node(new Token("inner-async", 2)); + n.parent = local; + return n; + }); + const after = new Node(new Token("after", 3)); + after.parent = before; + after.kids.push(local, later); + const gen = [...chain(tokenize("g0 g1 g2"))]; + return `${after.parent.token.text} ${after.kids.map((k) => k.token.text).join("+")} ${later.parent!.token.text} ${gen.at(-1)!.parent!.token.text}`; + }); + inner.release(); + outer.release(); + return result; +} + +async function rejects(): Promise { + const region = new LifetimeRegion(); + try { + await region.run(async () => { + const node = new Node(new Token("doomed", 0)); + await tick(); + node.kids.push(new Node(new Token("child", 1))); + throw new Error(`failed after ${node.kids.length} child`); + }); + return "no error"; + } catch (e) { + return e instanceof Error ? e.message : String(e); + } finally { + region.release(); + } +} + +async function releasedWhilePending(): Promise { + const region = new LifetimeRegion(); + const pending = region.run(async () => { + const first = new Node(new Token("first", 0)); + await tick(); + // The region was released meanwhile; the work still allocates in it. + const second = new Node(new Token("second", 1)); + second.parent = first; + await turn(); + return `${second.parent.token.text}>${second.token.text}`; + }); + region.release(); + return await pending; +} + +// Background work started in a request outlives it. +let background: Promise | undefined; +async function outlives(): Promise { + const region = new LifetimeRegion(); + const text = await region.run(async () => { + const node = new Node(new Token("request", 0)); + background = (async (): Promise => { + await tick(); + await tick(); + const late = new Node(new Token("late", 1)); + late.parent = node; + return `${late.parent.token.text}<-${late.token.text}`; + })(); + await turn(); + return node.token.text; + }); + region.release(); + return text; +} + +// A result that escapes the request into a module-level cache keeps the +// region allocated until the cache lets go of it. +const cache = new Map(); +async function escapes(key: string): Promise { + const region = new LifetimeRegion(); + const node = await region.run(async () => { + await turn(); + const n = new Node(new Token(key, 0)); + n.kids.push(new Node(new Token(`${key}-kid`, 1))); + return n; + }); + region.release(); + cache.set(key, node); + return `${node.token.text}/${node.kids[0]!.token.text}`; +} + +async function main(): Promise { + const sources = ["let a = b + c ;", "fn f ( x ) { x }", "1 2 3 4 5 6 7", "if ( x ) y else z"]; + for (let round = 0; round < 2; round++) { + const responses = await Promise.all(sources.map((s, i) => serve(round * 10 + i, s))); + for (const r of responses) console.log(r); + } + console.log(await nested()); + console.log(await rejects()); + console.log(await releasedWhilePending()); + console.log(await outlives()); + console.log(await background); + console.log(await escapes("cached")); + console.log(cache.get("cached")!.kids[0]!.token.pos); + cache.clear(); + // A later region, after the cache let go. + console.log(await serve(99, "done .")); +} + +main().catch((e) => { + console.log("unexpected", String(e)); +}); diff --git a/tests/harness/lifetime-regions.test.ts b/tests/harness/lifetime-regions.test.ts index 7eb294482..2b1516ef4 100644 --- a/tests/harness/lifetime-regions.test.ts +++ b/tests/harness/lifetime-regions.test.ts @@ -145,9 +145,9 @@ describe.skipIf(process.platform === "win32")("lifetime regions", { timeout: 240 }); test("async work, nesting, holders the walk does not inspect and handles", async () => { - // Objects allocated after an await live in the default region and keep - // the regions they refer into. - expect((await run("5013-lifetime-region-async.ts")).summaries).toEqual([summary(7, 2)]); + // Work that resumes after an await allocates in its region, which is + // freed once that work has finished. + expect((await run("5013-lifetime-region-async.ts")).summaries).toEqual([summary(7, 7)]); const nesting = await run("5014-lifetime-region-nesting.ts"); expect(nesting.summaries).toEqual([summary(4, 2)]); const opaque = await run("5021-lifetime-region-opaque-holders.ts"); @@ -156,6 +156,23 @@ describe.skipIf(process.platform === "win32")("lifetime regions", { timeout: 240 expect((await run("5019-lifetime-region-values.ts")).summaries).toEqual([summary(2, 0)]); }); + test("regions carried across await by concurrent requests are freed", async () => { + const stats = await run("5023-lifetime-region-await.ts"); + expect(stats.summaries).toEqual([summary(15, 15)]); + // Each request's region (eight interleaved ones, then a later one) is + // freed when the request releases it; a region released while its work + // is pending, or while work it started is still running, is freed once + // that work ends, without an attempt that keeps it. + for (const id of [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15]) + expect( + stats.attempts.filter((a) => a.startsWith(`${id} `)), + `region ${id}`, + ).toEqual([`${id} freed`]); + // The nested region is referenced by the outer one until that is freed; + // the escaping result keeps its region until the cache lets go. + keptThenFreed(stats.attempts, [10, 14]); + }); + test("weak keys of freed regions do not survive", async () => { const stats = await run("5016-lifetime-region-weak-keys.ts"); expect(stats.summaries).toEqual([summary(5, 4)]); From 1689404912c37cefa2f5719c305cd97767624d2b Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 12:07:26 -0700 Subject: [PATCH 005/117] Keep records, tuples and spread updates that own references in frame storage Frame storage for non-escaping records was limited to number, boolean and inline-union fields. Records with string, array, record or class fields, tuples, and same-shape spread updates (`{ ...state, count }`) were always heap-allocated, even when every use only projected them. Closed record and tuple shapes now qualify regardless of field types. The frame owns the reference fields: they start empty in entry-addressed slots and are registered before anything is stored, with the binding's lexical scope for locals and with the statement frame for call-argument temporaries, so an exception while the record is being built releases exactly what was stored. Interned string literal fields need no owner. A reassigned binding builds the new value apart, copies it over its slot and then releases the replaced fields. Result-slot entries cover producers returning such records, tuples and spreads of a binding, and store into the zeroed caller storage without releasing an old value. A spread of a binding is a projection for the lifetime analysis. Published shapes and switch-case bindings of reference-owning shapes keep heap storage. Co-Authored-By: Claude Opus 5.5 --- benchmarks/runtime/README.md | 1 + benchmarks/runtime/workloads.json | 7 + benchmarks/runtime/workloads/value-records.ts | 93 ++++++++++ .../src/backend/llvm/call-lifetimes.ts | 6 + packages/compiler/src/backend/llvm/emitter.ts | 74 +++++++- .../compiler/src/backend/llvm/expr-calls.ts | 5 +- .../src/backend/llvm/record-results.ts | 79 ++++++++- .../src/backend/llvm/stack-objects.test.ts | 61 +++++++ .../src/backend/llvm/stack-objects.ts | 158 +++++++++++++++-- .../5960-frame-records-own-references.ts.json | 6 + .../corpus/5961-frame-spread-updates.ts.json | 6 + .../tests/corpus/5962-frame-tuples.ts.json | 6 + .../5960-frame-records-own-references.ts | 164 ++++++++++++++++++ tests/corpus/5961-frame-spread-updates.ts | 96 ++++++++++ tests/corpus/5962-frame-tuples.ts | 57 ++++++ 15 files changed, 795 insertions(+), 24 deletions(-) create mode 100644 benchmarks/runtime/workloads/value-records.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-frame-records-own-references.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5961-frame-spread-updates.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5962-frame-tuples.ts.json create mode 100644 tests/corpus/5960-frame-records-own-references.ts create mode 100644 tests/corpus/5961-frame-spread-updates.ts create mode 100644 tests/corpus/5962-frame-tuples.ts diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index ed9ee0532..9635ee1f7 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -19,6 +19,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `intern-table`, `intern-table-map`, `intern-table-1`, `intern-table-map-1` | cpu | worker threads interning the same type-like objects under string keys and records under number keys, then hits and misses: one shared `InternTable` per kind of key, or a module-level `Map` per thread (the `-map` entries), with 8 threads or 1 (the `-1` entries); under Node.js every thread has its own tables | | `atomics-contended` | cpu | four worker threads updating `SharedArrayBuffer` counters with `Atomics`: one shared counter, one counter per worker, a `compareExchange` loop, and `Atomics.wait`/`notify` handoffs | | `value-objects` | cpu | small immutable records and class instances: vector helpers, method chains, particle updates | +| `value-records` | cpu | records that hold strings, spread state updates and destructured tuples: token helpers, an immutable reducer, tuple returns | | `region-builds` | cpu | a watch-mode build loop over `LifetimeRegion`: each build binds a program in a new region and releases the previous one, which a cache keeps referenced for two builds | | `optional-fields` | cpu | records and class instances with `number \| undefined` and other scalar-union fields | | `record-boundaries` | cpu | records built from unchecked array reads passed to and returned from annotated functions | diff --git a/benchmarks/runtime/workloads.json b/benchmarks/runtime/workloads.json index c0d643a58..b95791a1d 100644 --- a/benchmarks/runtime/workloads.json +++ b/benchmarks/runtime/workloads.json @@ -141,6 +141,13 @@ "2" ] }, + { + "name": "value-records", + "entry": "workloads/value-records.ts", + "args": [ + "1" + ] + }, { "name": "region-builds", "entry": "workloads/region-builds.ts", diff --git a/benchmarks/runtime/workloads/value-records.ts b/benchmarks/runtime/workloads/value-records.ts new file mode 100644 index 000000000..922fb8e43 --- /dev/null +++ b/benchmarks/runtime/workloads/value-records.ts @@ -0,0 +1,93 @@ +// Records that hold references: a tokenizer that builds token records with +// string fields and passes them to helpers, an immutable reducer that +// updates its state with object spread, and tuple-returning helpers whose +// results are destructured at once. None of these temporaries outlives +// the statement or loop iteration that builds it. +interface Token { + kind: string; + text: string; + pos: number; +} +const KEYWORDS = ["let", "const", "if", "else", "for", "while", "return", "function"]; +function classify(text: string): string { + return KEYWORDS.includes(text) ? "keyword" : "ident"; +} +function token(kind: string, text: string, pos: number): Token { + return { kind, text, pos }; +} +function weight(t: Token): number { + return t.kind === "keyword" ? t.text.length * 3 : t.text.length + (t.pos & 7); +} +function tokenize(source: string): number { + let sum = 0; + let start = -1; + for (let i = 0; i <= source.length; i++) { + const c = i < source.length ? source.charCodeAt(i) : 32; + const word = (c >= 97 && c <= 122) || (c >= 48 && c <= 57) || c === 95; + if (word) { + if (start < 0) start = i; + continue; + } + if (start >= 0) { + const text = source.slice(start, i); + const t = token(classify(text), text, start); + sum += weight(t); + start = -1; + } + if (c !== 32 && c !== 10) { + const punct = { kind: "punct", text: source[i]!, pos: i }; + sum += weight(punct) + (punct.text === ";" ? 1 : 0); + } + } + return sum; +} + +interface State { + mode: string; + depth: number; + count: number; + last: string; +} +function step(s: State, text: string): State { + if (text === "{") return { ...s, depth: s.depth + 1, last: text }; + if (text === "}") return { ...s, depth: s.depth - 1, last: text }; + return s.mode === "code" ? { ...s, count: s.count + 1 } : { ...s, mode: "code", last: text }; +} +function reduce(texts: string[], rounds: number): number { + let total = 0; + for (let r = 0; r < rounds; r++) { + let state: State = { mode: "start", depth: 0, count: 0, last: "" }; + for (const text of texts) { + state = step(state, text); + if (state.depth > 3) state = { ...state, depth: 3 }; + } + total += state.count + state.depth + state.last.length + state.mode.length; + } + return total; +} + +function divmod(a: number, b: number): [number, number] { + return [Math.floor(a / b), a % b]; +} +function split(text: string, at: number): [string, string] { + return [text.slice(0, at), text.slice(at)]; +} +function tuples(n: number, texts: string[]): number { + let sum = 0; + for (let i = 0; i < n; i++) { + const [q, r] = divmod(i * 31, 17); + const [head, tail] = split(texts[i % texts.length]!, r % 3); + sum += q + r + head.length * 2 + tail.length; + } + return sum; +} + +const scaleArg = Number(process.argv[2] ?? "1"); +const line = "function step ( s , text ) { if ( text ) { return s ; } let x = s ; while ( x ) { x = x ; } }\n"; +const source = line.repeat(Math.floor(400 * scaleArg)); +const texts = source.split(" ").filter((t) => t.length > 0); +let lexed = 0; +for (let i = 0; i < 240; i++) lexed += tokenize(source); +const reduced = reduce(texts, Math.floor(600 * scaleArg)); +const pairs = tuples(Math.floor(2_000_000 * scaleArg), texts); +console.log("tokens", lexed, "reduce", reduced, "tuples", pairs); diff --git a/packages/compiler/src/backend/llvm/call-lifetimes.ts b/packages/compiler/src/backend/llvm/call-lifetimes.ts index 72acc625e..5663047cd 100644 --- a/packages/compiler/src/backend/llvm/call-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/call-lifetimes.ts @@ -177,6 +177,12 @@ function collectUses( ) return true; break; + case "recordClone": + // A same-shape spread copies the source's fields (retaining the + // references) and keeps no reference to the source itself. + if (node.source.kind !== "varRef") break; + for (const field of node.overrides) expr(field.value); + return true; case "recordLit": if (node.type.kind !== "record") break; for (const field of node.fields) diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 09bf4979c..2acf4a35c 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -88,7 +88,7 @@ import { type StringSplit, } from "./split-loops.js"; import { scalarizeNumericRecords } from "../../ir/scalar-records.js"; -import { RESULT_ENTRY_PREFIX, addRecordResultEntries } from "./record-results.js"; +import { RESULT_DST_ID, RESULT_ENTRY_PREFIX, addRecordResultEntries } from "./record-results.js"; import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js"; import { everyExpr, everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js"; import { @@ -164,7 +164,9 @@ import { emitStackObject, findLocalStackObjects, findReassignedStackObjects, + stackObjectFields, stackObjectStruct, + type StackObjectField, type StackObjectSource, } from "./stack-objects.js"; import { @@ -574,6 +576,9 @@ export class LlEmitter { private reassignedStackObjects = new Set(); /** The binding slot of each reassigned stack-object local. */ private stackObjectSlots = new Map(); + /** Entry-block pointers to the reference fields of each frame object + * slot (stack-objects.ts stackObjectFields). */ + stackObjectFieldPtrs = new Map(); private localUnionStorageProofs = new Map(); private localUnionStorage = new Map(); integerArrayBindings = new Set(); @@ -4491,6 +4496,30 @@ export class LlEmitter { if (isRefCounted(type)) this.currentFrame().push({ name: slot, type, slot: true }); } + /** The innermost lexical scope releases a frame object's reference + * fields when it exits, as it releases its bindings. */ + ownScopeFields(fields: readonly StackObjectField[]): void { + const scope = this.scopes[this.scopes.length - 1]!; + for (const field of fields) scope.push({ slot: field.ptr, type: field.type }); + } + + /** Strike frame-owned slots (ownSlot) from their statement frames: their + * contents are moving to another owner. */ + disownSlots(slots: readonly { ptr: string }[]): void { + for (const { ptr } of slots) { + let found = false; + for (let i = this.frames.length - 1; i >= 0 && !found; i--) { + const idx = this.frames[i]!.findIndex((e) => e.slot === true && e.name === ptr); + if (idx >= 0) { + this.frames[i]!.splice(idx, 1); + found = true; + } + } + if (!found) + throw new InternalCompilerError(`llvm emitter bug: disowned slot ${ptr} not in a frame`); + } + } + /** Strike a refcounted temp from its frame: ownership is being moved. */ moveTemp(v: LlValue): void { if (!isRefCounted(v.type) || this.isImmortal(v.name)) return; @@ -6384,6 +6413,7 @@ export class LlEmitter { ? findReassignedStackObjects(this, fn, this.callLifetimes) : new Set(); this.stackObjectSlots = new Map(); + this.stackObjectFieldPtrs = new Map(); this.localUnionStorageProofs = findLocalUnionStorage(fn, this.callLifetimes, this.unionSources); this.localUnionStorage = new Map(); this.walkBorrows = this.walkBorrowsByFunction.get(fn.name) ?? new Set(); @@ -7415,12 +7445,18 @@ export class LlEmitter { } const stackObject = this.localStackObjects.get(s.localId); if (stackObject) { - B.line(`store ptr ${emitStackObject(this, stackObject).name}, ptr ${b.slot}`); + const value = emitStackObject(this, stackObject, (fields) => this.ownScopeFields(fields)); + B.line(`store ptr ${value.name}, ptr ${b.slot}`); break; } if (s.init && this.reassignedStackObjects.has(s.localId)) { const slot = this.stackObjectSlot(s.localId, s.init.type); - emitStackObject(this, s.init as StackObjectSource, slot); + emitStackObject( + this, + s.init as StackObjectSource, + (fields) => this.ownScopeFields(fields), + slot, + ); B.line(`store ptr ${slot}, ptr ${b.slot}`); break; } @@ -7592,12 +7628,28 @@ export class LlEmitter { break; } if (this.reassignedStackObjects.has(s.localId)) { - // The new value may read the old one: build it apart, then copy. + // The new value may read the old one: build it apart (its + // reference fields owned by this statement until it completes), + // then copy it over the binding's slot. The binding takes over the + // new fields; the old ones are released after the slot no longer + // holds them. const struct = stackObjectStruct(s.value.type); - const value = emitStackObject(this, s.value as StackObjectSource); + let owned: readonly StackObjectField[] = []; + const value = emitStackObject(this, s.value as StackObjectSource, (fields) => { + owned = fields; + for (const field of fields) this.ownSlot(field.ptr, field.type); + }); + const target = this.stackObjectSlot(s.localId, s.value.type); + const old = stackObjectFields(this, s.value.type, target).map((field) => { + const t = B.tmp(); + B.line(`${t} = load ptr, ptr ${field.ptr}`); + return { name: t, type: field.type }; + }); const bits = B.tmp(); B.line(`${bits} = load ${struct}, ptr ${value.name}`); - B.line(`store ${struct} ${bits}, ptr ${this.stackObjectSlot(s.localId, s.value.type)}`); + B.line(`store ${struct} ${bits}, ptr ${target}`); + this.disownSlots(owned); + for (const field of old) this.releaseValue(field.name, field.type); break; } const localStorage = this.localUnionStorage.get(s.localId); @@ -7807,7 +7859,15 @@ export class LlEmitter { s.kind === "fieldSet" ? this.classFieldPtr(obj.name, s.className, s.field) : this.recordFieldPtr(obj.name, s.shapeId, s.field); - this.replaceField(ptr, type, inline, v); + // A result-slot entry fills zeroed caller storage, each field once. + if ( + s.kind === "recordSet" && + s.obj.kind === "varRef" && + s.obj.localId === RESULT_DST_ID && + this.currentFunctionName.startsWith(RESULT_ENTRY_PREFIX) + ) + this.initField(ptr, type, inline, v); + else this.replaceField(ptr, type, inline, v); if ( s.kind === "fieldSet" && s.field === "name" && diff --git a/packages/compiler/src/backend/llvm/expr-calls.ts b/packages/compiler/src/backend/llvm/expr-calls.ts index 8c748cc93..d8f99140d 100644 --- a/packages/compiler/src/backend/llvm/expr-calls.ts +++ b/packages/compiler/src/backend/llvm/expr-calls.ts @@ -146,7 +146,10 @@ export function emitCallExpr( return emitScalarOptional(host, a); if (a.kind === "call" && host.scalarResultCall(a)) return emitCallExpr(host, a, false, true); - if (host.stackObjects && canStackObject(host, a)) return emitStackObject(host, a); + if (host.stackObjects && canStackObject(host, a)) + return emitStackObject(host, a, (fields) => { + for (const field of fields) host.ownSlot(field.ptr, field.type); + }); if (host.nullableFieldGet(a)) return { name: host.emitOwnedNullableStack(a).box, type: a.type }; // An inline union field read copies its tag and bits. diff --git a/packages/compiler/src/backend/llvm/record-results.ts b/packages/compiler/src/backend/llvm/record-results.ts index 41d76564e..47a7983d2 100644 --- a/packages/compiler/src/backend/llvm/record-results.ts +++ b/packages/compiler/src/backend/llvm/record-results.ts @@ -21,6 +21,16 @@ export function resultEntryName(name: string): string { return `${RESULT_ENTRY_PREFIX}${name}`; } +/** The local id of a result-slot entry's destination parameter. The + * caller passes zeroed frame storage, and on every path the entry stores + * each of its fields at most once, so a store into it is an + * initialization: there is no old value to release. */ +export const RESULT_DST_ID = "%into.dst"; + +function distinctNames(names: readonly string[]): boolean { + return new Set(names).size === names.length; +} + /** A plain record shape whose fields are numbers, booleans and inline * scalar unions (inline-unions.ts): its fields own nothing. */ export function scalarRecordShape( @@ -38,6 +48,15 @@ export function scalarRecordShape( ); } +/** A closed record or tuple shape: declared fields only. Its instance can + * live in caller storage; fields that own references are released by the + * frame that holds the storage (stack-objects.ts). Tuples are element + * records: destructuring and element reads project them, and every + * array-like use of one is a whole-value use that keeps it on the heap. */ +export function frameRecordShape(shape: IrRecordShape | undefined): boolean { + return shape !== undefined && !shape.indexValue; +} + /** A literal that stores every field of its shape, none of them through * the overflow map, and that sets no overflow-map flag. */ export function completeRecordLiteral( @@ -110,7 +129,7 @@ export function constructorInitializesFields(cls: IrClassDef, ctor: IrFunction): } /** Add a result-slot entry for every function whose returns all build a - * fresh scalar record or standalone scalar object, return another such + * fresh closed record or standalone scalar object, return another such * producer's result (forwarding the slot), or return a parameter of a * record shape no store can change (copied into the slot). The original * function stays as it is; the backend calls the entry only where the @@ -155,8 +174,12 @@ export function addRecordResultEntries(mod: IrModule): IrModule { }, }); const dynamicStores = dynamicFieldStores(mod); + // Copies are limited to scalar shapes: a copy of a reference-owning + // record would not carry the undeclared source keys a checked conversion + // may keep beside the original (record-sources.ts). const copyable = (type: IrType): boolean => type.kind === "record" && + scalarRecordShape(shapes.get(type.shapeId), inline) && mod.lib === undefined && !written.has(type.shapeId) && !dynamicStores.all && @@ -165,9 +188,11 @@ export function addRecordResultEntries(mod: IrModule): IrModule { const fillable = (value: IrExpr, params: ReadonlySet): boolean => { switch (value.kind) { case "recordLit": - return completeRecordLiteral( - value, - shapes.get((value.type as IrType & { kind: "record" }).shapeId), + return ( + completeRecordLiteral( + value, + shapes.get((value.type as IrType & { kind: "record" }).shapeId), + ) && distinctNames(value.fields.map((field) => field.name)) ); case "new": return stackClass(value.className); @@ -175,6 +200,15 @@ export function addRecordResultEntries(mod: IrModule): IrModule { return fillable(value.then, params) && fillable(value.else_, params); case "varRef": return params.has(value.localId) && copyable(value.type); + case "recordClone": + // A spread of a binding: the copies read it before any override + // evaluates, as the heap clone does. + return ( + value.source.kind === "varRef" && + value.type.kind === "record" && + frameRecordShape(shapes.get(value.type.shapeId)) && + distinctNames(value.overrides.map((override) => override.name)) + ); case "call": return producers.has(value.callee); default: @@ -210,6 +244,39 @@ export function addRecordResultEntries(mod: IrModule): IrModule { loc: value.loc, })); } + case "recordClone": { + const shapeId = (value.type as IrType & { kind: "record" }).shapeId; + const overridden = new Set(value.overrides.map((override) => override.name)); + const copies: IrStmt[] = shapes + .get(shapeId)! + .fields.filter((field) => !overridden.has(field.name)) + .map((field): IrStmt => ({ + kind: "recordSet", + obj: dst, + shapeId, + field: field.name, + value: { + kind: "recordGet", + obj: value.source, + shapeId, + field: field.name, + type: field.type, + loc: value.loc, + }, + loc: value.loc, + })); + return [ + ...copies, + ...value.overrides.map((override): IrStmt => ({ + kind: "recordSet", + obj: dst, + shapeId, + field: override.name, + value: override.value, + loc: override.value.loc, + })), + ]; + } case "call": return [ { @@ -327,7 +394,7 @@ export function addRecordResultEntries(mod: IrModule): IrModule { return false; const ret = fn.returnType; return ( - (ret.kind === "record" && scalarRecordShape(shapes.get(ret.shapeId), inline)) || + (ret.kind === "record" && frameRecordShape(shapes.get(ret.shapeId))) || (ret.kind === "object" && stackClass(ret.className)) ); }); @@ -360,7 +427,7 @@ export function addRecordResultEntries(mod: IrModule): IrModule { for (const fn of candidates) { if (!producers.has(fn.name)) continue; const ret = fn.returnType; - const dstId = "%into.dst"; + const dstId = RESULT_DST_ID; const dst: IrExpr = { kind: "varRef", localId: dstId, type: ret, loc: fn.loc }; const body = transformStmtList(fn.body, { expr: (e) => e, diff --git a/packages/compiler/src/backend/llvm/stack-objects.test.ts b/packages/compiler/src/backend/llvm/stack-objects.test.ts index 845d6ae5e..a413db333 100644 --- a/packages/compiler/src/backend/llvm/stack-objects.test.ts +++ b/packages/compiler/src/backend/llvm/stack-objects.test.ts @@ -275,3 +275,64 @@ console.log(pick({ x: 1, y: 2 }, { x: 3, y: 4 }, true).y, forward({ x: 1, y: 1 } .sort(); expect(entries).toEqual([`${RESULT_ENTRY_PREFIX}forward`, `${RESULT_ENTRY_PREFIX}pick`]); }); + +const TOKENS = ` +interface Token { kind: string; text: string; pos: number } +function make(kind: string, text: string, pos: number): Token { return { kind, text, pos }; } +function width(t: Token): number { return t.text.length + t.kind.length; } +function divmod(a: number, b: number): [number, number] { return [Math.floor(a / b), a % b]; } +interface State { name: string; count: number } +function bump(s: State): State { return { ...s, count: s.count + 1 }; } +export function tokens(n: number, w: string): number { + const t = { kind: "id", text: w, pos: n }; + const u = make("num", w, n); + const [q, r] = divmod(n, 7); + return t.pos + width(u) + width({ kind: w, text: w, pos: 0 }) + q + r; +} +export function states(n: number, w: string): number { + let s: State = { name: w, count: 0 }; + for (let i = 0; i < n; i++) { + s = { ...s, count: s.count + 1 }; + s = bump(s); + } + return s.count + s.name.length; +} +console.log(tokens(3, "ab"), states(4, "cd")); +`; + +test("records and tuples that own references live in frame storage", async () => { + const ir = emitLlvmModule(await moduleFor(TOKENS)); + const tokens = body(ir, "tokens"); + expect(tokens).not.toMatch(/@sc_rnew_/); + expect(tokens).toMatch(/call void @sc_\w*into_make\(/); + expect(tokens).toMatch(/call void @sc_\w*into_divmod\(/); + // Reference fields start empty in entry-addressed slots, and the frame + // releases them; an interned literal field (`kind: "id"`) needs neither. + const fields = [...tokens.matchAll(/(%s\d+) = getelementptr inbounds %sc_rs_\w+, ptr %s\d+/g)]; + const owned = fields.filter(([, ptr]) => tokens.includes(`store ptr null, ptr ${ptr}\n`)); + expect(owned.length).toBe(5); + expect(fields.length).toBe(6); + for (const [, ptr] of owned) + expect(tokens).toMatch(new RegExp(`load ptr, ptr ${ptr}\\n\\s+call void @\\w+\\(`)); +}); + +test("spread updates copy into the binding's slot and release the replaced fields", async () => { + const mod = await moduleFor(TOKENS); + const entries = addRecordResultEntries(mod) + .functions.map((fn) => fn.name) + .filter((name) => name.startsWith(RESULT_ENTRY_PREFIX)); + expect(entries).toEqual( + expect.arrayContaining([ + `${RESULT_ENTRY_PREFIX}make`, + `${RESULT_ENTRY_PREFIX}divmod`, + `${RESULT_ENTRY_PREFIX}bump`, + ]), + ); + const states = body(emitLlvmModule(mod), "states"); + expect(states).not.toMatch(/@sc_rnew_|@sc_rclone_/); + expect(states).toMatch(/call void @sc_\w*into_bump\(/); + // The old name is loaded before the copy and released after it. + expect(states).toMatch( + /(%t\d+) = load ptr, ptr %s\d+\n\s+(%t\d+) = load %sc_rs_\w+, ptr %s\d+\n\s+store %sc_rs_\w+ \2, ptr %s\d+\n(?:.*\n)*?\s+call void @\w+\(ptr \1\)/, + ); +}); diff --git a/packages/compiler/src/backend/llvm/stack-objects.ts b/packages/compiler/src/backend/llvm/stack-objects.ts index c03c7fb44..e9f437f14 100644 --- a/packages/compiler/src/backend/llvm/stack-objects.ts +++ b/packages/compiler/src/backend/llvm/stack-objects.ts @@ -1,9 +1,16 @@ -import { VOID, typeEquals, type IrExpr, type IrFunction, type IrType } from "../../ir/ir.js"; +import { + VOID, + isRefCounted, + typeEquals, + type IrExpr, + type IrFunction, + type IrType, +} from "../../ir/ir.js"; import { completeRecordLiteral, constructorInitializesFields, + frameRecordShape, resultEntryName, - scalarRecordShape, scalarStandaloneClass, } from "./record-results.js"; import { everyStmtList } from "../../ir/traverse.js"; @@ -14,23 +21,45 @@ import type { CallLifetimes } from "./call-lifetimes.js"; import { emitCallExpr, emitConstruction } from "./expr-calls.js"; import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; import { emitRecordLitFields } from "./expr-primitives.js"; +import { llFieldType } from "./shapes.js"; -export type StackObjectSource = IrExpr & { kind: "recordLit" | "new" | "call" }; +export type StackObjectSource = IrExpr & { kind: "recordLit" | "recordClone" | "new" | "call" }; -/** A record literal, `new` or result-slot producer call whose object can - * live in the frame's own storage: a plain scalar record shape, or a +/** A field of a frame object that owns a reference: an entry-block pointer + * to its slot, and the field's type for the release. */ +export interface StackObjectField { + name: string; + ptr: string; + type: IrType; +} + +/** Records the owners of a frame object's reference fields before anything + * stores them: a lexical scope for bindings, a statement frame for + * temporaries. */ +export type StackObjectFieldOwner = (fields: readonly StackObjectField[]) => void; + +/** A record literal, spread copy, `new` or result-slot producer call whose + * object can live in the frame's own storage: a closed record shape, or a * standalone scalar class whose constructor never lets `this` escape * (record-results.ts). The caller proves that every use of the value only - * projects it. */ + * projects it. Record fields may own references; the frame releases them + * (stackObjectFields). Published shapes keep heap storage: their field + * guards treat the immortal header as a frozen object. */ export function canStackObject(host: LlvmEmitterContext, e: IrExpr): e is StackObjectSource { + if (e.type.kind === "record" && host.publishedTypes?.recordGuarded(e.type.shapeId) === true) + return false; // A producer with a result-slot entry builds its fresh result in the // caller's storage. if (e.kind === "call") return host.fnByName.has(resultEntryName(e.callee)); if (e.kind === "recordLit") { if (e.type.kind !== "record") return false; const shape = host.recordsById.get(e.type.shapeId); - return scalarRecordShape(shape, host.inlineUnions) && completeRecordLiteral(e, shape); + return frameRecordShape(shape) && completeRecordLiteral(e, shape); } + // A same-shape spread (`{ ...source, field: value }`) copies the source's + // fields; the frontend builds it only for plain declared-field records. + if (e.kind === "recordClone") + return e.type.kind === "record" && frameRecordShape(host.recordsById.get(e.type.shapeId)); if (e.kind !== "new") return false; const meta = host.classMeta.get(e.className); return ( @@ -45,6 +74,33 @@ export function canStackObject(host: LlvmEmitterContext, e: IrExpr): e is StackO ); } +/** Whether a frame object of this type has fields that own references. */ +function ownsReferences(host: LlvmEmitterContext, type: IrType): boolean { + return ( + type.kind === "record" && + host + .recordShape(type.shapeId) + .fields.some((field) => isRefCounted(field.type) && !host.inlineUnions.record(field.type)) + ); +} + +/** Locals declared directly in a switch case. The cases share one scope + * whose exit runs whichever case was entered, so a scope-owned field would + * be released without its declaration having run. */ +function caseScopedLocals(fn: IrFunction): Set { + const ids = new Set(); + everyStmtList(fn.body, { + expr: () => true, + stmt: (stmt) => { + if (stmt.kind === "switch") + for (const c of stmt.cases) + for (const s of c.body) if (s.kind === "varDecl") ids.add(s.localId); + return true; + }, + }); + return ids; +} + /** Locals initialized once by a stack-eligible object and only projected * afterwards (CallLifetimes.locals): field reads, and arguments to * parameters that are themselves only projected. */ @@ -56,6 +112,7 @@ export function findLocalStackObjects( const result = new Map(); const safe = lifetimes.locals.get(fn.name); if (!safe?.size || fn.async || fn.generator) return result; + const caseScoped = caseScopedLocals(fn); everyStmtList(fn.body, { expr: () => true, stmt: (stmt) => { @@ -63,7 +120,8 @@ export function findLocalStackObjects( stmt.kind === "varDecl" && safe.has(stmt.localId) && stmt.init && - canStackObject(host, stmt.init) + canStackObject(host, stmt.init) && + !(caseScoped.has(stmt.localId) && ownsReferences(host, stmt.init.type)) ) result.set(stmt.localId, stmt.init); return true; @@ -112,7 +170,10 @@ export function findReassignedStackObjects( return true; }, }); - for (const id of result) if (!initialized.has(id)) result.delete(id); + const caseScoped = caseScopedLocals(fn); + for (const id of result) + if (!initialized.has(id) || (caseScoped.has(id) && ownsReferences(host, types.get(id)!))) + result.delete(id); return result; } @@ -122,13 +183,77 @@ export function stackObjectStruct(type: IrType): string { : `%${mangleClassStruct((type as IrType & { kind: "object" }).className)}`; } +/** The reference fields of the frame object in `slot`, addressed from the + * entry block so that every cleanup path can reach them. Inline union + * fields copy bits and own nothing; class objects in frame storage are + * scalar. */ +export function stackObjectFields( + host: LlvmEmitterContext, + type: IrType, + slot: string, +): readonly StackObjectField[] { + if (type.kind !== "record") return []; + const cached = host.stackObjectFieldPtrs.get(slot); + if (cached) return cached; + const struct = stackObjectStruct(type); + const fields: StackObjectField[] = []; + host.recordShape(type.shapeId).fields.forEach((field, index) => { + if (!isRefCounted(field.type) || host.inlineUnions.record(field.type)) return; + const ptr = host.B.slot(); + host.B.entryAllocas.push( + `${ptr} = getelementptr inbounds ${struct}, ptr ${slot}, i64 0, i32 ${index + 1}`, + ); + fields.push({ name: field.name, ptr, type: field.type }); + }); + host.stackObjectFieldPtrs.set(slot, fields); + return fields; +} + +/** Copy a same-shape spread's source fields into `slot`, retaining the + * references, then store the overrides in source order. The source is + * read once, before any override evaluates, as the heap clone helper + * reads it; an overridden field is never copied, so its slot stays empty + * until the override initializes it. */ +function emitRecordCloneFields( + host: LlvmEmitterContext, + e: IrExpr & { kind: "recordClone" }, + slot: string, +): void { + const B = host.B; + const shapeId = (e.type as IrType & { kind: "record" }).shapeId; + const overridden = new Set(e.overrides.map((override) => override.name)); + const source = host.emitReadReceiver(e.source); + for (const field of host.recordShape(shapeId).fields) { + if (overridden.has(field.name)) continue; + const from = host.recordFieldPtr(source.name, shapeId, field.name); + const to = host.recordFieldPtr(slot, shapeId, field.name); + const fieldTy = llFieldType(from.type, from.inline); + const v = B.tmp(); + B.line(`${v} = load ${fieldTy}, ptr ${from.ptr}`); + const stored = isRefCounted(from.type) && !from.inline ? host.retainValue(v, from.type) : v; + B.line(`store ${fieldTy} ${stored}, ptr ${to.ptr}`); + } + const initialized = new Set(); + for (const override of e.overrides) { + const v = host.emitFieldValue(override.value, host.recordFieldInline(shapeId, override.name)); + const { ptr, type, inline } = host.recordFieldPtr(slot, shapeId, override.name); + // The first store fills an empty slot; a repeated name replaces it. + if (initialized.has(override.name)) host.replaceField(ptr, type, inline, v); + else host.initField(ptr, type, inline, v); + initialized.add(override.name); + } +} + /** Build the object in an entry-block slot (or `into`, an existing one). * The immortal reference count makes every retain and release a no-op; * the proof that the value is only projected keeps the pointer from - * outliving the frame. */ + * outliving the frame. Reference fields start empty and are handed to + * `owner` before anything is stored, so an exception while the object is + * being built releases exactly the fields stored so far. */ export function emitStackObject( host: LlvmEmitterContext, e: StackObjectSource, + owner: StackObjectFieldOwner, into?: string, ): LlValue { const B = host.B; @@ -139,6 +264,18 @@ export function emitStackObject( slot = B.slot(); B.entryAllocas.push(`${slot} = alloca ${struct}, align 8`); } + // A literal's interned string fields are immortal and need no owner. A + // binding's own slot (`into`) keeps an owner for every field: later + // assignments copy arbitrary values into it. + const literals = + into === undefined && e.kind === "recordLit" + ? new Set(e.fields.filter((f) => f.value.kind === "strLit").map((f) => f.name)) + : new Set(); + const fields = stackObjectFields(host, type, slot).filter((f) => !literals.has(f.name)); + if (fields.length > 0) { + for (const field of fields) B.line(`store ptr null, ptr ${field.ptr}`); + owner(fields); + } // Literals store every field; constructors that store every field // before reading one need no zeroed storage either. if (type.kind === "object") { @@ -169,6 +306,7 @@ export function emitStackObject( host.markImmortal({ name: slot, type }), ); } else if (e.kind === "recordLit") emitRecordLitFields(host, e, slot); + else if (e.kind === "recordClone") emitRecordCloneFields(host, e, slot); else emitConstruction(host, e, slot, host.fnByName.get(`%${e.className}.constructor`)!); return { name: slot, type: e.type }; } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-frame-records-own-references.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-frame-records-own-references.ts.json new file mode 100644 index 000000000..afe039025 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-frame-records-own-references.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5960-frame-records-own-references.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5961-frame-spread-updates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5961-frame-spread-updates.ts.json new file mode 100644 index 000000000..255b1238e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5961-frame-spread-updates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5961-frame-spread-updates.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5962-frame-tuples.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5962-frame-tuples.ts.json new file mode 100644 index 000000000..ab8d80faf --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5962-frame-tuples.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5962-frame-tuples.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5960-frame-records-own-references.ts b/tests/corpus/5960-frame-records-own-references.ts new file mode 100644 index 000000000..894037ff7 --- /dev/null +++ b/tests/corpus/5960-frame-records-own-references.ts @@ -0,0 +1,164 @@ +// Records whose fields hold strings, arrays, other records and class +// instances, and that only flow into field reads, release exactly the +// references they hold: on normal scope exit, per loop iteration, on +// break/continue/return, and when a field expression or a producer +// throws while the record is half built. Records that are stored, +// returned, captured, compared by identity or printed stay observable +// exactly as in Node. +interface Token { + kind: string; + text: string; + pos: number; +} +interface Span { + label: string; + parts: string[]; + token: Token; +} +class Counter { + hits = 0; + name: string; + constructor(name: string) { + this.name = name; + } +} +interface Owned { + owner: Counter; + tag: string | undefined; + note?: string; +} + +const words = ["alpha", "beta", "gamma", "delta"]; +function word(i: number): string { + return words[i % words.length]! + i; +} +function makeToken(kind: string, text: string, pos: number): Token { + return { kind, text, pos }; +} +function pick(flag: boolean, a: string, b: string): Token { + return flag ? { kind: "a", text: a, pos: 1 } : makeToken("b", b, 2); +} +function width(t: Token): number { + return t.text.length + t.kind.length; +} +function spanWidth(s: Span): number { + return s.label.length + s.parts.length + width(s.token); +} +function failing(text: string, n: number): string { + if (n % 4 === 3) throw new Error(`bad ${text}`); + return text.toUpperCase(); +} +function strict(kind: string, n: number): Token { + return { kind, text: failing(kind + n, n), pos: n }; +} +const kept: Token[] = []; +function keep(t: Token): number { + kept.push(t); + return t.pos; +} + +let total = 0; +let log = ""; +for (let i = 0; i < 12; i++) { + const w = word(i); + const t = { kind: "id", text: w, pos: i }; + total += t.pos + t.text.length; + const u = makeToken("num", w + "!", i); + if (u.kind === "num") total += width(u); + total += width({ kind: w, text: w + w, pos: 0 }); + const s: Span = { label: "s" + i, parts: [w, t.text, u.text], token: makeToken("x", w, i) }; + total += spanWidth(s) + s.parts.join("").length; + const p = pick(i % 2 === 0, w, t.kind); + log += p.text[0]; + if (i % 5 === 4) total += keep(t); + try { + const bad = { kind: "k", text: failing(w, i), pos: i }; + log += bad.text.length; + } catch (e) { + log += "!"; + } + try { + const half = strict(w, i); + log += half.text.length; + } catch (e) { + log += "?"; + } + if (i === 6) continue; + const late = { kind: w, text: String(i), pos: -i }; + if (late.text === "9") break; + total += late.kind.length; +} +console.log(total, log, kept.map((t) => t.text).join(",")); + +function find(names: string[], target: string): number { + for (let i = 0; i < names.length; i++) { + const entry = { name: names[i]!, index: i, upper: names[i]!.toUpperCase() }; + if (entry.name === target) return entry.index * 10 + entry.upper.length; + } + return -1; +} +console.log(find(words, "gamma"), find(words, "omega")); + +function owners(n: number): string { + const counters = [new Counter("a"), new Counter("b")]; + let out = ""; + for (let i = 0; i < n; i++) { + const o: Owned = { owner: counters[i % 2]!, tag: i % 3 === 0 ? undefined : "t" + i }; + o.owner.hits++; + out += o.tag ?? "-"; + const optional: Owned = { owner: counters[0]!, tag: "x", note: i % 2 ? "odd" : undefined }; + out += optional.note === undefined ? "." : optional.note[0]; + } + return `${out} ${counters[0]!.hits} ${counters[1]!.hits}`; +} +console.log(owners(7)); + +function tally(lines: string[]): string { + let out = ""; + for (const line of lines) { + const parsed = { head: line.slice(0, 1), rest: line.slice(1), size: line.length }; + switch (parsed.head) { + case "a": { + const scoped = { head: parsed.rest, rest: parsed.head, size: 1 }; + out += scoped.head; + break; + } + case "b": + out += parsed.rest.toUpperCase(); + break; + default: + out += parsed.size; + } + } + return out; +} +console.log(tally(["abc", "bcd", "cde", "a"])); + +function guarded(n: number): string { + let out = ""; + for (let i = 0; i < n; i++) { + try { + const r = { name: word(i), list: [i, i + 1] }; + if (i % 2 === 0) throw new Error(r.name); + out += r.list.length; + } catch (e) { + out += (e as Error).message.length; + } finally { + const f = { name: "f" + i, list: [i] }; + out += f.name.length; + } + } + return out; +} +console.log(guarded(5)); + +// Identity, storage, capture and printing keep heap records. +const a = { kind: "same", text: "x", pos: 1 }; +const b = { kind: "same", text: "x", pos: 1 }; +const readers: (() => string)[] = []; +for (let i = 0; i < 3; i++) { + const r = { kind: "r", text: word(i), pos: i }; + readers.push(() => r.text); +} +console.log(a === b, readers.map((read) => read()).join(" ")); +console.log({ kind: "shown", text: word(2), pos: 3 }, JSON.stringify(makeToken("j", "s", 1))); diff --git a/tests/corpus/5961-frame-spread-updates.ts b/tests/corpus/5961-frame-spread-updates.ts new file mode 100644 index 000000000..ef2f79cd9 --- /dev/null +++ b/tests/corpus/5961-frame-spread-updates.ts @@ -0,0 +1,96 @@ +// Same-shape spread updates (`{ ...state, field: value }`) of records that +// hold strings and arrays: each update reads the whole old value before +// any override evaluates, releases the replaced fields exactly once, and +// keeps the previous value when an override throws. Aliases, identity, +// storage and printing keep the heap object Node would have. +interface State { + name: string; + count: number; + items: string[]; + last: string | undefined; +} +interface Num { + count: number; + total: number; +} +function bump(s: State, item: string): State { + return { ...s, count: s.count + 1, last: item }; +} +function rename(s: State, name: string): State { + return name.length > 3 ? { ...s, name } : s.count > 2 ? { ...s, name: name + "!" } : bump(s, name); +} +function check(n: number): number { + if (n === 3) throw new Error("three"); + return n * 2; +} +function describe(s: State): string { + return `${s.name}:${s.count}:${s.items.length}:${s.last ?? "-"}`; +} + +function run(n: number): string { + let state: State = { name: "s", count: 0, items: ["a"], last: undefined }; + let out = ""; + for (let i = 0; i < n; i++) { + state = { ...state, count: state.count + 1 }; + if (i % 2 === 0) state = { ...state, last: "i" + i, name: state.name + i }; + state = bump(state, "b" + i); + state = rename(state, i % 3 === 0 ? "long" + i : "x"); + try { + state = { ...state, count: check(i) }; + } catch (e) { + out += "!"; + } + out += describe(state) + " "; + } + return out + state.items.join(""); +} +console.log(run(6)); + +function numeric(n: number): number { + let state: Num = { count: 0, total: 0 }; + for (let i = 0; i < n; i++) { + state = { ...state, count: state.count + 1 }; + if (i % 3 === 0) state = { ...state, total: state.total + i }; + } + return state.count * 1000 + state.total; +} +console.log(numeric(10)); + +// Overrides see the old value and run after the copy. +function order(): string { + let s: State = { name: "n", count: 1, items: [], last: "l" }; + let log = ""; + s = { ...s, name: (log += s.name + s.count, s.name + "2"), count: s.count + 10 }; + s = { ...s, last: s.name }; + return `${log} ${describe(s)}`; +} +console.log(order()); + +// Spread of a temporary and of a producer result. +function fresh(i: number): State { + return { name: "f" + i, count: i, items: [String(i)], last: undefined }; +} +function temporaries(n: number): string { + let out = ""; + for (let i = 0; i < n; i++) { + const s = { ...fresh(i), count: 100 + i }; + const t = { ...s, items: [s.name, s.name] }; + out += describe(s) + "/" + describe(t) + " "; + } + return out; +} +console.log(temporaries(3)); + +// Aliases and identity are observable: these stay heap objects. +let current: State = { name: "c", count: 0, items: [], last: undefined }; +const before = current; +current = { ...current, count: 5 }; +console.log(before === current, before.count, current.count); +const history: State[] = []; +let tracked: State = { name: "h", count: 0, items: [], last: undefined }; +for (let i = 0; i < 3; i++) { + tracked = { ...tracked, count: tracked.count + 1 }; + history.push(tracked); +} +console.log(history.map((s) => s.count).join(","), history[0] === history[1]); +console.log({ ...tracked, last: "shown" }); diff --git a/tests/corpus/5962-frame-tuples.ts b/tests/corpus/5962-frame-tuples.ts new file mode 100644 index 000000000..b03cbc79d --- /dev/null +++ b/tests/corpus/5962-frame-tuples.ts @@ -0,0 +1,57 @@ +// Tuples that are only destructured or indexed: number and string +// elements, producer functions returning fresh tuples, literals passed to +// functions that only read their elements, and tuples that escape into +// arrays, closures, identity comparisons and printing. +function divmod(a: number, b: number): [number, number] { + return [Math.floor(a / b), a % b]; +} +const names = ["a", "bb", "ccc"]; +function entry(i: number): [string, number] { + return [names[i % 3]! + i, i]; +} +function flip(p: [string, number]): [number, string] { + return [p[1] * 2, p[0].toUpperCase()]; +} +function area(r: [number, number]): number { + return r[0] * r[1]; +} +function risky(i: number): [string, string] { + if (i % 4 === 2) throw new Error("risky " + i); + return ["r" + i, String(i * i)]; +} +const kept: [string, number][] = []; + +let acc = 0; +let log = ""; +for (let i = 0; i < 10; i++) { + const [q, r] = divmod(i * 13, 7); + acc += q + r; + const [k, v] = entry(i); + acc += k.length + v; + const pair: [number, number] = [i, i + 1]; + acc += pair[0] * pair[1] + area([i, 2]) + area(pair); + const [n, s] = flip(entry(i + 1)); + log += s + n; + try { + const [x, y] = risky(i); + log += x + y.length; + } catch (e) { + log += "!"; + } + if (i % 3 === 0) kept.push(entry(i)); +} +console.log(acc, log); +console.log(kept.map(([name, i]) => name + "=" + i).join(" ")); + +let [left, right] = ["l", "r"]; +for (let i = 0; i < 3; i++) [left, right] = [right, left + i]; +console.log(left, right); + +const t1: [number, string] = [1, "x"]; +const t2: [number, string] = [1, "x"]; +const getters: (() => string)[] = []; +for (let i = 0; i < 2; i++) { + const t: [string, number] = [names[i]!, i]; + getters.push(() => t[0] + t[1]); +} +console.log(t1 === t2, getters.map((get) => get()).join(","), entry(4), JSON.stringify(divmod(9, 4))); From 06b0bb293155e30a42f0f2821c40ad6644dce386 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 12:13:11 -0700 Subject: [PATCH 006/117] Write borrowed string slices into stack buffers A slice read only by lending consumers (string equality and ordering, length/charCodeAt/indexOf/includes/startsWith/endsWith, Number/unary plus/parseInt/parseFloat, typed string-keyed Map/Set get/has/set/add/ delete keys, string switch discriminants, and string parameters their callee only lends) is written by scr_str_slice_scratch into a per-site stack buffer as an immortal ASCII ScrStr marked as scratch (cap < len), instead of a heap allocation. Stable locals initialized by such a slice qualify when every read lends. Map/Set insertion stores a heap copy of a scratch key, and probes cache the key hash in the scratch header, so the counting idiom allocates only for new keys. Longer, non-ASCII, and interned results keep the owned slice; coroutines and debug builds are unchanged. Slice bounds are normalized without a libm trunc call. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/backend/llvm/emitter.ts | 18 ++ .../src/backend/llvm/expr-containers.ts | 4 +- .../src/backend/llvm/string-slices.test.ts | 151 ++++++++++- .../src/backend/llvm/string-slices.ts | 244 +++++++++++++++++- .../corpus/scratch-string-slices.ts.json | 6 + packages/runtime/src/scr_map.c | 9 +- packages/runtime/src/scr_string.c | 84 +++++- packages/runtime/src/scr_string.h | 8 + packages/runtime/src/scr_string_methods.h | 10 + packages/runtime/test/test_map.c | 31 +++ packages/runtime/test/test_string.c | 32 +++ tests/corpus/scratch-string-slices.ts | 116 +++++++++ 12 files changed, 697 insertions(+), 16 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/scratch-string-slices.ts.json create mode 100644 tests/corpus/scratch-string-slices.ts diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 09bf4979c..de661be9e 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -219,7 +219,10 @@ import { findAppendedArrayLiterals } from "./appended-array-literals.js"; import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callbacks.js"; import { findScalarStringSlices, + findScratchStringSlices, + findLentStringParameters, emitStringSliceSnapshot, + type LentStringParameters, type StringSliceSnapshot, } from "./string-slices.js"; import { LazyCaptures } from "./lazy-captures.js"; @@ -569,6 +572,10 @@ export class LlEmitter { private loopArrayBorrows: ReadonlySet = new Set(); private scalarStringSlices = new Map(); readonly stringSlices = new Map(); + /** Slices written into stack buffers (findScratchStringSlices). */ + scratchStringSlices: ReadonlySet = new Set(); + /** String parameters a caller may lend scratch slices to. */ + private lentStringParameters: LentStringParameters = new Map(); private localStackUnions = new Map(); private localStackObjects = new Map(); private reassignedStackObjects = new Set(); @@ -1245,6 +1252,8 @@ export class LlEmitter { return shape !== undefined && !recordDynKeepsIdentity(shape); }, ); + this.lentStringParameters = + this.debug === null ? findLentStringParameters(this.fnByName, this.callLifetimes) : new Map(); this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes); // Integer clones signal a stack overflow through their result, which // needs the single-threaded guard; worker programs also poll for @@ -6373,6 +6382,15 @@ export class LlEmitter { ); this.scalarStringSlices = this.debug === null ? findScalarStringSlices(fn, this.callLifetimes) : new Map(); + this.scratchStringSlices = + this.debug === null + ? findScratchStringSlices( + fn, + this.callLifetimes, + this.scalarStringSlices, + this.lentStringParameters, + ) + : new Set(); this.mapReadLifetimes = findMapReadLifetimes(fn, this.boxedUnionsById, this.callLifetimes); this.readNumberMapWrites = findReadNumberMapWrites(fn); this.mapEntryFusion = this.debug === null ? findMapEntryFusions(fn) : null; diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index a2d5fd35a..d5d192e89 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -42,7 +42,7 @@ import { } from "./map-number-lookup.js"; import { emitBorrowedInput } from "./borrowed-inputs.js"; import { emitFusedMapSet, rememberMapEntry } from "./map-entry-fusion.js"; -import { emitStringSliceRead } from "./string-slices.js"; +import { emitScratchStringSlice, emitStringSliceRead } from "./string-slices.js"; import { STRING_CHAR_CODE_AT_DECL, STRING_CHAR_CODE_AT_INT_MARKER, @@ -391,6 +391,7 @@ export function emitStrIntrinsic( false, ); case "slice": + if (host.scratchStringSlices.has(e)) return emitScratchStringSlice(host, e, r, args); return call( "scr_str_slice", "ptr (ptr, double, double)", @@ -399,6 +400,7 @@ export function emitStrIntrinsic( true, ); case "substring": + if (host.scratchStringSlices.has(e)) return emitScratchStringSlice(host, e, r, args); return call( "scr_str_substring", "ptr (ptr, double, double)", diff --git a/packages/compiler/src/backend/llvm/string-slices.test.ts b/packages/compiler/src/backend/llvm/string-slices.test.ts index 53cca6417..b2656e560 100644 --- a/packages/compiler/src/backend/llvm/string-slices.test.ts +++ b/packages/compiler/src/backend/llvm/string-slices.test.ts @@ -1,7 +1,11 @@ import { expect, test } from "vitest"; -import { F64, STRING, VOID, type IrExpr, type IrFunction, type IrStmt } from "../../ir/ir.js"; +import { BOOL, F64, STRING, VOID, type IrExpr, type IrFunction, type IrStmt } from "../../ir/ir.js"; import { analyzeCallLifetimes } from "./call-lifetimes.js"; -import { findScalarStringSlices } from "./string-slices.js"; +import { + findLentStringParameters, + findScalarStringSlices, + findScratchStringSlices, +} from "./string-slices.js"; const loc = { file: "slices.ts", start: 0, end: 0 }; const ref = (id: string): IrExpr => ({ kind: "varRef", localId: id, type: STRING, loc }); function fixture(): IrFunction { @@ -95,3 +99,146 @@ test.each(["escape", "capture", "write", "other-consumer", "suspend"])( expect(facts(fn).size).toBe(0); }, ); + +const slice = (receiver: string, start: number, end: number): IrExpr => ({ + kind: "strIntrinsic", + method: "slice", + receiver: ref(receiver), + args: [ + { kind: "numLit", value: start, type: F64, loc }, + { kind: "numLit", value: end, type: F64, loc }, + ], + type: STRING, + loc, +}); +const equals = (left: IrExpr): IrExpr => ({ + kind: "strEq", + negated: false, + left, + right: { kind: "strLit", value: "GET", type: STRING, loc }, + type: BOOL, + loc, +}); +const parse = (value: IrExpr): IrExpr => ({ + kind: "libCall", + fn: "num.fromString", + args: [value], + type: F64, + loc, +}); +function lending(body: IrStmt[]): IrFunction { + return { + name: "scan", + params: [{ localId: "source", name: "source", type: STRING }], + locals: [ + { id: "source", name: "source", type: STRING, mutable: false }, + { id: "word", name: "word", type: STRING, mutable: false }, + ], + returnType: VOID, + loc, + body, + }; +} +function scratch(fn: IrFunction, extra: IrFunction[] = []): Set { + const functions = new Map([fn, ...extra].map((f) => [f.name, f])); + const lifetimes = analyzeCallLifetimes(functions); + return findScratchStringSlices( + fn, + lifetimes, + findScalarStringSlices(fn, lifetimes), + findLentStringParameters(functions, lifetimes), + ); +} +test("slices read only by lending consumers use a stack buffer", () => { + const inline = slice("source", 0, 3); + const parsed = slice("source", 4, 6); + const init = slice("source", 1, 5); + const fn = lending([ + { kind: "exprStmt", expr: equals(inline), loc }, + { kind: "exprStmt", expr: parse(parsed), loc }, + { kind: "varDecl", localId: "word", init, loc }, + { kind: "exprStmt", expr: equals(ref("word")), loc }, + { kind: "exprStmt", expr: parse(ref("word")), loc }, + ]); + expect(scratch(fn)).toEqual(new Set([inline, parsed, init])); +}); +test.each(["return", "concat", "slice-of-slice", "capture", "async"])( + "a slice local that may be kept (%s) stays owned", + (reason) => { + const init = slice("source", 1, 5); + const fn = lending([ + { kind: "varDecl", localId: "word", init, loc }, + { kind: "exprStmt", expr: equals(ref("word")), loc }, + ]); + if (reason === "return") fn.body.push({ kind: "return", value: ref("word"), loc }); + if (reason === "concat") + fn.body.push({ + kind: "exprStmt", + expr: { + kind: "strConcat", + left: { kind: "strLit", value: "", type: STRING, loc }, + right: ref("word"), + type: STRING, + loc, + }, + loc, + }); + if (reason === "slice-of-slice") + fn.body.push({ kind: "exprStmt", expr: equals(slice("word", 0, 2)), loc }); + if (reason === "capture") fn.locals[1]!.boxed = true; + if (reason === "async") fn.async = true; + expect(scratch(fn).has(init)).toBe(false); + }, +); +function helper(name: string, body: IrStmt[]): IrFunction { + return { + name, + params: [{ localId: "text", name: "text", type: STRING }], + locals: [{ id: "text", name: "text", type: STRING, mutable: false }], + returnType: BOOL, + loc, + body, + }; +} +const callOf = (callee: string, arg: IrExpr): IrExpr => ({ + kind: "call", + callee, + args: [arg], + type: BOOL, + loc, +}); +test("helper parameters read only by lending consumers accept stack slices", () => { + const recursive = helper("isGet", [ + { + kind: "return", + value: { + kind: "logical", + op: "||", + left: equals(ref("text")), + right: callOf("isGet", ref("text")), + type: BOOL, + loc, + }, + loc, + }, + ]); + const keeps = helper("keeps", [{ kind: "return", value: callOf("stores", ref("text")), loc }]); + const stores = helper("stores", [ + { + kind: "exprStmt", + expr: { kind: "arrayLit", elems: [ref("text")], type: { kind: "array", elem: STRING }, loc }, + loc, + }, + { kind: "return", value: { kind: "boolLit", value: true, type: BOOL, loc }, loc }, + ]); + const lent = slice("source", 0, 3); + const kept = slice("source", 0, 4); + const fn = lending([ + { kind: "exprStmt", expr: callOf("isGet", lent), loc }, + { kind: "exprStmt", expr: callOf("keeps", kept), loc }, + ]); + const functions = [recursive, keeps, stores]; + expect(scratch(fn, functions)).toEqual(new Set([lent])); + const all = new Map([fn, ...functions].map((f) => [f.name, f])); + expect([...findLentStringParameters(all, analyzeCallLifetimes(all)).keys()]).toEqual(["isGet"]); +}); diff --git a/packages/compiler/src/backend/llvm/string-slices.ts b/packages/compiler/src/backend/llvm/string-slices.ts index 71a26e2f3..ae73f1ea1 100644 --- a/packages/compiler/src/backend/llvm/string-slices.ts +++ b/packages/compiler/src/backend/llvm/string-slices.ts @@ -1,4 +1,9 @@ -import { type IrExpr, type IrFunction, type IrStmt } from "../../ir/ir.js"; +import { + type IrExpr, + type IrFunction, + type IrStmt, + type IrStrIntrinsicMethod, +} from "../../ir/ir.js"; import { everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js"; import { F64_INF, f64Lit, sizeToDouble } from "./common.js"; import type { CallLifetimes } from "./call-lifetimes.js"; @@ -6,6 +11,12 @@ import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; type Slice = IrExpr & { kind: "strIntrinsic" }; +function isSlice(value: IrExpr): value is Slice { + return ( + value.kind === "strIntrinsic" && (value.method === "slice" || value.method === "substring") + ); +} + /** A local used exclusively for scalar indexing needs no copied bytes. * Snapshot the receiver and normalized bounds at its initializer, including * side effects in the bounds. Escapes, captures, writes, suspension, and all @@ -111,3 +122,234 @@ export function emitStringSliceRead(host: LlvmEmitterContext, value: Slice): LlV ); return { name: result, type: value.type }; } + +/** Bytes of the stack buffer behind one scratch slice, header included. */ +export const SCRATCH_SLICE_BYTES = 96; + +/** String methods that read a lent receiver or argument only during their + * runtime call and never return it. Methods returning a string can return + * their unchanged receiver, so they stay on the owned path. */ +const LENDING_METHODS: ReadonlySet = new Set([ + "length", + "charCodeAt", + "indexOf", + "includes", + "startsWith", + "endsWith", +]); + +/** Numeric parsers read their text during the call. */ +const LENDING_LIB_FNS: ReadonlySet = new Set([ + "num.fromString", + "num.parseInt", + "num.parseFloat", +]); + +/** Typed string-keyed collection operations: reads probe with the key, and + * an insertion stores scr_str_scratch_keep's copy (scr_map_append). */ +const LENDING_KEY_METHODS: ReadonlySet = new Set(["get", "has", "set", "add", "delete"]); + +function stringKeyed(value: IrExpr & { kind: "mapIntrinsic" | "setIntrinsic" }): boolean { + const receiver = value.receiver.type; + if (receiver.kind === "map") + return receiver.key.kind === "string" && receiver.value.kind !== "dyn"; + if (receiver.kind === "set") return receiver.elem.kind === "string"; + return false; +} + +/** String parameters, by function and index, that the body reads only in + * lending positions (findLentStringParameters). */ +export type LentStringParameters = ReadonlyMap>; + +/** The operands `value` reads only while it runs, keeping no reference. */ +function lentOperands(value: IrExpr, parameters: LentStringParameters): readonly IrExpr[] { + switch (value.kind) { + case "strEq": + case "strCmp": + return [value.left, value.right]; + case "strIntrinsic": + return LENDING_METHODS.has(value.method) ? [value.receiver, ...value.args] : []; + case "libCall": + return LENDING_LIB_FNS.has(value.fn) ? value.args.slice(0, 1) : []; + case "mapIntrinsic": + case "setIntrinsic": + return LENDING_KEY_METHODS.has(value.method) && stringKeyed(value) + ? value.args.slice(0, 1) + : []; + case "call": { + const lent = parameters.get(value.callee); + return lent ? value.args.filter((_, index) => lent.has(index)) : []; + } + default: + return []; + } +} + +interface LendingScan { + /** Slice operands of lending consumers, excluding any node also reached + * in an owning position. */ + scratch: Set; + /** Candidates read anywhere other than a lending position. */ + invalid: Set; + /** Direct callees, for the parameter fixpoint. */ + callees: Set; +} + +/** One pass over `fn`: which candidate bindings only lending consumers read + * (a slice initializer of a candidate local is not itself a read), and + * which slice operands those consumers lend. A switch discriminant is only + * compared with the case tests. */ +function scanLending( + fn: IrFunction, + candidates: ReadonlySet, + initializers: ReadonlyMap, + parameters: LentStringParameters, +): LendingScan { + const scan: LendingScan = { scratch: new Set(), invalid: new Set(), callees: new Set() }; + const owned = new Set(); + function lent(value: IrExpr): boolean { + if (value.kind === "varRef" && candidates.has(value.localId)) return true; + if (!isSlice(value)) return expr(value); + scan.scratch.add(value); + return everyExprChild(value, expr, stmt); + } + function expr(value: IrExpr): boolean { + if (isSlice(value)) owned.add(value); + if (value.kind === "varRef" && candidates.has(value.localId)) scan.invalid.add(value.localId); + if (value.kind === "closure" || value.kind === "classRef") + for (const id of value.captures ?? []) scan.invalid.add(id); + if (value.kind === "call") scan.callees.add(value.callee); + const operands = lentOperands(value, parameters); + if (operands.length === 0) return everyExprChild(value, expr, stmt); + return everyExprChild( + value, + (child) => (operands.includes(child) ? lent(child) : expr(child)), + stmt, + ); + } + function stmt(value: IrStmt): boolean { + // A candidate's single declaration initializes it with its slice. + if (value.kind === "varDecl" && value.init !== null && initializers.has(value.localId)) + return everyExprChild(value.init, expr, stmt); + if (value.kind === "switch" && value.disc.type.kind === "string") { + lent(value.disc); + for (const entry of value.cases) { + if (entry.test) expr(entry.test); + entry.body.forEach(stmt); + } + return true; + } + return everyStmtChild(value, expr, stmt); + } + fn.body.forEach(stmt); + for (const node of owned) scan.scratch.delete(node); + return scan; +} + +/** String parameters that every body reads only in lending positions, + * including lent arguments of other such parameters: a caller may pass a + * scratch slice to them. Start from every borrowed (unchanged) string + * parameter of a synchronous function and drop violations until nothing changes, so + * recursion through a lent parameter stays lent. A coroutine can keep its + * parameters past the caller's frame, so it never lends. */ +export function findLentStringParameters( + functions: ReadonlyMap, + lifetimes: CallLifetimes, +): Map> { + const lent = new Map>(); + for (const fn of functions.values()) { + if (fn.async || fn.generator) continue; + // Borrowed parameters are the unchanged ones nothing redeclares. + const stable = lifetimes.borrowed.get(fn.name); + const indexes = new Set(); + fn.params.forEach((param, index) => { + if (param.type.kind === "string" && stable?.has(index)) indexes.add(index); + }); + if (indexes.size > 0) lent.set(fn.name, indexes); + } + const callers = new Map>(); + const pending = new Set(lent.keys()); + while (pending.size > 0) { + const name = pending.values().next().value as string; + pending.delete(name); + const indexes = lent.get(name); + const fn = functions.get(name); + if (!indexes || !fn) continue; + const ids = new Set([...indexes].map((index) => fn.params[index]!.localId)); + const scan = scanLending(fn, ids, new Map(), lent); + for (const callee of scan.callees) { + let set = callers.get(callee); + if (!set) callers.set(callee, (set = new Set())); + set.add(name); + } + let changed = false; + for (const index of [...indexes]) { + if (!scan.invalid.has(fn.params[index]!.localId)) continue; + indexes.delete(index); + changed = true; + } + if (!changed) continue; + if (indexes.size === 0) lent.delete(name); + const affected = callers.get(name); + if (affected) for (const caller of affected) if (lent.has(caller)) pending.add(caller); + } + return lent; +} + +/** Slices whose every reader borrows them are written into a stack buffer + * instead of a heap allocation (scr_str_slice_scratch): a slice operand of + * a lending consumer, and the initializer of a stable local read only by + * lending consumers. The copy is ASCII, bounded, and immortal for retain and + * release, so it neither pins its source nor needs to be freed; longer or + * non-ASCII results keep the ordinary owned string. Each site owns its + * buffer: a site runs again only after its previous value is dead, since + * nothing can keep it. Coroutine frames do not keep stack buffers across a + * suspension, so they are left alone. */ +export function findScratchStringSlices( + fn: IrFunction, + lifetimes: CallLifetimes, + scalar: ReadonlyMap, + parameters: LentStringParameters = new Map(), +): Set { + if (fn.async || fn.generator) return new Set(); + const bindings = lifetimes.bindings.get(fn.name); + const locals = new Map(); + everyStmtList(fn.body, { + expr: () => true, + stmt: (stmt) => { + if ( + stmt.kind === "varDecl" && + bindings?.has(stmt.localId) && + !scalar.has(stmt.localId) && + stmt.init !== null && + isSlice(stmt.init) + ) + locals.set(stmt.localId, stmt.init); + return true; + }, + }); + const scan = scanLending(fn, new Set(locals.keys()), locals, parameters); + for (const [id, init] of locals) if (!scan.invalid.has(id)) scan.scratch.add(init); + return scan.scratch; +} + +/** Write a scratch slice into its own stack buffer. The result is owned: + * releasing the scratch copy does nothing, and a heap fallback is freed. */ +export function emitScratchStringSlice( + host: LlvmEmitterContext, + slice: Slice, + receiver: LlValue, + args: readonly LlValue[], +): LlValue { + const B = host.B; + const buffer = B.slot(); + B.entryAllocas.push(`${buffer} = alloca [${SCRATCH_SLICE_BYTES} x i8], align 8`); + host.declare( + `declare ptr @scr_str_slice_scratch(ptr, double, double, i1 zeroext, ptr, ${host.sizeType})`, + ); + const result = B.tmp(); + B.line( + `${result} = call ptr @scr_str_slice_scratch(ptr ${receiver.name}, double ${args[0]?.name ?? f64Lit(0)}, double ${args[1]?.name ?? F64_INF}, i1 ${slice.method === "substring" ? "true" : "false"}, ptr ${buffer}, ${host.sizeType} ${SCRATCH_SLICE_BYTES})`, + ); + return host.own({ name: result, type: slice.type }); +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/scratch-string-slices.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/scratch-string-slices.ts.json new file mode 100644 index 000000000..5145c33d1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/scratch-string-slices.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/scratch-string-slices.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_map.c b/packages/runtime/src/scr_map.c index 8e34533ad..14181968c 100644 --- a/packages/runtime/src/scr_map.c +++ b/packages/runtime/src/scr_map.c @@ -77,7 +77,8 @@ static inline uint64_t scr_map_hash_str(const ScrStr *k) { uint32_t h = k->hash; if (__builtin_expect(h != 0, 1)) return scr_map_hash_widen(h); h = scr_map_hash_fold(k->data, k->len); - if (k->rc != SIZE_MAX) ((ScrStr *)k)->hash = h; + /* A scratch slice is a writable stack copy (scr_str_is_scratch). */ + if (k->rc != SIZE_MAX || scr_str_is_scratch(k)) ((ScrStr *)k)->hash = h; return scr_map_hash_widen(h); #else return scr_map_hash_bytes(k->data, k->len); @@ -931,7 +932,11 @@ static void scr_map_append(ScrMap *m, uint64_t hash, uint64_t key, uint64_t val, m->filter |= scr_map_filter_bits(hash); m->nlive++; if (m->key_kind == SCR_MAP_KEY_STR) { - scr_str_retain((ScrStr *)scr_map_slot_to_ptr(key)); /* key is borrowed */ + ScrStr *k = scr_map_slot_to_ptr(key); /* key is borrowed */ + if (__builtin_expect(scr_str_is_scratch(k), 0)) + m->entries[idx].key = scr_map_slot_from_ptr(scr_str_scratch_keep(k)); + else + scr_str_retain(k); } else if (m->key_kind == SCR_MAP_KEY_DYN) { const ScrDyn *d = (ScrDyn *)scr_map_slot_to_ptr(key); if (d->kind == SCR_DYN_NUM && d->v.num == 0) { diff --git a/packages/runtime/src/scr_string.c b/packages/runtime/src/scr_string.c index 6f3529777..43cf21b0c 100644 --- a/packages/runtime/src/scr_string.c +++ b/packages/runtime/src/scr_string.c @@ -1999,20 +1999,34 @@ ScrStr *scr_str_slice(ScrStr *s, double start, double end) { return scr_str_slice_units(s, e, from, to); } +/* One slice() or substring() boundary in [0, length]: ToIntegerOrInfinity, + * then slice's end-relative negative or substring's clamp. Conversion to an + * integer truncates toward zero exactly like ToIntegerOrInfinity, so no + * libm call is needed; NaN fails both comparisons and lands on 0, and a + * negative fraction above -1 is -0, which slice treats as 0. */ +static inline size_t scr_slice_unit(double v, size_t length, bool substring) { + if (v >= 0) return v >= (double)length ? length : (size_t)v; + if (substring || !(v > -(double)length)) return 0; + long long unit = (long long)v; /* in (-length, 0] */ + return unit == 0 ? 0 : (size_t)((long long)length + unit); +} + +/* slice()/substring() boundaries in UTF-16 units over the receiver's length. */ +static void scr_str_slice_bounds(ScrStr *s, ScrSidx *e, double start, double end, bool substring, + size_t *from_out, size_t *to_out) { + size_t length = scr_sidx_len(s, e); + size_t from = scr_slice_unit(start, length, substring); + size_t to = scr_slice_unit(end, length, substring); + if (substring && from > to) { size_t swap = from; from = to; to = swap; } + *from_out = from; + *to_out = to; +} + void scr_str_slice_range(ScrStr *s, double start, double end, bool substring, ScrStringSlice *out) { ScrSidx *e = scr_sidx_for(s); - size_t length = scr_sidx_len(s, e); - double a = scr_to_integer_or_infinity(start), b = scr_to_integer_or_infinity(end); size_t from, to; - if (substring) { - from = a <= 0 ? 0 : a >= (double)length ? length : (size_t)a; - to = b <= 0 ? 0 : b >= (double)length ? length : (size_t)b; - if (from > to) { size_t swap = from; from = to; to = swap; } - } else { - from = scr_slice_boundary(a, length); - to = scr_slice_boundary(b, length); - } + scr_str_slice_bounds(s, e, start, end, substring, &from, &to); out->start = from; out->length = to > from ? to - from : 0; out->split = 0; @@ -2024,6 +2038,56 @@ void scr_str_slice_range(ScrStr *s, double start, double end, bool substring, } } +/* Fill a scratch buffer with `units` ASCII bytes (scr_str_is_scratch). */ +static inline ScrStr *scr_str_scratch_fill(ScrStr *scratch, const char *data, size_t units) { + scratch->rc = SIZE_MAX; + scratch->len = units; + scratch->cap = 0; /* below len: the scratch marker */ + scratch->ascii = 1; +#if SCR_STR_HASH_CACHE + scratch->hash = 0; +#endif + scr_copy_bytes(scratch->data, data, units); + scratch->data[units] = '\0'; + return scratch; +} + +ScrStr *scr_str_slice_scratch(ScrStr *s, double start, double end, bool substring, + ScrStr *scratch, size_t bytes) { + size_t capacity = bytes - sizeof(ScrStr) - 1; + if (__builtin_expect(s->ascii, 1)) { + /* Units are bytes: no index entry, and the bounds are byte offsets. */ + size_t length = s->len; + size_t from = scr_slice_unit(start, length, substring); + size_t to = scr_slice_unit(end, length, substring); + if (substring && from > to) { size_t swap = from; from = to; to = swap; } + size_t units = to > from ? to - from : 0; + /* Shorter results are interned statics. */ + if (units >= 2 && units <= capacity) return scr_str_scratch_fill(scratch, s->data + from, units); + return scr_str_slice_units(s, NULL, from, to); + } + ScrSidx *e = scr_sidx_for(s); + size_t from, to; + scr_str_slice_bounds(s, e, start, end, substring, &from, &to); + size_t units = to > from ? to - from : 0; + if (units >= 2 && units <= capacity) { + /* Equal unit and byte counts between two character boundaries prove + * the span is ASCII: every other character takes more bytes than + * UTF-16 units. Non-ASCII results keep the owned copy and its index. */ + bool first, last; + size_t from_b = scr_u16_to_byte_c(s, e, from, &first); + size_t to_b = scr_u16_to_byte_c(s, e, to, &last); + if (!first && !last && to_b - from_b == units) + return scr_str_scratch_fill(scratch, s->data + from_b, units); + } + return scr_str_slice_units(s, e, from, to); +} + +ScrStr *scr_str_scratch_keep(ScrStr *s) { + if (!scr_str_is_scratch(s)) return scr_str_retain(s); + return scr_str_from_span_ascii(s->data, s->len); +} + double scr_str_slice_char_code_at(ScrStr *s, const ScrStringSlice *range, double index) { double unit = scr_to_integer_or_infinity(index); if (!(unit >= 0) || unit >= (double)range->length) return NAN; diff --git a/packages/runtime/src/scr_string.h b/packages/runtime/src/scr_string.h index e4bf09995..425dfaabf 100644 --- a/packages/runtime/src/scr_string.h +++ b/packages/runtime/src/scr_string.h @@ -184,6 +184,14 @@ static inline ScrStr *scr_str_retain(ScrStr *s) { void scr_str_release(ScrStr *s); /* NULL-tolerant (uninitialized locals) */ +/* A transient stack copy of a slice (scr_str_slice_scratch): immortal for + * retain and release, and valid only while its borrowing consumer runs. No + * other string has a capacity below its length. Containers that keep a + * string they were lent store scr_str_scratch_keep's copy instead. */ +static inline bool scr_str_is_scratch(const ScrStr *s) { + return s->rc == SIZE_MAX && s->cap < s->len; +} + /* ── lone surrogates: canonical WTF-8 storage ───────────────────────── * String storage is UTF-8 extended to lone UTF-16 surrogates: an unpaired * surrogate is its generalized 3-byte encoding ED A0..BF 80..BF, while a diff --git a/packages/runtime/src/scr_string_methods.h b/packages/runtime/src/scr_string_methods.h index 537747530..62354142e 100644 --- a/packages/runtime/src/scr_string_methods.h +++ b/packages/runtime/src/scr_string_methods.h @@ -83,6 +83,16 @@ typedef struct ScrStringSlice { void scr_str_slice_range(ScrStr *s, double start, double end, bool substring, ScrStringSlice *out); double scr_str_slice_char_code_at(ScrStr *s, const ScrStringSlice *range, double index); +/* A slice that only borrowing consumers read (string-slices.ts) is written + * into the caller's `bytes`-sized stack buffer as an immortal ASCII string, + * whose header marks it as a scratch copy (scr_str_is_scratch). Results + * that do not fit, are not ASCII, or are interned statics are returned as + * the ordinary +1 slice. Releasing either result is correct. */ +ScrStr *scr_str_slice_scratch(ScrStr *s, double start, double end, bool substring, + ScrStr *scratch, size_t bytes); +/* The owning reference a container stores for `s`: a heap copy of a scratch + * string, else `s` retained. */ +ScrStr *scr_str_scratch_keep(ScrStr *s); /* repeat(count): count < 0 or Infinity is a JS RangeError; scriptc has no * exceptions, so it prints "scriptc: RangeError: Invalid count value" to diff --git a/packages/runtime/test/test_map.c b/packages/runtime/test/test_map.c index 6eee2d6bb..8899974a8 100644 --- a/packages/runtime/test/test_map.c +++ b/packages/runtime/test/test_map.c @@ -284,6 +284,36 @@ static void test_span_keys(void) { scr_map_release(numbers); } +/* A scratch slice probes like any key; an insertion stores a heap copy, so + * the stored key survives the buffer's next contents. */ +static void test_scratch_keys(void) { + ScrMap *m = scr_map_new(SCR_MAP_KEY_STR, SCR_MAP_VAL_F64, NULL); + ScrStr *line = S("alpha beta alpha"); + _Alignas(16) unsigned char buffer[96]; + ScrStr *alpha = scr_str_slice_scratch(line, 0, 5, false, (ScrStr *)buffer, sizeof buffer); + check(alpha == (ScrStr *)buffer && scr_str_is_scratch(alpha), "short ASCII slice uses the buffer"); + scr_map_set_str_f64(m, alpha, 1); + double out = 0; + check(scr_map_get_str_f64(m, alpha, &out) && out == 1, "scratch key probes its entry"); + ScrStr *beta = scr_str_slice_scratch(line, 6, 10, false, (ScrStr *)buffer, sizeof buffer); + check(!scr_map_has_str(m, beta), "refilled buffer probes its new text"); + scr_map_set_str_f64(m, beta, 2); + ScrStr *again = scr_str_slice_scratch(line, 11, 16, false, (ScrStr *)buffer, sizeof buffer); + scr_map_set_str_f64(m, again, 3); + check(scr_map_size(m) == 2, "scratch overwrite keeps one entry"); + ScrStr *first = scr_map_iter_key_str(m, 0), *second = scr_map_iter_key_str(m, 1); + ScrStr *a = S("alpha"), *b = S("beta"); + check(!scr_str_is_scratch(first) && scr_str_eq(first, a), "stored key is an owned copy"); + check(!scr_str_is_scratch(second) && scr_str_eq(second, b), "second stored key is a copy"); + check(scr_map_get_str_f64(m, a, &out) && out == 3, "overwrite through scratch key"); + scr_str_release(a); + scr_str_release(b); + scr_str_release(first); + scr_str_release(second); + scr_str_release(line); + scr_map_release(m); +} + static void test_same_value_zero(void) { ScrMap *m = scr_map_new(SCR_MAP_KEY_F64, SCR_MAP_VAL_BOOL, NULL); scr_map_set_f64_bool(m, 0.0 / 0.0, true); /* NaN key */ @@ -793,6 +823,7 @@ int main(void) { test_string_entries(); test_same_value_zero(); test_span_keys(); + test_scratch_keys(); test_string_hash_cache(); #ifdef SCR_RC_AUDIT test_rc_accounting(); diff --git a/packages/runtime/test/test_string.c b/packages/runtime/test/test_string.c index 55c49af7e..e49d8eb8b 100644 --- a/packages/runtime/test/test_string.c +++ b/packages/runtime/test/test_string.c @@ -205,6 +205,38 @@ static void surrogate_asserts(void) { } } } + /* Scratch slices hold the materialized text. Only ASCII results of at + * least two units use the caller's buffer, marked as scratch. */ + { + ScrStr *sources[] = {two, s, scr_str_new("GET /api/users 200", 18)}; + const double marks[] = {-INFINITY, -7.5, -3, -0.5, -0.0, 0, 0.5, 1, + 2, 3.9, 5, 9, 40, INFINITY, NAN}; + const size_t nmarks = sizeof marks / sizeof marks[0]; + _Alignas(16) unsigned char buffer[96]; + for (size_t k = 0; k < 3; k++) { + for (size_t a = 0; a < nmarks; a++) { + for (size_t b = 0; b < nmarks; b++) { + for (unsigned substring = 0; substring < 2; substring++) { + ScrStr *src = sources[k]; + ScrStr *scratch = scr_str_slice_scratch(src, marks[a], marks[b], substring != 0, + (ScrStr *)buffer, sizeof buffer); + ScrStr *copy = substring ? scr_str_substring(src, marks[a], marks[b]) + : scr_str_slice(src, marks[a], marks[b]); + bool used = scratch == (ScrStr *)buffer; + bool expected = copy->len >= 2 && scr_bytes_all_ascii(copy->data, copy->len); + total++; + if (scratch->len != copy->len || memcmp(scratch->data, copy->data, copy->len) != 0 || + used != expected || used != scr_str_is_scratch(scratch) || + scr_str_utf16_len(scratch) != scr_str_utf16_len(copy)) + failed++; + scr_str_release(scratch); + scr_str_release(copy); + } + } + } + } + scr_str_release(sources[2]); + } scr_str_release(two); scr_str_release(s); } diff --git a/tests/corpus/scratch-string-slices.ts b/tests/corpus/scratch-string-slices.ts new file mode 100644 index 000000000..487883d6e --- /dev/null +++ b/tests/corpus/scratch-string-slices.ts @@ -0,0 +1,116 @@ +// Slices read only by comparisons, numeric parsers, collection probes, +// switch discriminants and lent helper parameters, including the keys a +// map or set keeps after the slice that produced them is gone. +const ascii = "GET /api/users?id=42 200 17.5ms"; +const mixed = "Aé水x😀yz-12.5e1 ok"; +const bounds = [-Infinity, -40, -8, -2.5, -1, -0.5, -0, 0, 0.5, 1, 2, 3, 4.9, 5, 7, 10, 40, Infinity, NaN]; + +function compare(source: string, start: number, end: number): string { + const s = source.slice(start, end); + const t = source.substring(start, end); + const parts = [ + String(s === "GET"), + String(t === "GET"), + String(source.slice(start, end) === source.substring(start, end)), + String(source.slice(start, end) < "M"), + String(source.substring(start, end) >= "a"), + String(s.length), + String(t.length), + String(s.charCodeAt(0)), + String(t.charCodeAt(t.length - 1)), + String(s.indexOf("a")), + String(t.includes("😀")), + String(s.startsWith("A")), + String(t.endsWith("z")), + ]; + return parts.join(","); +} +for (const source of [ascii, mixed]) { + for (const start of bounds) { + const row: string[] = []; + for (const end of bounds) row.push(compare(source, start, end)); + console.log(row.join(" | ")); + } +} + +// Numeric parsing of slices. +const numbers = " 42|-0|0x1F|1e3|.5|Infinity|-Infinity|12px|abc|+7.25| 9 |0b11|1_000|"; +let offset = 0; +while (offset < numbers.length) { + const bar = numbers.indexOf("|", offset); + const field = numbers.slice(offset, bar); + console.log( + JSON.stringify(field), + Number(field), + +numbers.substring(offset, bar), + parseInt(field), + parseInt(numbers.slice(offset, bar), 16), + parseFloat(field), + Object.is(Number(numbers.slice(offset, bar)), -0), + ); + offset = bar + 1; +} +console.log(Number(mixed.slice(9, 16)), parseFloat(mixed.slice(9)), parseInt(mixed.slice(10, 12))); + +// Collection probes and insertions keyed by slices. The stored keys must +// outlive every later slice written to the same site. +const counts = new Map(); +const seen = new Set(); +const words = "alpha beta gamma alpha delta beta alpha epsilon-with-a-much-longer-key-than-the-stack-buffer-holds-alpha zeta é-key é-key x x"; +for (let round = 0; round < 3; round++) { + let start = 0; + while (start < words.length) { + let end = words.indexOf(" ", start); + if (end < 0) end = words.length; + const word = words.slice(start, end); + counts.set(word, (counts.get(word) ?? 0) + 1); + if (!seen.has(word)) seen.add(word); + if (counts.get(words.substring(start, end)) === 2) seen.delete(word); + start = end + 1; + } +} +console.log([...counts.entries()].map(([key, value]) => `${key}=${value}`).join(",")); +console.log([...seen].join(",")); +console.log(counts.has(ascii.slice(0, 3)), counts.has(words.slice(0, 5)), seen.has(words.slice(6, 10))); +const index = new Map(); +for (let i = 0; i + 3 <= ascii.length; i++) index.set(ascii.slice(i, i + 3), i); +console.log(index.size, index.get("api"), index.get(ascii.substring(5, 8)), [...index.keys()].slice(0, 6).join("/")); +const reads = new Map([["api", "first"], ["users", "second"]]); +console.log(reads.get(ascii.slice(5, 8)), reads.get(ascii.slice(9, 14)) ?? "none", reads.get(ascii.slice(0, 1)) ?? "none"); + +// Switch discriminants. +function method(line: string): number { + switch (line.slice(0, line.indexOf(" "))) { + case "GET": + return 1; + case "POST": + return 2; + case "é": + return 3; + default: + return 0; + } +} +console.log(method(ascii), method("POST /x"), method("é y"), method("PATCH /x"), method("nospace")); + +// Lent helper parameters, including recursion through a lent parameter. +function isKeyword(text: string): boolean { + return text === "let" || text === "const" || text === "return"; +} +function depth(text: string, n: number): number { + if (n === 0) return text.length; + return depth(text, n - 1) + (text === "abc" ? 1 : 0); +} +function keep(text: string): string[] { + return [text]; +} +const program = "let x = 1; const y = 2; return x + y; letter"; +let keywords = 0; +const kept: string[][] = []; +for (let i = 0; i < program.length; i++) { + for (let j = i + 2; j <= Math.min(program.length, i + 6); j++) { + if (isKeyword(program.slice(i, j))) keywords++; + } + if (i % 9 === 0) kept.push(keep(program.slice(i, i + 4))); +} +console.log(keywords, depth("abcdef".slice(0, 3), 4), kept.map((k) => k[0]).join("|")); From 63dae8775eddb2bcd37c61d860798558933190f6 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 12:24:47 -0700 Subject: [PATCH 007/117] Define the region fiber hooks in an always-linked runtime unit scr_async.c reads scr_region_fiber_hooks, but several runtime test links (cipher, bytes, sha-kernels, runtime) take scr_async.c without scr_region.c and failed with an undefined reference. scr_object.c is in every runtime link, so the pointer now lives there; scr_region.c still installs the hooks. Co-Authored-By: Claude Opus 5.5 --- packages/runtime/src/scr_object.c | 5 +++++ packages/runtime/src/scr_region.c | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/scr_object.c b/packages/runtime/src/scr_object.c index a533a409c..7cafbeca3 100644 --- a/packages/runtime/src/scr_object.c +++ b/packages/runtime/src/scr_object.c @@ -2,6 +2,11 @@ * one runtime layout, including captured bindings for local classes. */ #include "scr_runtime.h" +/* The lifetime-region fiber hooks (scr_region.h) live in this always-linked + * unit: scr_async.c reads them, and some runtime test links take + * scr_async.c without scr_region.c. scr_region_create installs them. */ +_Atomic(const ScrRgnFiberHooks *) scr_region_fiber_hooks = NULL; + void scr_classobj_trace_v(void *object, ScrTraceVisit visit, void *ctx) { ScrClassObj *c = object; for (size_t i = 0; i < c->ncaps; i++) visit(c->caps[i], ctx); diff --git a/packages/runtime/src/scr_region.c b/packages/runtime/src/scr_region.c index c8906ad0f..31d01296e 100644 --- a/packages/runtime/src/scr_region.c +++ b/packages/runtime/src/scr_region.c @@ -1288,8 +1288,6 @@ static const ScrRgnFiberHooks scr_rgn_fiber_hooks = { scr_rgn_fiber_suspend, }; -_Atomic(const ScrRgnFiberHooks *) scr_region_fiber_hooks = NULL; - /* ── program-facing entry points ─────────────────────────────────────── */ double scr_region_create(const ScrRgnType *types) { From 83517ecd8226a065aa20b8afc9c4fc5cc7bf9429 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 13:32:48 -0700 Subject: [PATCH 008/117] Accept a frame-stored tuple receiver in the tuple for-of test A for-of over a tuple producer's result only reads its elements, so the tuple now lives in frame storage and the producer runs through its result-slot entry. The test still checks that the receiver is computed once and that no array snapshot is allocated, whichever entry runs. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/test/tuple-forof.test.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/compiler/test/tuple-forof.test.ts b/packages/compiler/test/tuple-forof.test.ts index 3a66d9c09..78cc9376d 100644 --- a/packages/compiler/test/tuple-forof.test.ts +++ b/packages/compiler/test/tuple-forof.test.ts @@ -25,7 +25,12 @@ console.log(total, calls); const mod = deserializeModule(await readFile(outPath, "utf8")); expect(validateModule(mod)).toEqual([]); const llvm = emitLlvmModule(mod); - expect(llvm.match(/call ptr @sc_f_pair\(/g)).toHaveLength(1); + // The receiver is computed once: an ordinary call, or (when the loop + // only reads elements) the result-slot entry filling frame storage. + const calls = + (llvm.match(/call ptr @sc_f_pair\(/g) ?? []).length + + (llvm.match(/call void @sc_\w*into_pair\(ptr %s\d+\)/g) ?? []).length; + expect(calls).toBe(1); expect(llvm).not.toContain("@scr_arr_new"); } finally { await rm(dir, { recursive: true, force: true }); From 250097dd32d49cd70daaebe6681256fb69203b9d Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 13:57:35 -0700 Subject: [PATCH 009/117] Represent unions of records as the record pointer itself A union of two or more record arms and at most two unit arms (the discriminated unions of object literals behind Result, token, shape and AST types) now holds the record pointer instead of a reference-counted %ScrUnion box, like nullable unions already do. NULL and the existing null sentinel encode the unit arms. Every record shape that is an arm of such a union carries its module-wide shape number in a hidden i32 after the reference count; the arm of a value is that word mapped through a per-union tag helper, which LLVM folds into the consumer's switch. Records share one retain; release and trace dispatch on the arm, and every arm of a union with a traced arm carries a collector header. Wraps move the record, retypes between such unions reuse the pointer, and equality is identity. Record field indices come from the shape's field base. Unions over records that are also arms of runtime-inspected unions (Map keys, Set elements), library builds, lifetime-region programs and debug builds keep boxes. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/backend/llvm/dyn.ts | 20 ++- packages/compiler/src/backend/llvm/emitter.ts | 47 ++++-- .../src/backend/llvm/expr-callbacks.ts | 12 +- .../compiler/src/backend/llvm/expr-control.ts | 4 +- .../compiler/src/backend/llvm/expr-records.ts | 14 +- .../src/backend/llvm/expr-stream-bridges.ts | 11 +- .../compiler/src/backend/llvm/lib-datagram.ts | 4 +- .../src/backend/llvm/lib-filesystem.ts | 7 +- .../compiler/src/backend/llvm/lib-lookup.ts | 2 +- .../compiler/src/backend/llvm/lib-network.ts | 2 +- .../src/backend/llvm/nullable-unions.test.ts | 83 ++++++++++ .../src/backend/llvm/nullable-unions.ts | 156 ++++++++++++++++-- packages/compiler/src/backend/llvm/publish.ts | 23 ++- packages/compiler/src/backend/llvm/regions.ts | 9 +- packages/compiler/src/backend/llvm/shapes.ts | 143 +++++++++++++++- .../src/backend/llvm/stack-objects.ts | 12 ++ .../compiler/src/backend/llvm/union-repr.ts | 36 +++- .../src/backend/llvm/union-retype.test.ts | 19 ++- packages/compiler/src/backend/llvm/walkers.ts | 8 +- .../corpus/5930-record-union-pointers.ts.json | 6 + .../5931-record-union-unit-arms.ts.json | 6 + .../corpus/5932-record-union-trees.ts.json | 6 + .../5933-record-union-conversions.ts.json | 6 + .../5934-record-union-set-members.ts.json | 6 + tests/corpus/5930-record-union-pointers.ts | 79 +++++++++ tests/corpus/5931-record-union-unit-arms.ts | 67 ++++++++ tests/corpus/5932-record-union-trees.ts | 77 +++++++++ tests/corpus/5933-record-union-conversions.ts | 78 +++++++++ tests/corpus/5934-record-union-set-members.ts | 25 +++ 29 files changed, 886 insertions(+), 82 deletions(-) create mode 100644 packages/compiler/src/backend/llvm/nullable-unions.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5930-record-union-pointers.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5931-record-union-unit-arms.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-record-union-trees.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5933-record-union-conversions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5934-record-union-set-members.ts.json create mode 100644 tests/corpus/5930-record-union-pointers.ts create mode 100644 tests/corpus/5931-record-union-unit-arms.ts create mode 100644 tests/corpus/5932-record-union-trees.ts create mode 100644 tests/corpus/5933-record-union-conversions.ts create mode 100644 tests/corpus/5934-record-union-set-members.ts diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index b85ca0062..845633148 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -1179,12 +1179,13 @@ export class LlDyn { `llvm emitter bug: JSON schema of unknown shape ${t.shapeId}`, ); const struct = mangleRecordStruct(t.shapeId); - const index = new Map(shape.fields.map((f, i) => [f.name, i + 1])); + const base = host.nullableUnions.fieldBase(t.shapeId); + const index = new Map(shape.fields.map((f, i) => [f.name, i + base])); // The runtime names kept-source keys by this index (record-sources.ts). const order = recordSourceFieldOrder(shape); const fieldTy = `{ ptr, ${S}, ${S}, ptr }`; const entries = order.map((fieldName) => { - const field = shape.fields[index.get(fieldName)! - 1]!; + const field = shape.fields[index.get(fieldName)! - base]!; const sub = this.jsonSchema(field.type); const offset = `ptrtoint (ptr getelementptr (%${struct}, ptr null, i64 0, i32 ${index.get(fieldName)}) to ${S})`; return `${fieldTy} { ptr ${host.cstr(fieldName)}, ${S} ${Buffer.byteLength(fieldName, "utf8")}, ${S} ${offset}, ptr @${sub} }`; @@ -1421,18 +1422,19 @@ export class LlDyn { B.line(`call void @scr_arr_outline(ptr ${cached})`); B.line(`call void @scr_arr_outline(ptr ${checked})`); } + const base = t.kind === "record" ? host.nullableUnions.fieldBase(t.shapeId) : 1; const members = t.kind === "record" ? [ ...shape!.fields.map((field, index) => ({ - index: index + 1, + index: index + base, type: llFieldType(field.type, host.inlineUnions.record(field.type)), name: field.name, })), ...(shape!.indexValue ? [ { - index: shape!.fields.length + 1, + index: shape!.fields.length + base, type: "ptr" as const, name: "[key: string] overflow", }, @@ -1693,7 +1695,8 @@ export class LlDyn { `llvm emitter bug: dynCheck of unknown shape ${t.shapeId}`, ); const struct = mangleRecordStruct(t.shapeId); - const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + 1])); + const base = host.nullableUnions.fieldBase(t.shapeId); + const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + base])); const releaseR = (): void => { B.line(`call void ${releaseSym(host, t)}(ptr %r0)`); }; @@ -1870,7 +1873,7 @@ export class LlDyn { const ovfp = B.tmp(); const ovf = B.tmp(); B.line( - `${ovfp} = getelementptr inbounds %${struct}, ptr %r0, i64 0, i32 ${shape.fields.length + 1}`, + `${ovfp} = getelementptr inbounds %${struct}, ptr %r0, i64 0, i32 ${shape.fields.length + base}`, ); B.line(`${ovf} = load ptr, ptr ${ovfp} ; overflow map`); if (shape.fields.length === 0) { @@ -2443,7 +2446,8 @@ export class LlDyn { if (!shape) throw new InternalCompilerError(`llvm emitter bug: to-dyn of unknown shape ${t.shapeId}`); const struct = mangleRecordStruct(t.shapeId); - const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + 1])); + const base = host.nullableUnions.fieldBase(t.shapeId); + const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + base])); const loadFieldOf = (fname: string, ft: IrType): string => { const p = B.tmp(); B.line( @@ -2567,7 +2571,7 @@ export class LlDyn { const ovfp = B.tmp(); const ovf = B.tmp(); B.line( - `${ovfp} = getelementptr inbounds %${struct}, ptr %v, i64 0, i32 ${shape.fields.length + 1}`, + `${ovfp} = getelementptr inbounds %${struct}, ptr %v, i64 0, i32 ${shape.fields.length + base}`, ); B.line(`${ovf} = load ptr, ptr ${ovfp} ; overflow map`); const ks = B.tmp(); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 09bf4979c..a9e840837 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -373,6 +373,7 @@ import { elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, + emitShapeUnionHelpers, FN_ATTRS, inlineRcDecls, type InlineRcMode, @@ -1071,7 +1072,7 @@ export class LlEmitter { expr: (expr) => !(expr.kind === "libCall" && expr.fn === "error.stack"), }), ); - this.nullableUnions = new NullableUnions(mod); + this.nullableUnions = new NullableUnions(mod, options.debugSources === undefined); this.debug = options.debugSources === undefined ? null @@ -1165,8 +1166,10 @@ export class LlEmitter { // Optional array reads also cover nullable unions: emitLocalArrayRead // then yields the (borrowed or owned) element pointer, not a stack box. // Arrays of such a union are read the same way. - this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById, (id) => - this.nullableUnions.has(id), + this.optionalArrayReads = new OptionalArrayReads( + this.fnByName, + this.unionsById, + (id) => this.nullableUnions.single(id) !== null, ); this.unionSources = { unions: this.boxedUnionsById, @@ -1219,7 +1222,8 @@ export class LlEmitter { (type) => this.plainReference(type) && type.kind !== "string" && - (type.kind !== "union" || this.nullableUnions.get(type.unionId)?.arm.kind !== "string"), + (type.kind !== "union" || + this.nullableUnions.single(type.unionId)?.arm.kind !== "string"), this.walkBorrowsByFunction.get(fn.name) ?? new Set(), ); if (rebound.size === 0) continue; @@ -1270,6 +1274,15 @@ export class LlEmitter { const traced = computeTraced(mod); this.tracedShapes = traced.shapes; this.tracedUnions = traced.unions; + // A shape union's value is whichever record it holds, and the collector + // visits it as that record: when one arm carries a collector header, + // every arm must (nullable-unions.ts). + for (const union of this.nullableUnions.allShapeUnions()) + if ( + this.tracedUnions.has(union.unionId) || + union.arms.some((arm) => this.tracedShapes.has(`record:${arm.shapeId}`)) + ) + for (const arm of union.arms) this.tracedShapes.add(`record:${arm.shapeId}`); this.shapeHost = { sizeType: this.sizeType, cycleBufOffset: this.cycleBufOffset, @@ -3551,6 +3564,7 @@ export class LlEmitter { return [ ...late, ...emitNullableRetainWrappers(this.shapeHost), + ...emitShapeUnionHelpers(this.shapeHost), ...emitInlineRcHelpers(this.shapeHost), ]; } @@ -5527,7 +5541,11 @@ export class LlEmitter { const nullable = this.nullableUnions.get(unionId); if (nullable) { // The owned payload IS the nullable union's value. - if (tag !== nullable.refTag) + if ( + nullable.repr === "single" + ? tag !== nullable.refTag + : !nullable.arms.some((arm) => arm.tag === tag) + ) throw new InternalCompilerError( `llvm emitter bug: payload wrap into unit arm ${tag} of ${unionId}`, ); @@ -5632,7 +5650,7 @@ export class LlEmitter { const index = shape.fields.findIndex((entry) => entry.name === field); if (index < 0) throw new InternalCompilerError(`llvm emitter bug: missing union field ${field}`); - layout = "record:"; + layout = this.nullableUnions.fieldBase(arm.shapeId) === 2 ? "record:tagged;" : "record:"; for (let i = 0; i <= index; i++) { const type = shape.fields[i]!.type; layout += `${llFieldType(type, this.inlineUnions.record(type))};`; @@ -5668,7 +5686,7 @@ export class LlEmitter { ); const p = this.B.tmp(); this.B.line( - `${p} = getelementptr inbounds %${mangleRecordStruct(shapeId)}, ptr ${objName}, i64 0, i32 ${idx + 1}`, + `${p} = getelementptr inbounds %${mangleRecordStruct(shapeId)}, ptr ${objName}, i64 0, i32 ${idx + this.nullableUnions.fieldBase(shapeId)}`, ); const type = shape.fields[idx]!.type; return { ptr: p, type, inline: this.inlineUnions.record(type) }; @@ -5682,7 +5700,7 @@ export class LlEmitter { const p = this.B.tmp(); const v = this.B.tmp(); this.B.line( - `${p} = getelementptr inbounds %${mangleRecordStruct(shapeId)}, ptr ${objName}, i64 0, i32 ${shape.fields.length + 1}`, + `${p} = getelementptr inbounds %${mangleRecordStruct(shapeId)}, ptr ${objName}, i64 0, i32 ${shape.fields.length + this.nullableUnions.fieldBase(shapeId)}`, ); this.B.line(`${v} = load ptr, ptr ${p}`); return v; @@ -9564,7 +9582,12 @@ export class LlEmitter { unionsById: this.unionsById, recordsById: this.recordsById, inlineUnions: this.inlineUnions, - nullableArm: (t) => this.nullableUnions.of(t)?.arm ?? null, + nullableArm: (t) => { + const nullable = this.nullableUnions.of(t); + return nullable?.repr === "single" ? nullable.arm : null; + }, + shapeUnion: (t) => this.nullableUnions.of(t)?.repr === "shapes", + fieldBase: (shapeId) => this.nullableUnions.fieldBase(shapeId), classInfo: (className) => { const meta = this.classMetaOf(className); return { @@ -10280,7 +10303,11 @@ export class LlEmitter { const nullable = this.nullableUnions.get(e.unionId); if (!nullable) return null; if (isUnitType(e.value.type)) return e.value.kind === "unitLit" ? "unit" : null; - return e.tag === nullable.refTag && isRefCounted(e.value.type) ? "ref" : null; + const refArm = + nullable.repr === "single" + ? e.tag === nullable.refTag + : nullable.arms.some((arm) => arm.tag === e.tag); + return refArm && isRefCounted(e.value.type) ? "ref" : null; } materializeSplitLocal(localId: string): void { diff --git a/packages/compiler/src/backend/llvm/expr-callbacks.ts b/packages/compiler/src/backend/llvm/expr-callbacks.ts index e5560f14f..d71df333a 100644 --- a/packages/compiler/src/backend/llvm/expr-callbacks.ts +++ b/packages/compiler/src/backend/llvm/expr-callbacks.ts @@ -182,6 +182,7 @@ export function genResultThunkFor( sym = mangleGenResThunk(host.resolveThunks.size); host.resolveThunks.set(key, sym); const shape = host.recordsById.get(recT.shapeId); + const base = host.nullableUnions.fieldBase(recT.shapeId); const valueT = shape?.fields.find((f) => f.name === "value")?.type; if (!shape || !valueT) throw new InternalCompilerError("llvm emitter bug: genResume record lacks its value field"); @@ -242,7 +243,7 @@ export function genResultThunkFor( ` %r = call ptr @${mangleRecordNew(recT.shapeId)}()`, ` %d = call zeroext i1 @scr_gen_done(ptr %g)`, ` %dz = zext i1 %d to i8`, - ` %dp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${doneIdxD + 1}`, + ` %dp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${doneIdxD + base}`, ` store i8 %dz, ptr %dp`, ` %has = call zeroext i1 @scr_gen_out_has(ptr %g)`, ` br i1 %has, label %take, label %undefv`, @@ -259,7 +260,7 @@ export function genResultThunkFor( ` br label %join`, `join:`, ` %v = load ptr, ptr %vslot`, - ` %vp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${valueIdxD + 1}`, + ` %vp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${valueIdxD + base}`, ` store ptr %v, ptr %vp`, ` ret ptr %r`, `}`, @@ -293,7 +294,7 @@ export function genResultThunkFor( ` %r = call ptr @${mangleRecordNew(recT.shapeId)}()`, ` %d = call zeroext i1 @scr_gen_done(ptr %g)`, ` %dz = zext i1 %d to i8`, - ` %dp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${doneIdx + 1}`, + ` %dp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${doneIdx + base}`, ` store i8 %dz, ptr %dp`, ` br i1 %d, label %doneb, label %susp`, ]; @@ -410,7 +411,7 @@ export function genResultThunkFor( ` br label %join`, `join:`, ` %v = load ptr, ptr %vslot`, - ` %vp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${valueIdx + 1}`, + ` %vp = getelementptr inbounds %${mangleRecordStruct(recT.shapeId)}, ptr %r, i64 0, i32 ${valueIdx + base}`, // An inline value field copies the box's bits and drops the box. ...(host.inlineUnions.record(valueT) ? [ @@ -1092,7 +1093,8 @@ export function settledStoreFor( return { tag, arm }; }; const fieldIndex = (arm: IrType & { kind: "record" }, field: string): number => - host.recordsById.get(arm.shapeId)!.fields.findIndex((f) => f.name === field) + 1; + host.recordsById.get(arm.shapeId)!.fields.findIndex((f) => f.name === field) + + host.nullableUnions.fieldBase(arm.shapeId); const fulfilled = armOf("value"); const rejected = armOf("reason"); const valueT = host.recordsById diff --git a/packages/compiler/src/backend/llvm/expr-control.ts b/packages/compiler/src/backend/llvm/expr-control.ts index 298ea0199..fd4bc8787 100644 --- a/packages/compiler/src/backend/llvm/expr-control.ts +++ b/packages/compiler/src/backend/llvm/expr-control.ts @@ -330,7 +330,7 @@ export function emitControlExpr( ); B.line(`store ${ty} ${t}, ptr ${slot}`); if (host.mayThrow.has(e.retag)) host.emitPendingCheck(); - } else if (host.nullableUnions.has(e.left.type.unionId)) { + } else if (host.nullableUnions.single(e.left.type.unionId)) { // The owned nullable pointer IS the owned arm value. B.line(`store ${ty} ${l.name}, ptr ${slot}`); } else { @@ -440,7 +440,7 @@ export function emitControlExpr( host.emitBranchInto(slot, e.right); B.br(lj); B.startBlock(lv); - if (typeEquals(e.type, e.left.type) || host.nullableUnions.has(def.id)) { + if (typeEquals(e.type, e.left.type) || host.nullableUnions.single(def.id)) { // Pass-through, or a nullable pointer that IS its owned arm value. B.line(`store ${ty} ${l.name}, ptr ${slot}`); } else { diff --git a/packages/compiler/src/backend/llvm/expr-records.ts b/packages/compiler/src/backend/llvm/expr-records.ts index 4b03dbad2..1d1717613 100644 --- a/packages/compiler/src/backend/llvm/expr-records.ts +++ b/packages/compiler/src/backend/llvm/expr-records.ts @@ -62,9 +62,17 @@ export function emitUnionRetype( const from = host.nullableUnions.get(e.fromId); const to = host.nullableUnions.get(e.unionId); if (from && to) { - // Equal encodings make the pointer itself the target value. - if (from.refTag === to.refTag && from.unitTag === to.unitTag && from.nullTag === to.nullTag) - return host.own({ name: value.name, type: e.type }); + // Equal encodings make the pointer itself the target value. A shape + // union derives its record arms from the record, so only the unit + // encodings must agree. + const same = + from.repr === "single" && to.repr === "single" + ? from.refTag === to.refTag && from.unitTag === to.unitTag && from.nullTag === to.nullTag + : from.repr === "shapes" && + to.repr === "shapes" && + from.unitTag === to.unitTag && + from.nullTag === to.nullTag; + if (same) return host.own({ name: value.name, type: e.type }); return host.own({ name: rebuildRetype(host, value.name, e), type: e.type }); } if (from || to) return host.own({ name: rebuildRetype(host, value.name, e), type: e.type }); diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 55fa363cd..76ef35358 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -500,16 +500,17 @@ export function streamTypedRefCommitAdapter( ` br i1 %missing, label %done, label %swap`, `swap:`, ]; + const base = host.nullableUnions.fieldBase(t.shapeId); const members = [ ...shape.fields.map((field, index) => ({ - index: index + 1, + index: index + base, type: llFieldType(field.type, host.inlineUnions.record(field.type)), name: field.name, })), ...(shape.indexValue ? [ { - index: shape.fields.length + 1, + index: shape.fields.length + base, type: "ptr" as const, name: "[key: string] overflow", }, @@ -943,7 +944,7 @@ export function streamTypedRefMaterializeAdapter( B.line(`${out} = call ptr @scr_dyn_new_arr()`); const fields = [...shape.fields].sort((a, b) => Number(a.name) - Number(b.name)); for (const field of fields) { - const index = shape.fields.indexOf(field) + 1; + const index = shape.fields.indexOf(field) + host.nullableUnions.fieldBase(t.shapeId); const fieldPtr = B.tmp(); B.line( `${fieldPtr} = getelementptr inbounds %${mangleRecordStruct(t.shapeId)}, ptr %p, i64 0, i32 ${index}`, @@ -980,7 +981,7 @@ export function streamTypedRefMaterializeAdapter( liveRecordOps(host, t, snapshot, fields); } for (const field of fields) { - const index = shape.fields.indexOf(field) + 1; + const index = shape.fields.indexOf(field) + host.nullableUnions.fieldBase(t.shapeId); const fieldPtr = B.tmp(); B.line( `${fieldPtr} = getelementptr inbounds %${mangleRecordStruct(t.shapeId)}, ptr %p, i64 0, i32 ${index}`, @@ -1202,7 +1203,7 @@ function liveRecordOps( const names = `${snapshot}_names`; const ops = `${snapshot}_rops`; const loadField = (B: BlockBuilder, field: IrRecordShape["fields"][number]): string => { - const index = shape.fields.indexOf(field) + 1; + const index = shape.fields.indexOf(field) + host.nullableUnions.fieldBase(t.shapeId); const fieldPtr = B.tmp(); B.line(`${fieldPtr} = getelementptr inbounds %${struct}, ptr %p, i64 0, i32 ${index}`); return loadStructField( diff --git a/packages/compiler/src/backend/llvm/lib-datagram.ts b/packages/compiler/src/backend/llvm/lib-datagram.ts index 1553ecf4f..72de03830 100644 --- a/packages/compiler/src/backend/llvm/lib-datagram.ts +++ b/packages/compiler/src/backend/llvm/lib-datagram.ts @@ -29,7 +29,7 @@ function messageAdapter(host: LlvmEmitterContext, type: IrType): string { const isString = field === "address" || field === "family"; if (isString) lines.push(` %${field}.owned = call ptr @scr_str_retain_v(ptr %${field})`); lines.push( - ` %${field}.slot = getelementptr inbounds %${mangleRecordStruct(type.shapeId)}, ptr %record, i64 0, i32 ${index + 1}`, + ` %${field}.slot = getelementptr inbounds %${mangleRecordStruct(type.shapeId)}, ptr %record, i64 0, i32 ${index + host.nullableUnions.fieldBase(type.shapeId)}`, ` store ${isString ? "ptr" : "double"} %${field}${isString ? ".owned" : ""}, ptr %${field}.slot`, ); } @@ -167,7 +167,7 @@ export function emitDatagramLibCall(host: LlvmEmitterContext, e: LibCallExpr): L ); const slot = host.B.tmp(); host.B.line( - `${slot} = getelementptr inbounds %${mangleRecordStruct(type.shapeId)}, ptr ${record}, i64 0, i32 ${index + 1}`, + `${slot} = getelementptr inbounds %${mangleRecordStruct(type.shapeId)}, ptr ${record}, i64 0, i32 ${index + host.nullableUnions.fieldBase(type.shapeId)}`, ); host.B.line(`store ${ty} ${value}, ptr ${slot}`); } diff --git a/packages/compiler/src/backend/llvm/lib-filesystem.ts b/packages/compiler/src/backend/llvm/lib-filesystem.ts index 1083c69d5..bcb65c8fa 100644 --- a/packages/compiler/src/backend/llvm/lib-filesystem.ts +++ b/packages/compiler/src/backend/llvm/lib-filesystem.ts @@ -910,11 +910,8 @@ export function emitPathUrlLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll scopeid.inline, ); } - const rc = vAdapters(host.shapeHost, t); - const rowU = B.tmp(); - B.line( - `${rowU} = call ptr @scr_union_new_ref(i32 ${tag}, ptr ${r}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${traceArg(host.shapeHost, t)})`, - ); + // The row (+1) moves into its union arm (a shape union is the row). + const rowU = host.unionNewOwned(infoT.unionId, tag, { name: r, type: t }); B.line(`store ptr ${rowU}, ptr ${rowSlot}`); B.br(lRow); }; diff --git a/packages/compiler/src/backend/llvm/lib-lookup.ts b/packages/compiler/src/backend/llvm/lib-lookup.ts index 9fc23cb94..a6e76e4e0 100644 --- a/packages/compiler/src/backend/llvm/lib-lookup.ts +++ b/packages/compiler/src/backend/llvm/lib-lookup.ts @@ -65,7 +65,7 @@ export function emitLookupConnect(host: LlvmEmitterContext, e: LibCallExpr): LlV " br i1 %more, label %body, label %finish", "body:", " %record = call ptr @scr_arr_get_ref(ptr %addresses, double %index)", - ` %addressp = getelementptr inbounds %${struct}, ptr %record, i64 0, i32 ${field + 1}`, + ` %addressp = getelementptr inbounds %${struct}, ptr %record, i64 0, i32 ${field + host.nullableUnions.fieldBase(addresses.elem.shapeId)}`, " %address = load ptr, ptr %addressp", " %owned.address = call ptr @scr_str_retain_v(ptr %address)", " call double @scr_arr_push_ref(ptr %ips, ptr %owned.address)", diff --git a/packages/compiler/src/backend/llvm/lib-network.ts b/packages/compiler/src/backend/llvm/lib-network.ts index 3ac9fe050..322479a85 100644 --- a/packages/compiler/src/backend/llvm/lib-network.ts +++ b/packages/compiler/src/backend/llvm/lib-network.ts @@ -168,7 +168,7 @@ export function emitNetworkHttpLibCall(host: LlvmEmitterContext, e: LibCallExpr) const i = shape.fields.findIndex((f) => f.name === name); if (i < 0) throw new InternalCompilerError(`llvm emitter bug: net.serverAddress record lacks ${name}`); - return i + 1; + return i + host.nullableUnions.fieldBase(recT.shapeId); }; const store = (name: string, ty: string, v: string): void => { const p = B.tmp(); diff --git a/packages/compiler/src/backend/llvm/nullable-unions.test.ts b/packages/compiler/src/backend/llvm/nullable-unions.test.ts new file mode 100644 index 000000000..46bd688e7 --- /dev/null +++ b/packages/compiler/src/backend/llvm/nullable-unions.test.ts @@ -0,0 +1,83 @@ +import { expect, test } from "vitest"; +import { + F64, + NULL_T, + UNDEFINED_T, + type IrModule, + type IrType, + type IrUnionDef, +} from "../../ir/ir.js"; +import { NullableUnions } from "./nullable-unions.js"; + +const loc = { file: "nullable-unions.ts", start: 0, end: 0 }; +const a: IrType = { kind: "record", shapeId: "a" }; +const b: IrType = { kind: "record", shapeId: "b" }; +const c: IrType = { kind: "record", shapeId: "c" }; + +function module(unions: IrUnionDef[], extra: Partial = {}): IrModule { + return { + irVersion: 16, + sourceFile: loc.file, + entry: "main", + records: ["a", "b", "c"].map((id) => ({ id, fields: [{ name: id, type: F64 }] })), + unions, + functions: [], + ...extra, + }; +} + +test("unions of two or more records become shape unions", () => { + const unions = new NullableUnions( + module([ + { id: "ab", arms: [a, b] }, + { id: "abu", arms: [a, UNDEFINED_T, b] }, + { id: "abnu", arms: [a, b, NULL_T, UNDEFINED_T] }, + { id: "af", arms: [a, F64] }, + { id: "au", arms: [a, UNDEFINED_T] }, + ]), + ); + expect(unions.shapes("ab")).toMatchObject({ unitTag: -1, nullTag: -1 }); + expect(unions.shapes("abu")).toMatchObject({ unitTag: 1, nullTag: -1 }); + expect(unions.shapes("abnu")).toMatchObject({ unitTag: 3, nullTag: 2 }); + expect(unions.shapes("abnu")?.arms).toEqual([ + { tag: 0, shapeId: "a" }, + { tag: 1, shapeId: "b" }, + ]); + // A scalar arm keeps the box; one record arm is a single-arm nullable. + expect(unions.get("af")).toBeNull(); + expect(unions.single("au")).not.toBeNull(); + expect(unions.shapes("au")).toBeNull(); + // Tagged shapes number from 2 and move their fields after the word. + expect([unions.shapeNumber("a"), unions.shapeNumber("b"), unions.shapeNumber("c")]).toEqual([ + 2, 3, 0, + ]); + expect([unions.fieldBase("a"), unions.fieldBase("c")]).toEqual([2, 1]); + expect(unions.boxedUnions(new Map([["af", { id: "af", arms: [a, F64] }]])).size).toBe(1); +}); + +test("records of runtime-inspected unions keep every union over them boxed", () => { + const set: IrType = { kind: "set", elem: { kind: "union", unionId: "ab" } }; + const unions = new NullableUnions( + module( + [ + { id: "ab", arms: [a, b] }, + { id: "abu", arms: [a, b, UNDEFINED_T] }, + { id: "bc", arms: [b, c] }, + { id: "ac", arms: [a, c] }, + ], + { globals: [{ id: "%g.s", name: "s", type: set, mutable: false }] }, + ), + ); + expect(unions.get("ab")).toBeNull(); + expect(unions.get("abu")).toBeNull(); + expect(unions.get("bc")).toBeNull(); + expect(unions.get("ac")).toBeNull(); + expect(unions.shapeNumber("c")).toBe(0); +}); + +test("library, lifetime-region and debug builds keep record unions boxed", () => { + const unions = [{ id: "ab", arms: [a, b] }]; + expect(new NullableUnions(module(unions), false).get("ab")).toBeNull(); + expect(new NullableUnions(module(unions, { lifetimeRegions: true })).get("ab")).toBeNull(); + expect(new NullableUnions(module(unions)).shapes("ab")).not.toBeNull(); +}); diff --git a/packages/compiler/src/backend/llvm/nullable-unions.ts b/packages/compiler/src/backend/llvm/nullable-unions.ts index b1032f9d4..8729e9649 100644 --- a/packages/compiler/src/backend/llvm/nullable-unions.ts +++ b/packages/compiler/src/backend/llvm/nullable-unions.ts @@ -17,6 +17,7 @@ import { everyModuleNode } from "../../ir/traverse.js"; * every container, field, capture, parameter, and return slot holds the * plain pointer. Every other union keeps the tagged `%ScrUnion` box. */ export interface NullableUnion { + repr: "single"; unionId: string; refTag: number; /** The unit arm NULL encodes. */ @@ -24,7 +25,57 @@ export interface NullableUnion { /** The `null` arm of a two-unit-arm union, encoded by NULLABLE_NULL; * -1 when the union has one unit arm. */ nullTag: number; - arm: NullableRefArm; + /** One of NullableRefArm. Typed as the plain IrType so the self-hosted + * frontend keeps IrType's structurally identical arms one record shape + * (a PointerUnion arm holding the narrowed intersection would split them). */ + arm: IrType; +} + +/** A union of two or more record arms and at most two unit arms (`A | B`, + * `A | B | undefined`, discriminated unions of object literals) whose + * VALUES are the record pointer itself, like a NullableUnion: NULL is the + * unit arm (`undefined` when both exist, NULLABLE_NULL is then `null`). + * Every record shape that is an arm of such a union is a TAGGED shape: its + * struct carries the shape's module-wide number in a hidden `i32` word + * right after the reference count (struct index 1), stored by every + * allocation, so the arm of a pointer is that word mapped through the + * union's arm table (the per-union `@sc_stag.` helper). Records share + * one retain; release and trace dispatch on the arm. */ +export interface ShapeUnion { + repr: "shapes"; + unionId: string; + /** The unit arm NULL encodes; -1 when the union has no unit arm. */ + unitTag: number; + /** The `null` arm of a two-unit-arm union, encoded by NULLABLE_NULL; + * -1 otherwise. */ + nullTag: number; + /** The record arms in tag order. */ + arms: readonly { tag: number; shapeId: string }[]; +} + +/** A union whose values are plain pointers (no `%ScrUnion` box). */ +export type PointerUnion = NullableUnion | ShapeUnion; + +/** The struct index of a tagged record shape's hidden shape-number word. */ +export const SHAPE_WORD_INDEX = 1; + +/** The LLVM type through which any tagged record's shape word is read + * (the reference count, then the word). */ +export function shapeWordHeader(sizeType: "i32" | "i64"): string { + return `{ ${sizeType}, i32 }`; +} + +/** The per-union helper mapping a shape-union value to its tag. */ +export function shapeTagFn(unionId: string): string { + return `@sc_stag.${unionId.replace(/[^A-Za-z0-9_.]/g, "_")}`; +} + +/** The per-union release and trace dispatchers of a shape union. */ +export function shapeReleaseFn(unionId: string): string { + return `@sc_srelease.${unionId.replace(/[^A-Za-z0-9_.]/g, "_")}`; +} +export function shapeTraceFn(unionId: string): string { + return `@sc_strace.${unionId.replace(/[^A-Za-z0-9_.]/g, "_")}`; } /** The module-scope immortal sentinel standing for `null` in a @@ -48,44 +99,98 @@ export type NullableRefArm = | (IrType & { kind: "array" | "map" | "set" }); /** The arm is a JS object: always truthy, compared by identity. */ -export function isObjectArm(nullable: NullableUnion): boolean { - return nullable.arm.kind !== "string"; +export function isObjectArm(nullable: PointerUnion): boolean { + return nullable.repr === "shapes" || nullable.arm.kind !== "string"; } /** The representation decision for every union of one module. It is a * pure function of the module, so serialized-IR and in-memory emission * agree. */ export class NullableUnions { - private readonly byId = new Map(); + private readonly byId = new Map(); + /** Tagged record shapes (arms of a shape union) by their module-wide + * shape number (2 and up: 0 and 1 are the unit encodings' pseudo + * numbers, never stored). */ + private readonly shapeNumbers = new Map(); /** NULL-skipping retain wrappers requested so far: symbol → inner retain * call target. The emitter defines each once. */ readonly retainWrappers = new Map(); /** Some nullable union encodes `null` with NULLABLE_NULL. */ readonly usesNullSentinel: boolean = false; - constructor(mod: IrModule) { + /** `shapes`: allow shape unions (debug builds keep boxes, whose + * debug-info layouts describe every arm). */ + constructor(mod: IrModule, shapes = true) { const emitted = new Set(); for (const cls of mod.classes ?? []) if (!cls.runtime) emitted.add(cls.name); const records = new Set(); for (const shape of mod.records ?? []) records.add(shape.id); const boxed = boxedUnionIds(mod); + // Shape unions stay out of library builds (their host ABI marshals + // boxes) and of programs with lifetime regions (whose walks report a + // reference slot by its type's release entry point). + const allowShapes = shapes && mod.lib === undefined && mod.lifetimeRegions !== true; + // A record that is an arm of a boxed union never becomes a shape + // union's arm: conversions between unions over the same records then + // keep one representation. + const boxedRecords = new Set(); + for (const def of mod.unions ?? []) + if (boxed.has(def.id)) + for (const arm of def.arms) if (arm.kind === "record") boxedRecords.add(arm.shapeId); for (const def of mod.unions ?? []) { if (boxed.has(def.id)) continue; - const nullable = nullableShape(def, emitted, records); + const nullable = + nullableShape(def, emitted, records) ?? + (allowShapes ? shapeUnion(def, records, boxedRecords) : null); if (!nullable) continue; this.byId.set(def.id, nullable); if (nullable.nullTag >= 0) this.usesNullSentinel = true; + if (nullable.repr === "shapes") + for (const arm of nullable.arms) + if (!this.shapeNumbers.has(arm.shapeId)) + this.shapeNumbers.set(arm.shapeId, this.shapeNumbers.size + 2); } } - get(unionId: string): NullableUnion | null { + get(unionId: string): PointerUnion | null { return this.byId.get(unionId) ?? null; } - of(type: IrType): NullableUnion | null { + of(type: IrType): PointerUnion | null { return type.kind === "union" ? this.get(type.unionId) : null; } + /** The single-reference-arm form only (shape unions answer null). */ + single(unionId: string): NullableUnion | null { + const nullable = this.byId.get(unionId); + return nullable?.repr === "single" ? nullable : null; + } + + /** The shape-union form only. */ + shapes(unionId: string): ShapeUnion | null { + const nullable = this.byId.get(unionId); + return nullable?.repr === "shapes" ? nullable : null; + } + + /** Every shape union, in module order. */ + allShapeUnions(): ShapeUnion[] { + const out: ShapeUnion[] = []; + for (const nullable of this.byId.values()) if (nullable.repr === "shapes") out.push(nullable); + return out; + } + + /** The module-wide number a tagged record shape stores in its shape + * word, or 0 for shapes that carry none. */ + shapeNumber(shapeId: string): number { + return this.shapeNumbers.get(shapeId) ?? 0; + } + + /** The struct index of a record shape's first declared field: 2 for + * tagged shapes (after the shape word), 1 otherwise. */ + fieldBase(shapeId: string): number { + return this.shapeNumbers.has(shapeId) ? 2 : 1; + } + has(unionId: string): boolean { return this.byId.has(unionId); } @@ -94,10 +199,11 @@ export class NullableUnions { return this.byId.size; } - /** The reference arm of every nullable union, by union id. */ + /** The reference arm of every single-arm nullable union, by union id. */ armTypes(): Map { const result = new Map(); - for (const [id, nullable] of this.byId) result.set(id, nullable.arm); + for (const [id, nullable] of this.byId) + if (nullable.repr === "single") result.set(id, nullable.arm); return result; } @@ -129,7 +235,7 @@ function nullableShape( if (unitTag < 0 || nullTag < 0) return null; } const arm = def.arms[refTag]!; - const base = { unionId: def.id, refTag, unitTag, nullTag }; + const base = { repr: "single" as const, unionId: def.id, refTag, unitTag, nullTag }; if (arm.kind === "object" && emittedClasses.has(arm.className)) return { ...base, arm: { kind: "object", className: arm.className } }; if (arm.kind === "record" && records.has(arm.shapeId)) @@ -140,6 +246,34 @@ function nullableShape( return null; } +/** Two or more emitted record arms and at most two unit arms (both: + * undefined and null). */ +function shapeUnion( + def: IrUnionDef, + records: ReadonlySet, + boxedRecords: ReadonlySet, +): ShapeUnion | null { + const units = def.arms.filter(isUnitType).length; + if (units > 2 || def.arms.length - units < 2) return null; + const arms: { tag: number; shapeId: string }[] = []; + for (let tag = 0; tag < def.arms.length; tag++) { + const arm = def.arms[tag]!; + if (isUnitType(arm)) continue; + if (arm.kind !== "record" || !records.has(arm.shapeId) || boxedRecords.has(arm.shapeId)) + return null; + arms.push({ tag, shapeId: arm.shapeId }); + } + let unitTag = -1, + nullTag = -1; + if (units === 1) unitTag = def.arms.findIndex(isUnitType); + else if (units === 2) { + unitTag = def.arms.findIndex((arm) => arm.kind === "undefinedT"); + nullTag = def.arms.findIndex((arm) => arm.kind === "nullT"); + if (unitTag < 0 || nullTag < 0) return null; + } + return { repr: "shapes", unionId: def.id, unitTag, nullTag, arms }; +} + /** Unions the runtime itself inspects as tagged boxes keep that * representation: Map keys and Set elements hash and compare union keys by * tag and payload inside the C map. */ diff --git a/packages/compiler/src/backend/llvm/publish.ts b/packages/compiler/src/backend/llvm/publish.ts index c884339af..4f807424b 100644 --- a/packages/compiler/src/backend/llvm/publish.ts +++ b/packages/compiler/src/backend/llvm/publish.ts @@ -25,6 +25,7 @@ import type { IrClassDef, IrRecordShape, IrType, IrUnionDef, SrcLoc } from "../. import { mapOf, STRING, typeKey } from "../../ir/ir.js"; import { mangleClassStruct, mangleRecordStruct } from "../mangle.js"; import { FN_ATTRS } from "./shapes.js"; +import { shapeTagFn } from "./nullable-unions.js"; import type { InlineUnionFields } from "./inline-unions.js"; import { LlvmUnsupportedError } from "./unsupported.js"; @@ -44,6 +45,10 @@ export interface PublishHost { readonly inlineUnions: InlineUnionFields; /** The nullable-pointer representation of a union, when it has one. */ nullableArm(t: IrType): IrType | null; + /** The union's values are tagged record pointers (nullable-unions.ts). */ + shapeUnion(t: IrType): boolean; + /** The struct index of a record shape's first field. */ + fieldBase(shapeId: string): number; /** Class layout: hierarchy membership, preorder interval, field slots * (with their storage types), runtime roots. */ classInfo(className: string): PublishClassInfo; @@ -210,6 +215,19 @@ export class PublishWalkers { if (def.arms.some((arm) => scalarRefusal(arm))) throw new LlvmUnsupportedError(`publish of ${typeKey(t)}`, loc); const live = arms.flatMap((a) => (a.fn === null ? [] : [{ tag: a.tag, fn: a.fn }])); + if (this.host.shapeUnion(t)) { + // The value is the record itself (or a unit encoding): no box to + // mark; the arm's walker marks and walks the record. + const lines = [head, `entry:`]; + lines.push( + ` %tag = call i32 ${shapeTagFn(t.unionId)}(ptr %o)`, + ` switch i32 %tag, label %done [ ${live.map((a) => `i32 ${a.tag}, label %arm${a.tag}`).join(" ")} ]`, + ); + for (const a of live) + lines.push(`arm${a.tag}:`, ` call void ${a.fn}(ptr %o, ptr %ctx)`, ` br label %done`); + lines.push(`done:`, ` ret void`, `}`); + return lines; + } const lines = [ head, `entry:`, @@ -240,17 +258,18 @@ export class PublishWalkers { const shape = this.host.recordsById.get(t.shapeId); if (!shape) throw new LlvmUnsupportedError(`publish of an unknown record ${t.shapeId}`, loc); + const base = this.host.fieldBase(shape.id); const members = [ ...shape.fields.flatMap((f, i) => this.host.inlineUnions.record(f.type) ? [] - : [{ name: f.name, index: i + 1, type: f.type }], + : [{ name: f.name, index: i + base, type: f.type }], ), ...(shape.indexValue ? [ { name: "[key: string]", - index: shape.fields.length + 1, + index: shape.fields.length + base, type: mapOf(STRING, shape.indexValue), }, ] diff --git a/packages/compiler/src/backend/llvm/regions.ts b/packages/compiler/src/backend/llvm/regions.ts index 41f67c0cb..b789c644d 100644 --- a/packages/compiler/src/backend/llvm/regions.ts +++ b/packages/compiler/src/backend/llvm/regions.ts @@ -101,8 +101,8 @@ export class LifetimeRegions { /** Can a value of type `t` hold (or own something that holds) a * reference to a ProgramLifetime instance the walk can explain? */ private reaches(t: IrType): boolean { - const arm = this.host.nullableUnions.of(t)?.arm; - if (arm !== undefined) return this.reaches(arm); + const nullable = this.host.nullableUnions.of(t); + if (nullable?.repr === "single") return this.reaches(nullable.arm); switch (t.kind) { case "object": return this.isLifetime(t.className) || this.reach.get(`object:${t.className}`) === true; @@ -287,7 +287,8 @@ export class LifetimeRegions { * ProgramLifetime instance). */ private reportLines(struct: string, f: Field, i: number): string[] { if (!isRefCounted(f.type) || !this.reaches(f.type)) return []; - const arm = this.host.nullableUnions.of(f.type)?.arm ?? f.type; + const nullable = this.host.nullableUnions.of(f.type); + const arm = nullable?.repr === "single" ? nullable.arm : f.type; const load = [ ` %f${i} = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${f.index}`, ` %v${i} = load ptr, ptr %f${i}`, @@ -411,7 +412,7 @@ export class LifetimeRegions { ...this.reportBody( `define internal void ${walk}(ptr %o, ptr %w) ${FN_ATTRS} { ; region walk record ${shape.id}`, mangleRecordStruct(shape.id), - rcMembers(shape, this.host.inlineUnions), + rcMembers(shape, this.host.inlineUnions, this.host.nullableUnions.fieldBase(shape.id)), ), ); rows.push(`{ ptr, ptr } { ptr @${mangleRecordRelease(shape.id)}, ptr ${walk} }`); diff --git a/packages/compiler/src/backend/llvm/shapes.ts b/packages/compiler/src/backend/llvm/shapes.ts index 23565eff4..162b36425 100644 --- a/packages/compiler/src/backend/llvm/shapes.ts +++ b/packages/compiler/src/backend/llvm/shapes.ts @@ -31,7 +31,16 @@ import { import { cycTypeDescriptor, emitObjectAlloc, emitObjectFree } from "./alloc.js"; import type { BlockBuilder } from "./blocks.js"; import { SCR_ARR_FIELD, llvmCommentText } from "./common.js"; -import type { NullableUnions } from "./nullable-unions.js"; +import { + NULLABLE_NULL, + SHAPE_WORD_INDEX, + shapeReleaseFn, + shapeTagFn, + shapeTraceFn, + shapeWordHeader, + type NullableUnions, + type ShapeUnion, +} from "./nullable-unions.js"; import { INLINE_UNION_FIELD, loadInlineUnion, @@ -129,6 +138,7 @@ export { computeTraced } from "../cycle-analysis.js"; * `_v`-shaped. */ export function vAdapters(host: ShapeHost, t: IrType): { retain: string; release: string } { const nullable = host.nullableUnions.of(t); + if (nullable?.repr === "shapes") return shapeUnionRc(nullable); if (nullable) { const arm = vAdapters(host, nullable.arm); return { retain: nullableRetainSym(host, nullable.arm), release: arm.release }; @@ -184,6 +194,7 @@ export function vAdapters(host: ShapeHost, t: IrType): { retain: string; release * Families with a mirrored fast path call the inline helper instead. */ export function retainSym(host: ShapeHost, t: IrType): string { const nullable = host.nullableUnions.of(t); + if (nullable?.repr === "shapes") return shapeUnionRc(nullable).retain; if (nullable) return nullableRetainSym(host, nullable.arm); const stem = runtimeRcStem(t); if (host.rcHelpers !== null && stem !== null && inlineRcFamily(host, stem, "retain") !== null) { @@ -195,6 +206,99 @@ export function retainSym(host: ShapeHost, t: IrType): string { return vAdapters(host, t).retain; } +/** A shape union's RC entry points: every record retain is the same + * NULL- and immortal-skipping increment (the null sentinel is immortal), + * so the first arm's serves; release dispatches on the arm. */ +function shapeUnionRc(union: ShapeUnion): { retain: string; release: string } { + return { + retain: `@${mangleRecordRetain(union.arms[0]!.shapeId)}`, + release: shapeReleaseFn(union.unionId), + }; +} + +/** The tag, release and trace helpers of every shape union + * (nullable-unions.ts). The tag helper maps a value to its arm: NULL and + * the null sentinel are the unit arms, anything else a tagged record whose + * shape word names its arm (the switch folds to a lookup table). */ +export function emitShapeUnionHelpers(host: ShapeHost): string[] { + const out: string[] = []; + const S = host.sizeType; + for (const union of host.nullableUnions.allShapeUnions()) { + const header = shapeWordHeader(S); + const tagFn = shapeTagFn(union.unionId); + const cases = union.arms + .map((arm) => `i32 ${host.nullableUnions.shapeNumber(arm.shapeId)}, label %a${arm.tag}`) + .join(" "); + out.push( + `define internal i32 ${tagFn}(ptr %u) alwaysinline ${FN_ATTRS} { ; shape union tag`, + `entry:`, + ` %isnull = icmp eq ptr %u, null`, + ` br i1 %isnull, label %unit, label %ref`, + `unit:`, + ` ret i32 ${union.unitTag}`, + `ref:`, + ); + if (union.nullTag >= 0) + out.push( + ` %isnullarm = icmp eq ptr %u, ${NULLABLE_NULL}`, + ` br i1 %isnullarm, label %nullarm, label %rec`, + `nullarm:`, + ` ret i32 ${union.nullTag}`, + `rec:`, + ); + out.push( + ` %wp = getelementptr inbounds ${header}, ptr %u, i32 0, i32 ${SHAPE_WORD_INDEX}`, + ` %w = load i32, ptr %wp`, + ` switch i32 %w, label %bad [ ${cases} ]`, + ...union.arms.flatMap((arm) => [`a${arm.tag}:`, ` ret i32 ${arm.tag}`]), + `bad:`, + ` ret i32 -1`, + `}`, + ``, + ); + // release: unit encodings are NULL or immortal; each arm releases + // through its own (NULL- and immortal-tolerant) helper. + out.push( + `define internal void ${shapeReleaseFn(union.unionId)}(ptr %u) ${FN_ATTRS} { ; shape union release`, + `entry:`, + ` %t = call i32 ${tagFn}(ptr %u)`, + ` switch i32 %t, label %done [ ${union.arms.map((arm) => `i32 ${arm.tag}, label %a${arm.tag}`).join(" ")} ]`, + ...union.arms.flatMap((arm) => [ + `a${arm.tag}:`, + ` call void @${mangleRecordRelease(arm.shapeId)}(ptr %u)`, + ` br label %done`, + ]), + `done:`, + ` ret void`, + `}`, + ``, + ); + if (shapeUnionTraced(host, union)) + out.push( + `define internal void ${shapeTraceFn(union.unionId)}(ptr %u, ptr %visit, ptr %ctx) ${FN_ATTRS} { ; shape union trace`, + `entry:`, + ` %t = call i32 ${tagFn}(ptr %u)`, + ` switch i32 %t, label %done [ ${union.arms.map((arm) => `i32 ${arm.tag}, label %a${arm.tag}`).join(" ")} ]`, + ...union.arms.flatMap((arm) => [ + `a${arm.tag}:`, + ` call void @${mangleRecordTrace(arm.shapeId)}(ptr %u, ptr %visit, ptr %ctx)`, + ` br label %done`, + ]), + `done:`, + ` ret void`, + `}`, + ``, + ); + } + return out; +} + +/** A shape union's arms carry collector headers (all or none: the emitter + * traces every arm of a union with one traced arm). */ +function shapeUnionTraced(host: ShapeHost, union: ShapeUnion): boolean { + return union.arms.some((arm) => host.tracedShapes.has(`record:${arm.shapeId}`)); +} + /** The retain entry point of a nullable union's value: the arm's own when * it tolerates NULL (emitted class and record helpers), otherwise a * NULL-skipping wrapper around it (the null sentinel and literals are @@ -233,6 +337,7 @@ export function emitNullableRetainWrappers(host: ShapeHost): string[] { * Families with a mirrored fast path call the inline helper instead. */ export function releaseSym(host: ShapeHost, t: IrType): string { const nullable = host.nullableUnions.of(t); + if (nullable?.repr === "shapes") return shapeUnionRc(nullable).release; if (nullable) return releaseSym(host, nullable.arm); const stem = runtimeRcStem(t); if (host.rcHelpers !== null && stem !== null && inlineRcFamily(host, stem, "release") !== null) { @@ -643,6 +748,8 @@ export function traceAdapter(host: ShapeHost, t: IrType): string | null { return "@scr_promise_trace_v"; case "union": { const nullable = host.nullableUnions.get(t.unionId); + if (nullable?.repr === "shapes") + return shapeUnionTraced(host, nullable) ? shapeTraceFn(nullable.unionId) : null; if (nullable) return traceAdapter(host, nullable.arm); if (!host.tracedUnions.has(t.unionId)) return null; host.declare(`declare void @scr_union_trace_v(ptr, ptr, ptr)`); @@ -945,15 +1052,17 @@ export function mapValKindNum(value: IrType): number { export function rcMembers( shape: IrRecordShape, inline: InlineUnionFields, + /** The struct index of the first field (2 on tagged shapes). */ + base = 1, ): { index: number; type: IrType; name: string }[] { return [ ...shape.fields.flatMap((f, i) => - inline.record(f.type) ? [] : [{ index: i + 1, type: f.type, name: f.name }], + inline.record(f.type) ? [] : [{ index: i + base, type: f.type, name: f.name }], ), ...(shape.indexValue ? [ { - index: shape.fields.length + 1, + index: shape.fields.length + base, type: mapOf(STRING, shape.indexValue), name: "[key: string] overflow", }, @@ -1107,7 +1216,12 @@ export function directDestroyTarget( } function directDestroyKey(host: ShapeHost, type: IrType): string | null { - const t = host.nullableUnions.of(type)?.arm ?? type; + const nullable = host.nullableUnions.of(type); + let t = type; + if (nullable !== null) { + if (nullable.repr === "shapes") return null; + t = nullable.arm; + } if (t.kind === "record") return `record:${t.shapeId}`; return t.kind === "object" ? `object:${t.className}` : null; } @@ -1338,8 +1452,12 @@ export function emitRecordShapes( for (const shape of records) { const struct = mangleRecordStruct(shape.id); - const fieldTys = shape.fields.map((f) => llFieldType(f.type, host.inlineUnions.record(f.type))); + const fieldTys: string[] = shape.fields.map((f) => + llFieldType(f.type, host.inlineUnions.record(f.type)), + ); if (shape.indexValue) fieldTys.push("ptr"); // the overflow ScrMap * + // A tagged shape (an arm of a shape union) carries its shape number. + if (host.nullableUnions.shapeNumber(shape.id) !== 0) fieldTys.unshift("i32"); typeDefs.push( `%${struct} = type { ${host.sizeType}${fieldTys.length ? ", " + fieldTys.join(", ") : ""} } ` + `; record ${shape.id} { ${shape.fields.map((f) => llvmCommentText(f.name)).join("; ")}${shape.indexValue ? "; [key: string]" : ""} }`, @@ -1352,7 +1470,7 @@ export function emitRecordShapes( const candidates: [string, DirectDestroy][] = []; const memberTypes: IrType[] = []; for (const shape of records) { - const members = rcMembers(shape, host.inlineUnions); + const members = rcMembers(shape, host.inlineUnions, host.nullableUnions.fieldBase(shape.id)); for (const m of members) memberTypes.push(m.type); if (!members.some((m) => isRefCounted(m.type) && needsBoundedRelease(m.type))) continue; const release = mangleRecordRelease(shape.id); @@ -1370,7 +1488,9 @@ export function emitRecordShapes( for (const shape of records) { const struct = mangleRecordStruct(shape.id); const traced = host.tracedShapes.has(`record:${shape.id}`); - const members = rcMembers(shape, host.inlineUnions); + const base = host.nullableUnions.fieldBase(shape.id); + const shapeNumber = host.nullableUnions.shapeNumber(shape.id); + const members = rcMembers(shape, host.inlineUnions, base); const refMembers = members.filter((m) => isRefCounted(m.type)); const sizeOf = `ptrtoint (ptr getelementptr (%${struct}, ptr null, i32 1) to ${host.sizeType})`; @@ -1439,6 +1559,11 @@ export function emitRecordShapes( ); nw.push(...emitObjectAlloc(host, sizeOf, traced ? { type: cycType } : null)); nw.push(` store ${host.sizeType} 1, ptr %o`); + if (shapeNumber !== 0) + nw.push( + ` %shp = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${SHAPE_WORD_INDEX}`, + ` store i32 ${shapeNumber}, ptr %shp ; shape number`, + ); if (shape.indexValue) { // The overflow map (string-keyed): value handling is type-directed // exactly like shapes.ts's overflowNewC. @@ -1449,7 +1574,7 @@ export function emitRecordShapes( const trace = valKind === 2 ? traceArg(host, v) : "null"; nw.push( ` %ovf = call ptr @scr_map_new(i32 1, i32 ${valKind}, ptr ${host.mapOps(["null", "null", "null", rc.retain, rc.release, trace, "null"])})`, - ` %ovfp = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${shape.fields.length + 1}`, + ` %ovfp = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${shape.fields.length + base}`, ` store ptr %ovf, ptr %ovfp`, ); } @@ -1465,7 +1590,7 @@ export function emitRecordShapes( ]; let i = 0; for (const field of shape.fields) { - const index = i + 1; + const index = i + base; const inline = host.inlineUnions.record(field.type); const fieldTy = llFieldType(field.type, inline); clone.push( diff --git a/packages/compiler/src/backend/llvm/stack-objects.ts b/packages/compiler/src/backend/llvm/stack-objects.ts index c03c7fb44..3b9f97aae 100644 --- a/packages/compiler/src/backend/llvm/stack-objects.ts +++ b/packages/compiler/src/backend/llvm/stack-objects.ts @@ -14,6 +14,7 @@ import type { CallLifetimes } from "./call-lifetimes.js"; import { emitCallExpr, emitConstruction } from "./expr-calls.js"; import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; import { emitRecordLitFields } from "./expr-primitives.js"; +import { SHAPE_WORD_INDEX } from "./nullable-unions.js"; export type StackObjectSource = IrExpr & { kind: "recordLit" | "new" | "call" }; @@ -159,6 +160,17 @@ export function emitStackObject( } } B.line(`store ${host.sizeType} -1, ptr ${slot}`); + if (type.kind === "record") { + // A tagged shape's word names it to every shape union's tag read. + const shapeNumber = host.nullableUnions.shapeNumber(type.shapeId); + if (shapeNumber !== 0) { + const p = B.tmp(); + B.line( + `${p} = getelementptr inbounds ${struct}, ptr ${slot}, i64 0, i32 ${SHAPE_WORD_INDEX}`, + ); + B.line(`store i32 ${shapeNumber}, ptr ${p}`); + } + } if (e.kind === "call") { // The entry writes the result into the slot it receives last. emitCallExpr( diff --git a/packages/compiler/src/backend/llvm/union-repr.ts b/packages/compiler/src/backend/llvm/union-repr.ts index 415aeb851..959f9e51e 100644 --- a/packages/compiler/src/backend/llvm/union-repr.ts +++ b/packages/compiler/src/backend/llvm/union-repr.ts @@ -2,14 +2,19 @@ * helper generators (walkers, dyn). A tagged union is a `%ScrUnion` box; a * nullable union (nullable-unions.ts) is the arm pointer itself: NULL for * its NULL-encoded unit arm and, in `C | null | undefined`, the immortal - * NULLABLE_NULL sentinel for `null`. Every structural read of a union value + * NULLABLE_NULL sentinel for `null`. A shape union's value is likewise the + * record pointer; its tag comes from the record's shape word. Every structural read of a union value * goes through here. */ import type { BlockBuilder } from "./blocks.js"; -import { NULLABLE_NULL, type NullableUnion } from "./nullable-unions.js"; +import { NULLABLE_NULL, shapeTagFn, type PointerUnion } from "./nullable-unions.js"; /** The i32 tag of a union value. */ -export function emitUnionTag(B: BlockBuilder, nullable: NullableUnion | null, u: string): string { +export function emitUnionTag(B: BlockBuilder, nullable: PointerUnion | null, u: string): string { const t = B.tmp(); + if (nullable?.repr === "shapes") { + B.line(`${t} = call i32 ${shapeTagFn(nullable.unionId)}(ptr ${u})`); + return t; + } if (nullable) { const isNull = B.tmp(); B.line(`${isNull} = icmp eq ptr ${u}, null`); @@ -32,8 +37,13 @@ export function emitUnionTag(B: BlockBuilder, nullable: NullableUnion | null, u: /** i1: a nullable union value holds its reference arm (neither NULL nor * the `null` sentinel). */ -export function emitNullablePresent(B: BlockBuilder, nullable: NullableUnion, u: string): string { +export function emitNullablePresent(B: BlockBuilder, nullable: PointerUnion, u: string): string { const present = B.tmp(); + if (nullable.repr === "shapes" && nullable.unitTag < 0) { + // No unit arm: every value is a record (NULL only as a pending dummy). + B.line(`${present} = icmp ne ptr ${u}, null`); + return present; + } B.line(`${present} = icmp ne ptr ${u}, null`); if (nullable.nullTag < 0) return present; const notNullArm = B.tmp(), @@ -46,12 +56,18 @@ export function emitNullablePresent(B: BlockBuilder, nullable: NullableUnion, u: /** i1: a nullable union value holds the arm `tag` (`negated`: does not). */ export function emitNullableIsTag( B: BlockBuilder, - nullable: NullableUnion, + nullable: PointerUnion, u: string, tag: number, negated: boolean, ): string { - if (tag === nullable.refTag) { + if (nullable.repr === "shapes" && tag !== nullable.unitTag && tag !== nullable.nullTag) { + const actual = emitUnionTag(B, nullable, u), + t = B.tmp(); + B.line(`${t} = icmp ${negated ? "ne" : "eq"} i32 ${actual}, ${tag}`); + return t; + } + if (nullable.repr === "single" && tag === nullable.refTag) { const present = emitNullablePresent(B, nullable, u); if (!negated) return present; const t = B.tmp(); @@ -65,7 +81,7 @@ export function emitNullableIsTag( } /** The BORROWED payload pointer of a reference arm. */ -export function emitUnionPeek(B: BlockBuilder, nullable: NullableUnion | null, u: string): string { +export function emitUnionPeek(B: BlockBuilder, nullable: PointerUnion | null, u: string): string { if (nullable) return u; const p = B.tmp(); const t = B.tmp(); @@ -76,7 +92,9 @@ export function emitUnionPeek(B: BlockBuilder, nullable: NullableUnion | null, u /** Text-template forms for helpers written as raw LLVM lines: `%out` * receives the tag / payload of `u`. */ -export function unionTagLines(nullable: NullableUnion | null, u: string, out: string): string[] { +export function unionTagLines(nullable: PointerUnion | null, u: string, out: string): string[] { + if (nullable?.repr === "shapes") + return [` ${out} = call i32 ${shapeTagFn(nullable.unionId)}(ptr ${u})`]; if (nullable && nullable.nullTag < 0) return [ ` ${out}.isnull = icmp eq ptr ${u}, null`, @@ -95,7 +113,7 @@ export function unionTagLines(nullable: NullableUnion | null, u: string, out: st ]; } -export function unionPeekLines(nullable: NullableUnion | null, u: string, out: string): string[] { +export function unionPeekLines(nullable: PointerUnion | null, u: string, out: string): string[] { // A plain copy of the pointer (NULL included) under the template's name. if (nullable) return [` ${out} = getelementptr i8, ptr ${u}, i64 0`]; return [ diff --git a/packages/compiler/src/backend/llvm/union-retype.test.ts b/packages/compiler/src/backend/llvm/union-retype.test.ts index eca6adcd6..0f0abdb68 100644 --- a/packages/compiler/src/backend/llvm/union-retype.test.ts +++ b/packages/compiler/src/backend/llvm/union-retype.test.ts @@ -183,7 +183,9 @@ test("a nullable-pointer source rebuilds the target box", () => { expect(retag).not.toContain("retype.share"); }); -async function llvmFor(source: string): Promise<{ module: IrModule; ir: string }> { +/** `boxed`: keep every union a tagged box (record unions otherwise become + * shape unions, which retype without any box). */ +async function llvmFor(source: string, boxed = true): Promise<{ module: IrModule; ir: string }> { const dir = await mkdtemp(join(tmpdir(), "scriptc-union-retype-")); try { const entry = join(dir, "main.ts"), @@ -194,7 +196,7 @@ async function llvmFor(source: string): Promise<{ module: IrModule; ir: string } throw new Error(result.diagnostics.map((item) => `${item.code}: ${item.message}`).join("\n")); const module = deserializeModule(await readFile(output, "utf8")); expect(validateModule(module)).toEqual([]); - return { module, ir: emitLlvmModule(module) }; + return { module, ir: emitLlvmModule(boxed ? keepUnionsBoxed(module) : module) }; } finally { await rm(dir, { recursive: true, force: true }); } @@ -253,3 +255,16 @@ console.log(leafValue(parsed)); expect(stored).not.toBeNull(); expect(ir).toContain(`load i8, ptr ${stored![1]}`); }); + +test("record unions retype as the record pointer itself", async () => { + const { module, ir } = await llvmFor(VISITOR, false); + const helpers = module.functions.filter((fn) => fn.name.startsWith("%union.retag.")); + expect(helpers.length).toBeGreaterThan(0); + for (const helper of helpers) { + const symbol = `sc_bf__x25_union_retag_${helper.name.slice("%union.retag.".length)}`; + const retag = body(ir, symbol); + expect(retag).not.toMatch(/@scr_union_new|retype\.share|sc_retype_guard/); + } + // No record of the visitor is ever boxed. + expect(ir).not.toMatch(/call ptr @scr_union_new_ref/); +}); diff --git a/packages/compiler/src/backend/llvm/walkers.ts b/packages/compiler/src/backend/llvm/walkers.ts index e75e1679b..d0593313f 100644 --- a/packages/compiler/src/backend/llvm/walkers.ts +++ b/packages/compiler/src/backend/llvm/walkers.ts @@ -287,7 +287,8 @@ export class LlWalkers { throw new InternalCompilerError( `llvm emitter bug: jsonStringify of unknown shape ${shapeId}`, ); - const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + 1])); + const fieldBase = this.host.nullableUnions.fieldBase(shapeId); + const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + fieldBase])); if (recordMayKeepSource(shape)) this.emitRecordSourceWriter(B, shapeId); // CYCLE-CAPABLE shapes bracket the walk with the circular-detection // stack; edge labels stamp before members whose walk can re-enter — @@ -436,7 +437,8 @@ export class LlWalkers { throw new InternalCompilerError(`llvm emitter bug: field writer of unknown shape ${shapeId}`); const name = `sc_jwf_${this.recordFieldWriters.size}`; this.recordFieldWriters.set(shapeId, name); - const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + 1])); + const fieldBase = this.host.nullableUnions.fieldBase(shapeId); + const fieldIndex = new Map(shape.fields.map((f, i) => [f.name, i + fieldBase])); const byName = new Map(shape.fields.map((f) => [f.name, f])); const cyclic = traceAdapter(this.host, { kind: "record", shapeId }) !== null; const order = recordSourceFieldOrder(shape); @@ -529,7 +531,7 @@ export class LlWalkers { const ovfp = B.tmp(); const ovf = B.tmp(); B.line( - `${ovfp} = getelementptr inbounds %${mangleRecordStruct(shape.id)}, ptr %v, i64 0, i32 ${shape.fields.length + 1}`, + `${ovfp} = getelementptr inbounds %${mangleRecordStruct(shape.id)}, ptr %v, i64 0, i32 ${shape.fields.length + this.host.nullableUnions.fieldBase(shape.id)}`, ); B.line(`${ovf} = load ptr, ptr ${ovfp} ; overflow map`); host.declare(`declare ptr @scr_map_keys_js_order(ptr)`); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5930-record-union-pointers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5930-record-union-pointers.ts.json new file mode 100644 index 000000000..e6e3632f5 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5930-record-union-pointers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5930-record-union-pointers.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5931-record-union-unit-arms.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5931-record-union-unit-arms.ts.json new file mode 100644 index 000000000..53d531568 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5931-record-union-unit-arms.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5931-record-union-unit-arms.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-record-union-trees.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-record-union-trees.ts.json new file mode 100644 index 000000000..ee4281193 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-record-union-trees.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5932-record-union-trees.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5933-record-union-conversions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5933-record-union-conversions.ts.json new file mode 100644 index 000000000..a1fcec317 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5933-record-union-conversions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5933-record-union-conversions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5934-record-union-set-members.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5934-record-union-set-members.ts.json new file mode 100644 index 000000000..98b0ac1f4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5934-record-union-set-members.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5934-record-union-set-members.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5930-record-union-pointers.ts b/tests/corpus/5930-record-union-pointers.ts new file mode 100644 index 000000000..01882d730 --- /dev/null +++ b/tests/corpus/5930-record-union-pointers.ts @@ -0,0 +1,79 @@ +// Unions whose arms are all object literals (discriminated unions) hold the +// record itself: construction, narrowing, storage in arrays, maps, fields +// and closures, identity, and printing behave exactly as in Node. +type Shape = + | { kind: "circle"; r: number } + | { kind: "rect"; w: number; h: number } + | { kind: "tri"; b: number; h: number; label: string }; + +function area(s: Shape): number { + switch (s.kind) { + case "circle": + return Math.round(3.14159 * s.r * s.r); + case "rect": + return s.w * s.h; + case "tri": + return 0.5 * s.b * s.h; + } +} + +function make(i: number): Shape { + if (i % 3 === 0) return { kind: "circle", r: i }; + if (i % 3 === 1) return { kind: "rect", w: i, h: i + 1 }; + return { kind: "tri", b: i, h: 2, label: "t" + i }; +} + +const shapes: Shape[] = []; +for (let i = 0; i < 9; i++) shapes.push(make(i)); +let total = 0; +for (const s of shapes) total += area(s); +console.log("total", total); +console.log(shapes.map((s) => s.kind).join(",")); +console.log(shapes.filter((s) => s.kind === "rect").length); + +// Identity: the same record compares equal, a structurally equal one does not. +const first = shapes[0]!; +const again: Shape = shapes[0]!; +const copy: Shape = { kind: "circle", r: 0 }; +console.log(first === again, first === copy, shapes.indexOf(again), shapes.includes(copy)); + +// Mutation through one alias is visible through the union value. +const rect = { kind: "rect" as const, w: 2, h: 3 }; +const asShape: Shape = rect; +rect.w = 10; +console.log(area(asShape), asShape === rect); + +// Fields, maps and closures holding union values. +interface Holder { + current: Shape; + history: Shape[]; +} +const holder: Holder = { current: make(1), history: [] }; +for (let i = 0; i < 4; i++) { + holder.history.push(holder.current); + holder.current = make(i + 5); +} +console.log(holder.current.kind, holder.history.map(area).join(" ")); + +const byName = new Map(); +for (const s of shapes) byName.set(s.kind + area(s), s); +console.log(byName.size, byName.get("rect2")?.kind, byName.get("missing") === undefined); + +const pick = (k: Shape["kind"]): (() => Shape | undefined) => { + const found = shapes.find((s) => s.kind === k); + return () => found; +}; +const getTri = pick("tri"); +const tri = getTri(); +console.log(tri !== undefined && tri.kind === "tri" ? tri.label : "none"); + +// Printing and serialization see the plain objects. +console.log(shapes.slice(0, 3)); +console.log(JSON.stringify(shapes.slice(0, 3))); +const second = shapes[2]!; +console.log(`${String(shapes[1]!.kind)} ${"label" in second} ${"label" in shapes[1]!}`); + +// Spread copies and sorting. +const grown = shapes.map((s): Shape => (s.kind === "circle" ? { ...s, r: s.r + 1 } : s)); +grown.sort((a, b) => area(a) - area(b)); +console.log(grown.map((s) => `${s.kind}:${area(s)}`).join(" ")); diff --git a/tests/corpus/5931-record-union-unit-arms.ts b/tests/corpus/5931-record-union-unit-arms.ts new file mode 100644 index 000000000..1ade8a0a3 --- /dev/null +++ b/tests/corpus/5931-record-union-unit-arms.ts @@ -0,0 +1,67 @@ +// Record unions with undefined and null arms: NULL and the null sentinel +// encode the unit arms, optional properties keep their absent state, and +// narrowing, nullish operators and equality agree with Node. +type Ok = { ok: true; value: number }; +type Err = { ok: false; error: string }; +type Res = Ok | Err; + +function parse(text: string): Res { + const n = Number(text); + return Number.isNaN(n) ? { ok: false, error: `bad ${text}` } : { ok: true, value: n }; +} + +function lookup(table: Res[], i: number): Res | undefined { + return i < table.length ? table[i] : undefined; +} + +function maybe(i: number): Res | null | undefined { + if (i % 3 === 0) return null; + if (i % 3 === 1) return undefined; + return parse(String(i)); +} + +const table = ["1", "x", "3"].map(parse); +for (let i = 0; i < 4; i++) { + const r = lookup(table, i); + if (r === undefined) console.log(i, "missing"); + else if (r.ok) console.log(i, "value", r.value); + else console.log(i, "error", r.error); +} + +for (let i = 0; i < 6; i++) { + const m = maybe(i); + const tag = m === null ? "null" : m === undefined ? "undefined" : m.ok ? "ok" : "err"; + console.log(i, tag, m == null, m ?? "default", typeof m); +} + +// Optional properties of a record-union type. +interface Slot { + name: string; + result?: Res; + last?: Res | null; +} +const slots: Slot[] = [ + { name: "a" }, + { name: "b", result: parse("7") }, + { name: "c", result: parse("q"), last: null }, +]; +for (const s of slots) { + console.log(s.name, "result" in s, s.result?.ok, s.last === null, s.last === undefined); +} +console.log(JSON.stringify(slots)); +slots[0]!.result = table[1]; +slots[1]!.result = undefined; +console.log(slots.map((s) => (s.result === undefined ? "-" : s.result.ok ? "ok" : "err")).join("")); + +// Equality across arms and unit encodings. +const a: Res | undefined = table[0]; +const b: Res | undefined = undefined; +const c: Res | null = null; +console.log(a === table[0], a === b, b === undefined, c === null, (c as Res | null) === table[2]); + +// Unions of records reaching unknown and back. +const values: unknown[] = [table[0], table[1], undefined, null]; +for (const v of values) { + if (v === null || v === undefined) console.log("unit", v); + else console.log("object", JSON.stringify(v)); +} diff --git a/tests/corpus/5932-record-union-trees.ts b/tests/corpus/5932-record-union-trees.ts new file mode 100644 index 000000000..060cadc4b --- /dev/null +++ b/tests/corpus/5932-record-union-trees.ts @@ -0,0 +1,77 @@ +// A recursive discriminated union (an expression tree) whose leaf arm holds +// no references: every arm shares the cycle collector's header, so trees +// can be built, rewritten, shared and dropped in cycles. +type Expr = + | { kind: "num"; value: number } + | { kind: "neg"; arg: Expr } + | { kind: "add"; left: Expr; right: Expr } + | { kind: "ref"; target: { expr: Expr | null } }; + +function evaluate(e: Expr): number { + switch (e.kind) { + case "num": + return e.value; + case "neg": + return -evaluate(e.arg); + case "add": + return evaluate(e.left) + evaluate(e.right); + case "ref": + return e.target.expr === null ? 0 : evaluate(e.target.expr); + } +} + +function build(depth: number, seed: number): Expr { + if (depth === 0) return { kind: "num", value: seed % 10 }; + if (seed % 4 === 0) return { kind: "neg", arg: build(depth - 1, seed + 1) }; + return { kind: "add", left: build(depth - 1, seed * 3 + 1), right: build(depth - 1, seed + 7) }; +} + +function simplify(e: Expr): Expr { + switch (e.kind) { + case "neg": { + const inner = simplify(e.arg); + return inner.kind === "neg" ? inner.arg : inner.kind === "num" ? { kind: "num", value: -inner.value } : { kind: "neg", arg: inner }; + } + case "add": { + const l = simplify(e.left); + const r = simplify(e.right); + if (l.kind === "num" && r.kind === "num") return { kind: "num", value: l.value + r.value }; + return l === e.left && r === e.right ? e : { kind: "add", left: l, right: r }; + } + default: + return e; + } +} + +function show(e: Expr): string { + switch (e.kind) { + case "num": + return String(e.value); + case "neg": + return `-(${show(e.arg)})`; + case "add": + return `(${show(e.left)} + ${show(e.right)})`; + case "ref": + return "ref"; + } +} + +let checksum = 0; +for (let round = 0; round < 50; round++) { + const tree = build(6, round); + const simple = simplify(tree); + checksum += evaluate(tree) * 3 + evaluate(simple); + // A cycle through a record arm: the tree refers back to itself. + const target: { expr: Expr | null } = { expr: null }; + const loop: Expr = { kind: "add", left: tree, right: { kind: "ref", target } }; + target.expr = { kind: "num", value: round }; + checksum += evaluate(loop); + target.expr = loop.left; +} +console.log(checksum); +console.log(show(simplify(build(3, 5)))); +console.log(show(build(2, 4)), evaluate(build(4, 2))); + +const shared: Expr = { kind: "num", value: 4 }; +const twice: Expr = { kind: "add", left: shared, right: shared }; +console.log(evaluate(twice), twice.kind === "add" && twice.left === twice.right); diff --git a/tests/corpus/5933-record-union-conversions.ts b/tests/corpus/5933-record-union-conversions.ts new file mode 100644 index 000000000..80b411a9b --- /dev/null +++ b/tests/corpus/5933-record-union-conversions.ts @@ -0,0 +1,78 @@ +// Record unions meet other representations: widening into unions with +// string and number arms, narrowing back, `in` tests on undiscriminated +// arms, generic helpers, class fields and promises. +type Point = { x: number; y: number }; +type Named = { name: string }; +type Item = Point | Named; +type Wide = Item | string | number; + +function describe(i: Item): string { + return "x" in i ? `point(${i.x},${i.y})` : `named(${i.name})`; +} + +function widen(i: Item): Wide { + return i; +} + +function narrow(w: Wide): Item | undefined { + if (typeof w === "string" || typeof w === "number") return undefined; + return w; +} + +const items: Item[] = [{ x: 1, y: 2 }, { name: "a" }, { x: 3, y: 4 }]; +const wide: Wide[] = items.map(widen); +wide.push("text", 42); +for (const w of wide) { + const back = narrow(w); + console.log(typeof w, back === undefined ? "-" : describe(back), back !== undefined && items.includes(back)); +} + +// Generic helpers instantiate over the union. +function firstWhere(xs: T[], pred: (x: T) => boolean): T | undefined { + for (const x of xs) if (pred(x)) return x; + return undefined; +} +const named = firstWhere(items, (i) => "name" in i); +console.log(named === items[1], named !== undefined ? describe(named) : "none"); +const pair: [Item, Item] = [items[2]!, items[0]!]; +const [p0, p1] = pair; +console.log(describe(p0), describe(p1)); + +// Class fields and methods. +class Cursor { + private at: Item; + readonly seen: Item[] = []; + constructor(start: Item) { + this.at = start; + } + move(next: Item): Item { + const prev = this.at; + this.seen.push(prev); + this.at = next; + return prev; + } + get current(): Item { + return this.at; + } +} +const cursor = new Cursor(items[0]!); +for (const i of items) cursor.move(i); +console.log(describe(cursor.current), cursor.seen.map(describe).join(" ")); + +// Promises carry union payloads. +async function load(i: number): Promise { + await null; + return items[i % items.length]!; +} +async function main(): Promise { + const loaded: Item[] = []; + for (const i of [0, 1, 5]) loaded.push(await load(i)); + console.log(loaded.map(describe).join(" "), loaded[0] === items[0]); + const slow = new Promise((resolve) => setTimeout(() => resolve({ x: 9, y: 9 }), 5)); + const raced = await Promise.race([load(1), slow]); + console.log(describe(raced)); + const pending: Promise[] = [load(2), load(0)]; + const all = await Promise.all(pending); + console.log(all.map(describe).join(" "), all[1] === items[0]); +} +main().then(() => console.log("done")); diff --git a/tests/corpus/5934-record-union-set-members.ts b/tests/corpus/5934-record-union-set-members.ts new file mode 100644 index 000000000..46f838870 --- /dev/null +++ b/tests/corpus/5934-record-union-set-members.ts @@ -0,0 +1,25 @@ +// A record union used as Set elements and Map keys keeps the runtime's +// tagged representation; other unions over the same records convert to and +// from it without changing identity semantics. +type Point = { x: number; y: number }; +type Named = { name: string }; +type Item = Point | Named; + +const items: Item[] = [{ x: 1, y: 2 }, { name: "a" }, { x: 3, y: 4 }]; +const marked = new Set(); +marked.add(items[0]!); +marked.add(items[0]!); +marked.add({ x: 1, y: 2 }); +console.log(marked.size, marked.has(items[0]!), marked.has(items[1]!)); + +const counts = new Map(); +for (const i of [...items, items[0]!, items[2]!]) counts.set(i, (counts.get(i) ?? 0) + 1); +console.log([...counts.values()].join(",")); + +function maybeItem(i: number): Item | undefined { + return i < items.length ? items[i] : undefined; +} +for (let i = 0; i < 4; i++) { + const m = maybeItem(i); + console.log(i, m === undefined ? "none" : "x" in m ? m.x : m.name, m !== undefined && marked.has(m)); +} From d7623938c0f30b0e9b90df59f06755cf208c4f8b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 16:03:33 -0500 Subject: [PATCH 010/117] Keep declared methods of generic class instances after a computed-key write When a write with a computed string key can replace any method, calls of every method name read the receiver's property bag without checking for the key, and the bag falls back to the class's prototype data. Generic class instantiations, mixin classes and their subclasses have no prototype data, so their methods read as undefined and calls threw "x.status is not a function". Reads on these classes now check for an own property and otherwise use the declared method. Fixes #963 Co-authored-by: Quim T. <26749475+espetro@users.noreply.github.com> --- .../src/frontend/lowering/class-callbacks.ts | 24 +++-- .../lowering/class-dynamic-dispatch.ts | 16 ++-- .../src/frontend/lowering/class-prototypes.ts | 18 ++++ ...932-generic-class-observed-methods.ts.json | 6 ++ .../5932-generic-class-observed-methods.ts | 93 +++++++++++++++++++ 5 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-generic-class-observed-methods.ts.json create mode 100644 tests/corpus/5932-generic-class-observed-methods.ts diff --git a/packages/compiler/src/frontend/lowering/class-callbacks.ts b/packages/compiler/src/frontend/lowering/class-callbacks.ts index da40f361b..15e24f4a0 100644 --- a/packages/compiler/src/frontend/lowering/class-callbacks.ts +++ b/packages/compiler/src/frontend/lowering/class-callbacks.ts @@ -14,7 +14,7 @@ import { isJsSourceFile, locOf } from "../program.js"; import type { Lowerer } from "./lowerer.js"; import { findMethodOn, type ClassInfo } from "./lower-classes.js"; import { classPropertiesHelper } from "./class-dynamic-dispatch.js"; -import { classPrototypeData } from "./class-prototypes.js"; +import { observedPrototypeMethod } from "./class-prototypes.js"; import { checkedIterableSpread } from "./checked-iterable-spread.js"; import { tryLowerExpression } from "./expressions/try-lower-expression.js"; @@ -43,6 +43,16 @@ export function isClassCallback(lowerer: Lowerer, info: ClassInfo, name: string) ); } +/** The census marked `name` and the receiver's class keeps the method in + * its prototype data, so the property bag answers every read. */ +function observedSlot(lowerer: Lowerer, receiver: IrExpr, name: string, loc: SrcLoc): boolean { + const info = + receiver.type.kind === "object" ? lowerer.classes.get(receiver.type.className) : undefined; + return info + ? observedPrototypeMethod(lowerer, info, name, loc) + : lowerer.prototypeMethodAccesses.has(name); +} + function callbackBag( lowerer: Lowerer, receiver: IrExpr, @@ -50,9 +60,8 @@ function callbackBag( name: string, readOnly = false, ): IrExpr { - const info = - receiver.type.kind === "object" ? lowerer.classes.get(receiver.type.className) : null; - if (info && lowerer.prototypeMethodAccesses.has(name)) classPrototypeData(lowerer, info, loc); + // Builds the prototype data that an observed read falls back to. + observedSlot(lowerer, receiver, name, loc); return { kind: "call", callee: classPropertiesHelper(lowerer, loc, readOnly).name, @@ -116,7 +125,7 @@ export function classCallbackValue( const bag = lowerer.declareHiddenLocal("%callbackBag", DYN); const value = varRef(bag.id, DYN, loc); const key: IrExpr = { kind: "strLit", value: name, type: STRING, loc }; - const result: IrExpr = lowerer.prototypeMethodAccesses.has(name) + const result: IrExpr = observedSlot(lowerer, receiver, name, loc) ? { kind: "dynKeyGet", value, key, type: DYN, loc } : { kind: "ternary", @@ -173,7 +182,8 @@ export function classCallbackCall( type: DYN, loc, }; - const result: IrExpr = lowerer.prototypeMethodAccesses.has(name) + const observed = observedSlot(lowerer, receiver, name, loc); + const result: IrExpr = observed ? call : { kind: "ternary", @@ -206,7 +216,7 @@ export function classCallbackCall( { kind: "varDecl", localId: present.id, - init: lowerer.prototypeMethodAccesses.has(name) + init: observed ? { kind: "boolLit", value: true, type: BOOL, loc } : callbackPresent(value, key, loc), loc, diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index c9d7a4d82..e6038a9c6 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -40,6 +40,7 @@ import { import { classPrototypeData, hasClassPrototypeData, + observedPrototypeMethod, reflectClassPrototype, } from "./class-prototypes.js"; import { @@ -2417,8 +2418,12 @@ export class ClassDynamicDispatch { const value = varRef("p.0", DYN, loc); const { receiver, condition } = this.propertyReceiver(plan, loc); if (isClassCallback(lowerer, info, dispatch.source.method)) { - const prototypeMethod = lowerer.prototypeMethodAccesses.has(dispatch.source.method); - if (prototypeMethod) classPrototypeData(lowerer, info, loc); + const prototypeMethod = observedPrototypeMethod( + lowerer, + info, + dispatch.source.method, + loc, + ); const bag = this.readPropertyBagOrEmpty(lowerer, value, loc); dispatch.callback.body.unshift({ kind: "if", @@ -2724,7 +2729,8 @@ export class ClassDynamicDispatch { return dispatch.reflect ? this.reflectPropertyBody(lowerer, { ...dispatch, name }, info, receiver) : this.propertyBody(lowerer, { ...dispatch, name }, info, receiver); - const prototypeMethod = lowerer.prototypeMethodAccesses.has(name); + const prototypeMethod = + !info.fields.has(name) && observedPrototypeMethod(lowerer, info, name, loc, receiver); if (info.fields.has(name) || (dispatch.probe === "in" && !prototypeMethod)) { if (info.fields.has(name) && info.def.tracksOwnFields) { const bag = this.readPropertyBagOrEmpty( @@ -2757,7 +2763,6 @@ export class ClassDynamicDispatch { { kind: "return", value: { kind: "boolLit", value: true, type: BOOL, loc }, loc }, ]; } - if (prototypeMethod) classPrototypeData(lowerer, info, loc, receiver); const bag = this.readPropertyBagOrEmpty( lowerer, lowerer.coerceToExpected(receiver, DYN), @@ -4248,8 +4253,7 @@ export class ClassDynamicDispatch { const body: IrStmt[] = []; const symbol = symbolMemberKey(lowerer, info, name, loc); if (symbol || (isClassOwnEnumerableFieldName(name) && !name.startsWith("sym:"))) { - const prototypeMethod = lowerer.prototypeMethodAccesses.has(name); - if (prototypeMethod) classPrototypeData(lowerer, info, loc, receiver); + const prototypeMethod = observedPrototypeMethod(lowerer, info, name, loc, receiver); // Selecting the method must not give the object own storage. const bag = this.readPropertyBag(lowerer, receiver, loc); const key: IrExpr = symbol ?? { kind: "strLit", value: name, type: STRING, loc }; diff --git a/packages/compiler/src/frontend/lowering/class-prototypes.ts b/packages/compiler/src/frontend/lowering/class-prototypes.ts index 77f7cb541..f5280aaea 100644 --- a/packages/compiler/src/frontend/lowering/class-prototypes.ts +++ b/packages/compiler/src/frontend/lowering/class-prototypes.ts @@ -229,6 +229,24 @@ export function classPrototypeData( return { kind: "call", callee: info.def.prototypeDataHelper, args: [], type: DYN, loc }; } +/** Whether reads of method `name` on instances of `info` use the observed + * prototype slot: the census marked the name and the class has prototype + * data that holds the method. Classes without prototype data (generic + * instantiations, mixins and their subclasses) check for an own property + * and otherwise use the declared method. */ +export function observedPrototypeMethod( + lowerer: Lowerer, + info: ClassInfo, + name: string, + loc: SrcLoc, + receiver?: IrExpr, +): boolean { + return ( + lowerer.prototypeMethodAccesses.has(name) && + (info.localClass !== undefined || classPrototypeData(lowerer, info, loc, receiver) !== null) + ); +} + export function hasClassPrototypeData(info: ClassInfo): boolean { return ( info.callableBase !== undefined || diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-generic-class-observed-methods.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-generic-class-observed-methods.ts.json new file mode 100644 index 000000000..e3a78d9d8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5932-generic-class-observed-methods.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5932-generic-class-observed-methods.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5932-generic-class-observed-methods.ts b/tests/corpus/5932-generic-class-observed-methods.ts new file mode 100644 index 000000000..0756a88ce --- /dev/null +++ b/tests/corpus/5932-generic-class-observed-methods.ts @@ -0,0 +1,93 @@ +// A write with a computed string key can replace any method, so calls of +// every method name check the receiver for an own property first. Generic +// class instances, their subclasses and mixin classes keep their declared +// methods when no own property replaces them. +class Ctx { + v: number; + constructor() { + this.v = 0; + } + json(o: T): string { + return JSON.stringify(o); + } + status(n: number): Ctx { + this.v = n; + return this; + } +} + +class Box { + value: T; + constructor(value: T) { + this.value = value; + } + get(): T { + return this.value; + } + describe(): string { + return `box(${String(this.value)})`; + } +} + +class NumberBox extends Box { + double(): number { + return this.value * 2; + } + describe(): string { + return `number ${super.describe()}`; + } +} + +class Base { + name(): string { + return "base"; + } +} + +class Tagged extends Base { + tag: T; + constructor(tag: T) { + super(); + this.tag = tag; + } + label(): string { + return `${this.name()}:${String(this.tag)}`; + } +} + +type Ctor = new (...args: any[]) => T; +function Sized(Base: B) { + return class extends Base { + size(): number { + return 3; + } + }; +} +const SizedBase = Sized(Base); + +function write(target: object, key: string, value: unknown): void { + (target as any)[key] = value; +} + +const c = new Ctx<{ ok: boolean }>(); +write(c, "other", () => 42); +console.log(typeof c.json, typeof c.status, c.status(200).json({ ok: true }), c.v); + +const a = new Box("a"); +const b = new Box(1); +const n = new NumberBox(4); +const t = new Tagged(true); +const s = new SizedBase(); +console.log(a.get(), a.describe(), b.get(), b.describe()); +console.log(n.get(), n.double(), n.describe(), t.label(), t.name(), s.size(), s.name()); +console.log(Object.prototype.hasOwnProperty.call(a, "get")); +const read = a.get; +console.log(read.call(a)); + +write(b, "describe", () => "replaced"); +write(n, "double", () => -1); +write(s, "size", () => 0); +console.log(b.describe(), a.describe(), Object.prototype.hasOwnProperty.call(b, "describe")); +console.log(n.double(), new NumberBox(3).double(), s.size(), new SizedBase().size()); +const boxes: Box[] = [b, n, new Box(7)]; +console.log(boxes.map((box) => box.describe()).join(" | ")); From 714ef5aa09f02c2b4487ea1faf60600d08aec0aa Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 14:48:38 -0700 Subject: [PATCH 011/117] Prove array lengths stable in index loops and version dense array loops Index loops over arrays left the counter a double in several common shapes, and every element access at the counter tested the array's hole-free prefix on each pass: - A syntactic proof (ir/array-length-stability.ts) shows that a loop never changes an array's length: the body runs no user code, never rebinds the array or lets it escape, and only resizes local arrays that no other binding can hold. Element writes at a counter kept below the length are accepted. - Counted loops take a stable `a.length` as their limit, and an element access at the counter makes an unversioned counted loop worthwhile, so strided (`i += 2`) and descending (`i = a.length - 1; i >= 0`) loops get an integer counter. - Array lengths bound while-loop and for-loop counters by their range, which needs no stability proof. - A loop whose array length is stable and whose indexed arrays keep their storage runs as two copies. One test before the loop (the length is at most 2^31 - 1 and at most each indexed array's `filled` bound) selects a fast copy whose element accesses at the counter skip the prefix test and whose counter is an int32. LLVM can vectorize that copy. - Loop counters whose ranges fit in 32 bits convert to double from their low half, so an inlined callee's index conversion folds away. Co-Authored-By: Claude Opus 5.5 --- .../src/backend/llvm/dense-array-access.ts | 18 +- .../backend/llvm/dense-array-loops.test.ts | 131 +++++++++ .../src/backend/llvm/dense-array-loops.ts | 218 +++++++++++++++ packages/compiler/src/backend/llvm/emitter.ts | 108 +++++++- .../src/backend/llvm/expr-containers.ts | 11 +- .../src/backend/llvm/expr-primitives.ts | 24 +- .../src/backend/llvm/integer-values.ts | 7 +- .../src/ir/array-length-stability.test.ts | 129 +++++++++ .../compiler/src/ir/array-length-stability.ts | 259 ++++++++++++++++++ .../compiler/src/ir/integer-loop-facts.ts | 29 +- .../compiler/src/ir/integer-loops.test.ts | 108 ++++++++ packages/compiler/src/ir/integer-loops.ts | 58 +++- .../compiler/src/ir/integer-ranges.test.ts | 55 +++- .../corpus/5960-array-length-loop-resizing.ts | 167 +++++++++++ .../corpus/5961-array-length-sparse-loops.ts | 133 +++++++++ .../5962-array-dense-loop-boundaries.ts | 173 ++++++++++++ 16 files changed, 1599 insertions(+), 29 deletions(-) create mode 100644 packages/compiler/src/backend/llvm/dense-array-loops.test.ts create mode 100644 packages/compiler/src/backend/llvm/dense-array-loops.ts create mode 100644 packages/compiler/src/ir/array-length-stability.test.ts create mode 100644 packages/compiler/src/ir/array-length-stability.ts create mode 100644 tests/corpus/5960-array-length-loop-resizing.ts create mode 100644 tests/corpus/5961-array-length-sparse-loops.ts create mode 100644 tests/corpus/5962-array-dense-loop-boundaries.ts diff --git a/packages/compiler/src/backend/llvm/dense-array-access.ts b/packages/compiler/src/backend/llvm/dense-array-access.ts index aeaf3e70f..cffa8ee94 100644 --- a/packages/compiler/src/backend/llvm/dense-array-access.ts +++ b/packages/compiler/src/backend/llvm/dense-array-access.ts @@ -47,7 +47,8 @@ interface DenseGuard { * then extends the length over hole states exactly the same way). An index * below the hole-free prefix bound branches to `filledLabel` first; both * that block and the returned (state-checked) dense block may use the - * guard's values. */ + * guard's values. A `proven` index is known to lie below the bound (a dense + * array loop's fast copy, dense-array-loops.ts) and always takes it. */ function emitDenseGuard( host: LlvmEmitterContext, array: string, @@ -56,6 +57,7 @@ function emitDenseGuard( slow: string, requireBelowLen: boolean, filledLabel: string, + proven = false, ): DenseGuard { const B = host.B; const size = host.sizeType; @@ -137,8 +139,10 @@ function emitDenseGuard( B.line(`${offset} = trunc i64 ${wide} to i32`); } // The bound never exceeds the length or the dense capacity. - let inFilled = B.tmp(); - B.line(`${inFilled} = icmp ult i64 ${wide}, ${filledWide}`); + // The proof covers the counter's integer value only. + const below = proven && integral === null; + let inFilled = below ? "true" : B.tmp(); + if (!below) B.line(`${inFilled} = icmp ult i64 ${wide}, ${filledWide}`); if (integral) { const t = B.tmp(); B.line(`${t} = and i1 ${integral}, ${inFilled}`); @@ -272,6 +276,7 @@ export function emitDenseArrayGet( element: IrType, getter: string, retain: boolean, + proven = false, ): string { const B = host.B; const ty = acc === "f64" ? "double" : acc === "bool" ? "i1" : "ptr"; @@ -285,7 +290,7 @@ export function emitDenseArrayGet( const slow = B.newLabel("arr.get.slow"), join = B.newLabel("arr.get.join"), valueLabel = B.newLabel("arr.get.value"); - const guard = emitDenseGuard(host, array, index, indexExpr, slow, true, valueLabel); + const guard = emitDenseGuard(host, array, index, indexExpr, slow, true, valueLabel, proven); const state = loadState(host, guard); const present = B.tmp(); B.line(`${present} = icmp eq i8 ${state}, ${SCR_ARR_VALUE}`); @@ -331,6 +336,7 @@ export function emitDenseArrayNumber( array: string, index: LlValue, indexExpr: IrExpr | undefined, + proven = false, ): string { return emitDenseArrayGet( host, @@ -341,6 +347,7 @@ export function emitDenseArrayNumber( { kind: "f64" }, "scr_arr_get_number", false, + proven, ); } @@ -399,6 +406,7 @@ export function emitDenseArraySet( acc: ArrayAccess, element: IrType, value: string, + proven = false, ): void { const B = host.B; const ty = acc === "f64" ? "double" : acc === "bool" ? "i1" : "ptr"; @@ -413,7 +421,7 @@ export function emitDenseArraySet( const slow = B.newLabel("arr.set.slow"), join = B.newLabel("arr.set.join"), filledLabel = B.newLabel("arr.set.filled"); - const guard = emitDenseGuard(host, array, index, indexExpr, slow, false, filledLabel); + const guard = emitDenseGuard(host, array, index, indexExpr, slow, false, filledLabel, proven); const { offset, len } = guard; const storeValue = (valuePtr: string): void => { if (acc === "f64") { diff --git a/packages/compiler/src/backend/llvm/dense-array-loops.test.ts b/packages/compiler/src/backend/llvm/dense-array-loops.test.ts new file mode 100644 index 000000000..d9e18d7ef --- /dev/null +++ b/packages/compiler/src/backend/llvm/dense-array-loops.test.ts @@ -0,0 +1,131 @@ +import { expect, test } from "vitest"; +import { BOOL, F64, arrayOf, type IrExpr, type IrLocal, type IrStmt } from "../../ir/ir.js"; +import { countedDenseShape, matchDenseArrayLoop, type DenseLoopShape } from "./dense-array-loops.js"; + +const loc = { file: "dense-array-loops.ts", start: 0, end: 0 }; +const ARR = arrayOf(F64); +const num = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); +const ref = (localId: string): IrExpr => ({ kind: "varRef", localId, type: F64, loc }); +const arr = (localId: string): IrExpr & { kind: "varRef" } => ({ + kind: "varRef", + localId, + type: ARR, + loc, +}); +const method = ( + receiver: string, + name: Extract["method"], + args: IrExpr[] = [], +): IrExpr => ({ kind: "arrIntrinsic", method: name, receiver: arr(receiver), args, type: F64, loc }); +const read = (receiver: string, index = ref("i")): IrExpr => + method(receiver, "getNumber", [index]); +const write = (receiver: string, value: IrExpr, index = ref("i")): IrStmt => ({ + kind: "arraySet", + arr: arr(receiver), + index, + value, + loc, +}); +const locals = new Map([ + ["i", { id: "i", name: "i", type: F64, mutable: true }], + ["a", { id: "a", name: "a", type: ARR, mutable: false }], + ["b", { id: "b", name: "b", type: ARR, mutable: true }], + ["c", { id: "c", name: "c", type: ARR, mutable: false }], +]); + +/** for (let i = 0; i < a.length; i++) body */ +function loop(body: IrStmt[]): IrStmt & { kind: "for" } { + return { + kind: "for", + loc, + init: { kind: "varDecl", localId: "i", init: num(0), loc }, + cond: { kind: "bin", op: "<", left: ref("i"), right: method("a", "length"), type: BOOL, loc }, + update: { + kind: "assign", + localId: "i", + value: { kind: "bin", op: "+", left: ref("i"), right: num(1), type: F64, loc }, + loc, + }, + body, + }; +} +const shape: DenseLoopShape = { counter: "i", length: arr("a"), range: { min: 0, max: 4294967294 } }; +const match = (body: IrStmt[], initialized = new Set(["a", "b"])) => + matchDenseArrayLoop(loop(body), shape, locals, new Set(), initialized); + +test("arrays indexed at the counter of a length-preserving loop get an int32 fast copy", () => { + const scale = write("b", { + kind: "bin", + op: "*", + left: read("a"), + right: num(2), + type: F64, + loc, + }); + const dense = match([scale]); + expect([...dense!.arrays.keys()].sort()).toEqual(["a", "b"]); + expect(dense!.range).toEqual({ min: 0, max: 2147483646 }); + // A binding not definitely assigned before the loop is not read by the guard. + expect([...match([scale], new Set())!.arrays.keys()]).toEqual(["a"]); +}); + +test("loops that may resize, rebind or move storage keep the ordinary copy only", () => { + expect(match([{ kind: "exprStmt", expr: method("a", "push", [num(1)]), loc }])).toBeNull(); + expect(match([write("a", num(0), ref("unknown"))])).toBeNull(); + expect( + match([{ kind: "exprStmt", expr: { kind: "call", callee: "f", args: [], type: F64, loc }, loc }]), + ).toBeNull(); + // A nested loop would be duplicated too. + expect(match([{ kind: "exprStmt", expr: read("a"), loc }, loop([])])).toBeNull(); + // No access at the counter: nothing to prove. + expect(match([{ kind: "exprStmt", expr: read("a", num(0)), loc }])).toBeNull(); + // Copying the bounding array into another binding lets it escape. + expect( + match([ + { kind: "exprStmt", expr: read("a"), loc }, + { kind: "assign", localId: "b", value: arr("a"), loc }, + ]), + ).toBeNull(); + // A rebound array is not covered, but the bounding array still is. + const rebound = match([ + { kind: "exprStmt", expr: read("b"), loc }, + { kind: "exprStmt", expr: read("a"), loc }, + { kind: "assign", localId: "b", value: arr("c"), loc }, + ]); + expect([...rebound!.arrays.keys()]).toEqual(["a"]); +}); + +test("counted shapes need a non-negative counter strictly below the length", () => { + const ascending = (limit: IrExpr, inclusive: boolean, min = 0) => + countedDenseShape(loop([]), { + localId: "i", + start: num(min), + limit, + step: 1, + inclusive, + range: { min, max: 100 }, + }); + const minus = (offset: number): IrExpr => ({ + kind: "bin", + op: "-", + left: method("a", "length"), + right: num(offset), + type: F64, + loc, + }); + expect(ascending(method("a", "length"), false)?.length.localId).toBe("a"); + expect(ascending(minus(1), true)?.length.localId).toBe("a"); + expect(ascending(method("a", "length"), true)).toBeNull(); + expect(ascending(minus(1), false, -1)).toBeNull(); + const descending = (offset: number) => + countedDenseShape(loop([]), { + localId: "i", + start: minus(offset), + limit: num(0), + step: -1, + inclusive: true, + range: { min: 0, max: 100 }, + }); + expect(descending(1)?.length.localId).toBe("a"); + expect(descending(0)).toBeNull(); +}); diff --git a/packages/compiler/src/backend/llvm/dense-array-loops.ts b/packages/compiler/src/backend/llvm/dense-array-loops.ts new file mode 100644 index 000000000..5009e6c82 --- /dev/null +++ b/packages/compiler/src/backend/llvm/dense-array-loops.ts @@ -0,0 +1,218 @@ +/* Dense array loops: a versioned copy of an index loop over an array whose + * length the loop never changes. + * + * `for (let i = 0; i < a.length; i++) b[i] = a[i] * 2` reads its bound from + * `a`, and every element access at the counter normally tests the index + * against the array's hole-free prefix bound (`filled`, see + * dense-array-access.ts) before it touches the slot. When the loop provably + * never changes `a.length` (ir/array-length-stability.ts) and never moves or + * cuts the storage of the arrays it indexes, one test before the loop covers + * every pass: if `a.length` is at most each indexed array's `filled` bound, + * every counter value the loop can reach (at least 0, below `a.length`) + * names a present value in dense storage. The fast copy then reads and + * replaces those slots directly, which leaves LLVM a loop without + * per-element branches (vectorizable where the body allows it). The same + * test bounds `a.length` by 2^31 - 1, so the fast copy's counter is an int32. + * Arrays longer than that are sparse in practice (a dense one would need + * 16 GB of slots) and take the ordinary copy, as does every array with a + * hole, present undefined or sparse storage below `a.length`. */ + +import type { IrExpr, IrLocal, IrStmt } from "../../ir/ir.js"; +import type { IntegerRange } from "../../ir/integer-ranges.js"; +import { preservesArrayLength } from "../../ir/array-length-stability.js"; +import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; +import type { LlvmEmitterContext } from "./expr-context.js"; +import { SCR_ARR_FIELD } from "./common.js"; + +export const INT32_MAX = 2147483647; + +export interface DenseArrayLoop { + /** The loop's counter binding. */ + counter: string; + /** The array whose length bounds the counter. */ + length: IrExpr & { kind: "varRef" }; + /** Arrays whose accesses at the counter are proven to be inside the + * hole-free prefix in the fast copy, with a read of each binding. */ + arrays: ReadonlyMap; + /** The counter's range on every pass of the fast copy. */ + range: IntegerRange; +} + +/** The fast copy duplicates the loop; keep the duplicated code small. */ +const MAX_LOOP_NODES = 120; + +/** How a matched integer loop bounds its counter below `length.length`. */ +export interface DenseLoopShape { + counter: string; + length: IrExpr & { kind: "varRef" }; + /** The counter's proven range on every pass of the ordinary loop; the + * fast copy keeps its minimum, which must be at least 0. */ + range: IntegerRange; +} + +/** `length.length - c` (c an integer literal, 0 when absent). */ +function lengthOffset(e: IrExpr): { receiver: IrExpr & { kind: "varRef" }; offset: number } | null { + let offset = 0; + if ( + e.kind === "bin" && + e.op === "-" && + e.right.kind === "numLit" && + Number.isSafeInteger(e.right.value) + ) { + offset = e.right.value; + e = e.left; + } + return e.kind === "arrIntrinsic" && + e.method === "length" && + e.args.length === 0 && + e.receiver.kind === "varRef" && + e.receiver.type.kind === "array" + ? { receiver: e.receiver, offset } + : null; +} + +/** The array bounding a counted loop's counter below its length: an + * ascending loop compared below `a.length - c`, or a descending one starting + * at `a.length - c` (c >= 1). */ +export function countedDenseShape( + loop: IrStmt & { kind: "for" }, + counted: { + localId: string; + start: IrExpr; + limit: IrExpr; + step: number; + inclusive: boolean; + range: IntegerRange; + }, +): DenseLoopShape | null { + if (counted.range.min < 0) return null; + if (counted.step > 0) { + const bound = lengthOffset(counted.limit); + if (!bound || bound.offset < (counted.inclusive ? 1 : 0)) return null; + return { counter: counted.localId, length: bound.receiver, range: counted.range }; + } + // The start is evaluated once, before the loop; the counter only falls. + const start = lengthOffset(counted.start); + if (!start || start.offset < 1 || loop.init?.kind !== "varDecl") return null; + return { counter: counted.localId, length: start.receiver, range: counted.range }; +} + +/** Match the fast copy of a loop of the given shape. `initialized` holds the + * bindings definitely assigned when the loop starts; `unaliased` the local + * arrays no other binding holds. */ +export function matchDenseArrayLoop( + loop: IrStmt & { kind: "for" }, + shape: DenseLoopShape, + locals: ReadonlyMap, + unaliased: ReadonlySet, + initialized: ReadonlySet, +): DenseArrayLoop | null { + const { counter, length } = shape; + if (shape.range.min < 0 || !loop.cond) return null; + let nodes = 0, + nested = false; + const candidates = new Map(); + // Arrays written, resized, or indexed other than at the counter by an + // element write. + const disturbed = new Set(); + const access = (arr: IrExpr, index: IrExpr): void => { + if (arr.kind === "varRef" && index.kind === "varRef" && index.localId === counter) + candidates.set(arr.localId, arr); + }; + const expr = (e: IrExpr): boolean => { + if (++nodes > MAX_LOOP_NODES) return false; + if (e.kind === "assignExpr" || e.kind === "incDec") disturbed.add(e.localId); + if (e.kind === "arrayGet") access(e.arr, e.index); + if (e.kind === "arrIntrinsic") { + if (e.method === "getNumber" && e.args[0]) access(e.receiver, e.args[0]); + else if (e.method !== "length" && e.receiver.kind === "varRef") + disturbed.add(e.receiver.localId); + } + return everyExprChild(e, expr, stmt); + }; + const stmt = (s: IrStmt): boolean => { + if (++nodes > MAX_LOOP_NODES) return false; + if (s.kind === "for" || s.kind === "while" || s.kind === "doWhile" || s.kind === "forOf") + nested = true; + if (s.kind === "assign" || s.kind === "varDecl") disturbed.add(s.localId); + if (s.kind === "arraySet") { + access(s.arr, s.index); + if ( + s.arr.kind === "varRef" && + (s.index.kind !== "varRef" || s.index.localId !== counter) + ) + disturbed.add(s.arr.localId); + } + return everyStmtChild(s, expr, stmt); + }; + if (!loop.body.every(stmt) || !expr(loop.cond) || nested) return null; + if ( + !preservesArrayLength( + [loop.cond, ...loop.body], + { receiver: length.localId, inRange: counter }, + locals, + unaliased, + ) + ) + return null; + const arrays = new Map(); + for (const [id, ref] of candidates) { + const local = locals.get(id); + if ( + !local || + local.type.kind !== "array" || + local.boxed || + local.tdz || + disturbed.has(id) || + (id !== length.localId && !initialized.has(id)) + ) + continue; + arrays.set(id, ref); + } + if (arrays.size === 0) return null; + return { + counter, + length, + arrays, + range: { min: shape.range.min, max: Math.min(shape.range.max, INT32_MAX - 1) }, + }; +} + +/** The fast copy's entry test: the bounding length is at most 2^31 - 1 and + * at most every indexed array's hole-free prefix bound. */ +export function emitDenseLoopGuard(host: LlvmEmitterContext, loop: DenseArrayLoop): string { + const B = host.B; + const size = host.sizeType; + const header = (array: string, field: number): string => { + const ptr = B.tmp(); + B.line(`${ptr} = getelementptr inbounds %ScrArr, ptr ${array}, i32 0, i32 ${field}`); + host.markMemoryPointer(ptr, "array:header"); + return ptr; + }; + const receiver = host.emitStableReceiver(loop.length, []); + const lenPtr = header(receiver.name, 1), + len = B.tmp(), + small = B.tmp(); + B.line( + `${len} = load ${size}, ptr ${lenPtr}${host.fieldAliasAttachment(lenPtr)}${host.arrayLengthRange}`, + ); + B.line(`${small} = icmp ule ${size} ${len}, ${INT32_MAX}`); + let valid = small; + for (const [id, ref] of loop.arrays) { + const array = id === loop.length.localId ? receiver : host.emitStableReceiver(ref, []); + const filledPtr = header(array.name, SCR_ARR_FIELD.filled), + filled = B.tmp(), + covered = B.tmp(), + both = B.tmp(); + B.line(`${filled} = load i32, ptr ${filledPtr}${host.fieldAliasAttachment(filledPtr)}`); + let bound = filled; + if (size === "i64") { + bound = B.tmp(); + B.line(`${bound} = zext i32 ${filled} to i64`); + } + B.line(`${covered} = icmp ule ${size} ${len}, ${bound}`); + B.line(`${both} = and i1 ${valid}, ${covered}`); + valid = both; + } + return valid; +} diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 2c3a71457..634cf8d79 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -55,6 +55,13 @@ import { matchIntegerBytesForLoop, matchIntegerCountedForLoop, } from "../../ir/integer-loops.js"; +import { findUnaliasedLocalArrays } from "../../ir/array-length-stability.js"; +import { + countedDenseShape, + emitDenseLoopGuard, + matchDenseArrayLoop, + type DenseArrayLoop, +} from "./dense-array-loops.js"; import { emitCountedLoopLimit } from "./counted-loops.js"; import { emitSafeIntegerCheck, @@ -638,6 +645,21 @@ export class LlEmitter { return this.sizeType === "i64" ? ", !range !{i64 0, i64 4294967296}" : ""; } + /** Whether an element access at `index` of `arr` lies in the hole-free + * prefix: the counter of a dense array loop's fast copy indexing one of + * the arrays its entry test covered. */ + provenDenseIndex(arr: IrExpr, index: IrExpr): boolean { + const loop = this.denseLoop; + return ( + loop !== null && + arr.kind === "varRef" && + loop.arrays.has(arr.localId) && + index.kind === "varRef" && + index.localId === loop.counter && + this.integerLoopBindings.has(loop.counter) + ); + } + fieldAliasAttachment(ptr: string): string { const tag = this.fieldPointerTags.get(ptr); return tag === undefined ? "" : `, !tbaa !${tag}`; @@ -991,6 +1013,14 @@ export class LlEmitter { * immortal from construction (classes.ts programLifetimeClass). */ readonly programLifetime: ReadonlySet; private numericLocals = new Map(); + /** Local arrays of the current function that no other binding can hold + * (ir/array-length-stability.ts). */ + private unaliasedArrays: ReadonlySet = new Set(); + /** Dense array loops (dense-array-loops.ts) run in this function. */ + private denseLoopsEnabled = false; + private denseLoopEntries: ReturnType = new Map(); + /** The fast copy of a dense array loop being emitted. */ + private denseLoop: DenseArrayLoop | null = null; private captureIds = new Set(); /** Active induction bindings retain their width independently of size_t. */ integerLoopBindings = new Map< @@ -6553,6 +6583,7 @@ export class LlEmitter { const initializerBindings = this.initializerBindings.get(fn.name) ?? []; const numericFn = withInitializerBindings(fn, initializerBindings); this.numericLocals = new Map(numericFn.locals.map((l) => [l.id, l])); + this.unaliasedArrays = findUnaliasedLocalArrays(fn); this.borrowedParameters.clear(); this.referenceWrites?.enter(fn); this.reboundOwnerSlots.clear(); @@ -6591,6 +6622,12 @@ export class LlEmitter { this.finalFieldBorrows = !fn.async && !fn.generator && constructorClass(fn.name) === null && this.finalFields.size > 0; this.byteWindowsEnabled = this.countedLoopsEnabled; + this.denseLoopsEnabled = this.countedLoopsEnabled; + this.denseLoop = null; + this.denseLoopEntries = + this.denseLoopsEnabled && numericFn.locals.some((l) => l.type.kind === "array") + ? findInitializedByteLoopBindings(fn) + : new Map(); this.byteWindowEntries = this.byteWindowsEnabled && numericFn.locals.some((l) => l.type.kind === "bytes") ? findInitializedByteLoopBindings(fn) @@ -8030,7 +8067,16 @@ export class LlEmitter { const acc = elemAccess(s.arr.type.elem); this.emitPublishedArrayGuard(arr.name, s.arr.type, 0, idx.name); if (acc === "ref") this.moveTemp(v); - emitDenseArraySet(this, arr.name, idx, s.index, acc, s.arr.type.elem, v.name); + emitDenseArraySet( + this, + arr.name, + idx, + s.index, + acc, + s.arr.type.elem, + v.name, + this.provenDenseIndex(s.arr, s.index), + ); break; } case "arraySetLength": { @@ -8447,7 +8493,12 @@ export class LlEmitter { (this.debug === null ? matchIntegerBytesForLoop(s, this.numericLocals) : null); const countedLoop = !integerLoop && this.countedLoopsEnabled - ? matchIntegerCountedForLoop(s, this.numericLocals, this.integerRanges) + ? matchIntegerCountedForLoop( + s, + this.numericLocals, + this.integerRanges, + this.unaliasedArrays, + ) : null; const window = countedLoop && this.byteWindowsEnabled @@ -8460,6 +8511,49 @@ export class LlEmitter { this.byteWindowEntries.get(s) ?? new Set(), ) : null; + const denseShape = !this.denseLoopsEnabled + ? null + : integerArrayLoop + ? { + counter: integerArrayLoop.localId, + length: integerArrayLoop.limitReceiver as IrExpr & { kind: "varRef" }, + range: { min: 0, max: 4294967294 }, + } + : countedLoop && !countedLoop.guarded + ? countedDenseShape(s, countedLoop) + : null; + const dense = + denseShape && !window + ? matchDenseArrayLoop( + s, + denseShape, + this.numericLocals, + this.unaliasedArrays, + this.denseLoopEntries.get(s) ?? new Set(), + ) + : null; + if (dense) { + const valid = emitDenseLoopGuard(this, dense); + const fast = B.newLabel("dense.loop.fast"), + slow = B.newLabel("dense.loop.slow"), + done = B.newLabel("dense.loop.done"); + B.condBr(valid, fast, slow); + this.denseLoopsEnabled = false; + try { + B.startBlock(slow); + this.emitStmt(s); + B.br(done); + B.startBlock(fast); + this.denseLoop = dense; + this.emitStmt(s); + B.br(done); + } finally { + this.denseLoop = null; + this.denseLoopsEnabled = true; + } + B.startBlock(done); + break; + } if (window) { const valid = emitByteWindowGuard(this, window); const fast = B.newLabel("bytes.window.fast"), @@ -8562,7 +8656,10 @@ export class LlEmitter { this.integerLoopBindings.set(integerLoop.localId, { slot: integerSlot, type: this.sizeType, - range: { min: 0, max: integerArrayLoop ? 4294967294 : Number.MAX_SAFE_INTEGER - 1 }, + range: + this.denseLoop?.counter === integerLoop.localId + ? this.denseLoop.range + : { min: 0, max: integerArrayLoop ? 4294967294 : Number.MAX_SAFE_INTEGER - 1 }, }); } else if (countedLoop) { integerSlot = B.slot(); @@ -8577,7 +8674,10 @@ export class LlEmitter { slot: integerSlot, type: "i64", signed: true, - range: countedLoop.range, + range: + this.denseLoop?.counter === countedLoop.localId + ? this.denseLoop.range + : countedLoop.range, }); countedLimit = emitCountedLoopLimit(this, countedLoop); } else if (s.init) { diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index a2d5fd35a..1b0f1e638 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -571,7 +571,16 @@ export function emitArrIntrinsic( ? host.constantNumericTables.get(e.receiver.localId) : undefined; if (!table && elem.kind === "f64") - return { name: emitDenseArrayNumber(host, r.name, index, e.args[0]), type: e.type }; + return { + name: emitDenseArrayNumber( + host, + r.name, + index, + e.args[0], + host.provenDenseIndex(e.receiver, e.args[0]!), + ), + type: e.type, + }; host.declare(`declare double @scr_arr_get_number(ptr, double)`); const t = B.tmp(); B.line( diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index aaae4c35c..664689e91 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -64,16 +64,25 @@ export function emitLiteralExpr( const integer = B.tmp(); const number = B.tmp(); B.line(`${integer} = load ${integerSlot.type}, ptr ${integerSlot.slot}`); - // A 64-bit induction value is a safe integer, so its sign bit is - // clear and the signed conversion is exact: one cvtsi2sd instead of - // x86-64's multi-instruction unsigned 64-bit conversion. - const signedConversion = integerSlot.signed === true || integerSlot.type === "i64"; - B.line( - `${number} = ${signedConversion ? "sitofp" : "uitofp"} ${integerSlot.type} ${integer} to double`, - ); const uint32 = integerSlot.type === "i32" ? integer : B.tmp(); if (integerSlot.type !== "i32") B.line(`${uint32} = trunc ${integerSlot.type} ${integer} to i32`); + // A counter whose range fits 32 bits converts from its low half, so + // LLVM folds a later `fptosi` of the double (an inlined callee's + // index) back to the integer. Otherwise a 64-bit induction value is + // a safe integer, so its sign bit is clear and the signed conversion + // is exact: one cvtsi2sd instead of x86-64's multi-instruction + // unsigned 64-bit conversion. + const range = integerSlot.range; + const signedConversion = integerSlot.signed === true || integerSlot.type === "i64"; + if (range && range.min >= -2147483648 && range.max <= 2147483647) + B.line(`${number} = sitofp i32 ${uint32} to double`); + else if (range && range.min >= 0 && range.max <= 4294967295) + B.line(`${number} = uitofp i32 ${uint32} to double`); + else + B.line( + `${number} = ${signedConversion ? "sitofp" : "uitofp"} ${integerSlot.type} ${integer} to double`, + ); return { name: number, type: e.type, @@ -851,6 +860,7 @@ export function emitContainerExpr( elem, `scr_arr_get_${acc}`, true, + host.provenDenseIndex(e.arr, e.index), ); return host.own({ name: t, type: e.type }); } diff --git a/packages/compiler/src/backend/llvm/integer-values.ts b/packages/compiler/src/backend/llvm/integer-values.ts index 63e279d04..53e07462e 100644 --- a/packages/compiler/src/backend/llvm/integer-values.ts +++ b/packages/compiler/src/backend/llvm/integer-values.ts @@ -93,11 +93,16 @@ export function integerNumber( // `x | 0`), while a 64-bit source is not known to convert exactly. So a // counter written `i = (i + 1) | 0` stays an integer instead of taking a // double round trip on every iteration. + // A uint32 (an array index counter) converts from its low half unsigned, + // which LLVM likewise folds back through a later `fptosi` to i64. const int32 = range.min >= -2147483648 && range.max <= 2147483647; + const unsigned = !int32 && range.min >= 0 && range.max <= 4294967295; host.B.line( int32 ? `${number} = sitofp i32 ${uint32} to double` - : `${number} = sitofp i64 ${name} to double`, + : unsigned + ? `${number} = uitofp i32 ${uint32} to double` + : `${number} = sitofp i64 ${name} to double`, ); return { name: number, type, uint32, integer: { name, type: "i64", signed: true, range } }; } diff --git a/packages/compiler/src/ir/array-length-stability.test.ts b/packages/compiler/src/ir/array-length-stability.test.ts new file mode 100644 index 000000000..87e510a3f --- /dev/null +++ b/packages/compiler/src/ir/array-length-stability.test.ts @@ -0,0 +1,129 @@ +import { expect, test } from "vitest"; +import { findUnaliasedLocalArrays, preservesArrayLength } from "./array-length-stability.js"; +import { BOOL, F64, arrayOf, type IrExpr, type IrFunction, type IrLocal, type IrStmt } from "./ir.js"; + +const loc = { file: "array-length-stability.ts", start: 0, end: 0 }; +const ARR = arrayOf(F64); +const num = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); +const ref = (localId: string): IrExpr => ({ kind: "varRef", localId, type: F64, loc }); +const arr = (localId: string): IrExpr => ({ kind: "varRef", localId, type: ARR, loc }); +const method = ( + receiver: string, + name: Extract["method"], + args: IrExpr[] = [], +): IrExpr => ({ kind: "arrIntrinsic", method: name, receiver: arr(receiver), args, type: F64, loc }); +const length = (receiver: string): IrExpr => method(receiver, "length"); +const read = (receiver: string, index: IrExpr): IrExpr => method(receiver, "getNumber", [index]); +const plus = (left: IrExpr, right: IrExpr): IrExpr => ({ + kind: "bin", + op: "+", + left, + right, + type: F64, + loc, +}); +const stmt = (expr: IrExpr): IrStmt => ({ kind: "exprStmt", expr, loc }); +const set = (receiver: string, index: IrExpr, value: IrExpr): IrStmt => ({ + kind: "arraySet", + arr: arr(receiver), + index, + value, + loc, +}); +const cond: IrExpr = { kind: "bin", op: "<", left: ref("i"), right: length("a"), type: BOOL, loc }; +const sum: IrStmt = { + kind: "assign", + localId: "s", + value: plus(ref("s"), read("a", ref("i"))), + loc, +}; +const locals = new Map([ + ["i", { id: "i", name: "i", type: F64, mutable: true }], + ["s", { id: "s", name: "s", type: F64, mutable: true }], + ["a", { id: "a", name: "a", type: ARR, mutable: false }], + ["b", { id: "b", name: "b", type: ARR, mutable: false }], + ["out", { id: "out", name: "out", type: ARR, mutable: false }], +]); +const preserves = ( + body: IrStmt[], + inRange: string | null = "i", + unaliased: ReadonlySet = new Set(), + scope = locals, +): boolean => preservesArrayLength([cond, ...body], { receiver: "a", inRange }, scope, unaliased); + +test("reads, local arithmetic and element writes at the in-range counter keep the length", () => { + expect(preserves([sum])).toBe(true); + expect(preserves([set("a", ref("i"), num(1)), set("b", ref("i"), read("a", ref("i")))])).toBe( + true, + ); + expect(preserves([stmt(method("a", "indexOf", [num(3)]))])).toBe(true); +}); + +test("writes past the counter, without an in-range counter, or to the counter can grow it", () => { + expect(preserves([set("a", plus(ref("i"), num(1)), num(1))])).toBe(false); + expect(preserves([set("b", ref("s"), num(1))])).toBe(false); + expect(preserves([set("a", ref("i"), num(1))], null)).toBe(false); + expect(preserves([{ kind: "assign", localId: "i", value: num(0), loc }, sum])).toBe(false); +}); + +test("resizing methods, length stores, calls and escapes refuse the proof", () => { + for (const name of ["push", "pop", "shift", "unshift", "splice", "fill"] as const) + expect(preserves([stmt(method("a", name, [num(1)]))])).toBe(false); + // An unrelated array may alias the receiver. + expect(preserves([stmt(method("b", "push", [num(1)]))])).toBe(false); + expect(preserves([{ kind: "arraySetLength", arr: arr("a"), length: num(0), loc }])).toBe(false); + expect(preserves([{ kind: "arrayDelete", arr: arr("a"), index: ref("i"), loc }])).toBe(false); + expect(preserves([stmt({ kind: "call", callee: "f", args: [], type: F64, loc })])).toBe(false); + expect( + preserves([stmt({ kind: "call", callee: "f", args: [arr("a")], type: F64, loc })]), + ).toBe(false); + expect(preserves([{ kind: "varDecl", localId: "b", init: arr("a"), loc }])).toBe(false); + expect(preserves([{ kind: "assign", localId: "a", value: arr("b"), loc }])).toBe(false); +}); + +test("an unaliased local array other than the receiver may grow", () => { + const push = stmt(method("out", "push", [read("a", ref("i"))])); + expect(preserves([push], "i", new Set(["out"]))).toBe(true); + expect(preserves([set("out", ref("s"), num(1))], "i", new Set(["out"]))).toBe(true); + expect(preserves([push])).toBe(false); + // The receiver itself is never resized, even when no alias exists. + expect(preserves([stmt(method("a", "push", [num(1)]))], "i", new Set(["a"]))).toBe(false); +}); + +test("captured receivers have no local proof", () => { + const boxed = new Map(locals); + boxed.set("a", { ...locals.get("a")!, boxed: true }); + expect(preserves([sum], "i", new Set(), boxed)).toBe(false); +}); + +function fn(body: IrStmt[], params: string[] = []): IrFunction { + return { + loc, + name: "f", + params: params.map((localId) => ({ localId, type: ARR })), + returnType: ARR, + locals: [...locals.values()], + body, + } as IrFunction; +} +const fresh: IrExpr = { kind: "arrayLit", elems: [], type: ARR, loc }; + +test("fresh local arrays read only as receivers have no alias", () => { + const body: IrStmt[] = [ + { kind: "varDecl", localId: "out", init: fresh, loc }, + stmt(method("out", "push", [num(1)])), + { kind: "return", value: arr("out"), loc }, + ]; + expect([...findUnaliasedLocalArrays(fn(body))]).toEqual(["out"]); + // Parameters, copies into another binding, and arguments escape. + expect(findUnaliasedLocalArrays(fn(body, ["out"])).size).toBe(0); + const copied = [...body, { kind: "varDecl", localId: "b", init: arr("out"), loc } as IrStmt]; + expect(findUnaliasedLocalArrays(fn(copied)).has("out")).toBe(false); + const passed = [ + ...body, + stmt({ kind: "call", callee: "g", args: [arr("out")], type: F64, loc }), + ]; + expect(findUnaliasedLocalArrays(fn(passed)).has("out")).toBe(false); + const rebound = [...body, { kind: "assign", localId: "out", value: arr("a"), loc } as IrStmt]; + expect(findUnaliasedLocalArrays(fn(rebound)).has("out")).toBe(false); +}); diff --git a/packages/compiler/src/ir/array-length-stability.ts b/packages/compiler/src/ir/array-length-stability.ts new file mode 100644 index 000000000..2ac196d30 --- /dev/null +++ b/packages/compiler/src/ir/array-length-stability.ts @@ -0,0 +1,259 @@ +import type { IrExpr, IrFunction, IrLocal, IrStmt } from "./ir.js"; +import { isBorrowSafeMath } from "./analysis.js"; +import { byteNumberAccess } from "./byte-numbers.js"; +import { everyExprChild, everyStmtChild } from "./traverse.js"; + +/** Array methods that read the receiver without changing its length or its + * slot states and run no user code. */ +const READING_ARRAY_METHODS = new Set([ + "length", + "getNumber", + "indexEq", + "indexOf", + "includes", + "nextPresent", +]); + +/** String methods that read an immutable string and run no user code. */ +const READING_STRING_METHODS = new Set(["length", "charCodeAt", "codePointAt"]); + +/** Expressions that compute from their operands and run no user code. Their + * children are checked separately. */ +const PLAIN_EXPRESSIONS = new Set([ + "numLit", + "strLit", + "boolLit", + "unitLit", + "varRef", + "bin", + "unary", + "incDec", + "toBool", + "logical", + "ternary", + "strEq", + "strCmp", + "fieldGet", + "recordGet", + "unionNarrow", + "unionIsTag", + "unionDisc", + "unionWrap", + "upcast", + "downcast", + "instanceOf", + "nullish", + "seqExpr", +]); + +/** Statements whose own effect is a local write or control flow inside the + * loop. Their children are checked separately. */ +const PLAIN_STATEMENTS = new Set([ + "varDecl", + "assign", + "exprStmt", + "if", + "block", + "break", + "continue", + "for", + "while", + "doWhile", +]); + +/** Array methods whose result is never the receiver itself (unlike + * `reverse`, `fill` or `copyWithin`, which return it). */ +const CONTAINED_RECEIVER_METHODS = new Set([ + ...READING_ARRAY_METHODS, + "push", + "pop", + "shift", + "unshift", + "splice", + "join", + "slice", +]); + +/** Local arrays that no other binding can hold: every write of the local + * stores a fresh array literal and every read of it is the receiver of an + * element access or array method (or the value of a `return`, which ends the + * activation). No alias of such an array exists, so mutating it cannot change + * the length of an array held by any other binding. */ +export function findUnaliasedLocalArrays(fn: IrFunction): ReadonlySet { + const candidates = new Set(); + const captured = new Set( + [...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId), + ); + for (const local of fn.locals) + if (local.type.kind === "array" && !local.boxed && !local.tdz && !captured.has(local.id)) + candidates.add(local.id); + for (const param of fn.params) candidates.delete(param.localId); + const written = new Set(); + const fresh = (value: IrExpr | null): boolean => + value !== null && (value.kind === "arrayLit" || value.kind === "arrayNewLen"); + const receiver = (e: IrExpr): void => { + if (e.kind !== "varRef") expr(e); + }; + const expr = (e: IrExpr): boolean => { + switch (e.kind) { + case "varRef": + candidates.delete(e.localId); + return true; + case "assignExpr": + candidates.delete(e.localId); + break; + case "arrIntrinsic": + if (!CONTAINED_RECEIVER_METHODS.has(e.method)) break; + receiver(e.receiver); + e.args.forEach(expr); + return true; + case "arrayGet": + case "arrayHas": + case "arrayState": + receiver(e.arr); + expr(e.index); + return true; + } + return everyExprChild(e, expr, stmt); + }; + const stmt = (s: IrStmt): boolean => { + switch (s.kind) { + case "varDecl": + case "assign": { + const value = s.kind === "varDecl" ? s.init : s.value; + if (fresh(value)) written.add(s.localId); + else if (value) candidates.delete(s.localId); + if (value) expr(value); + return true; + } + case "arraySet": + receiver(s.arr); + expr(s.index); + expr(s.value); + return true; + case "return": + if (s.value) receiver(s.value); + return true; + case "forOf": + case "tryCatch": + if (s.kind === "forOf") candidates.delete(s.localId); + if (s.kind === "tryCatch" && s.catchLocalId) candidates.delete(s.catchLocalId); + break; + } + return everyStmtChild(s, expr, stmt); + }; + fn.body.every(stmt); + // A binding with no visible write takes its value some other way. + for (const id of candidates) if (!written.has(id)) candidates.delete(id); + return candidates; +} + +export interface ArrayLengthLoop { + /** The local holding the array whose length must not change. */ + receiver: string; + /** A binding that holds a value below the array's length wherever the + * loop's condition, body or update reads it (the induction variable of + * `for (let i = 0; i < a.length; i++)` when the body never writes it, as + * long as the length itself has not changed). An element write at this + * index replaces an existing element or sets a non-index property. */ + inRange: string | null; +} + +/** Whether running `nodes` (a loop's condition, body and update) can never + * change the length of the array held by local `loop.receiver`. The proof is + * syntactic and conservative: every expression and statement must be one + * that runs no user code (no calls, callbacks, closures, iterators, + * suspension or exception regions); the binding is never written and only + * ever read as the receiver of an element access or a reading array method, + * so the array cannot escape to code that resizes it; and nothing in the + * nodes resizes any array that may be the same one. Element writes are + * accepted at the in-range binding (no array grows by them: an alias of the + * receiver has the same length) and anywhere in an unaliased local array. + * Array methods that resize an array are accepted only on unaliased local + * arrays other than the receiver. */ +export function preservesArrayLength( + nodes: readonly (IrExpr | IrStmt)[], + loop: ArrayLengthLoop, + locals: ReadonlyMap, + unaliased: ReadonlySet, +): boolean { + const local = locals.get(loop.receiver); + if (!local || local.type.kind !== "array" || local.boxed || local.tdz) return false; + const separate = (e: IrExpr): boolean => + e.kind === "varRef" && e.localId !== loop.receiver && unaliased.has(e.localId); + // A receiver position: the receiver binding itself is read there without + // escaping. + const receiver = (e: IrExpr): boolean => + (e.kind === "varRef" && e.localId === loop.receiver) || expr(e); + const written = (id: string): boolean => id === loop.receiver || id === loop.inRange; + const expr = (e: IrExpr): boolean => { + switch (e.kind) { + case "varRef": + return e.localId !== loop.receiver; + case "assignExpr": + case "incDec": + return !written(e.localId) && everyExprChild(e, expr, stmt); + case "arrayGet": + case "arrayHas": + case "arrayState": + return receiver(e.arr) && expr(e.index); + case "arrIntrinsic": + if (READING_ARRAY_METHODS.has(e.method)) return receiver(e.receiver) && e.args.every(expr); + return separate(e.receiver) && e.args.every(expr); + case "strIntrinsic": + return ( + READING_STRING_METHODS.has(e.method) && + e.receiver.type.kind === "string" && + expr(e.receiver) && + e.args.every(expr) + ); + case "bytesIntrinsic": { + const numeric = byteNumberAccess(e); + return ( + (numeric ? !numeric.write : e.method === "get" || e.method === "length") && + expr(e.receiver) && + e.args.every(expr) + ); + } + case "libCall": + return ( + isBorrowSafeMath(e.fn) && + e.args.every((arg) => arg.type.kind === "f64") && + e.args.every(expr) + ); + case "strConcat": + return ( + e.left.type.kind === "string" && + e.right.type.kind === "string" && + expr(e.left) && + expr(e.right) + ); + default: + return PLAIN_EXPRESSIONS.has(e.kind) && everyExprChild(e, expr, stmt); + } + }; + const stmt = (s: IrStmt): boolean => { + switch (s.kind) { + case "varDecl": + case "assign": + if (written(s.localId)) return false; + break; + case "arraySet": + return ( + (separate(s.arr) || + (s.index.kind === "varRef" && + loop.inRange !== null && + s.index.localId === loop.inRange)) && + receiver(s.arr) && + expr(s.index) && + expr(s.value) + ); + case "return": + return s.value === null || expr(s.value); + default: + if (!PLAIN_STATEMENTS.has(s.kind)) return false; + } + return everyStmtChild(s, expr, stmt); + }; + return nodes.every((node) => ("type" in node ? expr(node as IrExpr) : stmt(node as IrStmt))); +} diff --git a/packages/compiler/src/ir/integer-loop-facts.ts b/packages/compiler/src/ir/integer-loop-facts.ts index 4c1a1ef1f..84fabf956 100644 --- a/packages/compiler/src/ir/integer-loop-facts.ts +++ b/packages/compiler/src/ir/integer-loop-facts.ts @@ -118,6 +118,9 @@ export function boundedIntegerLoopFacts( stable(e.receiver.localId) ) return { min: 0, max: Number.MAX_SAFE_INTEGER }; + // Every evaluation of an array length lies in its range, so the + // condition bounds each pass even when the body resizes the array. + if (isArrayLength(e)) return ARRAY_LENGTH_RANGE; return null; } let step: IntegerRange; @@ -134,12 +137,15 @@ export function boundedIntegerLoopFacts( if (step.min <= 0 || step.max > 2147483647) return result; } const limit = bound(loop.cond.right); - if (!limit || limit.max < start.min) return result; - const distance = limit.max - start.min; + // The counter is an integer, so a strict bound admits passes up to one + // below the limit. + const last = limit && (loop.cond.op === "<" ? limit.max - 1 : limit.max); + if (!limit || last === null || last < start.min) return result; + const distance = last - start.min; const iterations = Math.floor(distance / step.min) + 1; if (!Number.isSafeInteger(distance) || !Number.isSafeInteger(iterations)) return result; // Header facts also cover the failing final condition and zero iterations. - const maximum = Math.max(start.max, limit.max + step.max); + const maximum = Math.max(start.max, last + step.max); if (Number.isSafeInteger(maximum)) result.set(counter, { min: start.min, max: maximum }); for (const [id, hi] of upper) { const range = initial.get(id); @@ -154,6 +160,20 @@ export function boundedIntegerLoopFacts( return result; } +/** Every length an array can have: SCR_ARR_MAX_LENGTH (scr_array.c). */ +export const ARRAY_LENGTH_RANGE: IntegerRange = { min: 0, max: 4294967295 }; + +/** `a.length` of a typed array value (an ordinary JS array). */ +function isArrayLength(e: IrExpr): boolean { + return ( + e.kind === "arrIntrinsic" && + e.method === "length" && + e.args.length === 0 && + e.type.kind === "f64" && + e.receiver.type.kind === "array" + ); +} + /** The most UTF-16 code units a runtime string holds: SCR_STR_MAX_CAP * (scr_runtime.h) caps a string's UTF-8 bytes, and a UTF-16 length never * exceeds the UTF-8 byte length. */ @@ -241,6 +261,9 @@ export function guardedLoopCounterFacts( stable(e.receiver.localId) ) return { min: 0, max: STRING_MAX_UNITS }; + // An array length can change on any pass, but never leaves its range, + // which is all a ceiling needs. + if (isArrayLength(e)) return ARRAY_LENGTH_RANGE; return null; }; // The bounds a condition's conjuncts put on counters while it holds. diff --git a/packages/compiler/src/ir/integer-loops.test.ts b/packages/compiler/src/ir/integer-loops.test.ts index 0f7b9ae13..75968b262 100644 --- a/packages/compiler/src/ir/integer-loops.test.ts +++ b/packages/compiler/src/ir/integer-loops.test.ts @@ -208,3 +208,111 @@ test("a string read at the counter is an integer consumer", () => { s.body = [read(ref("limit"))]; expect(matchIntegerCountedForLoop(s, withText)).toBeNull(); }); + +test("a stable array length bounds a counted loop; a resizing body keeps it a condition", () => { + const ARR = arrayOf(F64); + const array = (localId: string): IrExpr => ({ kind: "varRef", localId, type: ARR, loc }); + const length: IrExpr = { + kind: "arrIntrinsic", + method: "length", + receiver: array("a"), + args: [], + type: F64, + loc, + }; + const read = (index: IrExpr): IrExpr => ({ + kind: "arrIntrinsic", + method: "getNumber", + receiver: array("a"), + args: [index], + type: F64, + loc, + }); + // for (let i = 0; i < a.length; i += 2) a[i]; + const strided = (body: IrStmt[]): IrStmt & { kind: "for" } => { + const s = counted(length); + s.update = { + kind: "assign", + localId: "i", + value: { kind: "bin", op: "+", left: ref("i"), right: number(2), type: F64, loc }, + loc, + }; + s.body = [{ kind: "exprStmt", expr: read(ref("i")), loc }, ...body]; + return s; + }; + const ranges = new Map([[length, { min: 0, max: 4294967295 }]]); + expect(matchIntegerCountedForLoop(strided([]), locals, ranges, new Set())).toMatchObject({ + localId: "i", + guarded: false, + range: { min: 0, max: 4294967294 }, + }); + // Without the alias facts there is no stability proof. + expect(matchIntegerCountedForLoop(strided([]), locals, ranges)).toBeNull(); + const push: IrStmt = { + kind: "exprStmt", + expr: { + kind: "arrIntrinsic", + method: "push", + receiver: array("a"), + args: [number(1)], + type: F64, + loc, + }, + loc, + }; + expect(matchIntegerCountedForLoop(strided([push]), locals, ranges, new Set())).toBeNull(); + // An element write at the counter stays below the length; one past it can grow the array. + const write = (index: IrExpr): IrStmt => ({ + kind: "arraySet", + arr: array("a"), + index, + value: number(0), + loc, + }); + expect( + matchIntegerCountedForLoop(strided([write(ref("i"))]), locals, ranges, new Set()), + ).not.toBeNull(); + const past = { kind: "bin", op: "+", left: ref("i"), right: number(1), type: F64, loc } as const; + expect(matchIntegerCountedForLoop(strided([write(past)]), locals, ranges, new Set())).toBeNull(); +}); + +test("a descending loop from an array's last index takes an integer counter for its reads", () => { + const ARR = arrayOf(F64); + const length: IrExpr = { + kind: "arrIntrinsic", + method: "length", + receiver: { kind: "varRef", localId: "a", type: ARR, loc }, + args: [], + type: F64, + loc, + }; + const start: IrExpr = { kind: "bin", op: "-", left: length, right: number(1), type: F64, loc }; + const s = loop(start); + s.cond = { kind: "bin", op: ">=", left: ref("i"), right: number(0), type: BOOL, loc }; + s.update = { + kind: "assign", + localId: "i", + value: { kind: "bin", op: "-", left: ref("i"), right: number(1), type: F64, loc }, + loc, + }; + s.body = [ + { + kind: "exprStmt", + expr: { + kind: "arrIntrinsic", + method: "getNumber", + receiver: { kind: "varRef", localId: "a", type: ARR, loc }, + args: [ref("i")], + type: F64, + loc, + }, + loc, + }, + ]; + const ranges = new Map([[start, { min: -1, max: 4294967294 }]]); + expect(matchIntegerCountedForLoop(s, locals, ranges)).toMatchObject({ + step: -1, + guarded: false, + range: { min: 0, max: 4294967294 }, + }); +}); diff --git a/packages/compiler/src/ir/integer-loops.ts b/packages/compiler/src/ir/integer-loops.ts index c854a99c5..3ba186376 100644 --- a/packages/compiler/src/ir/integer-loops.ts +++ b/packages/compiler/src/ir/integer-loops.ts @@ -3,6 +3,7 @@ import type { IntegerRange, IntegerRanges } from "./integer-ranges.js"; import { everyExprChild, everyStmtChild, everyStmtList } from "./traverse.js"; import { byteNumberAccess } from "./byte-numbers.js"; +import { preservesArrayLength } from "./array-length-stability.js"; /** A canonical byte loop whose induction variable is mathematically an * unsigned integer for every body entry. Backends may keep this binding in @@ -47,15 +48,17 @@ function constantStep(update: IrStmt | null, id: string): number | null { } /** Pure initial values may be evaluated again on a fallback path. Bounds - * additionally have to remain invariant throughout the loop. Array length - * is allowed only in the initializer; its mutable value is never hoisted - * from a condition. Typed-array lengths are fixed for a given receiver. */ + * additionally have to remain invariant throughout the loop. An array length + * is hoisted from a condition only when `stableLength` proves the loop never + * changes it; otherwise it is allowed only in the initializer. Typed-array + * lengths are fixed for a given receiver. */ function stableLoopValue( value: IrExpr, locals: ReadonlyMap, body: IrStmt[], invariant: boolean, counter: string, + stableLength: (receiver: string) => boolean = () => false, ): boolean { switch (value.kind) { case "numLit": @@ -77,16 +80,16 @@ function stableLoopValue( value.op === "&" || value.op === ">>>" || value.op === "|") && - stableLoopValue(value.left, locals, body, invariant, counter) && - stableLoopValue(value.right, locals, body, invariant, counter) + stableLoopValue(value.left, locals, body, invariant, counter, stableLength) && + stableLoopValue(value.right, locals, body, invariant, counter, stableLength) ); case "bytesIntrinsic": case "arrIntrinsic": return ( (value.method === "length" || (value.kind === "bytesIntrinsic" && value.method === "byteLength")) && - (value.kind === "bytesIntrinsic" || !invariant) && value.receiver.kind === "varRef" && + (value.kind === "bytesIntrinsic" || !invariant || stableLength(value.receiver.localId)) && stableLoopValue(value.receiver, locals, body, invariant, counter) ); default: @@ -103,6 +106,7 @@ export function matchIntegerCountedForLoop( stmt: IrStmt & { kind: "for" }, locals: ReadonlyMap, ranges: IntegerRanges = new Map(), + unaliased: ReadonlySet | null = null, ): IntegerCountedForLoop | null { const init = stmt.init; if (init?.kind !== "varDecl" || !init.init) return null; @@ -135,7 +139,38 @@ export function matchIntegerCountedForLoop( op = ({ "<": ">", "<=": ">=", ">": "<", ">=": "<=" } as Record)[op] ?? ""; } if (step > 0 ? op !== "<" && op !== "<=" : op !== ">" && op !== ">=") return null; - if (!stableLoopValue(limit, locals, stmt.body, true, local.id)) return null; + // An ascending counter compared below `a.length - c` holds an index below + // the length on every pass while that length is unchanged. + const belowLength = (receiver: string): boolean => { + let offset = 0, + length = limit; + if ( + length.kind === "bin" && + length.op === "-" && + length.right.kind === "numLit" && + Number.isFinite(length.right.value) + ) { + offset = length.right.value; + length = length.left; + } + return ( + step > 0 && + length.kind === "arrIntrinsic" && + length.method === "length" && + length.receiver.kind === "varRef" && + length.receiver.localId === receiver && + (op === "<" ? offset >= 0 : offset >= 1) + ); + }; + const stableLength = (receiver: string): boolean => + unaliased !== null && + preservesArrayLength( + [cond, ...stmt.body], + { receiver, inRange: belowLength(receiver) ? local.id : null }, + locals, + unaliased, + ); + if (!stableLoopValue(limit, locals, stmt.body, true, local.id, stableLength)) return null; const inclusive = op === "<=" || op === ">="; const guardLimit = step > 0 ? 2 ** 53 - (inclusive ? 1 : 0) : -(2 ** 53) + (inclusive ? 1 : 0); const boundRange = @@ -178,10 +213,19 @@ export function matchIntegerCountedForLoop( // A string read at the counter indexes with the integer directly. if (e.kind === "strIntrinsic" && e.method === "charCodeAt" && e.args[0] && counter(e.args[0])) useful = true; + // So does an array element read; only a loop that needs no versioned + // copy takes the integer counter for it. + if ( + !guarded && + ((e.kind === "arrayGet" && counter(e.index)) || + (e.kind === "arrIntrinsic" && e.method === "getNumber" && e.args[0] && counter(e.args[0]))) + ) + useful = true; return (!guarded || ++cost <= 80) && everyExprChild(e, expr, bodyStmt); }; const bodyStmt = (s: IrStmt): boolean => { if (s.kind === "bytesSet" && counter(s.index)) useful = true; + if (!guarded && s.kind === "arraySet" && counter(s.index)) useful = true; if ( guarded && (s.kind === "for" || s.kind === "forOf" || s.kind === "while" || s.kind === "doWhile") diff --git a/packages/compiler/src/ir/integer-ranges.test.ts b/packages/compiler/src/ir/integer-ranges.test.ts index e9d1797d1..0d0762d16 100644 --- a/packages/compiler/src/ir/integer-ranges.test.ts +++ b/packages/compiler/src/ir/integer-ranges.test.ts @@ -334,7 +334,8 @@ test("filtered strided loops retain decoded values and bound secondary cursors", const ranges = analyzeIntegerRanges(f); expect(ranges.get(cursor)).toEqual({ min: 0, max: 80 }); expect(ranges.get(decoded)).toEqual({ min: 0, max: 4294967295 }); - expect(ranges.get(conditionRead)).toEqual({ min: 0, max: 124 }); + // The last pass enters at most at 99, so the failing test reads at most 123. + expect(ranges.get(conditionRead)).toEqual({ min: 0, max: 123 }); for (const mutation of ["fraction", "repeat", "overflow", "counter"] as const) { const changed = structuredClone(f); const body = (changed.body[1] as IrStmt & { kind: "for" }).body; @@ -795,6 +796,58 @@ test("a while condition on a string's length bounds a counter, and guarded incre expect(run((inside) => [observe(inside), bump, rebound]).after).toBeNull(); }); +test("an array length bounds while and for counters even when the body resizes the array", () => { + // let i = 0; while (i < items.length) { observe(i); items.push(i); i++; } observe(i); + const ARR = { kind: "array", elem: F64 } as const; + const items: IrExpr = { loc, kind: "varRef", localId: "items", type: ARR }; + const length: IrExpr = { loc, kind: "arrIntrinsic", method: "length", receiver: items, args: [], type: F64 }; + const push: IrStmt = { + loc, + kind: "exprStmt", + expr: { loc, kind: "arrIntrinsic", method: "push", receiver: items, args: [ref("i")], type: F64 }, + }; + const bump: IrStmt = { + loc, + kind: "exprStmt", + expr: { loc, kind: "incDec", op: "+", prefix: false, localId: "i", type: F64 }, + }; + const inside = ref("i"), + after = ref("i"); + const f = fn([ + { loc, kind: "assign", localId: "i", value: num(0) }, + { loc, kind: "while", cond: condition("<", ref("i"), length), body: [observe(inside), push, bump] }, + observe(after), + ]); + f.locals.push( + { id: "i", name: "i", type: F64, mutable: true }, + { id: "items", name: "items", type: ARR, mutable: false }, + ); + const ranges = analyzeIntegerRanges(f); + expect(ranges.get(inside)).toEqual({ min: 0, max: 4294967294 }); + expect(ranges.get(after)).toEqual({ min: 0, max: 4294967295 }); + // A secondary cursor of `for (let j = 0; j < items.length; j++) k++` stays a uint32. + const cursor = ref("k"); + const loop: IrStmt = { + loc, + kind: "for", + init: { loc, kind: "varDecl", localId: "j", init: num(0) }, + cond: condition("<", ref("j"), length), + update: { loc, kind: "assign", localId: "j", value: bin("+", ref("j"), num(1)) }, + body: [ + push, + observe(cursor), + { loc, kind: "assign", localId: "k", value: bin("+", ref("k"), num(1)) }, + ], + }; + const g = fn([{ loc, kind: "assign", localId: "k", value: num(0) }, loop]); + g.locals.push( + { id: "j", name: "j", type: F64, mutable: true }, + { id: "k", name: "k", type: F64, mutable: true }, + { id: "items", name: "items", type: ARR, mutable: false }, + ); + expect(analyzeIntegerRanges(g).get(cursor)).toEqual({ min: 0, max: 4294967295 }); +}); + test("whole-program slot facts seed parameters, field reads and call results", () => { const field: IrExpr = { loc, diff --git a/tests/corpus/5960-array-length-loop-resizing.ts b/tests/corpus/5960-array-length-loop-resizing.ts new file mode 100644 index 000000000..a1d5f6d11 --- /dev/null +++ b/tests/corpus/5960-array-length-loop-resizing.ts @@ -0,0 +1,167 @@ +// Index loops bounded by an array's length whose bodies resize that array, +// directly, through an alias, a helper or a closure: the bound is re-read on +// every pass, exactly like Node. + +function pushInBody(): string { + const a = [1, 2, 3]; + const seen: number[] = []; + for (let i = 0; i < a.length; i++) { + seen.push(a[i]); + if (a.length < 6) a.push(a[i] * 10); + } + return `${seen.join(",")} | ${a.length}`; +} + +function stridedPush(): string { + const a = [0, 1, 2, 3]; + let visits = 0; + for (let i = 0; i < a.length; i += 2) { + visits++; + if (a.length < 9) a.push(i); + } + return `${visits} ${a.join(",")}`; +} + +function truncateInBody(): string { + const a = [5, 6, 7, 8, 9, 10]; + let sum = 0; + for (let i = 0; i < a.length; i++) { + sum += a[i]; + if (i === 2) a.length = 4; + } + return `${sum} ${a.length}`; +} + +function growLengthInBody(): string { + const a = [1, 2]; + let holes = 0; + for (let i = 0; i < a.length; i++) { + if (a[i] === undefined) holes++; + if (i === 0) a.length = 5; + } + return `${holes} ${a.length}`; +} + +function helperPush(xs: number[], v: number): void { + if (xs.length < 7) xs.push(v); +} + +function pushThroughHelper(): string { + const a = [1, 2, 3]; + let sum = 0; + for (let i = 0; i < a.length; i++) { + sum += a[i]; + helperPush(a, i + 100); + } + return `${sum} ${a.length}`; +} + +function pushThroughClosure(): string { + const a = [1, 2, 3]; + const grow = (v: number): void => { + if (a.length < 6) a.push(v); + }; + let sum = 0; + for (let i = 0; i < a.length; i++) { + sum += a[i]; + grow(i); + } + return `${sum} ${a.length}`; +} + +function pushThroughAlias(): string { + const a = [1, 2, 3]; + const alias = a; + let sum = 0; + for (let i = 0; i < a.length; i++) { + sum += a[i]; + if (alias.length < 8) alias.push(i * 2); + } + return `${sum} ${a.length}`; +} + +function aliasedParameters(a: number[], out: number[]): string { + // `out` may be `a` itself. + let n = 0; + for (let i = 0; i < a.length; i++) { + n++; + if (out.length < 10) out.push(a[i]); + } + return `${n} ${a.length} ${out.length}`; +} + +function writePastEnd(): string { + const a = [1, 2, 3]; + let passes = 0; + for (let i = 0; i < a.length; i++) { + passes++; + if (i + 1 === a.length && a.length < 6) a[i + 1] = i; + } + return `${passes} ${a.join(",")}`; +} + +function shiftInBody(): string { + const a = [1, 2, 3, 4, 5, 6]; + const seen: number[] = []; + for (let i = 0; i < a.length; i++) { + seen.push(a[i]); + a.shift(); + } + return `${seen.join(",")} | ${a.join(",")}`; +} + +function spliceInDescendingLoop(): string { + const a = [1, 2, 3, 4, 5, 6, 7]; + for (let i = a.length - 1; i >= 0; i--) if (a[i] % 2 === 0) a.splice(i, 1); + return a.join(","); +} + +function whilePush(): string { + const a = [3, 1]; + let i = 0; + let sum = 0; + while (i < a.length) { + sum += a[i]; + if (a.length < 5) a.push(sum); + i++; + } + return `${sum} ${i} ${a.join(",")}`; +} + +function nestedResize(): string { + const rows = [[1], [2, 3], [4, 5, 6]]; + let total = 0; + for (let r = 0; r < rows.length; r++) { + const row = rows[r]; + for (let c = 0; c < row.length; c++) { + total += row[c]; + if (row.length < 3) row.push(c); + } + } + return `${total} ${rows.map((row) => row.length).join(",")}`; +} + +function pushIntoOther(): string { + const a = [2, 4, 6]; + const out: number[] = []; + for (let i = 0; i < a.length; i++) out.push(a[i] + 1); + for (let i = 0; i < out.length; i += 2) out.push(-1); + return `${out.join(",")}`; +} + +console.log(pushInBody()); +console.log(stridedPush()); +console.log(truncateInBody()); +console.log(growLengthInBody()); +console.log(pushThroughHelper()); +console.log(pushThroughClosure()); +console.log(pushThroughAlias()); +const shared = [7, 8, 9]; +console.log(aliasedParameters(shared, shared)); +console.log(aliasedParameters([7, 8, 9], [])); +console.log(writePastEnd()); +console.log(shiftInBody()); +console.log(spliceInDescendingLoop()); +console.log(whilePush()); +console.log(nestedResize()); +console.log(pushIntoOther()); diff --git a/tests/corpus/5961-array-length-sparse-loops.ts b/tests/corpus/5961-array-length-sparse-loops.ts new file mode 100644 index 000000000..589c1df60 --- /dev/null +++ b/tests/corpus/5961-array-length-sparse-loops.ts @@ -0,0 +1,133 @@ +// Index loops over sparse arrays with lengths beyond 2^31, holes, and arrays +// that become sparse while a loop runs. Dense-loop fast paths must leave all +// of these on the general path. + +function partialAscending(a: number[], limit: number): string { + let sum = 0; + let passes = 0; + for (let i = 0; i < a.length; i++) { + if (passes++ === limit) break; + sum += a[i] === undefined ? -1 : a[i]; + } + return `${passes} ${sum}`; +} + +function partialDescending(a: number[], limit: number): string { + let last = -1; + let passes = 0; + for (let i = a.length - 1; i >= 0; i--) { + if (passes++ === limit) break; + last = i; + } + return `${passes} ${last}`; +} + +function stridedFromEnd(a: number[]): string { + const hits: number[] = []; + for (let i = a.length - 1; i >= 0 && hits.length < 3; i -= 1000000000) hits.push(i); + return hits.join(","); +} + +function whileWithLimit(a: number[], limit: number): number { + let i = 0; + let present = 0; + while (i < a.length && i < limit) { + if (a[i] !== undefined) present++; + i++; + } + return present * 1000 + i; +} + +function writeAtCounter(a: number[], limit: number): string { + for (let i = 0; i < a.length && i < limit; i++) a[i] = i * 2; + return `${a.length} ${a[0]} ${a[limit - 1]} ${a[limit]}`; +} + +function holeSum(a: number[]): string { + let sum = 0; + let nan = 0; + for (let i = 0; i < a.length; i++) { + const v = a[i]; + if (Number.isNaN(v + 0)) nan++; + else sum += v; + } + return `${sum} ${nan}`; +} + +function firstValues(a: number[]): string { + let s = 0; + for (let i = 0; i < a.length; i++) { + if (i === 4) break; + s += a[i]; + } + let t = 0; + for (let i = a.length - 1; i >= 0; i--) { + if (i < a.length - 2) break; + t += a[i]; + } + let u = 0; + for (let i = 0; i < a.length; i += 2) { + if (i > 2) break; + u += a[i]; + } + return `${s} ${t} ${u}`; +} + +const huge: number[] = [1, 2, 3]; +huge.length = 3e9; +console.log(huge.length); +console.log(partialAscending(huge, 5)); +console.log(firstValues(huge), firstValues([1, 2, 3, 4, 5])); +console.log(partialDescending(huge, 4)); +console.log(stridedFromEnd(huge)); +console.log(whileWithLimit(huge, 6)); +console.log(writeAtCounter(huge, 4)); +console.log(huge.length); + +const edge: number[] = []; +edge[4294967294] = 7; +console.log(edge.length, partialDescending(edge, 2), partialAscending(edge, 3)); + +const holey = [1, 2]; +holey[3] = 4; +holey[5] = 6; +console.log(holeSum(holey)); +const sparse: number[] = [1, 2]; +sparse[10] = 5; +console.log(holeSum(sparse)); + +// Becomes sparse mid-loop: a write far past the end through another binding. +function sparseMidLoop(): string { + const a = [1, 2, 3, 4]; + const b = a; + let sum = 0; + for (let i = 0; i < a.length; i++) { + if (i === 1) b[3000000000] = 9; + if (i > 6) break; + sum += a[i] === undefined ? 100 : a[i]; + } + return `${sum} ${a.length}`; +} +console.log(sparseMidLoop()); + +function holeMidLoop(): string { + const a = [1, 2, 3, 4, 5]; + let sum = 0; + for (let i = 0; i < a.length; i++) { + if (i === 1) a.length = 3; + if (i === 2) a.length = 5; + sum += a[i] === undefined ? 100 : a[i]; + } + return `${sum}`; +} +console.log(holeMidLoop()); + +const objects: { v: number }[] = [{ v: 1 }, { v: 2 }, { v: 3 }]; +objects.length = 5; +try { + let total = 0; + for (let i = 0; i < objects.length; i++) total += objects[i].v; + console.log(total); +} catch (e) { + console.log(e instanceof TypeError ? "TypeError" : "other"); +} diff --git a/tests/corpus/5962-array-dense-loop-boundaries.ts b/tests/corpus/5962-array-dense-loop-boundaries.ts new file mode 100644 index 000000000..5efad78ec --- /dev/null +++ b/tests/corpus/5962-array-dense-loop-boundaries.ts @@ -0,0 +1,173 @@ +// Index loops whose array length the loop never changes, run over dense, +// holey, partially filled, aliased and short arrays, with fractional, +// negative and offset bounds, ascending, strided and descending counters. + +interface Point { + x: number; + y: number; +} + +function sum(a: number[]): number { + let s = 0; + for (let i = 0; i < a.length; i++) s += a[i]; + return s; +} + +function scale(a: number[], b: number[]): string { + for (let i = 0; i < a.length; i++) b[i] = a[i] * 2; + return `${b.length}:${b.join(",")}`; +} + +function inPlace(a: number[]): string { + for (let i = 0; i < a.length; i++) a[i] = a[i] + 1; + return a.join(","); +} + +function strided(a: number[], step: number): string { + let s = 0; + if (step === 2) for (let i = 0; i < a.length; i += 2) s += a[i]; + else for (let i = 1; i < a.length; i += 3) s += a[i]; + return `${s}`; +} + +function descending(a: number[]): string { + const out: number[] = []; + for (let i = a.length - 1; i >= 0; i--) out.push(a[i]); + return out.join(","); +} + +function descendingPairs(a: number[]): number { + let s = 0; + for (let i = a.length - 2; i > 0; i -= 2) s += a[i] - a[i + 1]; + return s; +} + +function offsetBounds(a: number[]): string { + let inner = 0; + for (let i = 1; i < a.length - 1; i++) inner += a[i]; + let inclusive = 0; + for (let i = 0; i <= a.length - 1; i++) inclusive += a[i]; + let diffs = 0; + for (let i = 0; i < a.length - 1; i++) diffs += a[i + 1] - a[i]; + return `${inner} ${inclusive} ${diffs}`; +} + +function fractionalBounds(a: number[]): string { + const seen: number[] = []; + for (let i = 0.5; i < a.length; i++) seen.push(a[i] === undefined ? -1 : 1); + for (let i = -2; i < a.length - 3; i++) seen.push(a[i] === undefined ? -2 : a[i]); + for (let i = 0; i < a.length - 0.5; i++) seen.push(i); + return seen.join(","); +} + +function whileLoop(a: number[]): number { + let i = 0; + let s = 0; + while (i < a.length) { + s += a[i] * i; + i++; + } + return s; +} + +function constLength(a: number[]): number { + const n = a.length; + let s = 0; + for (let i = 0; i < n; i++) s += a[i]; + return s; +} + +function points(ps: Point[]): string { + let s = 0; + for (let i = 0; i < ps.length; i++) s += ps[i].x * ps[i].y; + return `${s}`; +} + +function flags(bs: boolean[]): number { + let n = 0; + for (let i = 0; i < bs.length; i++) if (bs[i]) n++; + return n; +} + +function names(ss: string[]): string { + let out = ""; + for (let i = ss.length - 1; i >= 0; i--) out += ss[i]; + return out; +} + +function maybe(xs: (number | undefined)[]): string { + let s = 0; + let missing = 0; + for (let i = 0; i < xs.length; i++) { + const v = xs[i]; + if (v === undefined) missing++; + else s += v; + } + return `${s} ${missing}`; +} + +function nested(g: number[][]): number { + let s = 0; + for (let r = 0; r < g.length; r++) { + const row = g[r]; + for (let c = 0; c < row.length; c++) s += row[c] * (r + 1); + } + return s; +} + +function counterAsNumber(a: number[]): string { + let mixed = 0; + for (let i = 0; i < a.length; i++) mixed += i / 2 + (i | 0) + a[i] * -0; + return `${mixed} ${Object.is(mixed, -0)}`; +} + +function earlyExit(a: number[], target: number): number { + for (let i = 0; i < a.length; i++) if (a[i] === target) return i; + return -1; +} + +const dense = [1, 2, 3, 4, 5, 6, 7, 8]; +console.log(sum(dense), sum([]), sum([0.5, -0.25])); +console.log(scale(dense, new Array(8).fill(0))); +console.log(scale(dense, [9, 9])); +console.log(scale([1, 2, 3], [])); +const self = [1, 2, 3, 4]; +console.log(scale(self, self)); +console.log(inPlace([10, 20, 30])); +console.log(strided(dense, 2), strided(dense, 3)); +console.log(descending(dense), descending([])); +console.log(descendingPairs(dense), descendingPairs([1])); +console.log(offsetBounds(dense), offsetBounds([4]), offsetBounds([])); +console.log(fractionalBounds([1, 2, 3, 4, 5])); +console.log(whileLoop(dense)); +console.log(constLength(dense)); +console.log(points([{ x: 1, y: 2 }, { x: 3, y: 4 }])); +console.log(flags([true, false, true, true])); +console.log(names(["a", "b", "c"])); +console.log(maybe([1, undefined, 3])); +console.log(nested([[1, 2], [3], [], [4, 5, 6]])); +console.log(counterAsNumber([1, 2, 3])); +console.log(earlyExit(dense, 5), earlyExit(dense, 50)); + +// Holes and partially filled storage take the checked path. +const holey = [1]; +holey[2] = 3; +holey[4] = 5; +console.log(sum(holey), descending(holey), whileLoop(holey)); +const target = [0, 0, 0]; +target[4] = 0; +console.log(scale(dense.slice(0, 5), target)); +const gap: number[] = []; +gap[3] = 1; +console.log(sum(gap), scale([1, 2, 3, 4], gap)); +const shortened = [1, 2, 3, 4, 5, 6]; +shortened.length = 3; +shortened.length = 6; +console.log(sum(shortened), constLength(shortened)); +const holeyPoints: Point[] = [{ x: 1, y: 1 }]; +holeyPoints[2] = { x: 2, y: 2 }; +try { + console.log(points(holeyPoints)); +} catch (e) { + console.log(e instanceof TypeError ? "TypeError" : "other"); +} From 0580460c46299b60f24c8392b79f62363153e557 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 17:54:52 -0500 Subject: [PATCH 012/117] Match Node 24 in URLSearchParams, querystring, string_decoder and os - URLSearchParams iterators compile outside a for-of head - URLSearchParams can be built from [string, string] tuple pairs - querystring.stringify writes bigint values - StringDecoder accepts an encoding known only at run time - os.setPriority is lowered --- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 32 ++--- .../generated/node-v24-backlog.json | 72 ++++++---- .../generated/node-v24-internal.json | 54 +++++--- internal/compatibility/static-support.json | 4 +- .../ambient/scriptc-node-fallback.d.ts | 5 +- .../compiler/src/backend/llvm/lib-shared.ts | 2 + .../src/backend/target-diagnostics.ts | 1 + .../lowering/builtins/module-calls.ts | 4 + .../lowering/builtins/operating-system.ts | 24 ++++ .../src/frontend/lowering/builtins/url.ts | 128 +++++++++++++++++- .../lowering/containers/array-construction.ts | 4 + .../lowering/containers/collection-methods.ts | 6 + .../src/frontend/lowering/lower-classes.ts | 35 +++-- .../src/frontend/lowering/lower-exprs.ts | 10 +- .../src/frontend/lowering/surfaces.ts | 3 + packages/compiler/src/ir/builtin-effects.ts | 2 + .../compiler/src/ir/builtin-signatures.ts | 7 + packages/compiler/surface-manifest.json | 6 + .../5833-url-search-params-iterators.ts.json | 6 + ...l-search-params-iterators-dynamic.mjs.json | 6 + ...5836-url-search-params-tuple-pairs.ts.json | 6 + .../corpus/5838-qs-stringify-bigint.ts.json | 6 + ...82-string-decoder-runtime-encoding.ts.json | 6 + .../tests/corpus/5883-os-set-priority.ts.json | 6 + packages/runtime/src/scr_bytes.c | 16 +++ packages/runtime/src/scr_bytes.h | 1 + packages/runtime/src/scr_json.c | 36 +++++ packages/runtime/src/scr_os.c | 54 +++++++- packages/runtime/src/scr_os.h | 4 + packages/runtime/src/scr_qs.c | 12 +- packages/runtime/src/scr_url.c | 3 +- .../5833-url-search-params-iterators.ts | 40 ++++++ ...34-url-search-params-iterators-dynamic.mjs | 22 +++ .../5836-url-search-params-tuple-pairs.ts | 34 +++++ tests/corpus/5838-qs-stringify-bigint.ts | 19 +++ .../5882-string-decoder-runtime-encoding.ts | 39 ++++++ tests/corpus/5883-os-set-priority.ts | 33 +++++ tests/fixtures/node-types/fenced.ts | 4 +- .../__snapshots__/node-types-fenced.txt | 10 +- 40 files changed, 667 insertions(+), 97 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5833-url-search-params-iterators.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5834-url-search-params-iterators-dynamic.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5836-url-search-params-tuple-pairs.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5838-qs-stringify-bigint.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5882-string-decoder-runtime-encoding.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5883-os-set-priority.ts.json create mode 100644 tests/corpus/5833-url-search-params-iterators.ts create mode 100644 tests/corpus/5834-url-search-params-iterators-dynamic.mjs create mode 100644 tests/corpus/5836-url-search-params-tuple-pairs.ts create mode 100644 tests/corpus/5838-qs-stringify-bigint.ts create mode 100644 tests/corpus/5882-string-decoder-runtime-encoding.ts create mode 100644 tests/corpus/5883-os-set-priority.ts diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 956d5f2ac..f2b70d48f 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "ce6ef79fa85eaff8f503", + "artifactVersion": "b46eb8d41373f21deb05", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 0421113a4..2a74349bb 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -509,9 +509,9 @@ "apiEntries": 24, "static": { "supported": 0, - "partial": 23, + "partial": 24, "refused": 0, - "not-implemented": 1, + "not-implemented": 0, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -779,9 +779,9 @@ "apiEntries": 62, "static": { "supported": 0, - "partial": 39, + "partial": 42, "refused": 0, - "not-implemented": 23, + "not-implemented": 20, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -52503,9 +52503,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -71599,9 +71599,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -71714,9 +71714,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -71806,9 +71806,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index e03c17638..65e28f522 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1088, - "verify-gap": 2241, + "audit-partial": 1092, + "verify-gap": 2237, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -51735,12 +51735,14 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:os", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "surface-manifest:node-builtin.os.setPriority", + "tests": [ + "tests/corpus/5883-os-set-priority.ts" + ] } } }, @@ -65613,7 +65615,8 @@ "source": "compiler-dedicated:StringDecoder", "tests": [ "tests/corpus/1662-string-decoder-encodings.ts", - "tests/corpus/node24-string-decoder.ts" + "tests/corpus/node24-string-decoder.ts", + "tests/corpus/5882-string-decoder-runtime-encoding.ts" ] } } @@ -65641,7 +65644,8 @@ "source": "compiler-dedicated:stringDecoder.end", "tests": [ "tests/corpus/1662-string-decoder-encodings.ts", - "tests/corpus/node24-string-decoder.ts" + "tests/corpus/node24-string-decoder.ts", + "tests/corpus/5882-string-decoder-runtime-encoding.ts" ] } } @@ -65669,7 +65673,8 @@ "source": "compiler-dedicated:stringDecoder.write", "tests": [ "tests/corpus/1662-string-decoder-encodings.ts", - "tests/corpus/node24-string-decoder.ts" + "tests/corpus/node24-string-decoder.ts", + "tests/corpus/5882-string-decoder-runtime-encoding.ts" ] } } @@ -73429,12 +73434,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:url", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:url.urlSearchParams.entries", + "tests": [ + "tests/corpus/5833-url-search-params-iterators.ts", + "tests/corpus/5834-url-search-params-iterators-dynamic.mjs" + ] } } }, @@ -73554,12 +73562,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:url", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:url.urlSearchParams.keys", + "tests": [ + "tests/corpus/5833-url-search-params-iterators.ts", + "tests/corpus/5834-url-search-params-iterators-dynamic.mjs" + ] } } }, @@ -73654,12 +73665,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:url", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:url.urlSearchParams.values", + "tests": [ + "tests/corpus/5833-url-search-params-iterators.ts", + "tests/corpus/5834-url-search-params-iterators-dynamic.mjs" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 64f3b8e4c..7f9e62f9b 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -536,9 +536,9 @@ "apiEntries": 24, "static": { "supported": 0, - "partial": 23, + "partial": 24, "refused": 0, - "not-implemented": 1, + "not-implemented": 0, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -836,9 +836,9 @@ "apiEntries": 62, "static": { "supported": 0, - "partial": 39, + "partial": 42, "refused": 0, - "not-implemented": 23, + "not-implemented": 20, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -74090,7 +74090,8 @@ "tests/corpus/2917-builtin-callable-widths.ts", "tests/corpus/4598-os-available-parallelism.ts", "tests/corpus/5140-os-host-facts.ts", - "tests/corpus/5141-os-constants.ts" + "tests/corpus/5141-os-constants.ts", + "tests/corpus/5883-os-set-priority.ts" ] }, "anchorSource": "chapter" @@ -74639,8 +74640,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:os" + "status": "partial", + "evidence": "surface-manifest:node-builtin.os.setPriority", + "tests": [ + "tests/corpus/5883-os-set-priority.ts" + ] }, "anchorSource": "exact" }, @@ -90806,6 +90810,7 @@ "evidence": "derived:descendants", "tests": [ "tests/corpus/1662-string-decoder-encodings.ts", + "tests/corpus/5882-string-decoder-runtime-encoding.ts", "tests/corpus/node24-string-decoder.ts" ] }, @@ -90833,7 +90838,8 @@ "evidence": "compiler-dedicated:StringDecoder", "tests": [ "tests/corpus/1662-string-decoder-encodings.ts", - "tests/corpus/node24-string-decoder.ts" + "tests/corpus/node24-string-decoder.ts", + "tests/corpus/5882-string-decoder-runtime-encoding.ts" ] }, "anchorSource": "exact" @@ -90860,7 +90866,8 @@ "evidence": "compiler-dedicated:stringDecoder.end", "tests": [ "tests/corpus/1662-string-decoder-encodings.ts", - "tests/corpus/node24-string-decoder.ts" + "tests/corpus/node24-string-decoder.ts", + "tests/corpus/5882-string-decoder-runtime-encoding.ts" ] }, "anchorSource": "exact" @@ -90887,7 +90894,8 @@ "evidence": "compiler-dedicated:stringDecoder.write", "tests": [ "tests/corpus/1662-string-decoder-encodings.ts", - "tests/corpus/node24-string-decoder.ts" + "tests/corpus/node24-string-decoder.ts", + "tests/corpus/5882-string-decoder-runtime-encoding.ts" ] }, "anchorSource": "exact" @@ -98970,6 +98978,8 @@ "tests/corpus/5227-url-legacy-dependency/main.ts", "tests/corpus/5228-url-domain-conversion.ts", "tests/corpus/5229-url-legacy-errors.cjs", + "tests/corpus/5833-url-search-params-iterators.ts", + "tests/corpus/5834-url-search-params-iterators-dynamic.mjs", "tests/corpus/node24-file-url-buffer.ts", "tests/corpus/node24-file-url-errors.js", "tests/corpus/node24-file-url-options.ts", @@ -99754,8 +99764,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:url" + "status": "partial", + "evidence": "compiler-feature:url.urlSearchParams.entries", + "tests": [ + "tests/corpus/5833-url-search-params-iterators.ts", + "tests/corpus/5834-url-search-params-iterators-dynamic.mjs" + ] }, "anchorSource": "exact" }, @@ -99869,8 +99883,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:url" + "status": "partial", + "evidence": "compiler-feature:url.urlSearchParams.keys", + "tests": [ + "tests/corpus/5833-url-search-params-iterators.ts", + "tests/corpus/5834-url-search-params-iterators-dynamic.mjs" + ] }, "anchorSource": "exact" }, @@ -99961,8 +99979,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:url" + "status": "partial", + "evidence": "compiler-feature:url.urlSearchParams.values", + "tests": [ + "tests/corpus/5833-url-search-params-iterators.ts", + "tests/corpus/5834-url-search-params-iterators-dynamic.mjs" + ] }, "anchorSource": "exact" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 63c032c73..2c411355d 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -104,6 +104,7 @@ "node-builtin.os.endianness": ["tests/corpus/5140-os-host-facts.ts"], "node-builtin.os.freemem": ["tests/corpus/5140-os-host-facts.ts"], "node-builtin.os.getPriority": ["tests/corpus/5140-os-host-facts.ts"], + "node-builtin.os.setPriority": ["tests/corpus/5883-os-set-priority.ts"], "node-builtin.os.hostname": ["tests/corpus/5140-os-host-facts.ts"], "node-builtin.os.loadavg": ["tests/corpus/5140-os-host-facts.ts"], "node-builtin.os.machine": ["tests/corpus/5140-os-host-facts.ts"], @@ -337,6 +338,7 @@ { "chapter": "webstreams", "signatures": ["`streamConsumers.arrayBuffer(stream)`"], "status": "partial", "evidence": ["tests/corpus/4875-stream-consumers-array-buffer.ts"] }, { "chapter": "url", "symbols": ["url.fileURLToPath", "url.fileURLToPathBuffer", "url.pathToFileURL"], "status": "partial", "evidence": ["tests/corpus/node24-file-url-buffer.ts", "tests/corpus/node24-file-url-options.ts", "tests/corpus/node24-file-url-errors.js", "tests/fixtures/node-types/file-url-conversion.ts"] }, { "chapter": "url", "symbols": ["URL.canParse", "URL.parse", "url.toString", "url.toJSON"], "status": "partial", "evidence": ["tests/corpus/node24-url-factories.ts", "tests/corpus/node24-url-factory-errors.ts", "tests/fixtures/node-types/url-factories.ts", "tests/harness/project-config.test.ts"] }, + { "chapter": "url", "symbols": ["urlSearchParams.entries", "urlSearchParams.keys", "urlSearchParams.values"], "status": "partial", "evidence": ["tests/corpus/5833-url-search-params-iterators.ts", "tests/corpus/5834-url-search-params-iterators-dynamic.mjs"] }, { "chapter": "url", "signatures": ["Class: `URL`"], "status": "partial", "evidence": ["tests/corpus/url-runtime-base.ts", "tests/corpus/node24-url-mutation.ts", "tests/corpus/node24-url-mutation-coercion.js", "tests/fixtures/node-types/url-mutation.ts"] }, { "chapter": "url", "parent": "Class: `URL`", "signatures": ["`protocol` Type: {string}", "`username` Type: {string}", "`password` Type: {string}", "`host` Type: {string}", "`hostname` Type: {string}", "`port` Type: {string}"], "status": "partial", "evidence": ["tests/corpus/node24-url-authority.ts", "tests/corpus/node24-url-authority-coercion.js", "tests/fixtures/node-types/url-mutation.ts"] }, { "chapter": "url", "parent": "Class: `URL`", "signatures": ["`href` Type: {string}", "`pathname` Type: {string}", "`search` Type: {string}", "`hash` Type: {string}"], "status": "partial", "evidence": ["tests/corpus/node24-url-mutation.ts", "tests/corpus/node24-url-mutation-coercion.js", "tests/fixtures/node-types/url-mutation.ts"] }, @@ -376,7 +378,7 @@ { "symbols": ["crypto.hkdf", "crypto.hkdfSync", "crypto.scrypt", "crypto.scryptSync"], "status": "partial", "evidence": ["tests/corpus/node24-crypto-kdf.ts", "tests/corpus/node24-crypto-kdf-errors.ts", "tests/corpus/node24-crypto-kdf-options.ts", "tests/corpus/5438-crypto-kdf-digests.ts"] }, { "symbols": ["EventEmitter", "emitter.on", "emitter.addListener", "emitter.once", "emitter.prependListener", "emitter.prependOnceListener", "emitter.off", "emitter.removeListener", "emitter.removeAllListeners", "emitter.emit", "emitter.listenerCount", "emitter.listeners", "emitter.rawListeners", "emitter.eventNames", "emitter.setMaxListeners", "emitter.getMaxListeners", "events.getEventListeners", "events.listenerCount", "events.once", "events.on", "events.setMaxListeners"], "status": "partial", "evidence": ["tests/corpus/1677-emitter-listeners.ts", "tests/corpus/2620-ee-override-once-order.ts"] }, { "symbols": ["AsyncLocalStorage", "asyncLocalStorage.run", "asyncLocalStorage.exit", "asyncLocalStorage.getStore", "asyncLocalStorage.enterWith", "asyncLocalStorage.disable"], "status": "partial", "evidence": ["tests/corpus/2213-async-local-storage.cjs"] }, - { "symbols": ["StringDecoder", "stringDecoder.write", "stringDecoder.end"], "status": "partial", "evidence": ["tests/corpus/1662-string-decoder-encodings.ts", "tests/corpus/node24-string-decoder.ts"] }, + { "symbols": ["StringDecoder", "stringDecoder.write", "stringDecoder.end"], "status": "partial", "evidence": ["tests/corpus/1662-string-decoder-encodings.ts", "tests/corpus/node24-string-decoder.ts", "tests/corpus/5882-string-decoder-runtime-encoding.ts"] }, { "symbols": ["setImmediate", "setInterval", "setTimeout", "clearImmediate", "clearInterval", "clearTimeout", "timersPromises.setTimeout", "timersPromises.setImmediate", "timersPromises.setInterval", "immediate.hasRef", "immediate.ref", "immediate.unref", "timeout.hasRef", "timeout.ref", "timeout.unref", "timeout.refresh"], "status": "partial", "evidence": ["tests/corpus/1804-timers-module.ts", "tests/corpus/1805-timer-callback-args.ts", "tests/corpus/2093-timers-promises.ts", "tests/corpus/2852-timers-promises-interval.ts"] }, { "symbols": ["stream.finished", "stream.pipeline", "stream.getDefaultHighWaterMark", "readable.push", "readable.unshift", "readable.read", "readable.pause", "readable.resume", "readable.isPaused", "readable.setEncoding", "readable.pipe", "readable.unpipe", "readable.destroy", "writable.write", "writable.end", "writable.cork", "writable.uncork", "writable.setDefaultEncoding"], "status": "partial", "evidence": ["tests/corpus/1685-stream-readable-basics.ts", "tests/corpus/1688-stream-writable-basics.ts", "tests/corpus/1814-stream-pipeline.cjs", "tests/corpus/5302-stream-promises-options.ts", "tests/corpus/5303-stream-finished-callback-opts.cjs", "tests/corpus/5425-pipeline-generator-stage.ts", "tests/corpus/5428-pipeline-generator-stages.cjs", "tests/corpus/5617-pipeline-function-ends.ts", "tests/corpus/5619-pipeline-function-ends.cjs"] }, { "symbols": ["net.createServer", "net.connect", "net.createConnection", "net.getDefaultAutoSelectFamilyAttemptTimeout", "net.setDefaultAutoSelectFamilyAttemptTimeout", "server.address", "server.close", "server.listen", "socket.destroy", "socket.end", "socket.pause", "socket.resume", "socket.setEncoding", "socket.setTimeout", "socket.write"], "status": "partial", "evidence": ["tests/corpus/2500-net-autosel-timeout.ts", "tests/corpus/2596-net-arg-ladders.cjs"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 0b9f7867b..a56aeaf1d 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -2109,6 +2109,8 @@ declare module "os" { export function version(): string; export function endianness(): "BE" | "LE"; export function getPriority(pid?: number): number; + export function setPriority(priority: number): void; + export function setPriority(pid: number, priority: number): void; /* The TARGET platform's null device ("\\\\.\\nul" under a win32 triple). */ export const devNull: string; /* The platform's constants: null-prototype objects with read-only @@ -3618,7 +3620,8 @@ declare module "querystring" { | string | number | boolean - | ReadonlyArray + | bigint + | ReadonlyArray | null | undefined; } diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 02b882353..6260a1992 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -188,6 +188,7 @@ export const LIB_FN_SYMS: Record = { "os.uptime": "scr_os_uptime", "os.loadavg": "scr_os_loadavg", "os.getPriority": "scr_os_get_priority", + "os.setPriority": "scr_os_set_priority", "os.cpusTake": "scr_os_cpus_take", "os.cpusModel": "scr_os_cpus_model", "os.cpusField": "scr_os_cpus_field", @@ -477,6 +478,7 @@ export const LIB_FN_SYMS: Record = { "strdec.write": "scr_strdec_write", "strdec.next": "scr_strdec_next", "strdec.end": "scr_strdec_end", + "strdec.encoding": "scr_strdec_encoding", "stats.isFile": "scr_stats_is_file", "stats.isDirectory": "scr_stats_is_dir", "stats.isSymbolicLink": "scr_stats_is_symlink", diff --git a/packages/compiler/src/backend/target-diagnostics.ts b/packages/compiler/src/backend/target-diagnostics.ts index 65d954fb5..365d5e913 100644 --- a/packages/compiler/src/backend/target-diagnostics.ts +++ b/packages/compiler/src/backend/target-diagnostics.ts @@ -129,6 +129,7 @@ const WASI_UNAVAILABLE_HOST_FACTS: ReadonlyMap = new Map([ ["os.loadavg", "system load averages (WASI Preview 1 has no load API)"], ["os.uptime", "system uptime (WASI Preview 1 has no boot-time API)"], ["os.getPriority", "process scheduling priority (WASI Preview 1 has no priority API)"], + ["os.setPriority", "process scheduling priority (WASI Preview 1 has no priority API)"], ["process.memoryUsageTake", "process memory statistics (WASI Preview 1 has no memory API)"], ["process.rss", "process memory statistics (WASI Preview 1 has no memory API)"], ["process.ppid", "the parent process id (WASI Preview 1 has no process API)"], diff --git a/packages/compiler/src/frontend/lowering/builtins/module-calls.ts b/packages/compiler/src/frontend/lowering/builtins/module-calls.ts index dc141045f..58ac85aba 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-calls.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-calls.ts @@ -40,6 +40,7 @@ import { lowerForkCall } from "./child-process.js"; import { lowerOsCpusCall, lowerOsGetPriorityCall, + lowerOsSetPriorityCall, lowerOsNetworkInterfacesCall, lowerOsUserInfoCall, lowerPathFormatCall, @@ -163,6 +164,9 @@ export function lowerBuiltinModuleCall( if (bi.module === "os" && bi.member === "cpus") { return lowerOsCpusCall(lowerer, expr, loc); } + if (bi.module === "os" && bi.member === "setPriority") { + return lowerOsSetPriorityCall(lowerer, expr, loc); + } if (bi.module === "os" && bi.member === "getPriority") { return lowerOsGetPriorityCall(lowerer, expr, loc); } diff --git a/packages/compiler/src/frontend/lowering/builtins/operating-system.ts b/packages/compiler/src/frontend/lowering/builtins/operating-system.ts index 051981f09..b88b97eb6 100644 --- a/packages/compiler/src/frontend/lowering/builtins/operating-system.ts +++ b/packages/compiler/src/frontend/lowering/builtins/operating-system.ts @@ -10,6 +10,7 @@ import { STRING, type SrcLoc, UNDEFINED_T, + VOID, arrayOf, typeKey, } from "../../../ir/ir.js"; @@ -511,6 +512,29 @@ export function lowerPathFormatCall( return { kind: "call", callee: helper, args: [value], type: STRING, loc }; } +/** `os.setPriority([pid, ]priority)` — the one-argument form is pid 0 + * (Node's `if (priority === undefined) { priority = pid; pid = 0; }`); + * the runtime validates both. */ +export function lowerOsSetPriorityCall( + lowerer: Lowerer, + call: ts.CallExpression, + loc: SrcLoc, +): IrExpr { + const args = call.arguments; + if (args.length < 1 || args.length > 2 || args.some(ts.isSpreadElement)) { + lowerer.noLowering( + "setPriority with these arguments", + call, + "setPriority(priority) or setPriority(pid, priority) takes numbers", + ); + } + const [pid, priority] = + args.length === 1 + ? [numLit(0, loc), lowerer.lowerExprExpecting(args[0]!, F64)] + : [lowerer.lowerExprExpecting(args[0]!, F64), lowerer.lowerExprExpecting(args[1]!, F64)]; + return { kind: "libCall", fn: "os.setPriority", args: [pid, priority], type: VOID, loc }; +} + /** `os.getPriority(pid?)` — an omitted or undefined pid is 0 (Node's * `if (pid === undefined) pid = 0`); the runtime validates the rest. */ export function lowerOsGetPriorityCall( diff --git a/packages/compiler/src/frontend/lowering/builtins/url.ts b/packages/compiler/src/frontend/lowering/builtins/url.ts index 6e3beb9c2..daf857650 100644 --- a/packages/compiler/src/frontend/lowering/builtins/url.ts +++ b/packages/compiler/src/frontend/lowering/builtins/url.ts @@ -26,6 +26,7 @@ import { } from "../../../ir/ir.js"; import { optionalStringTags } from "./arguments.js"; import { type BuiltinModuleFn } from "../surfaces.js"; +import { lowerDynDispatchMethodCall } from "../lower-calls.js"; /** URL component assignment captures its receiver and RHS once, and yields * the original RHS after the setter performs string conversion. */ @@ -255,10 +256,12 @@ export function lowerSearchParamsNew( return { kind: "libCall", fn: "sp.fromPairs", args: [init], type: SEARCH_PARAMS_T, loc }; } if (init.type.kind === "array" && init.type.elem.kind === "record") { + const pairs = searchParamsFromTuples(lowerer, init, init.type.elem, loc); + if (pairs) return pairs; lowerer.unsupported( "SC1090", arg, - "URLSearchParams from tuple-typed pairs (type the pairs as string[][] — the tuple rows have a different layout)", + "URLSearchParams from tuple rows other than [string, string] (type the pairs as [string, string][] or string[][])", ); } lowerer.unsupported( @@ -268,6 +271,97 @@ export function lowerSearchParamsNew( ); } +/** `new URLSearchParams(pairs)` over a `[string, string][]` (an + * Object.entries result, for example): a helper per tuple shape appends + * each pair's name and value in array order. Null for other row types. */ +function searchParamsFromTuples( + lowerer: Lowerer, + init: IrExpr, + row: IrType & { kind: "record" }, + loc: SrcLoc, +): IrExpr | null { + const shape = lowerer.shapes.get(row.shapeId); + if ( + !shape?.tuple || + shape.fields.length !== 2 || + !shape.fields.every( + (field) => (field.name === "0" || field.name === "1") && field.type.kind === "string", + ) + ) + return null; + const key = `sp.fromTuples:${row.shapeId}`; + let helper = lowerer.valueHelpers.get(key); + if (!helper) { + helper = `%sp.fromTuples.${lowerer.valueHelpers.size}`; + lowerer.valueHelpers.set(key, helper); + const pairsT = init.type; + const sp = (): IrExpr => varRef("sp.0", SEARCH_PARAMS_T, loc); + const pair = (): IrExpr => varRef("pair.0", row, loc); + const field = (name: "0" | "1"): IrExpr => ({ + kind: "recordGet", + obj: pair(), + shapeId: row.shapeId, + field: name, + type: STRING, + loc, + }); + const body: IrStmt[] = [ + { + kind: "varDecl", + localId: "sp.0", + init: { kind: "libCall", fn: "sp.new", args: [], type: SEARCH_PARAMS_T, loc }, + loc, + }, + countedFor( + loc, + { + kind: "arrIntrinsic", + method: "length", + receiver: varRef("pairs.0", pairsT, loc), + args: [], + type: F64, + loc, + }, + (index) => [ + { + kind: "varDecl", + localId: "pair.0", + init: { kind: "arrayGet", arr: varRef("pairs.0", pairsT, loc), index, type: row, loc }, + loc, + }, + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "sp.append", + args: [sp(), field("0"), field("1")], + type: VOID, + loc, + }, + loc, + }, + ], + ), + { kind: "return", value: sp(), loc }, + ]; + const fn: IrFunction = { + name: helper, + params: [{ localId: "pairs.0", name: "pairs", type: pairsT }], + returnType: SEARCH_PARAMS_T, + locals: [ + { id: "pairs.0", name: "pairs", type: pairsT, mutable: false }, + { id: "sp.0", name: "sp", type: SEARCH_PARAMS_T, mutable: false }, + { id: "i.0", name: "i", type: F64, mutable: true }, + { id: "pair.0", name: "pair", type: row, mutable: false }, + ], + body, + loc, + }; + lowerer.liftedFns.push(fn); + } + return { kind: "call", callee: helper, args: [init], type: SEARCH_PARAMS_T, loc }; +} + function lowerOptionalStringSearchParams( lowerer: Lowerer, init: IrExpr, @@ -534,12 +628,14 @@ export function lowerSearchParamsMethodCall( if (name === "forEach" && args.length === 1) { return lowerSpForEachCall(lowerer, call, access); } - if (name === "keys" || name === "values" || name === "entries") { - lowerer.unsupported( - "SC1090", - call, - `URLSearchParams iterator objects outside a for-of head (write \`for (const x of sp.${name}())\` directly)`, - ); + if ((name === "keys" || name === "values" || name === "entries") && args.length === 0) { + // Outside a for-of head the iterator is a live object: the checked- + // dynamic view's iterator walks the pair list by index + // (scr_native_sp_step), so entries appended after it was created are + // visited, as in Node. + const boxed = lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN); + const iterator = lowerDynDispatchMethodCall(lowerer, call, access, boxed, false); + if (iterator) return iterator; } lowerer.noLowering( `URLSearchParams.${name}`, @@ -751,3 +847,21 @@ export function lowerLegacyUrlCall( } return { kind: "libCall", fn: fn.fn, args, type: fn.result, loc }; } + +/** A URLSearchParams value, or a keys()/values()/entries() call on one: an + * iterable whose checked-dynamic view walks the live pair list. */ +export function isSearchParamsIterable(lowerer: Lowerer, node: ts.Expression): boolean { + while (ts.isParenthesizedExpression(node)) node = node.expression; + if (lowerer.mapTypeOf(lowerer.typeOf(node))?.kind === "searchParams") return true; + if ( + !ts.isCallExpression(node) || + node.arguments.length !== 0 || + !ts.isPropertyAccessExpression(node.expression) + ) + return false; + const name = node.expression.name.text; + return ( + (name === "keys" || name === "values" || name === "entries") && + lowerer.mapTypeOf(lowerer.typeOf(node.expression.expression))?.kind === "searchParams" + ); +} diff --git a/packages/compiler/src/frontend/lowering/containers/array-construction.ts b/packages/compiler/src/frontend/lowering/containers/array-construction.ts index 88c542ec0..015cb2123 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-construction.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-construction.ts @@ -1004,6 +1004,10 @@ export function lowerArrayFromCall( if (src.type.kind === "dyn" && args.length === 1) { return lowerCheckedArrayFrom(lowerer, src, loc); } + // Array.from(sp): the checked-dynamic view's live pair iteration. + if (src.type.kind === "searchParams" && args.length === 1) { + return lowerCheckedArrayFrom(lowerer, lowerer.coerceInto(args[0]!, src, DYN), loc); + } // A generator (or an iterator adapted into one) drains in order. if (src.type.kind === "generator" && args.length === 1) { const arrT = lowerer.mapTypeOf(lowerer.typeOf(call)); diff --git a/packages/compiler/src/frontend/lowering/containers/collection-methods.ts b/packages/compiler/src/frontend/lowering/containers/collection-methods.ts index d9bf8bcd4..8c8349c0b 100644 --- a/packages/compiler/src/frontend/lowering/containers/collection-methods.ts +++ b/packages/compiler/src/frontend/lowering/containers/collection-methods.ts @@ -41,6 +41,7 @@ import { } from "../collection-ingestion.js"; import { strCharsCall } from "./array-construction.js"; import { arrayElementRead } from "./array-iteration.js"; +import { isSearchParamsIterable } from "../builtins/url.js"; /** Ambient Map method calls. `get`/`set`/`has`/`delete`/`clear` lower to * mapIntrinsic; `forEach` desugars to a direct call of a synthetic loop @@ -1173,6 +1174,11 @@ export function lowerMapSeedNew( mapT, ); } + // new Map(sp) / new Map(sp.entries()): the checked-dynamic view's live + // pairs seed the map in order. + if (isSearchParamsIterable(lowerer, argNode)) { + return mapFromSeedValue(lowerer, lowerer.lowerExprExpecting(argNode, DYN), mapT); + } const input = collectionInput(lowerer, argNode); if (input) { if (!collectionDestinationMatches(lowerer, input, mapT)) return null; diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index aa8a7ef59..18ac9efbb 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -74,7 +74,7 @@ import { isAssertClassNew } from "./assert-instances.js"; import { lowerArrayConstructor } from "./containers/array-construction.js"; import { lowerMapSeedNew, lowerSetSeedNew } from "./containers/collection-methods.js"; import { lowerObjectConstructor } from "./containers/indexed-objects.js"; -import { bufEncoding } from "./containers/bytes.js"; +import { knownBufEncoding } from "./containers/bytes.js"; import { isSafeToRepeat } from "./expressions/evaluation-safety.js"; import { lowerSearchParamsNew } from "./builtins/url.js"; import { lowerTextCodecNew } from "./builtins/text-codecs.js"; @@ -8905,24 +8905,41 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { ); } // `new StringDecoder(encoding?)` (node:string_decoder): the decoder - // is a two-field record — the CANONICAL encoding name (aliases fold - // at compile time, exactly what `.encoding` answers in Node) and - // the packed-f64 pending state starting at 0 (nothing buffered). - // The encoding must be a literal (Node's alias set); omitted means - // utf8, Node's default. + // is a two-field record — the CANONICAL encoding name (exactly what + // `.encoding` answers in Node) and the packed-f64 pending state + // starting at 0 (nothing buffered). A literal Buffer encoding folds + // its alias at compile time; any other encoding argument is + // normalized at run time (Node's normalizeEncoding, which throws + // ERR_UNKNOWN_ENCODING for an unknown name). Omitted means utf8, + // Node's default. if (symbol && symbol.name === "StringDecoder" && lowerer.isStdlibSymbol(symbol)) { const args = expr.arguments ?? []; if (args.length > 1) { lowerer.noLowering("new StringDecoder with 2 arguments", expr, undefined, symbol); } - const encName = - args.length === 1 ? bufEncoding(lowerer, "new StringDecoder", args[0]!) : "utf8"; + const encNode = args[0]; + const encT = encNode ? lowerer.typeOf(encNode) : undefined; + const encName = !encNode + ? "utf8" + : encT!.isStringLiteralType() + ? knownBufEncoding(encT!.value) + : undefined; + const encoding: IrExpr = + encName !== undefined + ? { kind: "strLit", value: encName, type: STRING, loc } + : { + kind: "libCall", + fn: "strdec.encoding", + args: [lowerer.lowerExprExpecting(encNode!, DYN)], + type: STRING, + loc, + }; const decT = lowerer.mapTypeOf(lowerer.typeOf(expr)); if (decT?.kind !== "record") lowerer.badType(expr, lowerer.typeOf(expr)); return { kind: "recordLit", fields: [ - { name: "%enc", value: { kind: "strLit", value: encName, type: STRING, loc } }, + { name: "%enc", value: encoding }, { name: "%pending", value: { kind: "numLit", value: 0, type: F64, loc } }, ], type: decT, diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 08e12518b..77676f8f2 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -225,7 +225,7 @@ import { } from "./lower-builtin-values.js"; import { lowerArrayFromValue } from "./containers/array-construction.js"; import { lowerPerfHooksTypeof } from "./builtins/performance.js"; -import { lowerUrlAssignment } from "./builtins/url.js"; +import { isSearchParamsIterable, lowerUrlAssignment } from "./builtins/url.js"; import { jsBindingHasOpenWrites } from "./lower-stmts.js"; import { checkedClassInstanceOf } from "./class-construction.js"; import { lowerModuleNamespaceElement } from "./module-namespace-elements.js"; @@ -5889,6 +5889,11 @@ export function lowerArrayLiteral( const drained = generatorDrain(lowerer, src, type.elem, locOf(el)); if (drained) src = drained; } + // `[...sp]` and `[...sp.entries()]` over a URLSearchParams: its + // checked-dynamic view iterates the live pair list, and the drained + // [name, value] pairs convert to the literal's tuple elements. + const searchParamsSource = isSearchParamsIterable(lowerer, el.expression); + if (src.type.kind === "searchParams") src = lowerer.coerceInto(el.expression, src, DYN); // A native checked iterable can supply scalar elements even when // the checker inferred a typed array from its producer. Drain once // and validate the elements before the ordinary spread copy. @@ -5897,7 +5902,8 @@ export function lowerArrayLiteral( (type.elem.kind === "dyn" || type.elem.kind === "f64" || type.elem.kind === "string" || - type.elem.kind === "bool") + type.elem.kind === "bool" || + searchParamsSource) ) { src = lowerer.coerceInto(el.expression, checkedIteratorPack(lowerer, src, locOf(el)), type); } diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index ec931350a..1a61645e8 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -1485,6 +1485,9 @@ export const BUILTIN_MODULE_FNS: Record< result: F64, valueParams: [{ mode: "optional", type: F64, defaultValue: 0 }], }, + // A one-argument call is setPriority(0, priority) + // (lowerOsSetPriorityCall completes it). + setPriority: { fn: "os.setPriority", params: [F64, F64], result: VOID }, // Special-cased (lowerOsCpusCall): the call site's CpuInfo[] assembles // from one uv_cpu_info snapshot. cpus: { fn: "os.cpusTake", params: [], result: VOID }, diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index bd87a470d..b4155e85c 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -34,6 +34,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "cp.spawnDynamic", "child.onDyn", "text.decoderEncoding", + "strdec.encoding", "dyn.construct", "dyn.reflectApply", "dyn.reflectGet", @@ -555,6 +556,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "dyn.arrayProtoCall", "process.chdir", "os.getPriority", + "os.setPriority", // Pattern length TypeError, brace-sequence RangeError, and the // SyntaxError of a segment regex invalid under the u flag. "path.matchesGlob", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 612916a59..0b85d4bd5 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -549,6 +549,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ /** os.getPriority(pid): validateInt32 (RangeError ERR_OUT_OF_RANGE), * then the priority; a failure throws Node's SystemError. */ "os.getPriority": { argTypes: [F64], result: F64 }, + /** os.setPriority(pid, priority): validateInt32 for both (priority in + * -20..19, RangeError ERR_OUT_OF_RANGE), then the priority; a failure + * throws Node's SystemError. */ + "os.setPriority": { argTypes: [F64, F64], result: VOID }, /** os.cpus(): cpusTake snapshots every CPU and answers the count; * cpusModel(i) and cpusField(i, k) (k: 0 speed, 1 user, 2 nice, 3 sys, * 4 idle, 5 irq) read the snapshot. Never throw. */ @@ -3784,6 +3788,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "strdec.write": { argTypes: [STRING, F64, BYTES_U8], result: STRING }, "strdec.next": { argTypes: [STRING, F64, BYTES_U8], result: F64 }, "strdec.end": { argTypes: [STRING, F64], result: STRING }, + /** A runtime encoding argument's canonical name (Node's normalizeEncoding: + * nullish and "" are utf8); an unknown name throws ERR_UNKNOWN_ENCODING. */ + "strdec.encoding": { argTypes: [DYN], result: STRING }, // node:readline: the interface handle is f64; the callbacks' func types // are program-dependent (the emitter picks the adapter by parameter // count), so those slots are null like child.onExit's. diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index af481ee53..3f8ae9482 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -1512,6 +1512,12 @@ "name": "os.release", "status": "static" }, + { + "id": "node-builtin.os.setPriority", + "kind": "node-builtin", + "name": "os.setPriority", + "status": "static" + }, { "id": "node-builtin.os.tmpdir", "kind": "node-builtin", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5833-url-search-params-iterators.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5833-url-search-params-iterators.ts.json new file mode 100644 index 000000000..b1626d547 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5833-url-search-params-iterators.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5833-url-search-params-iterators.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5834-url-search-params-iterators-dynamic.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5834-url-search-params-iterators-dynamic.mjs.json new file mode 100644 index 000000000..3a60dda60 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5834-url-search-params-iterators-dynamic.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5834-url-search-params-iterators-dynamic.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5836-url-search-params-tuple-pairs.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5836-url-search-params-tuple-pairs.ts.json new file mode 100644 index 000000000..20a6b62bf --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5836-url-search-params-tuple-pairs.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5836-url-search-params-tuple-pairs.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5838-qs-stringify-bigint.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5838-qs-stringify-bigint.ts.json new file mode 100644 index 000000000..0c1b09788 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5838-qs-stringify-bigint.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5838-qs-stringify-bigint.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5882-string-decoder-runtime-encoding.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5882-string-decoder-runtime-encoding.ts.json new file mode 100644 index 000000000..29b8b2759 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5882-string-decoder-runtime-encoding.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5882-string-decoder-runtime-encoding.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5883-os-set-priority.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5883-os-set-priority.ts.json new file mode 100644 index 000000000..5be1d2b3c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5883-os-set-priority.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5883-os-set-priority.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index e0fb55464..b55bcd591 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -2457,6 +2457,22 @@ static ScrStr *scr_bytes_normalize_encoding(const ScrStr *raw) { return NULL; } +/* new StringDecoder(encoding) with an encoding known only at run time: + * Node's normalizeEncoding. undefined, null and "" are utf8; a Buffer + * encoding name in any ASCII case answers its canonical name (+1); any + * other string throws ERR_UNKNOWN_ENCODING (NULL). Encodings that are not + * strings have no lowering. */ +ScrStr *scr_strdec_encoding(const ScrDyn *enc) { + if (enc->kind == SCR_DYN_UNDEF || enc->kind == SCR_DYN_NULL) return scr_str_new("utf8", 4); + if (enc->kind != SCR_DYN_STR) { + static const char message[] = "new StringDecoder with an encoding that is not a string has no lowering"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); + return NULL; + } + if (enc->v.str->len == 0) return scr_str_new("utf8", 4); + return scr_bytes_normalize_encoding(enc->v.str); +} + ScrStr *scr_bytes_to_str_checked(const ScrBytes *b, const ScrStr *enc) { /* Node returns before resolving the encoding when there are no bytes * to decode, so even an unknown runtime name answers the empty string. */ diff --git a/packages/runtime/src/scr_bytes.h b/packages/runtime/src/scr_bytes.h index b56f9477d..766c24514 100644 --- a/packages/runtime/src/scr_bytes.h +++ b/packages/runtime/src/scr_bytes.h @@ -119,6 +119,7 @@ double scr_bytes_to_u8_clamp(double value); ScrStr *scr_strdec_write(const ScrStr *enc, double pending, const ScrBytes *chunk); double scr_strdec_next(const ScrStr *enc, double pending, const ScrBytes *chunk); ScrStr *scr_strdec_end(const ScrStr *enc, double pending); +ScrStr *scr_strdec_encoding(const ScrDyn *enc); /* +1, or NULL with ERR_UNKNOWN_ENCODING pending */ /* `new Uint8Array(n)` / Buffer.alloc(n): zero-filled. n goes through * ToIndex like JS (NaN → 0, truncate toward zero; negative or > 2^53-1 diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 62f55e9aa..aaebf48bb 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1449,6 +1449,8 @@ ScrDyn *scr_dyn_iter_pack(const ScrDyn *src, const ScrStr *msg) { return scr_dyn_not_iterable(src, msg); } +static ScrDyn *scr_native_iterator_drain(const ScrDyn *src); + /* The for-of-over-dyn pack accessors: the emitted index loop drives them * over a scr_dyn_iter_pack result (ARR by construction — the defensive * arms cover nothing reachable from that lowering). Never throw. */ @@ -1463,6 +1465,13 @@ ScrDyn *scr_dyn_map_seed_entries(const ScrDyn *src) { scr_dyn_release(view); if (scr_exc_pending()) return NULL; } + /* A native iterator (sp.entries(), a Map's entries()) or a handle that + * steps through live entries (URLSearchParams): producing its entries + * runs no program code, so draining them first is what the consumer + * observes. */ + if (src->kind == SCR_DYN_HANDLE && + (src->v.handle.tag == SCR_DYNH_ITERATOR || scr_dyn_handle_ops_of(src)->iter_step)) + return scr_native_iterator_drain(src); if (src->kind == SCR_DYN_HANDLE || src->kind == SCR_DYN_TYPED_REF) { static const char message[] = "new Map(entries) over native non-array iterables has no lowering"; scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); @@ -4554,6 +4563,33 @@ ScrDyn *scr_dyn_native_handle_iterator(ScrDyn *source, unsigned selection) { return scr_native_collection_iterator(source, selection); } +/* The values a native iterator (or a live-stepping handle's entries + * iterator) produces from its current position, into a fresh array; NULL + * with the exception pending. */ +static ScrDyn *scr_native_iterator_drain(const ScrDyn *src) { + ScrDyn *iterator = src->v.handle.tag == SCR_DYNH_ITERATOR + ? scr_dyn_retain((ScrDyn *)src) + : scr_dyn_native_handle_iterator((ScrDyn *)src, 2); + ScrDyn *out = scr_dyn_new_arr(); + for (;;) { + ScrDyn *step = scr_native_iterator_next(iterator->v.handle.ptr); + if (!step) { + scr_dyn_release(out); + out = NULL; + break; + } + bool done = scr_dyn_truthy(scr_dyn_obj_get(step, "done", 4)); + if (!done) { + const ScrDyn *value = scr_dyn_obj_get(step, "value", 5); + scr_dyn_arr_push(out, scr_dyn_retain((ScrDyn *)(value ? value : scr_dyn_undefined()))); + } + scr_dyn_release(step); + if (done) break; + } + scr_dyn_release(iterator); + return out; +} + static ScrDyn *scr_builtin_iterator_checked(int kind) { ScrDyn *self = scr_dyn_this_get(); ScrDyn *result = NULL; diff --git a/packages/runtime/src/scr_os.c b/packages/runtime/src/scr_os.c index 0bc50fb3f..76f69588e 100644 --- a/packages/runtime/src/scr_os.c +++ b/packages/runtime/src/scr_os.c @@ -296,23 +296,27 @@ static void scr_os_system_error(const char *syscall, int uv_code) { if (cell->kind == SCR_EXC_OBJ) scr_error_set_code((ScrError *)cell->payload, "ERR_SYSTEM_ERROR"); } -static bool scr_os_validate_int32(const char *name, double value) { +static bool scr_os_validate_int32_in(const char *name, double value, int min, int max) { if (isfinite(value) && trunc(value) == value) { - if (value >= -2147483648.0 && value <= 2147483647.0) return true; + if (value >= (double)min && value <= (double)max) return true; } char received[48]; scr_num_received(value, received); char text[192]; int n = isfinite(value) && trunc(value) == value ? snprintf(text, sizeof text, - "The value of \"%s\" is out of range. It must be >= -2147483648 && <= 2147483647. Received %s", - name, received) + "The value of \"%s\" is out of range. It must be >= %d && <= %d. Received %s", + name, min, max, received) : snprintf(text, sizeof text, "The value of \"%s\" is out of range. It must be an integer. Received %s", name, received); scr_throw_error_msg_code(SCR_ERR_RANGE, text, n < 0 ? 0 : (size_t)n, "ERR_OUT_OF_RANGE"); return false; } +static bool scr_os_validate_int32(const char *name, double value) { + return scr_os_validate_int32_in(name, value, INT32_MIN, INT32_MAX); +} + double scr_os_get_priority(double pid) { if (!scr_os_validate_int32("pid", pid)) return 0; #ifdef _WIN32 @@ -351,6 +355,48 @@ double scr_os_get_priority(double pid) { #endif } +/* ── setPriority ────────────────────────────────────────────────────── + * validateInt32(pid, 'pid') and validateInt32(priority, 'priority', -20, + * 19) (a one-argument call passes pid 0), then uv_os_setpriority; a + * failure is Node's ERR_SYSTEM_ERROR. */ + +void scr_os_set_priority(double pid, double priority) { + if (!scr_os_validate_int32("pid", pid)) return; + if (!scr_os_validate_int32_in("priority", priority, SCR_OS_PRIORITY_HIGHEST, SCR_OS_PRIORITY_LOW)) return; + int value = (int)priority; +#ifdef _WIN32 + /* libuv's mapping of nice values to Windows priority classes. */ + DWORD klass = value < SCR_OS_PRIORITY_HIGH ? REALTIME_PRIORITY_CLASS + : value < SCR_OS_PRIORITY_ABOVE_NORMAL ? HIGH_PRIORITY_CLASS + : value < SCR_OS_PRIORITY_NORMAL ? ABOVE_NORMAL_PRIORITY_CLASS + : value < SCR_OS_PRIORITY_BELOW_NORMAL ? NORMAL_PRIORITY_CLASS + : value < SCR_OS_PRIORITY_LOW ? BELOW_NORMAL_PRIORITY_CLASS + : IDLE_PRIORITY_CLASS; + HANDLE handle = pid == 0 ? GetCurrentProcess() + : OpenProcess(PROCESS_SET_INFORMATION, FALSE, (DWORD)(int)pid); + if (handle == NULL) { + DWORD err = GetLastError(); + scr_os_system_error("uv_os_setpriority", err == ERROR_ACCESS_DENIED ? SCR_NODE_UV__EPERM + : err == ERROR_INVALID_PARAMETER ? SCR_NODE_UV__EINVAL + : SCR_NODE_UV__UNKNOWN); + return; + } + BOOL ok = SetPriorityClass(handle, klass); + DWORD err = ok ? 0 : GetLastError(); + if (pid != 0) CloseHandle(handle); + if (!ok) { + scr_os_system_error("uv_os_setpriority", err == ERROR_ACCESS_DENIED ? SCR_NODE_UV__EPERM + : SCR_NODE_UV__UNKNOWN); + } +#elif defined(__wasi__) + (void)value; + scr_os_system_error("uv_os_setpriority", SCR_NODE_UV__ENOSYS); +#else + if (setpriority(PRIO_PROCESS, (id_t)(int)pid, value) != 0) + scr_os_system_error("uv_os_setpriority", SCR_NODE_UV__ERR(errno)); +#endif +} + /* ── cpus ───────────────────────────────────────────────────────────── * uv_cpu_info, snapshotted once per os.cpus() call: scr_os_cpus_take * reads every CPU and answers the count; the accessors read that diff --git a/packages/runtime/src/scr_os.h b/packages/runtime/src/scr_os.h index b40a8027a..3c5009fc5 100644 --- a/packages/runtime/src/scr_os.h +++ b/packages/runtime/src/scr_os.h @@ -27,6 +27,10 @@ ScrArr *scr_os_loadavg(void); /* os.getPriority(pid): validateInt32, then the scheduling priority; * failures throw Node's RangeError or SystemError (ERR_SYSTEM_ERROR). */ double scr_os_get_priority(double pid); +/* os.setPriority(pid, priority): validateInt32 for both (priority within + * -20..19), then the scheduling priority; failures throw Node's RangeError + * or SystemError (ERR_SYSTEM_ERROR). */ +void scr_os_set_priority(double pid, double priority); /* os.cpus(): take answers the CPU count of a fresh snapshot; model and * field (0 speed, 1 user, 2 nice, 3 sys, 4 idle, 5 irq) read it. */ double scr_os_cpus_take(void); diff --git a/packages/runtime/src/scr_qs.c b/packages/runtime/src/scr_qs.c index a61f95d94..1b110ba0d 100644 --- a/packages/runtime/src/scr_qs.c +++ b/packages/runtime/src/scr_qs.c @@ -478,8 +478,8 @@ ScrDyn *scr_qs_parse_dyn(const ScrStr *qs) { /* ── stringify ───────────────────────────────────────────────────────── */ /* Node's encodeStringified over one dyn value: strings escape, finite - * numbers render then escape, booleans are bare, everything else is the - * empty value. Appends to b. */ + * numbers render then escape, bigints and booleans are bare, everything + * else is the empty value. Appends to b. */ static void qs_stringify_value(QsBuf *b, const ScrDyn *v) { switch (v->kind) { case SCR_DYN_STR: { @@ -497,12 +497,18 @@ static void qs_stringify_value(QsBuf *b, const ScrDyn *v) { scr_str_release(num); return; } + case SCR_DYN_BIGINT: { + ScrStr *text = scr_bigint_to_string(v->v.bigint, 10); + qb_append_str(b, text); + scr_str_release(text); + return; + } case SCR_DYN_BOOL: if (v->v.b) qb_append(b, "true", 4); else qb_append(b, "false", 5); return; default: - return; /* null/undefined/objects/arrays/functions → '' */ + return; /* null/undefined/symbols/objects/arrays/functions → '' */ } } diff --git a/packages/runtime/src/scr_url.c b/packages/runtime/src/scr_url.c index b6fdb9cd6..eeadba98f 100644 --- a/packages/runtime/src/scr_url.c +++ b/packages/runtime/src/scr_url.c @@ -1686,9 +1686,10 @@ static ScrDyn *scr_native_sp_step(void *ptr, double *index, unsigned selection) } else value = scr_dyn_new_str(selection == 1 ? key : text); scr_str_release(key); scr_str_release(text); } + /* { value, done }, in the iterator result's own key order. */ ScrDyn *result = scr_dyn_new_obj(); - scr_dyn_obj_set(result, "done", 4, scr_dyn_new_bool(done)); scr_dyn_obj_set(result, "value", 5, value); + scr_dyn_obj_set(result, "done", 4, scr_dyn_new_bool(done)); return result; } diff --git a/tests/corpus/5833-url-search-params-iterators.ts b/tests/corpus/5833-url-search-params-iterators.ts new file mode 100644 index 000000000..eb0b99d33 --- /dev/null +++ b/tests/corpus/5833-url-search-params-iterators.ts @@ -0,0 +1,40 @@ +// URLSearchParams keys(), values() and entries() outside a for-of head: +// a stored iterator steps with next() ({ value, done }), spreads from its +// current position, and walks the live pair list by index, so pairs +// appended after it was created are visited. Spreads, Array.from, Object.fromEntries and +// new Map over the params or their iterators read the same pairs. +const sp = new URLSearchParams("b=2&a=1&a=3&c=%20x"); + +const keys = sp.keys(); +console.log(JSON.stringify(keys.next()), JSON.stringify(keys.next())); +sp.append("d", "4"); +console.log(JSON.stringify([...keys])); +console.log(JSON.stringify(keys.next())); + +console.log(JSON.stringify([...sp])); +console.log(JSON.stringify([...sp.keys()])); +console.log(JSON.stringify([...sp.values()])); +console.log(JSON.stringify([...sp.entries()])); +console.log(JSON.stringify(Array.from(sp))); +console.log(JSON.stringify(Array.from(sp.entries()))); +console.log(JSON.stringify(Array.from(sp.values()))); +console.log(JSON.stringify(Object.fromEntries(sp))); +console.log(JSON.stringify(Object.fromEntries(sp.entries()))); +console.log(JSON.stringify([...new Map(sp)])); +console.log(JSON.stringify([...new Map(sp.entries())])); + +const values = sp.values(); +const seen: string[] = []; +for (const v of values) { + seen.push(v); + if (v === "1") sp.delete("b"); +} +console.log(JSON.stringify(seen), sp.toString()); + +const entries = new URL("https://h.example/p?x=1&y=2&x=3").searchParams.entries(); +const pairs: string[] = []; +for (const [k, v] of entries) pairs.push(`${k}:${v}`); +console.log(pairs.join(" ")); + +const empty = new URLSearchParams().entries(); +console.log(JSON.stringify(empty.next()), JSON.stringify([...empty])); diff --git a/tests/corpus/5834-url-search-params-iterators-dynamic.mjs b/tests/corpus/5834-url-search-params-iterators-dynamic.mjs new file mode 100644 index 000000000..82b0c6d28 --- /dev/null +++ b/tests/corpus/5834-url-search-params-iterators-dynamic.mjs @@ -0,0 +1,22 @@ +// URLSearchParams iterators in a checked-dynamic program: next() results, +// live iteration after append and delete, and the consumers (spread, +// Array.from with and without a mapper, Object.fromEntries, new Map) over +// the params and each projection. +const sp = new URLSearchParams("b=2&a=1&a=3"); +const it = sp.keys(); +console.log(it.next()); +sp.append("c", "4"); +console.log(JSON.stringify([...it]), it.next()); +console.log(JSON.stringify([...sp.values()]), JSON.stringify(Array.from(sp.entries()))); +console.log(JSON.stringify(Array.from(sp.keys(), (k) => k.toUpperCase()))); +console.log(JSON.stringify(Object.fromEntries(sp.entries())), JSON.stringify(Object.fromEntries(sp))); +console.log(JSON.stringify([...new Map(sp.entries())]), new Map(sp).size); +const values = sp.values(); +const seen = []; +let step = values.next(); +while (!step.done) { + seen.push(step.value); + if (step.value === "2") sp.delete("a"); + step = values.next(); +} +console.log(JSON.stringify(seen), sp.toString()); diff --git a/tests/corpus/5836-url-search-params-tuple-pairs.ts b/tests/corpus/5836-url-search-params-tuple-pairs.ts new file mode 100644 index 000000000..d6fe1a86a --- /dev/null +++ b/tests/corpus/5836-url-search-params-tuple-pairs.ts @@ -0,0 +1,34 @@ +// new URLSearchParams(pairs) over [string, string] tuple rows, such as an +// Object.entries result: each pair appends its name and value in array +// order, so repeated names keep every value and an empty array gives empty +// params. The params are then as mutable as any other. +const record: Record = { a: "1", "b c": "x&y", é: "ü" }; +const fromEntries = new URLSearchParams(Object.entries(record)); +console.log(fromEntries.toString(), fromEntries.size); + +const pairs: [string, string][] = [ + ["k", "v"], + ["k", "w"], + ["", ""], + ["plus", "a+b c"], +]; +const repeated = new URLSearchParams(pairs); +console.log(repeated.toString(), JSON.stringify(repeated.getAll("k"))); + +const none: [string, string][] = []; +const empty = new URLSearchParams(none); +console.log(JSON.stringify(empty.toString()), empty.size); + +const edited = new URLSearchParams(pairs); +edited.append("y", "2"); +edited.delete("k"); +edited.sort(); +console.log(edited.toString(), pairs.length); + +const lone: [string, string][] = [["z", "\uD800x"]]; +console.log(new URLSearchParams(lone).toString()); + +const url = new URL("https://example.test/?q=1"); +for (const [name, value] of new URLSearchParams(Object.entries({ q: "2", r: "3" }))) + url.searchParams.set(name, value); +console.log(url.href); diff --git a/tests/corpus/5838-qs-stringify-bigint.ts b/tests/corpus/5838-qs-stringify-bigint.ts new file mode 100644 index 000000000..cdc668a55 --- /dev/null +++ b/tests/corpus/5838-qs-stringify-bigint.ts @@ -0,0 +1,19 @@ +// querystring.stringify writes a bigint value as its decimal digits, bare +// like a boolean (Node's encodeStringified), in plain and array-valued +// fields and under custom separators. url.format's query object follows +// the same rule. +import { encode, stringify } from "node:querystring"; +import { format } from "node:url"; + +console.log(stringify({ a: 1n, b: -2n, c: 0n })); +console.log(stringify({ big: 12345678901234567890n, neg: -(2n ** 70n) })); +console.log(stringify({ list: [1n, "two", 3, true, -4n] })); +console.log(stringify({ a: 5n, b: [6n, 7n] }, ";", ":")); +console.log(encode({ id: 42n, name: "x y" })); + +const counts: Record = { first: 10n, second: 20n }; +console.log(stringify(counts)); +const mixed: Record = { n: 1n, s: "v", z: null }; +console.log(stringify(mixed)); + +console.log(format({ protocol: "https", host: "example.test", pathname: "/p", query: { id: 99n, tag: ["a", 2n] } })); diff --git a/tests/corpus/5882-string-decoder-runtime-encoding.ts b/tests/corpus/5882-string-decoder-runtime-encoding.ts new file mode 100644 index 000000000..059d2144f --- /dev/null +++ b/tests/corpus/5882-string-decoder-runtime-encoding.ts @@ -0,0 +1,39 @@ +// new StringDecoder(encoding) with an encoding known only at run time +// normalizes it as Node does: any ASCII case of a Buffer encoding name +// selects that decoder and `.encoding` answers the canonical name +// (ucs2 and utf-16le are utf16le, binary is latin1), undefined and "" +// mean utf8, and an unknown name throws a TypeError with code +// ERR_UNKNOWN_ENCODING. Literal names keep their compile-time form. +import { StringDecoder } from "node:string_decoder"; + +const bytes = Buffer.from([0xe2, 0x82, 0xac, 0x41, 0xc3, 0xa9, 0xff, 0x00]); + +function decodeAll(encoding: string | undefined): string { + const decoder = new StringDecoder(encoding as BufferEncoding | undefined); + const parts: string[] = []; + for (let i = 0; i < bytes.length; i += 3) parts.push(decoder.write(bytes.subarray(i, i + 3))); + parts.push(decoder.end()); + return `${decoder.encoding} ${JSON.stringify(parts)}`; +} + +const names = [ + "utf8", "UTF-8", "Utf8", "hex", "HEX", "base64", "Base64Url", "latin1", "BINARY", + "ascii", "utf16le", "UTF-16LE", "ucs2", "Ucs-2", "", undefined, +]; +for (const name of names) console.log(JSON.stringify(name), decodeAll(name)); + +for (const bad of ["utf-16", "buffer", "utf 8", "latin-1"]) { + try { + new StringDecoder(bad as BufferEncoding); + console.log("no throw", bad); + } catch (error) { + const e = error as Error & { code?: string }; + console.log(e.name, e.code, e.message); + } +} + +const fromOptions: { encoding?: BufferEncoding } = { encoding: "hex" }; +const viaOption = new StringDecoder(fromOptions.encoding); +console.log(viaOption.encoding, viaOption.write(Buffer.from("hi")), viaOption.end(Buffer.from("!"))); +const literal = new StringDecoder("ucs2"); +console.log(literal.encoding, JSON.stringify(literal.write(Buffer.from([0x3d, 0xd8, 0x00, 0xde])))); diff --git a/tests/corpus/5883-os-set-priority.ts b/tests/corpus/5883-os-set-priority.ts new file mode 100644 index 000000000..d87100183 --- /dev/null +++ b/tests/corpus/5883-os-set-priority.ts @@ -0,0 +1,33 @@ +// os.setPriority([pid, ]priority): the one-argument form sets the current +// process, both arguments go through validateInt32 (the priority within +// -20..19, a RangeError with code ERR_OUT_OF_RANGE otherwise), and a +// refused change is a SystemError with code ERR_SYSTEM_ERROR naming +// uv_os_setpriority. Raising the nice value is always allowed; lowering it +// again depends on the privileges of the user running the program. +import * as os from "node:os"; +import { getPriority, setPriority } from "node:os"; + +function attempt(label: string, run: () => void): void { + try { + run(); + console.log(label, "ok", getPriority()); + } catch (error) { + const e = error as Error & { code?: string }; + console.log(label, e.name, e.code, e.message); + } +} + +const start = getPriority(); +attempt("same value", () => setPriority(start)); +attempt("same value with pid 0", () => os.setPriority(0, start)); +attempt("same value with own pid", () => setPriority(process.pid, start)); +attempt("raise", () => setPriority(Math.min(start + 5, 19))); +console.log("raised by 5 or to 19:", getPriority() === Math.min(start + 5, 19)); +attempt("lower again", () => setPriority(start)); +attempt("priority 20", () => setPriority(20)); +attempt("priority -21", () => setPriority(0, -21)); +attempt("priority 1.5", () => setPriority(1.5)); +attempt("priority NaN", () => setPriority(Number.NaN)); +attempt("pid 2 ** 31", () => setPriority(2 ** 31, 0)); +attempt("pid -1.5", () => setPriority(-1.5, 0)); +attempt("missing process", () => setPriority(2147483646, 19)); diff --git a/tests/fixtures/node-types/fenced.ts b/tests/fixtures/node-types/fenced.ts index 3ad6839c8..b884de3ce 100644 --- a/tests/fixtures/node-types/fenced.ts +++ b/tests/fixtures/node-types/fenced.ts @@ -33,10 +33,10 @@ ReadableStream.from(new Set([1, 2])); * typecheck under @types/node and fence with the module-qualified name — * calls and value reads alike. */ import { watchFile } from "fs"; -import { setPriority } from "node:os"; +import { EventEmitter, on } from "node:events"; import { win32 } from "path"; watchFile("x", () => {}); -setPriority(0); +on(new EventEmitter(), "tick"); console.log(win32.sep); /* URL getters and serialization lower under @types/node, but object-URL * registry operations still fence by member name with the supported diff --git a/tests/harness/__snapshots__/node-types-fenced.txt b/tests/harness/__snapshots__/node-types-fenced.txt index dca88df39..29e4a2ee9 100644 --- a/tests/harness/__snapshots__/node-types-fenced.txt +++ b/tests/harness/__snapshots__/node-types-fenced.txt @@ -48,22 +48,22 @@ fenced.ts:38:1 - error SC2020: 'fs.watchFile' is typed by @types/node but has no 37 | import { win32 } from "path"; 38 | watchFile("x", () => {}); | ^~~~~~~~~~~~~~~~~~~~~~~~ - 39 | setPriority(0); + 39 | on(new EventEmitter(), "tick"); hint: the type checker sees everything @types/node declares, but only the supported surface compiles (https://scriptc.dev/limitations) -fenced.ts:39:1 - error SC2020: 'os.setPriority' is typed by @types/node but has no scriptc lowering yet +fenced.ts:39:1 - error SC2020: 'events.on' is typed by @types/node but has no scriptc lowering yet 38 | watchFile("x", () => {}); - 39 | setPriority(0); - | ^~~~~~~~~~~~~~ + 39 | on(new EventEmitter(), "tick"); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 | console.log(win32.sep); hint: the type checker sees everything @types/node declares, but only the supported surface compiles (https://scriptc.dev/limitations) fenced.ts:40:13 - error SC2020: 'PlatformPath.sep' is typed by @types/node but has no scriptc lowering yet - 39 | setPriority(0); + 39 | on(new EventEmitter(), "tick"); 40 | console.log(win32.sep); | ^~~~~~~~~ 41 | /* URL getters and serialization lower under @types/node, but object-URL From 1ad47f1f77fa04a0b7591d14fc9b11a6a4770a78 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 17:58:40 -0500 Subject: [PATCH 013/117] Match Node 24 in util.format, util.types and util.inspect - util.format %d and %i format bigint, symbol, null and undefined arguments - util.format %j prints [Circular] for circular arguments - util.types answers the remaining brand checks - util.inspect prints WeakMap, WeakSet, Date and numeric typed array values as Node does - util.inspect lowers the breakLength, compact and sorted options --- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 118 ++--- .../generated/node-v24-backlog.json | 417 +++++++++++++----- .../generated/node-v24-internal.json | 295 +++++++++++-- internal/compatibility/static-support.json | 6 +- .../ambient/scriptc-node-fallback.d.ts | 16 + .../compiler/src/backend/llvm/expr-async.ts | 13 +- .../compiler/src/backend/llvm/lib-shared.ts | 5 +- .../frontend/lowering/builtins/util-types.ts | 16 + .../src/frontend/lowering/lower-inspect.ts | 255 ++++++++--- .../src/frontend/lowering/surfaces.ts | 16 + .../compiler/src/ir/builtin-signatures.ts | 7 + packages/compiler/src/ir/ir.ts | 13 +- .../corpus/5831-util-types-brands.ts.json | 6 + .../5832-util-types-brands-dynamic.js.json | 6 + ...835-util-format-integer-specifiers.ts.json | 6 + .../5837-util-format-json-circular.ts.json | 6 + .../5881-inspect-weak-collections.ts.json | 6 + .../5884-inspect-layout-options.ts.json | 6 + .../tests/corpus/5886-inspect-dates.ts.json | 6 + .../corpus/5887-inspect-typed-arrays.ts.json | 6 + .../tests/corpus/5888-inspect-sorted.ts.json | 6 + packages/runtime/src/scr_dyn.h | 9 +- packages/runtime/src/scr_inspect.c | 153 +++++-- packages/runtime/src/scr_inspect.h | 9 + packages/runtime/src/scr_json.c | 71 ++- packages/runtime/src/scr_util_callable.c | 2 +- tests/corpus/5831-util-types-brands.ts | 73 +++ .../corpus/5832-util-types-brands-dynamic.js | 31 ++ .../5835-util-format-integer-specifiers.ts | 29 ++ .../corpus/5837-util-format-json-circular.ts | 67 +++ tests/corpus/5881-inspect-weak-collections.ts | 24 + tests/corpus/5884-inspect-layout-options.ts | 51 +++ tests/corpus/5886-inspect-dates.ts | 32 ++ tests/corpus/5887-inspect-typed-arrays.ts | 30 ++ tests/corpus/5888-inspect-sorted.ts | 34 ++ .../__snapshots__/console-fences.ts.txt | 2 +- .../index-signature-values.ts.txt | 2 +- .../__snapshots__/utility-types.ts.txt | 7 - 39 files changed, 1519 insertions(+), 340 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5831-util-types-brands.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5832-util-types-brands-dynamic.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5835-util-format-integer-specifiers.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5837-util-format-json-circular.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5881-inspect-weak-collections.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5884-inspect-layout-options.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5886-inspect-dates.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5887-inspect-typed-arrays.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5888-inspect-sorted.ts.json create mode 100644 tests/corpus/5831-util-types-brands.ts create mode 100644 tests/corpus/5832-util-types-brands-dynamic.js create mode 100644 tests/corpus/5835-util-format-integer-specifiers.ts create mode 100644 tests/corpus/5837-util-format-json-circular.ts create mode 100644 tests/corpus/5881-inspect-weak-collections.ts create mode 100644 tests/corpus/5884-inspect-layout-options.ts create mode 100644 tests/corpus/5886-inspect-dates.ts create mode 100644 tests/corpus/5887-inspect-typed-arrays.ts create mode 100644 tests/corpus/5888-inspect-sorted.ts diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 956d5f2ac..3c1f80337 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "ce6ef79fa85eaff8f503", + "artifactVersion": "806fe99332e41d8441e0", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 0421113a4..04c0c16eb 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -794,9 +794,9 @@ "apiEntries": 109, "static": { "supported": 0, - "partial": 53, + "partial": 72, "refused": 0, - "not-implemented": 56, + "not-implemented": 37, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -73324,9 +73324,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -73347,9 +73347,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -73508,9 +73508,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -74060,9 +74060,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74083,9 +74083,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74106,9 +74106,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74129,9 +74129,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74152,9 +74152,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74175,9 +74175,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74221,9 +74221,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74244,9 +74244,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74267,9 +74267,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74451,9 +74451,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74497,9 +74497,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74566,9 +74566,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74681,9 +74681,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74704,9 +74704,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74727,9 +74727,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { @@ -74750,9 +74750,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Checks existing native runtime brands without inspecting public properties, with stored function values and tested predicate narrowing; unrepresented object forms retain compiler boundaries.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index e03c17638..306a382c7 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1088, - "verify-gap": 2241, + "audit-partial": 1107, + "verify-gap": 2222, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -5885,7 +5885,8 @@ "source": "compiler-dedicated:console.assert", "tests": [ "tests/corpus/5096-console-assert-dir.ts", - "tests/corpus/5099-console-methods-dynamic.cjs" + "tests/corpus/5099-console-methods-dynamic.cjs", + "tests/corpus/5884-inspect-layout-options.ts" ] } } @@ -6029,7 +6030,8 @@ "source": "compiler-dedicated:console.dir", "tests": [ "tests/corpus/5096-console-assert-dir.ts", - "tests/corpus/5099-console-methods-dynamic.cjs" + "tests/corpus/5099-console-methods-dynamic.cjs", + "tests/corpus/5884-inspect-layout-options.ts" ] } } @@ -6057,7 +6059,8 @@ "source": "compiler-dedicated:console.dirxml", "tests": [ "tests/corpus/5096-console-assert-dir.ts", - "tests/corpus/5099-console-methods-dynamic.cjs" + "tests/corpus/5099-console-methods-dynamic.cjs", + "tests/corpus/5884-inspect-layout-options.ts" ] } } @@ -75473,12 +75476,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.format", + "tests": [ + "tests/corpus/1636-util-format.ts", + "tests/corpus/2440-console-inspect-args.ts", + "tests/corpus/5835-util-format-integer-specifiers.ts" + ] } } }, @@ -75498,12 +75505,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.formatWithOptions", + "tests": [ + "tests/corpus/1636-util-format.ts", + "tests/corpus/2440-console-inspect-args.ts", + "tests/corpus/5835-util-format-integer-specifiers.ts" + ] } } }, @@ -75692,12 +75703,18 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.inspect", + "tests": [ + "tests/corpus/1630-inspect-scalars.ts", + "tests/corpus/1632-inspect-records.ts", + "tests/corpus/1637-inspect-dyn.ts", + "tests/corpus/2485-inspect-circular-refs.ts", + "tests/corpus/5884-inspect-layout-options.ts" + ] } } }, @@ -76237,6 +76254,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isAnyArrayBuffer", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76267,6 +76286,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isArrayBufferView", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76322,6 +76343,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isArrayBuffer", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76352,6 +76375,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isAsyncFunction", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76376,12 +76401,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isBigInt64Array", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76401,12 +76433,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isBigIntObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76426,12 +76465,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isBigUint64Array", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76451,12 +76497,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isBooleanObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76476,12 +76529,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isBoxedPrimitive", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76501,12 +76561,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isCryptoKey", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76532,6 +76599,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isDataView", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76556,12 +76625,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isDate", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76581,12 +76657,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isExternal", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76606,12 +76689,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isFloat16Array", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76637,6 +76727,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isFloat32Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76667,6 +76759,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isFloat64Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76697,6 +76791,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isGeneratorFunction", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76727,6 +76823,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isGeneratorObject", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76757,6 +76855,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isInt8Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76787,6 +76887,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isInt16Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76817,6 +76919,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isInt32Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76841,12 +76945,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isKeyObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76872,6 +76983,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isMap", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76896,12 +77009,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isMapIterator", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -76952,6 +77072,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isNativeError", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -76976,12 +77098,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isNumberObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -77007,6 +77136,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isPromise", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77037,6 +77168,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isProxy", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77067,6 +77200,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isRegExp", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77097,6 +77232,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isSet", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77121,12 +77258,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isSetIterator", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -77146,12 +77290,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isSharedArrayBuffer", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -77171,12 +77322,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isStringObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -77196,12 +77354,19 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:util", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:util.util.types.isSymbolObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] } } }, @@ -77227,6 +77392,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isTypedArray", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77257,6 +77424,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isUint8Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77287,6 +77456,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isUint8ClampedArray", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77317,6 +77488,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isUint16Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77347,6 +77520,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isUint32Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77377,6 +77552,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isWeakMap", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -77407,6 +77584,8 @@ "confidence": "high", "source": "compiler-feature:util.util.types.isWeakSet", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 64f3b8e4c..7c7a824c6 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -851,9 +851,9 @@ "apiEntries": 109, "static": { "supported": 0, - "partial": 53, + "partial": 72, "refused": 0, - "not-implemented": 56, + "not-implemented": 37, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -19141,6 +19141,7 @@ "tests/corpus/5097-console-table.ts", "tests/corpus/5098-console-time-warnings.ts", "tests/corpus/5099-console-methods-dynamic.cjs", + "tests/corpus/5884-inspect-layout-options.ts", "tests/corpus/console-native-value.js", "tests/harness/npm-static.test.ts" ] @@ -19297,7 +19298,8 @@ "evidence": "compiler-dedicated:console.assert", "tests": [ "tests/corpus/5096-console-assert-dir.ts", - "tests/corpus/5099-console-methods-dynamic.cjs" + "tests/corpus/5099-console-methods-dynamic.cjs", + "tests/corpus/5884-inspect-layout-options.ts" ] }, "anchorSource": "exact" @@ -19436,7 +19438,8 @@ "evidence": "compiler-dedicated:console.dir", "tests": [ "tests/corpus/5096-console-assert-dir.ts", - "tests/corpus/5099-console-methods-dynamic.cjs" + "tests/corpus/5099-console-methods-dynamic.cjs", + "tests/corpus/5884-inspect-layout-options.ts" ] }, "anchorSource": "exact" @@ -19463,7 +19466,8 @@ "evidence": "compiler-dedicated:console.dirxml", "tests": [ "tests/corpus/5096-console-assert-dir.ts", - "tests/corpus/5099-console-methods-dynamic.cjs" + "tests/corpus/5099-console-methods-dynamic.cjs", + "tests/corpus/5884-inspect-layout-options.ts" ] }, "anchorSource": "exact" @@ -100840,6 +100844,12 @@ "packages/compiler/test/deep-equality.test.ts", "tests/corpus/1473-promisify-execfile.ts", "tests/corpus/1573-promisify-execfile-env-spread.ts", + "tests/corpus/1630-inspect-scalars.ts", + "tests/corpus/1632-inspect-records.ts", + "tests/corpus/1636-util-format.ts", + "tests/corpus/1637-inspect-dyn.ts", + "tests/corpus/2440-console-inspect-args.ts", + "tests/corpus/2485-inspect-circular-refs.ts", "tests/corpus/2678-util-parseargs.ts", "tests/corpus/2912-promisify-fs-readfile.ts", "tests/corpus/3133-text-decoder-streaming.ts", @@ -100862,6 +100872,10 @@ "tests/corpus/5628-promisify-timers.ts", "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/5835-util-format-integer-specifiers.ts", + "tests/corpus/5884-inspect-layout-options.ts", "tests/corpus/node24-deep-equality-properties.js", "tests/corpus/node24-deep-equality.cjs", "tests/corpus/node24-deep-equality.ts", @@ -101958,8 +101972,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.format", + "tests": [ + "tests/corpus/1636-util-format.ts", + "tests/corpus/2440-console-inspect-args.ts", + "tests/corpus/5835-util-format-integer-specifiers.ts" + ] }, "anchorSource": "exact" }, @@ -101981,8 +102000,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.formatWithOptions", + "tests": [ + "tests/corpus/1636-util-format.ts", + "tests/corpus/2440-console-inspect-args.ts", + "tests/corpus/5835-util-format-integer-specifiers.ts" + ] }, "anchorSource": "exact" }, @@ -102165,8 +102189,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.inspect", + "tests": [ + "tests/corpus/1630-inspect-scalars.ts", + "tests/corpus/1632-inspect-records.ts", + "tests/corpus/1637-inspect-dyn.ts", + "tests/corpus/2485-inspect-circular-refs.ts", + "tests/corpus/5884-inspect-layout-options.ts" + ] }, "anchorSource": "exact" }, @@ -102793,6 +102824,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isAnyArrayBuffer", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -102822,6 +102855,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isArrayBufferView", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -102874,6 +102909,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isArrayBuffer", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -102903,6 +102940,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isAsyncFunction", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -102929,8 +102968,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isBigInt64Array", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -102952,8 +102999,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isBigIntObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -102975,8 +103030,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isBigUint64Array", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -102998,8 +103061,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isBooleanObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103021,8 +103092,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isBoxedPrimitive", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103044,8 +103123,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isCryptoKey", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103070,6 +103157,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isDataView", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103096,8 +103185,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isDate", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103119,8 +103216,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isExternal", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103142,8 +103247,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isFloat16Array", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103168,6 +103281,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isFloat32Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103197,6 +103312,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isFloat64Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103226,6 +103343,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isGeneratorFunction", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103255,6 +103374,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isGeneratorObject", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103284,6 +103405,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isInt8Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103313,6 +103436,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isInt16Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103342,6 +103467,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isInt32Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103368,8 +103495,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isKeyObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103394,6 +103529,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isMap", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103420,8 +103557,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isMapIterator", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103469,6 +103614,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isNativeError", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103495,8 +103642,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isNumberObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103521,6 +103676,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isPromise", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103550,6 +103707,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isProxy", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103579,6 +103738,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isRegExp", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103608,6 +103769,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isSet", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103634,8 +103797,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isSetIterator", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103657,8 +103828,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isSharedArrayBuffer", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103680,8 +103859,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isStringObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103703,8 +103890,16 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:util" + "status": "partial", + "evidence": "compiler-feature:util.util.types.isSymbolObject", + "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", + "tests/corpus/node24-util-types.ts", + "tests/corpus/node24-util-types.js", + "tests/corpus/node24-util-types.cjs", + "tests/fixtures/node-types/util-types.ts" + ] }, "anchorSource": "exact" }, @@ -103729,6 +103924,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isTypedArray", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103758,6 +103955,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isUint8Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103787,6 +103986,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isUint8ClampedArray", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103816,6 +104017,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isUint16Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103845,6 +104048,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isUint32Array", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103874,6 +104079,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isWeakMap", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", @@ -103903,6 +104110,8 @@ "status": "partial", "evidence": "compiler-feature:util.util.types.isWeakSet", "tests": [ + "tests/corpus/5831-util-types-brands.ts", + "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 63c032c73..aec7acc16 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -207,7 +207,9 @@ {"chapter": "worker_threads", "parent": "Class: `Worker`", "signatures": ["Event: `'online'`", "Event: `'message'`", "Event: `'error'`", "Event: `'exit'`"], "status": "partial", "evidence": ["tests/corpus/native-worker-references.ts", "tests/corpus/native-worker-error.ts", "tests/corpus/native-worker-exit-listeners.ts"]}, {"chapter": "worker_threads", "parent": "Class: `MessagePort`", "signatures": ["Event: `'message'`", "Event: `'close'`"], "status": "partial", "evidence": ["tests/corpus/native-worker-port-lifetime.ts", "tests/corpus/native-worker-messages.ts"]}, {"chapter": "worker_threads", "symbols": ["MessageChannel", "worker_threads.receiveMessageOnPort"], "status": "partial", "evidence": ["tests/corpus/5793-worker-message-channel.ts", "tests/corpus/5796-worker-message-channel.cjs", "tests/corpus/5797-worker-message-port-transfer.ts"]}, - {"chapter": "util", "symbols": ["util.types.isAnyArrayBuffer", "util.types.isArrayBuffer", "util.types.isArrayBufferView", "util.types.isDataView", "util.types.isTypedArray", "util.types.isUint8Array", "util.types.isUint8ClampedArray", "util.types.isUint16Array", "util.types.isUint32Array", "util.types.isInt8Array", "util.types.isInt16Array", "util.types.isInt32Array", "util.types.isFloat32Array", "util.types.isFloat64Array", "util.types.isMap", "util.types.isSet", "util.types.isWeakMap", "util.types.isWeakSet", "util.types.isRegExp", "util.types.isNativeError", "util.types.isPromise", "util.types.isProxy", "util.types.isAsyncFunction", "util.types.isGeneratorFunction", "util.types.isGeneratorObject"], "status": "partial", "evidence": ["tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", "tests/fixtures/node-types/util-types.ts"]}, + {"chapter": "util", "symbols": ["util.format", "util.formatWithOptions"], "status": "partial", "evidence": ["tests/corpus/1636-util-format.ts", "tests/corpus/2440-console-inspect-args.ts", "tests/corpus/5835-util-format-integer-specifiers.ts"]}, + {"chapter": "util", "symbols": ["util.types.isAnyArrayBuffer", "util.types.isArrayBuffer", "util.types.isArrayBufferView", "util.types.isDataView", "util.types.isTypedArray", "util.types.isUint8Array", "util.types.isUint8ClampedArray", "util.types.isUint16Array", "util.types.isUint32Array", "util.types.isInt8Array", "util.types.isInt16Array", "util.types.isInt32Array", "util.types.isFloat32Array", "util.types.isFloat64Array", "util.types.isMap", "util.types.isSet", "util.types.isWeakMap", "util.types.isWeakSet", "util.types.isRegExp", "util.types.isNativeError", "util.types.isPromise", "util.types.isProxy", "util.types.isAsyncFunction", "util.types.isGeneratorFunction", "util.types.isGeneratorObject", "util.types.isDate", "util.types.isSharedArrayBuffer", "util.types.isMapIterator", "util.types.isSetIterator", "util.types.isKeyObject", "util.types.isNumberObject", "util.types.isStringObject", "util.types.isBooleanObject", "util.types.isBigIntObject", "util.types.isSymbolObject", "util.types.isBoxedPrimitive", "util.types.isBigInt64Array", "util.types.isBigUint64Array", "util.types.isFloat16Array", "util.types.isCryptoKey", "util.types.isExternal"], "status": "partial", "evidence": ["tests/corpus/5831-util-types-brands.ts", "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", "tests/fixtures/node-types/util-types.ts"]}, + { "chapter": "util", "signatures": ["`util.inspect(object[, options])`"], "status": "partial", "evidence": ["tests/corpus/1630-inspect-scalars.ts", "tests/corpus/1632-inspect-records.ts", "tests/corpus/1637-inspect-dyn.ts", "tests/corpus/2485-inspect-circular-refs.ts", "tests/corpus/5884-inspect-layout-options.ts"] }, { "chapter": "util", "symbols": ["util.styleText"], "status": "partial", "evidence": ["tests/corpus/node24-style-text.ts", "tests/corpus/node24-style-text-validation.js", "tests/corpus/node24-style-text-environment.js", "tests/corpus/node24-style-text.cjs", "tests/fixtures/node-types/style-text.ts"] }, { "chapter": "util", "symbols": ["util.isDeepStrictEqual"], "status": "partial", "evidence": ["tests/corpus/node24-deep-equality.ts", "tests/corpus/node24-deep-equality.cjs", "tests/corpus/node24-deep-equality-properties.js", "tests/fixtures/node-types/deep-equality.ts", "packages/compiler/test/deep-equality.test.ts"] }, { "chapter": "deprecations", "symbols": ["util.toUSVString"], "status": "not-applicable" }, @@ -359,7 +361,7 @@ { "symbols": ["console.log", "console.info", "console.debug", "console.error", "console.warn"], "status": "partial", "evidence": ["tests/corpus/1460-console-error-warn.ts", "tests/corpus/2440-console-inspect-args.ts", "tests/corpus/2631-create-require/main.ts", "tests/corpus/console-native-value.js", "tests/harness/npm-static.test.ts"] }, { "symbols": ["console.count", "console.countReset", "console.group", "console.groupCollapsed", "console.groupEnd"], "status": "partial", "evidence": ["tests/corpus/5095-console-count-group.ts", "tests/corpus/5098-console-time-warnings.ts", "tests/corpus/5099-console-methods-dynamic.cjs"] }, { "symbols": ["console.time", "console.timeEnd", "console.timeLog"], "status": "partial", "evidence": ["tests/corpus/5098-console-time-warnings.ts"] }, - { "symbols": ["console.assert", "console.dir", "console.dirxml"], "status": "partial", "evidence": ["tests/corpus/5096-console-assert-dir.ts", "tests/corpus/5099-console-methods-dynamic.cjs"] }, + { "symbols": ["console.assert", "console.dir", "console.dirxml"], "status": "partial", "evidence": ["tests/corpus/5096-console-assert-dir.ts", "tests/corpus/5099-console-methods-dynamic.cjs", "tests/corpus/5884-inspect-layout-options.ts"] }, { "symbols": ["console.table"], "status": "partial", "evidence": ["tests/corpus/5097-console-table.ts", "tests/corpus/5099-console-methods-dynamic.cjs"] }, { "symbols": ["console.clear", "console.profile", "console.profileEnd", "console.timeStamp"], "status": "partial", "evidence": ["tests/corpus/5099-console-methods-dynamic.cjs"] }, { "symbols": ["assert.AssertionError"], "status": "partial", "evidence": ["tests/corpus/5510-assert-error-properties.js", "tests/corpus/5511-assert-error-class.ts", "tests/corpus/5512-assert-error-options.js"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 0b9f7867b..28cb31dd4 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3264,6 +3264,22 @@ declare module "util/types" { export function isGeneratorFunction(value: unknown): boolean; export function isGeneratorObject(value: unknown): boolean; export function isModuleNamespaceObject(value: unknown): boolean; + export function isDate(value: unknown): value is Date; + export function isSharedArrayBuffer(value: unknown): value is SharedArrayBuffer; + export function isMapIterator(value: unknown): boolean; + export function isSetIterator(value: unknown): boolean; + export function isKeyObject(value: unknown): boolean; + export function isNumberObject(value: unknown): boolean; + export function isStringObject(value: unknown): boolean; + export function isBooleanObject(value: unknown): boolean; + export function isBigIntObject(value: unknown): boolean; + export function isSymbolObject(value: unknown): boolean; + export function isBoxedPrimitive(value: unknown): boolean; + export function isBigInt64Array(value: unknown): value is BigInt64Array; + export function isBigUint64Array(value: unknown): value is BigUint64Array; + export function isFloat16Array(value: unknown): boolean; + export function isCryptoKey(value: unknown): boolean; + export function isExternal(value: unknown): boolean; } declare module "node:util/types" { export * from "util/types"; diff --git a/packages/compiler/src/backend/llvm/expr-async.ts b/packages/compiler/src/backend/llvm/expr-async.ts index 7b1d870df..6731e13c9 100644 --- a/packages/compiler/src/backend/llvm/expr-async.ts +++ b/packages/compiler/src/backend/llvm/expr-async.ts @@ -338,8 +338,17 @@ export function emitSerializationExpr( // checked source can throw from the dyn walker: finish still runs // (frees the buffer, the partial string joins the frame and // releases on unwind), then the pending check unwinds — the - // runtime ABI’s contract exactly. - if (host.walkers.jsonWriteMayThrow(e.value.type)) host.emitPendingCheck(); + // runtime ABI’s contract exactly. Under %j the runtime first turns + // a circular-structure TypeError into the text "[Circular]". + if (host.walkers.jsonWriteMayThrow(e.value.type)) { + if (e.circular) { + host.declare(`declare ptr @scr_util_format_j_text(ptr)`); + const shown = B.tmp(); + B.line(`${shown} = call ptr @scr_util_format_j_text(ptr ${t})`); + compact = host.own({ name: shown, type: e.type }); + } + host.emitPendingCheck(); + } } // A pretty-print form (`stringify(v, null, 2)`): the frontend // resolved the space to a compile-time indent string (Node's diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 02b882353..63558bf13 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -37,7 +37,7 @@ export const ASSERT_VERDICT_LIB_FNS: ReadonlyMap = new Ma export const LIB_FN_SYMS: Record = { "assert.expectsErrDyn": "scr_assert_expects_err_dyn", - "insp.jsonDyn": "scr_dyn_format_j", + "insp.jsonDyn": "scr_util_format_j", "http.reqH2StreamOrThrow": "scr_http_req_h2_stream_or_throw", "intl.segmenterNew": "scr_intl_segmenter_new", "weakMap.is": "scr_weak_map_is", @@ -575,14 +575,17 @@ export const LIB_FN_SYMS: Record = { "process.stdoutWriteBytes": "scr_process_stdout_write_bytes", "process.stderrWriteBytes": "scr_process_stderr_write_bytes", "insp.buffer": "scr_insp_buffer", + "insp.typedArray": "scr_insp_typed_array", // util.inspect (scr_inspect.c): all args borrowed; string results +1; // the begin/entry/key/moreItems/end accumulator drives the emitted // container walks. None of these throw. "insp.f64": "scr_insp_f64", "insp.str": "scr_insp_str", "insp.regex": "scr_insp_regex", + "insp.date": "scr_insp_date", "insp.error": "scr_insp_error", "insp.begin": "scr_insp_begin", + "insp.layout": "scr_insp_layout", "insp.entry": "scr_insp_entry", "insp.key": "scr_insp_key", "insp.moreItems": "scr_insp_more_items", diff --git a/packages/compiler/src/frontend/lowering/builtins/util-types.ts b/packages/compiler/src/frontend/lowering/builtins/util-types.ts index 979a996d8..4399c730e 100644 --- a/packages/compiler/src/frontend/lowering/builtins/util-types.ts +++ b/packages/compiler/src/frontend/lowering/builtins/util-types.ts @@ -12,6 +12,22 @@ export function lowerUtilTypeCall( ): IrExpr { if (expr.arguments.some(ts.isSpreadElement)) lowerer.noLowering(`${name} with spread arguments`, expr); + const first = expr.arguments[0]; + if (first !== undefined && lowerer.mapTypeOf(lowerer.typeOf(first))?.kind === "date") { + // A Date value has no checked-dynamic form; its static type decides + // every brand. The arguments still evaluate in order. + return { + kind: "seqExpr", + stmts: expr.arguments.map((arg): IrStmt => ({ + kind: "exprStmt", + expr: lowerer.lowerExpr(arg), + loc, + })), + result: { kind: "boolLit", value: bi.member === "isDate", type: BOOL, loc }, + type: BOOL, + loc, + }; + } const input = expr.arguments[0] ? lowerer.lowerExprExpecting(expr.arguments[0], DYN) : dynUndefinedExpr(loc); diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index 7c08a34f9..f91ec77bc 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -135,12 +135,17 @@ function inspectSupport( case "regex": case "symbol": case "bigint": + case "date": case "dyn": return null; case "array": return inspectSupport(lowerer, t.elem, visiting, out); case "bytes": - return "typed arrays inside composites have no inspect lowering yet (Buffer's form vs Uint8Array's is not recorded in the static type here)"; + // A Uint8Array and a Buffer share the u8 representation and print + // differently; the other element kinds are never Buffers. + return t.elem === "u8" + ? "Uint8Array and Buffer values inside composites have no inspect lowering yet (Buffer's form vs Uint8Array's is not recorded in the static type here)" + : null; case "record": { if (visiting.has(t.shapeId)) { out.recursive = true; @@ -321,7 +326,20 @@ export function inspectExpr( return { kind: "libCall", fn: "sym.toString", args: [value], type: STRING, loc }; case "bigint": return { kind: "libCall", fn: "bigint.inspect", args: [value], type: STRING, loc }; + case "date": + // Node prints a Date's toISOString() at every depth, and its + // toString() ("Invalid Date") when the time value is NaN. + return { kind: "libCall", fn: "insp.date", args: [value], type: STRING, loc }; case "bytes": + if (t.elem !== "u8") { + return { + kind: "libCall", + fn: "insp.typedArray", + args: [value, recurse, depth], + type: STRING, + loc, + }; + } return { kind: "libCall", fn: "insp.buffer", args: [value], type: STRING, loc }; case "dyn": return { kind: "libCall", fn: "insp.dyn", args: [value, recurse, depth], type: STRING, loc }; @@ -1436,23 +1454,27 @@ export function lowerConsoleInspectArg( } if (t.kind === "bytes") { // One runtime representation serves Buffer AND Uint8Array; their - // renderings differ, so the argument's checker type picks — and only - // Buffer lowers (lowerInspectCall's stance). + // renderings differ, so the argument's checker type picks + // (lowerInspectCall's stance). const tname = lowerer.checker.typeToString( lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(node)), ); - const isBuffer = - tname === "Buffer" || - tname === "NonSharedBuffer" || - tname.startsWith("Buffer<") || - tname.startsWith("NonSharedBuffer<"); - if (t.elem !== "u8" || !isBuffer) { + if (isDataViewTypeName(tname)) { lowerer.unsupported( "SC1090", node, - `${surface} of '${tname}' values (Buffer's form is the lowered typed-array rendering; other typed arrays fence)`, + `${surface} of '${tname}' values (Buffer and the numeric typed arrays are the lowered byte renderings; DataView has none yet)`, ); } + if (!isBufferTypeName(tname)) { + return { + kind: "libCall", + fn: "insp.typedArray", + args: [value, numLit(0, loc), numLit(2, loc)], + type: STRING, + loc, + }; + } return inspectExpr(lowerer, t, value, numLit(0, loc), numLit(2, loc), loc); } if (t.kind === "void") { @@ -1472,18 +1494,41 @@ export function lowerConsoleInspectArg( return formatValueExpr(lowerer, t, value, 2, loc); } +/** The checker's spelling of a Buffer, whose bytes print as . */ +function isBufferTypeName(tname: string): boolean { + return ( + tname === "Buffer" || + tname === "NonSharedBuffer" || + tname.startsWith("Buffer<") || + tname.startsWith("NonSharedBuffer<") + ); +} + +function isDataViewTypeName(tname: string): boolean { + return tname === "DataView" || tname.startsWith("DataView<"); +} + /* ── the callsite: options, direct function/class names ──────────────── */ /** The parsed options literal: the resolved depth (numeric; Infinity for - * `null`), with every non-default knob fenced by name. */ + * `null`), breakLength (numeric; default 80) and compact (numeric, 0 for + * false; default 3), with every other non-default knob fenced by name. */ +interface InspectOptions { + depth: number; + breakLength: number; + compact: number; + sorted: boolean; +} + function parseInspectOptions( lowerer: Lowerer, node: ts.Expression | undefined, recursive: boolean, dir = false, -): number { +): InspectOptions { const surface = dir ? "console.dir" : "util.inspect"; - if (!node || (ts.isIdentifier(node) && node.text === "undefined")) return 2; + const options: InspectOptions = { depth: 2, breakLength: 80, compact: 3, sorted: false }; + if (!node || (ts.isIdentifier(node) && node.text === "undefined")) return options; if (!ts.isObjectLiteralExpression(node)) { lowerer.noLowering( `${surface} with a non-literal options argument`, @@ -1491,7 +1536,6 @@ function parseInspectOptions( "the options must be an object literal ({ depth, colors: false, ... }) so the knobs resolve at compile time", ); } - let depth = 2; for (const prop of node.properties) { if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) { lowerer.noLowering( @@ -1522,7 +1566,7 @@ function parseInspectOptions( // machinery ([Circular *N]) cuts every cycle, so the walk is // bounded by the (finite) object graph — exactly Node. void recursive; - depth = Infinity; + options.depth = Infinity; } else if (!(ts.isIdentifier(value) && value.text === "undefined")) { const n = numeric(); if (n === null) { @@ -1532,7 +1576,7 @@ function parseInspectOptions( "depth must be a numeric literal (or null)", ); } - depth = n; + options.depth = n; } } else if (key === "colors") { if (value.kind !== ts.SyntaxKind.FalseKeyword) { @@ -1543,21 +1587,37 @@ function parseInspectOptions( ); } } else if (key === "compact") { - if (numeric() !== 3) { + // Node tries the single-line form and groups arrays only for a + // compact of at least 1; false and smaller numbers break every + // composite onto its own lines. compact: true is the older layout. + const n = value.kind === ts.SyntaxKind.FalseKeyword ? 0 : numeric(); + if (n === null || Number.isNaN(n)) { lowerer.noLowering( - `${surface} with a non-default compact option`, + `${surface} with this compact option`, value, - "only the default compact: 3 is lowered", + "compact must be false or a numeric literal (compact: true has no lowering)", ); } + options.compact = Math.max(n, 0); + } else if (key === "sorted") { + if (value.kind !== ts.SyntaxKind.TrueKeyword && value.kind !== ts.SyntaxKind.FalseKeyword) { + lowerer.noLowering( + `${surface} with this sorted option`, + value, + "sorted must be true or false (a comparator function has no lowering)", + ); + } + options.sorted = value.kind === ts.SyntaxKind.TrueKeyword; } else if (key === "breakLength") { - if (numeric() !== 80) { + const n = ts.isIdentifier(value) && value.text === "Infinity" ? Infinity : numeric(); + if (n === null || Number.isNaN(n)) { lowerer.noLowering( - `${surface} with a non-default breakLength option`, + `${surface} with a non-literal breakLength option`, value, - "only the default breakLength: 80 is lowered", + "breakLength must be a numeric literal or Infinity", ); } + options.breakLength = n; } else if (dir && key === "customInspect") { // console.dir's own default; only that value is lowered. if (value.kind !== ts.SyntaxKind.FalseKeyword) { @@ -1571,11 +1631,49 @@ function parseInspectOptions( lowerer.noLowering( `${surface} with the '${key}' option`, prop, - `the lowered options are depth (numeric literal or null), colors: false, compact: 3, ${dir ? "breakLength: 80, and customInspect: false" : "and breakLength: 80"}`, + `the lowered options are depth (numeric literal or null), colors: false, compact (false or a number), breakLength, ${dir ? "sorted (true or false), and customInspect: false" : "and sorted (true or false)"}`, ); } } - return depth; + return options; +} + +/** A render under non-default breakLength/compact/sorted: the value is evaluated + * first, the layout applies to this render only, and the defaults return + * afterwards. */ +function withInspectLayout( + lowerer: Lowerer, + options: InspectOptions, + value: IrExpr, + render: (value: IrExpr) => IrExpr, + loc: SrcLoc, +): IrExpr { + if (options.breakLength === 80 && options.compact === 3 && !options.sorted) return render(value); + const input = lowerer.declareHiddenLocal("%inspectInput", value.type); + const text = lowerer.declareHiddenLocal("%inspectText", STRING); + const layout = (breakLength: number, compact: number, sorted: boolean): IrStmt => ({ + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "insp.layout", + args: [numLit(breakLength, loc), numLit(compact, loc), boolLit(sorted, loc)], + type: VOID, + loc, + }, + loc, + }); + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: input.id, init: value, loc }, + layout(options.breakLength, options.compact, options.sorted), + { kind: "varDecl", localId: text.id, init: render(varRef(input.id, value.type, loc)), loc }, + layout(80, 3, false), + ], + result: varRef(text.id, STRING, loc), + type: STRING, + loc, + }; } /** `util.inspect(fn)` / `util.inspect(Cls)` over a DIRECT identifier @@ -1664,33 +1762,45 @@ export function lowerInspectValue( if (value.type.kind === "bytes") { // One runtime representation serves Buffer AND Uint8Array; their // renderings differ ( vs Uint8Array(1) [ 170 ]), so the - // TOP-LEVEL argument's checker type picks — and only Buffer lowers. - // Nested bytes fence in inspectSupport (no checker type survives - // into shapes). + // TOP-LEVEL argument's checker type picks. Nested u8 bytes fence in + // inspectSupport (no checker type survives into shapes). const tname = lowerer.checker.typeToString( lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(valueNode)), ); - const isBuffer = - tname === "Buffer" || - tname === "NonSharedBuffer" || - tname.startsWith("Buffer<") || - tname.startsWith("NonSharedBuffer<"); - if (dir) { + const isBuffer = isBufferTypeName(tname); + if (dir && isBuffer) { lowerer.noLowering( `console.dir of '${tname}' values`, valueNode, "console.dir disables custom inspection, and the typed-array rendering it falls back to has no lowering yet — use console.log", ); } - if (value.type.elem !== "u8" || !isBuffer) { + if (isDataViewTypeName(tname)) { lowerer.noLowering( `util.inspect of '${tname}' values`, valueNode, - "Buffer's form is the lowered typed-array rendering; other typed arrays fence", + "Buffer and the numeric typed arrays are the lowered byte renderings; DataView has none yet", ); } - const bufDepth = parseInspectOptions(lowerer, optionsNode, false, dir); - void bufDepth; // Buffers render fully at any depth (custom inspect) + const options = parseInspectOptions(lowerer, optionsNode, false, dir); + if (!isBuffer) { + // A numeric typed array: Uint8Array(n) [ ... ] under the depth and + // layout options. + return withInspectLayout( + lowerer, + options, + value, + (input) => ({ + kind: "libCall", + fn: "insp.typedArray", + args: [input, numLit(0, loc), numLit(options.depth, loc)], + type: STRING, + loc, + }), + loc, + ); + } + // Buffers render fully at any depth and on one line (custom inspect). return inspectExpr(lowerer, value.type, value, numLit(0, loc), numLit(2, loc), loc); } const walk = { recursive: false }; @@ -1698,17 +1808,30 @@ export function lowerInspectValue( if (reason !== null) { lowerer.noLowering(`${surface} of '${lowerer.fmt(value.type)}' values`, valueNode, reason); } - const depth = parseInspectOptions(lowerer, optionsNode, walk.recursive, dir); + const options = parseInspectOptions(lowerer, optionsNode, walk.recursive, dir); + const depth = options.depth; if (dir && value.type.kind === "dyn") { - return { - kind: "libCall", - fn: "console.dirDyn", - args: [value, numLit(depth, loc)], - type: STRING, + return withInspectLayout( + lowerer, + options, + value, + (input) => ({ + kind: "libCall", + fn: "console.dirDyn", + args: [input, numLit(depth, loc)], + type: STRING, + loc, + }), loc, - }; + ); } - return inspectExpr(lowerer, value.type, value, numLit(0, loc), numLit(depth, loc), loc); + return withInspectLayout( + lowerer, + options, + value, + (input) => inspectExpr(lowerer, value.type, input, numLit(0, loc), numLit(depth, loc), loc), + loc, + ); } /* ── util.format / util.formatWithOptions ────────────────────────────── */ @@ -1811,6 +1934,34 @@ function formatOArg(lowerer: Lowerer, node: ts.Expression, depth: number, loc: S return inspectExpr(lowerer, value.type, value, numLit(0, loc), numLit(depth, loc), loc); } +/** %d and %i over the argument types Node formats without a number + * conversion: a bigint prints as `${n}n` (formatBigInt) and a symbol as NaN; + * null is Number(null) (0) under %d and parseInt("null") (NaN) under %i, and + * undefined (including a void call) is NaN under both. Other arguments + * still evaluate. Null for other types. */ +function formatIntegerFixed(value: IrExpr, spec: "%d" | "%i", loc: SrcLoc): IrExpr | null { + if (value.type.kind === "bigint") { + return { kind: "libCall", fn: "bigint.inspect", args: [value], type: STRING, loc }; + } + let text: string; + if ( + value.type.kind === "symbol" || + value.type.kind === "undefinedT" || + value.type.kind === "void" + ) + text = "NaN"; + else if (value.type.kind === "nullT") text = spec === "%d" ? "0" : "NaN"; + else return null; + if (value.kind === "unitLit") return strLit(text, loc); + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: value, loc }], + result: strLit(text, loc), + type: STRING, + loc, + }; +} + /** util.format(...) / util.formatWithOptions({}, ...): the compile-time * %-substitution over a literal format string (formatWithOptionsInternal * ported exactly — the arg cursor, the args-exhausted guard, %c's @@ -1880,6 +2031,8 @@ export function lowerFormatCall( // strings through the runtime's ECMA-exact StringToNumber // (num.fromString — the same lowering Number(aString) takes). const value = lowerer.lowerExpr(node); + const fixed = formatIntegerFixed(value, "%d", loc); + if (fixed) return fixed; if (value.type.kind === "f64") return { kind: "libCall", fn: "insp.f64", args: [value], type: STRING, loc }; if (value.type.kind === "string") { @@ -1935,6 +2088,8 @@ export function lowerFormatCall( case 105: { // %i — parseInt(ToString(arg)): the spec-exact composition. const value = lowerer.lowerExpr(node); + const fixed = formatIntegerFixed(value, "%i", loc); + if (fixed) return fixed; if ( value.type.kind === "f64" || value.type.kind === "bool" || @@ -1975,10 +2130,10 @@ export function lowerFormatCall( return strLit("undefined", loc); } // A checked-dynamic argument (`console.error('headers: %j', - // headers)` — the suite's http logging idiom): the runtime dyn - // walk stringifies JS-exactly (root undefined/function prints - // "undefined"; a handle in the tree throws the "not supported yet" - // Error). + // headers)` — the suite's http logging idiom): the runtime runs + // JSON.stringify's walk (toJSON hooks included; a root it drops + // prints "undefined") and prints "[Circular]" for a circular + // structure. A typed argument prints "[Circular]" the same way. if (value.type.kind === "dyn") { return { kind: "libCall", fn: "insp.jsonDyn", args: [value], type: STRING, loc }; } @@ -1989,7 +2144,7 @@ export function lowerFormatCall( "only JSON-safe static types lower", ); } - return { kind: "jsonStringify", value, type: STRING, loc }; + return { kind: "jsonStringify", value, circular: true, type: STRING, loc }; } case 102: { // %f — parseFloat(String(arg)) formatted: a number keeps its value diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index ec931350a..1584dc1b5 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -1758,6 +1758,22 @@ export const BUILTIN_MODULE_FNS: Record< isAsyncFunction: { fn: "util.typeIs", params: [DYN], result: BOOL }, isGeneratorFunction: { fn: "util.typeIs", params: [DYN], result: BOOL }, isGeneratorObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isDate: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isSharedArrayBuffer: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isMapIterator: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isSetIterator: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isKeyObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isNumberObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isStringObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBooleanObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBigIntObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isSymbolObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBoxedPrimitive: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBigInt64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBigUint64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isFloat16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isCryptoKey: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isExternal: { fn: "util.typeIs", params: [DYN], result: BOOL }, }, buffer: { isAscii: { fn: "buffer.isAscii", params: [DYN], result: BOOL }, diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 612916a59..60459e8be 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3741,11 +3741,18 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "insp.jsonDyn": { argTypes: [DYN], result: STRING }, "insp.str": { argTypes: [STRING], result: STRING }, "insp.regex": { argTypes: [REGEX], result: STRING }, + /** A Date's inspect text: toISOString(), or "Invalid Date". */ + "insp.date": { argTypes: [DATE_T], result: STRING }, "insp.buffer": { argTypes: [BYTES_U8], result: STRING }, + /** A numeric typed array that is not a Buffer (any element kind). */ + "insp.typedArray": { argTypes: [null, F64, F64], result: STRING }, "insp.error": { argTypes: [null, F64, F64], result: STRING }, "insp.dyn": { argTypes: [DYN, F64, F64], result: STRING }, "insp.dynS": { argTypes: [DYN, F64], result: STRING }, "insp.begin": { argTypes: [F64], result: VOID }, + /** util.inspect's breakLength, compact (0 for false) and sorted for the + * renders that follow; the call site restores 80, 3 and false afterwards. */ + "insp.layout": { argTypes: [F64, F64, BOOL], result: VOID }, "insp.entry": { argTypes: [STRING, BOOL], result: VOID }, // Circular references: the receiver slot is program-dependent (any // cycle-capable record/array/map/class type — the insp.error precedent). diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index cac5ababa..1177fc1dd 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -3573,8 +3573,17 @@ export type IrExpr = * `null` and -0 as `0`, exactly like JS; a record field holding the * undefined arm of its union (an optional field) is DROPPED from the * output — Node's rule for undefined-valued properties. The value is - * BORROWED; the result string is owned (+1). Never throws. */ - | { kind: "jsonStringify"; value: IrExpr; indent?: string; type: IrType; loc: SrcLoc } + * BORROWED; the result string is owned (+1). Never throws. `circular` + * is util.format's %j (Node's tryStringify): a circular structure gives + * the text "[Circular]" instead of the TypeError. */ + | { + kind: "jsonStringify"; + value: IrExpr; + indent?: string; + circular?: true; + type: IrType; + loc: SrcLoc; + } /** The dynamic-boundary check — a CHECKED cast `dynValue as T`: validate * the dyn value's JSON dyn against `type` (a non-dyn, JSON-representable * IR type) and BUILD the typed value (+1), or THROW a catchable diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5831-util-types-brands.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5831-util-types-brands.ts.json new file mode 100644 index 000000000..64ba3cdd4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5831-util-types-brands.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5831-util-types-brands.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5832-util-types-brands-dynamic.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5832-util-types-brands-dynamic.js.json new file mode 100644 index 000000000..9ed42a8ce --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5832-util-types-brands-dynamic.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5832-util-types-brands-dynamic.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5835-util-format-integer-specifiers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5835-util-format-integer-specifiers.ts.json new file mode 100644 index 000000000..07c8e6c79 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5835-util-format-integer-specifiers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5835-util-format-integer-specifiers.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5837-util-format-json-circular.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5837-util-format-json-circular.ts.json new file mode 100644 index 000000000..55daf6bd8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5837-util-format-json-circular.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5837-util-format-json-circular.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5881-inspect-weak-collections.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5881-inspect-weak-collections.ts.json new file mode 100644 index 000000000..342179cde --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5881-inspect-weak-collections.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5881-inspect-weak-collections.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5884-inspect-layout-options.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5884-inspect-layout-options.ts.json new file mode 100644 index 000000000..17935d5a4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5884-inspect-layout-options.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5884-inspect-layout-options.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5886-inspect-dates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5886-inspect-dates.ts.json new file mode 100644 index 000000000..65525fb9b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5886-inspect-dates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5886-inspect-dates.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5887-inspect-typed-arrays.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5887-inspect-typed-arrays.ts.json new file mode 100644 index 000000000..7c49ebfaa --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5887-inspect-typed-arrays.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5887-inspect-typed-arrays.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5888-inspect-sorted.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5888-inspect-sorted.ts.json new file mode 100644 index 000000000..5e0eedde2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5888-inspect-sorted.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5888-inspect-sorted.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 3d8afa1a7..4d30bc24e 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1217,11 +1217,18 @@ ScrDyn *scr_gen_receiver(void); void scr_dyn_chunk_enc(bool utf8); ScrDyn *scr_dyn_new_chunk(const ScrBytes *b); -/* util.format's %j over a dyn value: the JSON.stringify text (+1), +/* The JSON text of a dyn value: the JSON.stringify text (+1), * "undefined" when the root drops (undefined/function), or NULL with a * pending exception (a runtime handle inside the tree throws the "not * supported yet" Error). */ ScrStr *scr_dyn_format_j(const ScrDyn *d); +/* util.format's %j (Node's tryStringify), +1: over a dyn value, the + * JSON.stringify(d) text, or "undefined" when it returns undefined; over + * the text of a typed serializer that may have thrown, the text itself. + * A circular-structure TypeError becomes "[Circular]"; any other + * exception stays pending and the result is NULL. */ +ScrStr *scr_util_format_j(const ScrDyn *d); +ScrStr *scr_util_format_j_text(ScrStr *text); /* borrows text */ /* Node's ERR_INVALID_ARG_TYPE listener gate over a dyn value — shared by * the emitter unit's checked-dynamic registrations and the handle * dispatchers' .on(...) paths (both render errors.js's diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index e0615635a..7479cb548 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -6,9 +6,10 @@ * escapes, the 10000-char string cap and the per-line ` +` continuation * form), Buffer's hex form, and the LAYOUT engine — a * frame stack reproducing reduceToSingleString, isBelowBreakLength, and - * groupArrayElements from Node v24's lib/internal/util/inspect.js for the - * DEFAULT options (compact: 3, breakLength: 80, maxArrayLength: 100, - * maxStringLength: 10000; non-default options fence in the frontend). + * groupArrayElements from Node v24's lib/internal/util/inspect.js for + * maxArrayLength: 100 and maxStringLength: 10000, a numeric or false + * compact (default 3), any breakLength (default 80) and a boolean sorted; + * other non-default options fence in the frontend. * * Lengths follow Node exactly: the break-length math counts UTF-16 code * units (JS .length); the grid-grouping math counts DISPLAY WIDTH. Node @@ -242,8 +243,20 @@ static SCR_TL size_t g_nframes; static SCR_TL size_t g_frames_cap; static SCR_TL size_t g_indent; /* ctx.indentationLvl */ static SCR_TL bool g_no_break; /* breakLength: Infinity (console.table cells) */ +static SCR_TL double g_break_length = 80; /* ctx.breakLength */ +static SCR_TL double g_compact = 3; /* ctx.compact: a number, 0 for false */ +static SCR_TL bool g_sorted; /* ctx.sorted === true */ static SCR_TL double g_cur_depth; /* ctx.currentDepth (last-entered composite) */ +/* util.inspect's breakLength, compact and sorted for the renders that + * follow (compact false is 0); the call site restores 80, 3 and false + * after its render. */ +void scr_insp_layout(double break_length, double compact, bool sorted) { + g_break_length = break_length; + g_compact = compact; + g_sorted = sorted; +} + static InspFrame *insp_top(void) { return &g_frames[g_nframes - 1]; } static void insp_circ_reset(void); /* circular-reference state, below */ @@ -360,6 +373,13 @@ ScrStr *scr_insp_ref_wrap(const void *v, ScrStr *s) { return out; } +/* formatRaw's Date base: toISOString(), or toString()'s "Invalid Date" + * when the time value is NaN (the only time value outside the ISO range). */ +ScrStr *scr_insp_date(double ms) { + if (isnan(ms)) return scr_str_new("Invalid Date", 12); + return scr_date_to_iso(ms); +} + /* remainingText: the "... N more items" tail entry. */ ScrStr *scr_insp_more_items(double remaining) { char buf[64]; @@ -382,15 +402,15 @@ static void insp_group(InspFrame *f, bool trailing_more) { if ((double)w > max_length) max_length = (double)w; } double actual_max = max_length + 2; - if (actual_max * 3 + (double)g_indent < 80 && + if (actual_max * 3 + (double)g_indent < g_break_length && (total_length / actual_max > 5 || max_length <= 6)) { double approx_char_heights = 2.5; double average_bias = sqrt(actual_max - total_length / (double)f->len); double biased_max = fmax(actual_max - 3 - average_bias, 1); double columns_d = fmin( fmin(round(sqrt(approx_char_heights * biased_max * (double)output_len) / biased_max), - floor((80 - (double)g_indent) / actual_max)), - fmin(3 * 4 /* ctx.compact * 4 */, 15)); + floor((g_break_length - (double)g_indent) / actual_max)), + fmin(g_compact * 4, 15)); if (columns_d <= 1) { free(data_len); return; @@ -458,18 +478,23 @@ static void insp_group(InspFrame *f, bool trailing_more) { free(data_len); } -/* isBelowBreakLength: UTF-16 lengths against breakLength 80. */ +static int insp_item_cmp(const void *a, const void *b) { + return scr_str_cmp_u16(*(ScrStr *const *)a, *(ScrStr *const *)b); +} + +/* isBelowBreakLength: UTF-16 lengths against ctx.breakLength. */ static bool insp_below_break_length(InspFrame *f, size_t start, const ScrStr *base) { size_t total = f->len + start; - if (total + f->len > 80) return false; + if ((double)(total + f->len) > g_break_length) return false; for (size_t i = 0; i < f->len; i++) { total += insp_utf16_len(f->items[i]->data, f->items[i]->len); - if (total > 80) return false; + if ((double)total > g_break_length) return false; } return base->len == 0 || !insp_contains_byte(base->data, base->len, '\n'); } -/* reduceToSingleString for the default options (compact: 3). Pops the +/* reduceToSingleString for a numeric or false compact (only a compact of + * at least 1 groups arrays and tries the single line). Pops the * frame. base/b0/b1 are borrowed; +1 result. `recurse` is the frame's * recurseTimes (the children's depth); array_extras marks kArrayExtrasType * (grid grouping applies); trailing_more marks a "... N more items" tail @@ -478,10 +503,15 @@ ScrStr *scr_insp_end(ScrStr *base, ScrStr *b0, ScrStr *b1, double recurse, bool bool trailing_more) { InspFrame *f = insp_top(); g_indent -= 2; + /* sorted: true orders an object-type composite's entries (properties, + * and Map and Set entries) by their rendered text, in UTF-16 code-unit + * order; arrays keep their element order. */ + if (g_sorted && !array_extras && f->len > 1) qsort(f->items, f->len, sizeof *f->items, insp_item_cmp); size_t entries = f->len; - if (array_extras && entries > 6) insp_group(f, trailing_more); + bool compact = g_compact >= 1; + if (compact && array_extras && entries > 6) insp_group(f, trailing_more); InspBuf out = {0}; - if (g_cur_depth - recurse < 3 && entries == f->len) { + if (compact && g_cur_depth - recurse < g_compact && entries == f->len) { size_t start = f->len + g_indent + insp_utf16_len(b0->data, b0->len) + insp_utf16_len(base->data, base->len) + 10; if (insp_below_break_length(f, start, base)) { @@ -619,7 +649,7 @@ static size_t insp_utf16_offset(const char *data, size_t len, size_t units, bool /* formatPrimitive over a string value under the default options: * maxStringLength 10000, then the per-line ` +` continuation when the - * (truncated) text is longer than 16 chars AND breakLength(80) - + * (truncated) text is longer than 16 chars AND breakLength - * indentationLvl - 4, split after each newline; the trailer counts the * cut characters. Uses the CURRENT indentation. */ ScrStr *scr_insp_str(ScrStr *s) { @@ -652,7 +682,8 @@ ScrStr *scr_insp_str(ScrStr *s) { if (surrogate_tail_len) ib_bytes(&val, surrogate_tail, surrogate_tail_len); size_t vlen = val.len; const char *v = val.data ? val.data : ""; - if (!g_no_break && units > 16 && units > 80 - g_indent - 4 && memchr(v, '\n', vlen) != NULL) { + if (!g_no_break && units > 16 && (double)units > g_break_length - (double)g_indent - 4 && + memchr(v, '\n', vlen) != NULL) { /* split after each newline; quote each chunk; join with ` +\n` */ size_t chunk_start = 0; bool first = true; @@ -946,6 +977,22 @@ static ScrStr *scr_insp_class_tag(const char *cls, const char *tail) { /* A native Set or Map held as a checked-dynamic value: `Set(n) { a, b }`, * `Map(n) { k => v }`, at most 100 entries like Node's maxArrayLength. */ +/* Node's formatWeakCollection: the entries of a WeakMap or WeakSet are not + * listed without showHidden, so the body is the one "" + * entry, and past the depth limit the value prints as [WeakMap]. */ +static ScrStr *scr_insp_weak_collection(const char *label, double recurse, double depth) { + InspBuf out = {0}; + if (recurse > depth) { + ib_char(&out, '['); + ib_cstr(&out, label); + ib_char(&out, ']'); + return ib_take(&out); + } + ib_cstr(&out, label); + ib_cstr(&out, " { }"); + return ib_take(&out); +} + static ScrStr *scr_insp_dyn_collection(ScrDyn *d, double recurse, double depth, bool is_map) { ScrMap *map = d->v.handle.ptr; const char *label = is_map ? "Map" : "Set"; @@ -1077,6 +1124,46 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char return out; } +/* A numeric typed array (not a Buffer): `Uint8Array(n) [ ... ]` with + * Node's maxArrayLength (100) and array grid, `[Uint8Array]` past the + * depth limit. Borrows b; +1. */ +ScrStr *scr_insp_typed_array(ScrBytes *b, double recurse, double depth) { + char prefix[48]; + int pn = snprintf(prefix, sizeof prefix, "%s(%zu) [", scr_bytes_elem_name(b->elem), b->len); + if (b->len == 0) { + InspBuf out = {0}; + ib_bytes(&out, prefix, (size_t)pn); + ib_char(&out, ']'); + return ib_take(&out); + } + if (recurse > depth) { + char tag[32]; + int n = snprintf(tag, sizeof tag, "[%s]", scr_bytes_elem_name(b->elem)); + return scr_str_new(tag, (size_t)n); + } + scr_insp_begin(recurse + 1); + size_t shown = b->len < 100 ? b->len : 100; + for (size_t i = 0; i < shown; i++) { + ScrStr *s = scr_insp_f64(scr_bytes_get(b, (double)i)); + scr_insp_entry(s, true); + scr_str_release(s); + } + bool more = b->len > 100; + if (more) { + ScrStr *m = scr_insp_more_items((double)(b->len - 100)); + scr_insp_entry(m, true); + scr_str_release(m); + } + ScrStr *base = scr_str_new("", 0); + ScrStr *b0 = scr_str_new(prefix, (size_t)pn); + ScrStr *b1 = scr_str_new("]", 1); + ScrStr *out = scr_insp_end(base, b0, b1, recurse + 1, true, more); + scr_str_release(base); + scr_str_release(b0); + scr_str_release(b1); + return out; +} + ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { if (d->kind == SCR_DYN_PROXY) return scr_insp_dyn(d->v.proxy.target, recurse, depth); switch (d->kind) { @@ -1153,6 +1240,9 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { } if (d->v.handle.tag == SCR_DYNH_SET || d->v.handle.tag == SCR_DYNH_MAP) return scr_insp_dyn_collection(d, recurse, depth, d->v.handle.tag == SCR_DYNH_MAP); + if (d->v.handle.tag == SCR_DYNH_WEAK_MAP || d->v.handle.tag == SCR_DYNH_WEAK_SET) + return scr_insp_weak_collection(d->v.handle.tag == SCR_DYNH_WEAK_MAP ? "WeakMap" : "WeakSet", + recurse, depth); const ScrDynHandleOps *ops = scr_dyn_handle_ops_of(d); if (ops->inspect_view) { /* Node's custom inspectors answer the bare class name beyond the @@ -1245,40 +1335,7 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { /* Buffer-flavored (a stream chunk): Node's form. */ return scr_insp_buffer(b); } - char prefix[48]; - int pn = snprintf(prefix, sizeof prefix, "%s(%zu) [", scr_bytes_elem_name(b->elem), b->len); - if (b->len == 0) { - InspBuf out = {0}; - ib_bytes(&out, prefix, (size_t)pn); - ib_char(&out, ']'); - return ib_take(&out); - } - if (recurse > depth) { - char tag[32]; - int n = snprintf(tag, sizeof tag, "[%s]", scr_bytes_elem_name(b->elem)); - return scr_str_new(tag, (size_t)n); - } - scr_insp_begin(recurse + 1); - size_t shown = b->len < 100 ? b->len : 100; - for (size_t i = 0; i < shown; i++) { - ScrStr *s = scr_insp_f64(scr_bytes_get(b, (double)i)); - scr_insp_entry(s, true); - scr_str_release(s); - } - bool more = b->len > 100; - if (more) { - ScrStr *m = scr_insp_more_items((double)(b->len - 100)); - scr_insp_entry(m, true); - scr_str_release(m); - } - ScrStr *base = scr_str_new("", 0); - ScrStr *b0 = scr_str_new(prefix, (size_t)pn); - ScrStr *b1 = scr_str_new("]", 1); - ScrStr *out = scr_insp_end(base, b0, b1, recurse + 1, true, more); - scr_str_release(base); - scr_str_release(b0); - scr_str_release(b1); - return out; + return scr_insp_typed_array(b, recurse, depth); } } return scr_str_new("undefined", 9); /* unreachable */ diff --git a/packages/runtime/src/scr_inspect.h b/packages/runtime/src/scr_inspect.h index e489b23b7..f8d28b4f0 100644 --- a/packages/runtime/src/scr_inspect.h +++ b/packages/runtime/src/scr_inspect.h @@ -23,6 +23,8 @@ ScrStr *scr_insp_f64(double x); /* JS ToString, except -0 → "-0" */ ScrStr *scr_insp_str(ScrStr *s); /* the quoting ladder + line splitting */ ScrStr *scr_insp_regex(ScrRegex *re); /* /source/flags */ +/* A Date (its time value): toISOString(), or "Invalid Date" for NaN (+1). */ +ScrStr *scr_insp_date(double ms); ScrStr *scr_insp_buffer(ScrBytes *b); /* , 50-byte cap */ /* The stackless error form: [Name: message] / [Name], plus the stamped * code slot as its one extra property ({ code: 'X' }); [Name] beyond @@ -32,9 +34,16 @@ ScrStr *scr_insp_error(ScrError *e, double recurse, double depth); * traversal is here. dyn-boxed bytes render in the checked-dynamic tree's documented * Uint8Array identity. */ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth); +/* A numeric typed array that is not a Buffer: `Uint8Array(n) [ ... ]`, + * `[Uint8Array]` past the depth limit. Borrows b; +1. */ +ScrStr *scr_insp_typed_array(ScrBytes *b, double recurse, double depth); /* format's %s / rest-args twin: dyn strings pass verbatim. */ ScrStr *scr_insp_dyn_s(ScrDyn *d, double depth); void scr_insp_begin(double recurse); +/* util.inspect's breakLength, compact (0 for false) and sorted for the + * renders that follow; the call site restores the defaults (80, 3, false) + * afterwards. */ +void scr_insp_layout(double break_length, double compact, bool sorted); void scr_insp_entry(ScrStr *s, bool is_num); /* Circular references, Node-exact ( / [Circular *N]): the * compiler-emitted helpers over CYCLE-CAPABLE composites call circ_check diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 62f55e9aa..91a07eebb 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -3095,6 +3095,8 @@ bool scr_dyn_typed_array_is(const ScrDyn *d, int elem) { return d && d->kind == SCR_DYN_BYTES && !d->v.bytes->is_data_view && d->v.bytes->elem == (ScrBytesElem)elem; } +static bool scr_native_iterator_over(const ScrDyn *value, unsigned kind); + /* Node util.types reads internal brands, never user properties or prototypes. */ bool scr_dyn_util_type_is(const ScrDyn *value, const ScrStr *probe) { if (!value) return false; @@ -3125,6 +3127,18 @@ bool scr_dyn_util_type_is(const ScrDyn *value, const ScrStr *probe) { if (PROBE("isAsyncFunction")) return value->kind == SCR_DYN_FUNC && (scr_closure_identity(value->v.fn.clo)->function_kind & 2) != 0; if (PROBE("isGeneratorFunction")) return value->kind == SCR_DYN_FUNC && (scr_closure_identity(value->v.fn.clo)->function_kind & 1) != 0; if (PROBE("isGeneratorObject")) return scr_dyn_generator(value); + if (PROBE("isDate")) return value->kind == SCR_DYN_HANDLE && value->v.handle.tag == SCR_DYNH_DATE; + if (PROBE("isMapIterator")) return scr_native_iterator_over(value, 2); + if (PROBE("isSetIterator")) return scr_native_iterator_over(value, 3); + if (PROBE("isKeyObject")) return value->kind == SCR_DYN_HANDLE && value->v.handle.tag == SCR_DYNH_KEY_OBJECT; + /* Boxed primitives, BigInt64Array, BigUint64Array, Float16Array, CryptoKey + * and external values cannot be created here, so no value has these + * brands. */ + if (PROBE("isNumberObject") || PROBE("isStringObject") || PROBE("isBooleanObject") || + PROBE("isBigIntObject") || PROBE("isSymbolObject") || PROBE("isBoxedPrimitive") || + PROBE("isBigInt64Array") || PROBE("isBigUint64Array") || PROBE("isFloat16Array") || + PROBE("isCryptoKey") || PROBE("isExternal")) + return false; if (PROBE("isNativeError")) { ScrError *error = scr_errdyn_err_of(value); if (!error) return false; @@ -4294,6 +4308,13 @@ typedef struct { static ScrDyn *scr_iterator_read(const ScrDyn *value, const char *key, size_t len); +/* A Map (kind 2) or Set (kind 3) iterator: util.types.isMapIterator and + * isSetIterator. */ +static bool scr_native_iterator_over(const ScrDyn *value, unsigned kind) { + return value->kind == SCR_DYN_HANDLE && value->v.handle.tag == SCR_DYNH_ITERATOR && + ((const ScrNativeIterator *)value->v.handle.ptr)->kind == kind; +} + static SCR_TL ScrDyn *scr_iterator_functions[11]; static SCR_TL bool scr_iterator_functions_registered; @@ -5500,8 +5521,8 @@ static bool scr_dyn_json_write(ScrJsonBuf *b, const ScrDyn *d) { } } -/* util.format's %j argument (+1): the stringify text, "undefined" for a - * root the stringify drops, or NULL with a pending exception (a handle +/* The JSON text of a dyn value (+1): the stringify text, "undefined" for + * a root the stringify drops, or NULL with a pending exception (a handle * inside the tree). */ ScrStr *scr_dyn_format_j(const ScrDyn *d) { ScrJsonBuf b; @@ -9094,6 +9115,52 @@ ScrDyn *scr_json_stringify_value(const ScrDyn *value, const ScrDyn *replacer, co return result; } +/* util.format's %j over a pending stringify exception (Node's + * tryStringify): a TypeError whose first message line is "Converting + * circular structure to JSON" is cleared and the result is the text + * "[Circular]" (+1). Any other exception is put back and the result is + * NULL. */ +static ScrStr *scr_json_circular_or_rethrow(void) { + ScrCaught *caught = scr_exc_take(); + ScrDyn *thrown = scr_caught_to_dyn(caught); + ScrError *error = scr_errdyn_err_of(thrown); + scr_dyn_release(thrown); + static const char circular[] = "Converting circular structure to JSON"; + bool is_circular = false; + if (error && error->name && error->message) { + const ScrStr *message = error->message; + const char *newline = memchr(message->data, '\n', message->len); + size_t first_line = newline ? (size_t)(newline - message->data) : message->len; + is_circular = error->name->len == 9 && memcmp(error->name->data, "TypeError", 9) == 0 && + first_line == sizeof circular - 1 && memcmp(message->data, circular, first_line) == 0; + } + scr_error_release(error); + if (!is_circular) scr_rethrow(caught); + scr_caught_release(caught); + return is_circular ? scr_str_new("[Circular]", 10) : NULL; +} + +/* util.format's %j over a dynamic value (+1): JSON.stringify(d), the text + * "undefined" when the stringify returns undefined, and "[Circular]" for a + * circular structure. NULL with any other exception pending. */ +ScrStr *scr_util_format_j(const ScrDyn *d) { + ScrStr *gap = scr_str_new("", 0); + ScrDyn *result = scr_json_stringify_replacer(d, scr_dyn_undefined(), gap); + scr_str_release(gap); + if (!result) return scr_exc_pending() ? scr_json_circular_or_rethrow() : NULL; + ScrStr *text = result->kind == SCR_DYN_STR ? scr_str_retain(result->v.str) : scr_str_new("undefined", 9); + scr_dyn_release(result); + return text; +} + +/* util.format's %j over a typed value whose serializer can throw (+1): the + * serialized text when no exception is pending, "[Circular]" for a circular + * structure, NULL with any other exception pending. Borrows text. */ +ScrStr *scr_util_format_j_text(ScrStr *text) { + if (!scr_exc_pending()) return scr_str_retain(text); + return scr_json_circular_or_rethrow(); +} + /* Untyped RC adapters (box/promise/exception-cell currency). */ void *scr_dyn_retain_v(void *d) { return scr_dyn_retain((ScrDyn *)d); } void scr_dyn_release_v(void *d) { scr_dyn_release((ScrDyn *)d); } diff --git a/packages/runtime/src/scr_util_callable.c b/packages/runtime/src/scr_util_callable.c index a005015d6..f5ef488dc 100644 --- a/packages/runtime/src/scr_util_callable.c +++ b/packages/runtime/src/scr_util_callable.c @@ -610,7 +610,7 @@ static ScrStr *uc_format(ScrDyn *const *args, size_t argc, bool colors) { ScrStr *piece = NULL; switch (next) { case 's': piece = uc_format_s(args[++a]); break; - case 'j': piece = scr_dyn_format_j(args[++a]); break; + case 'j': piece = scr_util_format_j(args[++a]); break; case 'd': case 'i': case 'f': piece = uc_format_number(args[++a], next); break; diff --git a/tests/corpus/5831-util-types-brands.ts b/tests/corpus/5831-util-types-brands.ts new file mode 100644 index 000000000..7deec967d --- /dev/null +++ b/tests/corpus/5831-util-types-brands.ts @@ -0,0 +1,73 @@ +// util.types brand checks over typed values: isDate, isSharedArrayBuffer, +// isMapIterator, isSetIterator and isKeyObject answer from the value's +// internal brand, and isBoxedPrimitive (with the per-kind boxed checks), +// isBigInt64Array, isBigUint64Array, isFloat16Array, isCryptoKey and +// isExternal answer false for every value a program here can create. A +// Date-typed argument answers from its static type. +import { types } from "node:util"; +import * as direct from "node:util/types"; +import { createSecretKey } from "node:crypto"; + +const map = new Map([["a", 1]]); +const set = new Set([1, 2]); +const values: [string, unknown][] = [ + ["shared buffer", new SharedArrayBuffer(8)], + ["array buffer", new ArrayBuffer(8)], + ["map keys", map.keys()], + ["map entries", map.entries()], + ["map values", map.values()], + ["set values", set.values()], + ["set entries", set.entries()], + ["array values", [1, 2].values()], + ["map", map], + ["set", set], + ["key object", createSecretKey(Buffer.from("secret"))], + ["number", 1], + ["string", "s"], + ["boolean", true], + ["bigint", 1n], + ["symbol", Symbol("s")], + ["object", { getTime: () => 0 }], + ["uint8", new Uint8Array(2)], + ["null", null], + ["undefined", undefined], +]; + +function brands(value: unknown): string { + const hits: string[] = []; + if (types.isDate(value)) hits.push("isDate"); + if (types.isSharedArrayBuffer(value)) hits.push("isSharedArrayBuffer"); + if (types.isAnyArrayBuffer(value)) hits.push("isAnyArrayBuffer"); + if (types.isMapIterator(value)) hits.push("isMapIterator"); + if (types.isSetIterator(value)) hits.push("isSetIterator"); + if (types.isKeyObject(value)) hits.push("isKeyObject"); + if (types.isBoxedPrimitive(value)) hits.push("isBoxedPrimitive"); + if (types.isNumberObject(value)) hits.push("isNumberObject"); + if (types.isStringObject(value)) hits.push("isStringObject"); + if (types.isBooleanObject(value)) hits.push("isBooleanObject"); + if (types.isBigIntObject(value)) hits.push("isBigIntObject"); + if (types.isSymbolObject(value)) hits.push("isSymbolObject"); + if (types.isBigInt64Array(value)) hits.push("isBigInt64Array"); + if (types.isBigUint64Array(value)) hits.push("isBigUint64Array"); + if (types.isFloat16Array(value)) hits.push("isFloat16Array"); + if (types.isCryptoKey(value)) hits.push("isCryptoKey"); + if (types.isExternal(value)) hits.push("isExternal"); + return hits.join(",") || "-"; +} + +for (const [label, value] of values) console.log(label, brands(value)); + +let reads = 0; +function date(ms: number): Date { + reads++; + return new Date(ms); +} +console.log("date", types.isDate(date(0)), types.isDate(date(Number.NaN)), direct.isDate(date(1))); +console.log("date others", types.isMap(date(0)), types.isRegExp(date(0)), types.isBoxedPrimitive(date(0)), types.isNativeError(date(0)), reads); + +// The node:util/types spellings and a consumed iterator. +const it = map.keys(); +for (const _ of it) { + // drain +} +console.log("drained", direct.isMapIterator(it), direct.isSetIterator(set.keys())); diff --git a/tests/corpus/5832-util-types-brands-dynamic.js b/tests/corpus/5832-util-types-brands-dynamic.js new file mode 100644 index 000000000..cc8688f5d --- /dev/null +++ b/tests/corpus/5832-util-types-brands-dynamic.js @@ -0,0 +1,31 @@ +// util.types brand checks over checked-dynamic values: Dates, Map and Set +// iterators (before and after they are consumed), SharedArrayBuffer and +// KeyObject carry their brands; arrays, plain objects and objects that +// imitate a Date or an iterator do not. +import { types } from "node:util"; +import { createSecretKey } from "node:crypto"; + +const map = new Map([["a", 1]]); +const set = new Set([1, 2]); +const drained = set.values(); +for (const _ of drained) { + // drain +} +const values = [ + ["date", new Date(0)], + ["map keys", map.keys()], + ["map iterator", map[Symbol.iterator]()], + ["set values", set.values()], + ["drained set iterator", drained], + ["array iterator", [1].values()], + ["shared buffer", new SharedArrayBuffer(4)], + ["key object", createSecretKey(Buffer.from("k"))], + ["date-like", { getTime() { return 0; }, [Symbol.toStringTag]: "Date" }], + ["iterator-like", { next() { return { done: true }; }, [Symbol.toStringTag]: "Map Iterator" }], + ["array", [1, 2]], + ["number", 1], +]; +const probes = ["isDate", "isMapIterator", "isSetIterator", "isSharedArrayBuffer", "isKeyObject", "isBoxedPrimitive", "isNumberObject", "isBigInt64Array", "isExternal"]; +for (const [label, value] of values) { + console.log(label, probes.filter((name) => types[name](value)).join(",") || "-"); +} diff --git a/tests/corpus/5835-util-format-integer-specifiers.ts b/tests/corpus/5835-util-format-integer-specifiers.ts new file mode 100644 index 000000000..ed5648761 --- /dev/null +++ b/tests/corpus/5835-util-format-integer-specifiers.ts @@ -0,0 +1,29 @@ +// util.format and console.log %d / %i over arguments Node formats without a +// number conversion: a bigint prints with its n suffix, a symbol as NaN, +// null as 0 under %d and NaN under %i, and undefined as NaN. Arguments still +// evaluate in order. +import { format } from "node:util"; + +const calls: string[] = []; +function big(n: bigint): bigint { + calls.push(`big ${n}`); + return n; +} +function sym(): symbol { + calls.push("sym"); + return Symbol("s"); +} +function nothing(): undefined { + calls.push("nothing"); + return undefined; +} + +console.log(format("%d %i", 10n, -5n)); +console.log(format("%d", 2n ** 70n), format("%i", -(2n ** 65n))); +console.log(format("%d|%i", 0n, 0n)); +console.log(format("%d %i", Symbol("x"), Symbol.iterator)); +console.log(format("%d %i", null, null)); +console.log(format("%d %i", undefined, undefined)); +console.log(format("%d-%i-%d", big(3n), sym(), nothing()), calls.join(", ")); +console.log("count %d of %i", 42n, 7n); +console.log("missing %d", null, "extra"); diff --git a/tests/corpus/5837-util-format-json-circular.ts b/tests/corpus/5837-util-format-json-circular.ts new file mode 100644 index 000000000..5e79c7ce2 --- /dev/null +++ b/tests/corpus/5837-util-format-json-circular.ts @@ -0,0 +1,67 @@ +// util.format, formatWithOptions and console.log %j over circular values: +// Node's tryStringify prints "[Circular]" when JSON.stringify throws the +// circular-structure TypeError, and rethrows every other error. A checked- +// dynamic argument stringifies as JSON.stringify does (toJSON hooks, +// dropped members, shared references); a recursive typed value prints +// "[Circular]" where JSON.stringify throws. +import { format, formatWithOptions } from "node:util"; + +const parsed = JSON.parse('{"name":"root","children":[{"name":"leaf"}]}'); +parsed.children[0].parent = parsed; +console.log(format("%j", parsed)); +console.log(format("%j|%j", parsed.children, parsed.children[0].name)); +console.log("%j", parsed); + +const bag: Record = { id: 1 }; +bag.self = bag; +console.log(format("%j", bag), formatWithOptions({}, "[%j]", bag)); + +const list: unknown[] = [1, 2]; +list.push(list); +console.log(format("%j", list), format("%j", [list])); + +const shared = { s: 1 }; +const twice: unknown = { a: shared, b: shared }; +console.log(format("%j", twice)); + +const hooked: unknown = { toJSON: (key: string) => `toJSON(${JSON.stringify(key)})` }; +const dropped: unknown = { skip: undefined, n: NaN, f: () => 1 }; +console.log(format("%j %j", hooked, dropped)); + +const big: unknown = { n: 1n }; +try { + format("%j", big); +} catch (error) { + console.log("rethrown", (error as Error).name, (error as Error).message); +} +const ranged: unknown = { + toJSON: () => { + throw new RangeError("Converting circular structure to JSON"); + }, +}; +try { + format("%j", ranged); +} catch (error) { + console.log("rethrown", (error as Error).name); +} +const firstLine: unknown = { + toJSON: () => { + throw new TypeError("Converting circular structure to JSON\n --> elsewhere"); + }, +}; +console.log(format("%j", firstLine)); + +interface Item { + name: string; + next: Item | null; +} +const item: Item = { name: "a", next: null }; +console.log(format("%j", item)); +item.next = { name: "b", next: item }; +console.log(format("%j", item), format("%j", [item])); +console.log("%j and %j", { item }, 5); +try { + JSON.stringify(item); +} catch (error) { + console.log((error as Error).name, (error as Error).message.split("\n")[0]); +} diff --git a/tests/corpus/5881-inspect-weak-collections.ts b/tests/corpus/5881-inspect-weak-collections.ts new file mode 100644 index 000000000..b281dcb12 --- /dev/null +++ b/tests/corpus/5881-inspect-weak-collections.ts @@ -0,0 +1,24 @@ +// util.inspect, console.log and util.format's %s and %O print a WeakMap or +// WeakSet as Node's formatWeakCollection does: the entries are not +// listed, so the body is "", and past the depth limit the +// value prints as [WeakMap] / [WeakSet]. Nested positions follow the +// usual line breaking. +import { format, inspect } from "node:util"; + +const cache = new WeakMap(); +const seen = new WeakSet(); +const key = {}; +cache.set(key, 1); +seen.add(key); + +console.log(cache, seen); +console.log(inspect(cache), inspect(new WeakSet())); +console.log({ cache, seen }); +console.log([cache, [seen, [cache]]]); +console.log(inspect({ a: { b: { c: cache } } }), inspect({ a: { b: { c: { d: seen } } } })); +console.log(inspect({ cache }, { depth: 0 }), inspect([seen], { depth: 0 })); +console.log(inspect({ cache }, { depth: null })); +console.log(new Map>([["k", cache]])); +console.log(new Set>([seen])); +console.log(format("%s|%O", cache, seen), inspect(cache).length); +console.log(cache.has(key), seen.has(key), cache.get(key)); diff --git a/tests/corpus/5884-inspect-layout-options.ts b/tests/corpus/5884-inspect-layout-options.ts new file mode 100644 index 000000000..f75528b9b --- /dev/null +++ b/tests/corpus/5884-inspect-layout-options.ts @@ -0,0 +1,51 @@ +// util.inspect and console.dir with the breakLength and compact options: +// breakLength (a number or Infinity) is the line width the single-line +// form and the array grid must fit, and compact sets how many inner +// levels may join one line and the grid's column limit (compact * 4). +// compact: false (or a number below 1) puts every entry of every +// composite on its own line. A render with these options leaves later +// renders at the defaults. +import { inspect } from "node:util"; + +class Point { + x: number; + y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } +} + +const config = { + name: "service", + ports: [80, 443], + limits: { cpu: 2, memory: { soft: "1G", hard: "2G" } }, + tags: new Set(["a", "b"]), + routes: new Map([["/", { handler: "index", methods: ["GET", "HEAD"] }]]), +}; +const numbers = Array.from({ length: 30 }, (_, i) => i * 37); +const words = Array.from({ length: 26 }, (_, i) => String.fromCharCode(97 + i).repeat((i % 5) + 1)); +const points = Array.from({ length: 8 }, (_, i) => new Point(i, i * i)); +const text = { text: "line one\nline two\nline three is a longer one" }; + +console.log(inspect(config, { compact: false })); +console.log(inspect(config, { compact: 1 })); +console.log(inspect(config, { compact: 5, depth: Infinity })); +console.log(inspect(config, { breakLength: 40 })); +console.log(inspect(config, { breakLength: Infinity })); +console.log(inspect(config, { breakLength: 120, compact: 2 })); +console.log(inspect(numbers, { compact: false })); +console.log(inspect(numbers, { compact: 1 })); +console.log(inspect(numbers, { breakLength: 40 }), inspect(numbers, { breakLength: 150 })); +console.log(inspect(words, { compact: 6 }), inspect(words, { breakLength: 60 })); +console.log(inspect(points, { compact: 2, breakLength: 120 })); +console.log(inspect(points, { compact: false })); +console.log(inspect(text, { breakLength: Infinity }), inspect(text, { compact: false })); +console.log(inspect(text.text, { breakLength: 20 })); +console.log(inspect([], { compact: false }), inspect({}, { compact: false }), inspect(new Map([[1, 2]]), { compact: false })); +console.log(inspect({ a: 1 }, { compact: 0 }), inspect({ a: [1, 2] }, { breakLength: 0 })); +const parsed: unknown = JSON.parse('{"x":[1,2,{"y":"z"}],"w":{"v":null}}'); +console.log(inspect(parsed, { compact: false }), inspect(parsed, { breakLength: 10 })); +console.dir(config, { compact: false, depth: 0 }); +console.dir(parsed, { breakLength: 20 }); +console.log(config); diff --git a/tests/corpus/5886-inspect-dates.ts b/tests/corpus/5886-inspect-dates.ts new file mode 100644 index 000000000..37338135d --- /dev/null +++ b/tests/corpus/5886-inspect-dates.ts @@ -0,0 +1,32 @@ +// util.inspect, console.log, console.dir and util.format's %s, %O and %o +// print a Date as Node does: its toISOString() at every depth (including +// six-digit signed years), and "Invalid Date" for a NaN time value. Dates +// in record fields and class instances follow the usual layout. +import { format, inspect } from "node:util"; + +const epoch = new Date(0); +console.log(epoch); +console.log(inspect(epoch), inspect(epoch, { depth: 0 }), inspect(new Date("garbage"))); +console.log(inspect({ a: { b: { c: { epoch } } } }), inspect({ a: { b: { epoch } } })); +console.log(format("%s|%O|%o", epoch, epoch, { epoch })); +console.log("at %s", new Date(1e12)); +console.log({ + epoch, + invalid: new Date(Number.NaN), + latest: new Date(8.64e15), + earliest: new Date(-8.64e15), +}); +console.log({ + leap: new Date(Date.UTC(2024, 1, 29, 12, 30, 45, 123)), + negativeYear: new Date(Date.UTC(-1, 0, 1)), + farFuture: new Date(Date.UTC(10000, 0, 1)), + parsed: new Date("2020-06-15T08:09:10.011+02:00"), +}); + +class Entry { + at = new Date(5); + name = "entry"; +} +console.log(new Entry(), [new Entry()]); +console.error(epoch); +console.dir({ epoch }, { depth: 0 }); diff --git a/tests/corpus/5887-inspect-typed-arrays.ts b/tests/corpus/5887-inspect-typed-arrays.ts new file mode 100644 index 000000000..eb6fb6750 --- /dev/null +++ b/tests/corpus/5887-inspect-typed-arrays.ts @@ -0,0 +1,30 @@ +// util.inspect, console.log and console.dir print a numeric typed array +// that is not a Buffer as Node does: `Float64Array(n) [ ... ]` with the +// number formatting, the 100-element maxArrayLength tail, the array grid +// and `[Int16Array]` past the depth limit. Typed arrays other than +// Uint8Array also print inside records and arrays, and under the +// breakLength, compact and sorted options; Buffers keep their +// form. +import { inspect } from "node:util"; + +console.log(new Uint8Array([1, 2, 3]), new Uint8Array(0)); +console.log(new Float64Array([1.5, -0, Number.NaN, Infinity, -1e21])); +console.log(new Float32Array([0.1, 16777217])); +console.log(new Int32Array(30)); +console.log(new Uint8ClampedArray([300, -5, 1.5]), new Int8Array([-1, 127, 128])); +console.log(inspect(new Uint16Array(150))); +console.log({ samples: new Uint16Array([7, 8]), deltas: new Int8Array([-1, 2]) }); +console.log([new Float32Array([1, 2]), new Float32Array(10)]); +console.log(inspect({ x: { y: { z: new Uint32Array([1]) } } }), inspect(new Int16Array([5]), { depth: 0 })); +console.log(inspect({ x: { y: new Int16Array([5]) } }, { depth: 1 })); +console.dir(new Uint8Array([4, 5])); +console.log(new Uint8Array([1, 2, 3, 4]).subarray(1, 3), new Uint8Array(Buffer.from("hi")), Buffer.from("hi")); +const grid = new Float64Array(12); +for (let i = 0; i < grid.length; i++) grid[i] = i * 1.25; +console.log(grid); +const wide = new Uint8Array(40); +for (let i = 0; i < wide.length; i++) wide[i] = i * 7; +console.log(inspect(wide, { breakLength: 40 })); +console.log(inspect(new Int16Array([1, -2, 300, -4000, 5]), { compact: false })); +console.log(inspect(new Uint32Array(120), { depth: 0, breakLength: 60 })); +console.log(inspect(new Int8Array([3, 1, 2]), { sorted: true, breakLength: Infinity })); diff --git a/tests/corpus/5888-inspect-sorted.ts b/tests/corpus/5888-inspect-sorted.ts new file mode 100644 index 000000000..97a6ffb30 --- /dev/null +++ b/tests/corpus/5888-inspect-sorted.ts @@ -0,0 +1,34 @@ +// util.inspect and console.dir with sorted: true order the entries of +// objects, class instances, Maps and Sets by their rendered text, in +// UTF-16 code-unit order (quoted keys sort by their quote, the "... more +// items" tail sorts with the rest), at every nesting level. Arrays keep +// their element order. sorted: false is the default. +import { inspect } from "node:util"; + +const record = { + zeta: 1, + alpha: { c: 3, b: 2, a: 1 }, + "quoted-key": true, + Beta: [3, 1, 2], + _under: null, + 10: "ten", + 2: "two", +}; +console.log(inspect(record, { sorted: true })); +console.log(inspect(record, { sorted: false })); +console.log(inspect(new Map([["b", 1], ["a", 2], ["c", { z: 1, y: 2 }]]), { sorted: true })); +console.log(inspect(new Set(["pear", "apple", "fig"]), { sorted: true })); +console.log(inspect({ é: 1, e: 2, "😀": 3, "￿": 4 }, { sorted: true })); +console.log(inspect([{ b: 1, a: 2 }, { d: 1, c: 2 }], { sorted: true, compact: false })); + +class Point { + y = 1; + x = 2; +} +console.log(inspect(new Point(), { sorted: true }), inspect([3, 1, 2], { sorted: true })); +const many = new Set(Array.from({ length: 105 }, (_, i) => `k${i}`)); +console.log(inspect(many, { sorted: true, breakLength: Infinity })); +const parsed: unknown = JSON.parse('{"b":1,"a":{"d":1,"c":2}}'); +console.log(inspect(parsed, { sorted: true })); +console.dir({ b: 1, a: 2 }, { sorted: true }); +console.log(record); diff --git a/tests/harness/__snapshots__/console-fences.ts.txt b/tests/harness/__snapshots__/console-fences.ts.txt index 98865ff68..1841fec65 100644 --- a/tests/harness/__snapshots__/console-fences.ts.txt +++ b/tests/harness/__snapshots__/console-fences.ts.txt @@ -59,7 +59,7 @@ console-fences.ts:17:25 - error SC2020: 'console.dir with the 'showHidden' optio | ^~~~~~~~~~~~~~~~ 18 | - hint: the lowered options are depth (numeric literal or null), colors: false, compact: 3, breakLength: 80, and customInspect: false + hint: the lowered options are depth (numeric literal or null), colors: false, compact (false or a number), breakLength, sorted (true or false), and customInspect: false console-fences.ts:22:35 - error SC2020: 'console.assert with a format string and computed arguments' is part of the standard library types but has no scriptc lowering yet diff --git a/tests/harness/__snapshots__/index-signature-values.ts.txt b/tests/harness/__snapshots__/index-signature-values.ts.txt index 9774ab9ae..d1e9395ed 100644 --- a/tests/harness/__snapshots__/index-signature-values.ts.txt +++ b/tests/harness/__snapshots__/index-signature-values.ts.txt @@ -16,7 +16,7 @@ index-signature-values.ts:9:13 - error SC2004: uses of 'bySymbol' inherit the bl hint: the declaration of 'bySymbol' did not compile — fix the diagnostic reported there and these sites clear with it -index-signature-values.ts:13:13 - error SC1090: console.log of '{ [key: string]: Uint8Array }' values (typed arrays inside composites have no inspect lowering yet (Buffer's form vs Uint8Array's is not recorded in the static type here)) are not supported yet +index-signature-values.ts:13:13 - error SC1090: console.log of '{ [key: string]: Uint8Array }' values (Uint8Array and Buffer values inside composites have no inspect lowering yet (Buffer's form vs Uint8Array's is not recorded in the static type here)) are not supported yet 12 | const buffers: Record = {}; 13 | console.log(buffers); diff --git a/tests/harness/__snapshots__/utility-types.ts.txt b/tests/harness/__snapshots__/utility-types.ts.txt index 371215a65..f8209335a 100644 --- a/tests/harness/__snapshots__/utility-types.ts.txt +++ b/tests/harness/__snapshots__/utility-types.ts.txt @@ -34,13 +34,6 @@ utility-types.ts:19:14 - error SC2004: uses of 'dateBag' inherit the blocker on hint: the declaration of 'dateBag' did not compile — fix the diagnostic reported there and these sites clear with it -utility-types.ts:20:13 - error SC1090: console.log of 'Date' values ('Date' values have no inspect lowering) are not supported yet - - 19 | const boot = dateBag["boot"]; - 20 | console.log(boot); - | ^~~~ - 21 | - utility-types.ts:22:33 - error SC1101: converting typed values to 'unknown' is not supported yet 21 | From 5e020e9ea6d52cca4c329aaade07c4ed10c39437 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 18:25:15 -0500 Subject: [PATCH 014/117] Regenerate the surface manifest for the new util.types brand checks --- packages/compiler/surface-manifest.json | 96 +++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index af481ee53..4f11e26c9 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -2489,12 +2489,66 @@ "name": "util/types.isAsyncFunction", "status": "static" }, + { + "id": "node-builtin.util.types.isBigInt64Array", + "kind": "node-builtin", + "name": "util/types.isBigInt64Array", + "status": "static" + }, + { + "id": "node-builtin.util.types.isBigIntObject", + "kind": "node-builtin", + "name": "util/types.isBigIntObject", + "status": "static" + }, + { + "id": "node-builtin.util.types.isBigUint64Array", + "kind": "node-builtin", + "name": "util/types.isBigUint64Array", + "status": "static" + }, + { + "id": "node-builtin.util.types.isBooleanObject", + "kind": "node-builtin", + "name": "util/types.isBooleanObject", + "status": "static" + }, + { + "id": "node-builtin.util.types.isBoxedPrimitive", + "kind": "node-builtin", + "name": "util/types.isBoxedPrimitive", + "status": "static" + }, + { + "id": "node-builtin.util.types.isCryptoKey", + "kind": "node-builtin", + "name": "util/types.isCryptoKey", + "status": "static" + }, { "id": "node-builtin.util.types.isDataView", "kind": "node-builtin", "name": "util/types.isDataView", "status": "static" }, + { + "id": "node-builtin.util.types.isDate", + "kind": "node-builtin", + "name": "util/types.isDate", + "status": "static" + }, + { + "id": "node-builtin.util.types.isExternal", + "kind": "node-builtin", + "name": "util/types.isExternal", + "status": "static" + }, + { + "id": "node-builtin.util.types.isFloat16Array", + "kind": "node-builtin", + "name": "util/types.isFloat16Array", + "status": "static" + }, { "id": "node-builtin.util.types.isFloat32Array", "kind": "node-builtin", @@ -2537,18 +2591,36 @@ "name": "util/types.isInt8Array", "status": "static" }, + { + "id": "node-builtin.util.types.isKeyObject", + "kind": "node-builtin", + "name": "util/types.isKeyObject", + "status": "static" + }, { "id": "node-builtin.util.types.isMap", "kind": "node-builtin", "name": "util/types.isMap", "status": "static" }, + { + "id": "node-builtin.util.types.isMapIterator", + "kind": "node-builtin", + "name": "util/types.isMapIterator", + "status": "static" + }, { "id": "node-builtin.util.types.isNativeError", "kind": "node-builtin", "name": "util/types.isNativeError", "status": "static" }, + { + "id": "node-builtin.util.types.isNumberObject", + "kind": "node-builtin", + "name": "util/types.isNumberObject", + "status": "static" + }, { "id": "node-builtin.util.types.isPromise", "kind": "node-builtin", @@ -2573,6 +2645,30 @@ "name": "util/types.isSet", "status": "static" }, + { + "id": "node-builtin.util.types.isSetIterator", + "kind": "node-builtin", + "name": "util/types.isSetIterator", + "status": "static" + }, + { + "id": "node-builtin.util.types.isSharedArrayBuffer", + "kind": "node-builtin", + "name": "util/types.isSharedArrayBuffer", + "status": "static" + }, + { + "id": "node-builtin.util.types.isStringObject", + "kind": "node-builtin", + "name": "util/types.isStringObject", + "status": "static" + }, + { + "id": "node-builtin.util.types.isSymbolObject", + "kind": "node-builtin", + "name": "util/types.isSymbolObject", + "status": "static" + }, { "id": "node-builtin.util.types.isTypedArray", "kind": "node-builtin", From 50d101f612336a8eb9f9922c0cd3038ff82d0804 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 18:45:15 -0500 Subject: [PATCH 015/117] Record corpus costs for the worker programs and order 5805's reads The worker series adds 16 corpus programs without measured costs in tests/harness/corpus-costs.json, which dropped the measured share below shard.test.ts's 0.9. Their plain and san costs are local timings of each program's differential and llvm-differential cases, scaled by the median ratio between the recorded and local timings of four programs timed in the same run (001-hello, 1000-json-stringify-basics, 5022-lifetime-region-workers, 5164-worker-field-callback-receiver). 5805 read its second message right after the first arrived; under load the parent's second postMessage could still be in flight, so the read answered undefined. The worker now waits on a shared flag that the parent sets after posting its first three messages. The output is unchanged. --- ...5805-worker-receive-message-parent-port.ts | 9 ++++-- tests/harness/corpus-costs.json | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/tests/corpus/5805-worker-receive-message-parent-port.ts b/tests/corpus/5805-worker-receive-message-parent-port.ts index 99d429169..5cda1574d 100644 --- a/tests/corpus/5805-worker-receive-message-parent-port.ts +++ b/tests/corpus/5805-worker-receive-message-parent-port.ts @@ -2,13 +2,17 @@ import { Worker, isMainThread, parentPort, receiveMessageOnPort, workerData } fr // receiveMessageOnPort(parentPort) in a worker takes the parent's messages // one at a time, before and between 'message' listener deliveries, and -// answers undefined once the queue is empty. +// answers undefined once the queue is empty. The worker starts reading +// once the parent has posted its first three messages (flag[1]), so the +// second read does not depend on thread timing. if (isMainThread) { - const flag = new Int32Array(new SharedArrayBuffer(4)); + const flag = new Int32Array(new SharedArrayBuffer(8)); const worker = new Worker(new URL(import.meta.url), { workerData: flag }); worker.postMessage("a"); worker.postMessage({ b: 2 }); worker.postMessage("c"); + Atomics.store(flag, 1, 1); + Atomics.notify(flag, 1); worker.on("message", (m: unknown) => { console.log("main got", JSON.stringify(m)); if (m === "ready") { @@ -22,6 +26,7 @@ if (isMainThread) { } else { const flag = workerData as Int32Array; const port = parentPort!; + Atomics.wait(flag, 1, 0); let first = receiveMessageOnPort(port); while (first === undefined) first = receiveMessageOnPort(port); port.postMessage(["first", first]); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index f87883acd..1c3cc266a 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,22 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5800-broadcast-channel.ts": 2899, + "5801-broadcast-channel.cjs": 2727, + "5802-broadcast-channel-workers.ts": 2809, + "5803-worker-environment-data.ts": 2748, + "5804-worker-environment-data.cjs": 2469, + "5805-worker-receive-message-parent-port.ts": 2839, + "5806-worker-resource-limits.ts": 3153, + "5807-worker-error-values.ts": 3304, + "5808-worker-unhandled-rejections.ts": 3430, + "5809-process-exit-and-rejections.cjs": 3294, + "5870-worker-thread-names.ts": 3106, + "5871-worker-untransferable.cjs": 2786, + "5874-worker-stdio-streams.ts": 2839, + "5875-worker-stdout-pipe.cjs": 2740, + "5879-worker-stdin.ts": 3158, + "5992-worker-thread-name-lifetime.mjs": 2687, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4465,6 +4481,22 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5800-broadcast-channel.ts": 28374, + "5801-broadcast-channel.cjs": 27251, + "5802-broadcast-channel-workers.ts": 27251, + "5803-worker-environment-data.ts": 29298, + "5804-worker-environment-data.cjs": 26404, + "5805-worker-receive-message-parent-port.ts": 30268, + "5806-worker-resource-limits.ts": 29711, + "5807-worker-error-values.ts": 35248, + "5808-worker-unhandled-rejections.ts": 33209, + "5809-process-exit-and-rejections.cjs": 30261, + "5870-worker-thread-names.ts": 31697, + "5871-worker-untransferable.cjs": 27481, + "5874-worker-stdio-streams.ts": 27801, + "5875-worker-stdout-pipe.cjs": 31391, + "5879-worker-stdin.ts": 33232, + "5992-worker-thread-name-lifetime.mjs": 28932, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 2b6f15c7fa02b2bd34850a4f2fde741dccace493 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 19:35:34 -0500 Subject: [PATCH 016/117] Answer undefined for missing Record and index-signature keys A keyed or dot read of an index signature that misses now answers undefined, as in Node, instead of aborting with "record has no key". The read carries an explicit optional value through the same analysis that already widens bindings, parameters, returns and fields for missing array elements; TypeScript's static types are unchanged. Numeric reads whose consumers treat undefined like NaN lower to plain doubles, and nested reads and writes through a missing entry throw Node's TypeError. Fixes #964 Co-authored-by: Quim T. <26749475+espetro@users.noreply.github.com> --- .../array-bounds-and-runtime-errors.mdx | 2 + packages/compiler/src/backend/llvm/emitter.ts | 2 + .../compiler/src/backend/llvm/expr-records.ts | 8 + .../src/frontend/lowering/lower-calls.ts | 9 +- .../src/frontend/lowering/lower-exprs.ts | 287 ++++++++++++++++-- .../src/frontend/lowering/lower-stmts.ts | 12 +- .../compiler/src/frontend/lowering/lowerer.ts | 78 ++++- .../src/frontend/lowering/nan-coded-reads.ts | 16 +- packages/compiler/src/ir/ir.ts | 26 +- .../corpus/5952-record-missing-keys.ts.json | 6 + .../5953-nan-coded-method-returns.ts.json | 6 + tests/corpus/5952-record-missing-keys.ts | 127 ++++++++ tests/corpus/5953-nan-coded-method-returns.ts | 44 +++ 13 files changed, 573 insertions(+), 50 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5952-record-missing-keys.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5953-nan-coded-method-returns.ts.json create mode 100644 tests/corpus/5952-record-missing-keys.ts create mode 100644 tests/corpus/5953-nan-coded-method-returns.ts diff --git a/docs/content/limitations/array-bounds-and-runtime-errors.mdx b/docs/content/limitations/array-bounds-and-runtime-errors.mdx index 431e60efe..8eb664a24 100644 --- a/docs/content/limitations/array-bounds-and-runtime-errors.mdx +++ b/docs/content/limitations/array-bounds-and-runtime-errors.mdx @@ -2,6 +2,8 @@ Typed-array reads at an index that is not an integer in the array's range return Ordinary arrays track holes separately from present `undefined` values. Missing reads and empty `pop()`/`shift()` return `undefined`, indexed writes can grow the array, and length growth creates holes. +Keyed reads of a `Record` or an index signature return `undefined` for a missing key, as in Node.js, with or without `noUncheckedIndexedAccess`. A missing array element or key that reaches storage that cannot hold `undefined`, such as a class field typed `number`, throws a `TypeError`. + Runtime traps cannot be caught. User-thrown values and supported exceptions, including JSON parse, checked-cast, filesystem, regex, and `String.prototype.repeat` count errors, can be caught; hard traps such as out-of-range reads of statically typed ordinary arrays terminate the process. Deep recursion in Linux and macOS executables throws Node's catchable `RangeError: Maximum call stack size exceeded`, on the main thread, in worker threads, and inside async functions and generators. The depth at which it is thrown differs from Node: the main thread uses the process stack limit (usually 8 MiB), worker threads get an 8 MiB stack, and async functions and generators run on 512 KiB stacks, so native code usually recurses deeper than Node on threads and somewhat less deeply inside async bodies. Recursion inside runtime library operations, such as serializing deeply nested data, is not checked. Windows executables, WASI builds and library builds do not check the stack, and exhausting it there terminates the process. diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 2c3a71457..f960944b1 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -10915,6 +10915,7 @@ export class LlEmitter { resultType: IrType, overflowOnly: boolean, loc?: SrcLoc, + missNaN = false, ): void { return keyedRecordReadInto( this, @@ -10926,6 +10927,7 @@ export class LlEmitter { resultType, overflowOnly, loc, + missNaN, ); } diff --git a/packages/compiler/src/backend/llvm/expr-records.ts b/packages/compiler/src/backend/llvm/expr-records.ts index 4b03dbad2..fc9df6daf 100644 --- a/packages/compiler/src/backend/llvm/expr-records.ts +++ b/packages/compiler/src/backend/llvm/expr-records.ts @@ -339,6 +339,7 @@ export function emitRecordKeyGet( e.type, e.overflowOnly === true, e.loc, + e.missNaN === true, ); B.startBlock(join); const t = B.tmp(); @@ -356,6 +357,7 @@ export function keyedRecordReadInto( resultType: IrType, overflowOnly: boolean, loc?: SrcLoc, + missNaN = false, ): void { const B = host.B; const shape = host.recordShape(shapeId); @@ -563,6 +565,12 @@ export function keyedRecordReadInto( B.br(join); return; } + if (missNaN && resultType.kind === "f64") { + // A NaN-coded read: every consumer treats undefined like NaN. + B.line(`store double ${f64Lit(NaN)}, ptr ${slot}`); + B.br(join); + return; + } // A direct result cannot represent a miss. This is unreachable for // programs whose behavior matches Node, but preserve the missing-key trap. host.needsBadKey = true; diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 2ba83a3d5..7d6e28031 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -123,6 +123,7 @@ import { recordMayKeepSource, throughRecordSource } from "./record-sources.js"; import { lowerReflectCall } from "./builtins/reflection.js"; import { lowerAbsenceProbe, + v8CalleeText, lowerOptionalNumber, lowerPromiseAllTupleCall, lowerPromiseRejectCall, @@ -1430,7 +1431,7 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { kind: "dynCall", callee: staticField, receiver: lowerer.lowerExprExpecting(expr.expression.expression, DYN), - calleeName: expr.expression.getText(), + calleeName: v8CalleeText(expr.expression), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc: locOf(expr), @@ -1449,7 +1450,7 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { return { kind: "dynCall", callee, - calleeName: expr.expression.getText(), + calleeName: v8CalleeText(expr.expression), args, type: DYN, loc: locOf(expr), @@ -1700,7 +1701,7 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { return { kind: "dynCall", callee: lowerer.coerceToExpected(callee, DYN), - calleeName: expr.expression.getText(), + calleeName: v8CalleeText(expr.expression), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc, @@ -1782,7 +1783,7 @@ function lowerCheckedCallableValue( return { kind: "dynCall", callee, - calleeName: call.expression.getText(), + calleeName: v8CalleeText(call.expression), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc, diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 08e12518b..eb0ed0162 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -3512,6 +3512,22 @@ function checkedStaleArm( return helper ? lowerer.checkedNarrowCall(helper, value, arm, value.loc) : null; } +/** V8's spelling of a callee in "is not a function": a string-literal + * element key reads as a property name (`o["a"]` is `o.a`), other keys + * keep their brackets. */ +export function v8CalleeText(node: ts.Node): string { + if (ts.isElementAccessExpression(node)) { + const key = node.argumentExpression; + const object = v8CalleeText(node.expression); + return ts.isStringLiteral(key) || ts.isNoSubstitutionTemplateLiteral(key) + ? `${object}.${key.text}` + : `${object}[${key.getText()}]`; + } + if (ts.isPropertyAccessExpression(node) && !node.questionDotToken) + return `${v8CalleeText(node.expression)}.${node.name.text}`; + return node.getText(); +} + /** Node's TypeError for the operation consuming `node` when it holds a * value of type `found`, or null where Node would not throw. */ function staleReadMessage(node: ts.Node, found: IrType): string | null { @@ -3522,7 +3538,7 @@ function staleReadMessage(node: ts.Node, found: IrType): string | null { parent = parent.parent; } if (ts.isCallExpression(parent) && parent.expression === child && !parent.questionDotToken) { - return found.kind === "func" ? null : `${node.getText()} is not a function`; + return found.kind === "func" ? null : `${v8CalleeText(node)} is not a function`; } const unit = found.kind === "undefinedT" ? "undefined" : found.kind === "nullT" ? "null" : null; if (unit === null) return null; @@ -6963,15 +6979,173 @@ export function lowerElementAccess(lowerer: Lowerer, expr: ts.ElementAccessExpre return lowerer.maybeNarrow({ kind: "arrayGet", arr, index, type: elemT, loc: locOf(expr) }, expr); } +/** A record receiver that an outer keyed read left optional + * (`nested[a][b]`, where `nested[a]` can miss). The receiver evaluates + * once into `stmts`; `present` is its record arm, valid only once the + * access has tested `stable` against the undefined arm. */ +interface OptionalRecordReceiver { + stmts: IrStmt[]; + stable: IrExpr; + present: IrExpr; + unionId: string; + undefTag: number; +} + +function optionalRecordReceiver( + lowerer: Lowerer, + value: IrExpr, + loc: SrcLoc, +): OptionalRecordReceiver | null { + if (value.type.kind !== "union") return null; + const unionId = value.type.unionId; + const undefTag = lowerer.armTag(unionId, UNDEFINED_T); + if (undefTag < 0 || lowerer.unions.get(unionId)?.arms.length !== 2) return null; + const record = lowerer.stripUndefinedArm(value.type); + if (record.kind !== "record") return null; + const stmts: IrStmt[] = []; + const stable = stabilized(lowerer, value, "%recordReceiver", stmts); + const present: IrExpr = { + kind: "unionNarrow", + unionId, + tag: lowerer.armTag(unionId, record), + value: stable, + type: record, + loc, + }; + return { stmts, stable, present, unionId, undefTag }; +} + +/** `value`, evaluated once at this point of `out`. */ +function stabilized(lowerer: Lowerer, value: IrExpr, name: string, out: IrStmt[]): IrExpr { + if (isSafeToRepeat(value)) return value; + const tmp = lowerer.declareHiddenLocal(name, value.type); + out.push({ kind: "varDecl", localId: tmp.id, init: value, loc: value.loc }); + return varRef(tmp.id, value.type, value.loc); +} + +function undefinedReceiver(receiver: OptionalRecordReceiver, loc: SrcLoc): IrExpr { + return { + kind: "unionIsTag", + unionId: receiver.unionId, + tag: receiver.undefTag, + negated: false, + value: receiver.stable, + type: BOOL, + loc, + }; +} + +/** Node's TypeError for a keyed read or write on an undefined receiver. */ +function undefinedReceiverThrow( + key: IrExpr, + action: "read" | "set", + type: IrType, + loc: SrcLoc, +): IrExpr { + const head = `Cannot ${action} properties of undefined (${action === "read" ? "reading" : "setting"} '`; + const message: IrExpr = { + kind: "strConcat", + left: { + kind: "strConcat", + left: { kind: "strLit", value: head, type: STRING, loc }, + right: key, + type: STRING, + loc, + }, + right: { kind: "strLit", value: "')", type: STRING, loc }, + type: STRING, + loc, + }; + return { + kind: "libCall", + fn: "error.nodeThrow", + args: [numLit(1, loc), { kind: "strLit", value: "", type: STRING, loc }, message], + type, + loc, + }; +} + +/** The receiver and key of a keyed access whose receiver can be undefined, + * evaluated in order into `stmts`, with the receiver's record arm and the + * key's property-name string. Null when the receiver is not optional. */ +function guardedRecordAccess( + lowerer: Lowerer, + access: ts.ElementAccessExpression, + rawObj: IrExpr, +): { receiver: OptionalRecordReceiver; key: IrExpr; name: IrExpr } | null { + const receiver = optionalRecordReceiver(lowerer, rawObj, locOf(access.expression)); + if (!receiver) return null; + const keyNode = access.argumentExpression; + const litKey = recordKeyLiteralText(keyNode) ?? recordKeyTypeLiteralText(lowerer, keyNode); + const key = + litKey !== null + ? ({ kind: "strLit", value: litKey, type: STRING, loc: locOf(keyNode) } satisfies IrExpr) + : stabilized(lowerer, lowerer.lowerExpr(keyNode), "%recordKey", receiver.stmts); + // A symbol key names no string property; its message spelling is not + // modeled. + const name = + key.type.kind === "symbol" + ? ({ kind: "strLit", value: "Symbol()", type: STRING, loc: locOf(keyNode) } satisfies IrExpr) + : lowerRecordPropertyKey(lowerer, key, keyNode); + return { receiver, key, name }; +} + +/** `nested[a][b] = v` where `nested[a]` can miss: the receiver, the key and + * the value evaluate in order, then an undefined receiver throws Node's + * TypeError and a present one takes the write. Only member and identifier + * receivers are probed, since a probe that finds no optional receiver + * lowers the receiver again. */ +function lowerGuardedRecordWrite( + lowerer: Lowerer, + expr: ts.BinaryExpression, + target: ts.ElementAccessExpression, +): IrStmt | null { + let receiverNode: ts.Expression = target.expression; + while (ts.isParenthesizedExpression(receiverNode)) receiverNode = receiverNode.expression; + if ( + lowerer.chainRecvByNode.has(target.expression) || + !( + ts.isElementAccessExpression(receiverNode) || + ts.isPropertyAccessExpression(receiverNode) || + ts.isIdentifier(receiverNode) + ) + ) + return null; + const guarded = guardedRecordAccess(lowerer, target, lowerer.lowerExpr(target.expression)); + if (!guarded) return null; + const { receiver, key, name } = guarded; + const loc = locOf(expr); + const value = stabilized(lowerer, lowerer.lowerExpr(expr.right), "%recordValue", receiver.stmts); + const write = lowerer.withExpressionOverride(target.expression, receiver.present, () => + lowerer.withExpressionOverride(target.argumentExpression, key, () => + lowerer.withExpressionOverride(expr.right, value, () => lowerElementWrite(lowerer, expr)), + ), + ); + return { + kind: "block", + body: [ + ...receiver.stmts, + { + kind: "if", + cond: undefinedReceiver(receiver, loc), + then: [{ kind: "exprStmt", expr: undefinedReceiverThrow(name, "set", VOID, loc), loc }], + else_: [write], + loc, + }, + ], + loc, + }; +} + /** `r[k]` over a (non-tuple) record shape. A LITERAL key naming a declared * field is the bracket spelling of field access (the ONLY spelling tsc * permits for signature-declared fields under * noPropertyAccessFromIndexSignature) — an ordinary recordGet. Everything * else is a runtime-keyed read (recordKeyGet): declared fields answer * first via an emitted string-switch, index-signature shapes fall through - * to the overflow map. The result type is the CHECKER's for the access — - * the index signature's value type (dyn for `unknown`), or its - * undefined-armed union under noUncheckedIndexedAccess. Every declared + * to the overflow map. The result type is the index signature's value type + * armed with undefined (dyn for `unknown`): a missing key reads undefined, + * as in JavaScript, whatever noUncheckedIndexedAccess says. Every declared * field must be able to SURFACE as that type (equal, an arm of it, or — * for dyn results — JSON-safe for the dyn conversion); shapes mixing in * fields outside that stay fenced. Declared-only shapes support reads @@ -6995,9 +7169,39 @@ export function lowerRecordKeyRead( // a generic instance) is the same static read — identifier evaluation // is pure, so skipping it matches JS exactly. const litKey = recordKeyLiteralText(keyNode) ?? recordKeyTypeLiteralText(lowerer, keyNode); + // An outer keyed read can leave the receiver undefined: evaluate the + // receiver and the key, then throw Node's TypeError or read the present + // record. // The receiver lowers FIRST (both branches below read it, and JS // evaluates the receiver before the key). const obj = lowerer.lowerExpr(expr.expression); + { + const guarded = guardedRecordAccess(lowerer, expr, obj); + if (guarded) { + const { receiver, key, name } = guarded; + const read = lowerer.withExpressionOverride(expr.expression, receiver.present, () => + litKey !== null + ? lowerRecordKeyRead(lowerer, expr, shapeId, shape, includeUndefined) + : lowerer.withExpressionOverride(keyNode, key, () => + lowerRecordKeyRead(lowerer, expr, shapeId, shape, includeUndefined), + ), + ); + return { + kind: "seqExpr", + stmts: receiver.stmts, + result: { + kind: "ternary", + cond: undefinedReceiver(receiver, loc), + then: undefinedReceiverThrow(name, "read", read.type, loc), + else_: read, + type: read.type, + loc, + }, + type: read.type, + loc, + }; + } + } // A record-mapped CHECKER type over a VALUE living in the checked-dynamic tree (a JS // file-scope object-literal global): the checked-dynamic keyed read — // dynKeyGet against the runtime keys (a missing key answers the checked-dynamic tree @@ -7111,21 +7315,29 @@ export function lowerRecordKeyRead( loc, }; } - // The DECLARED result type of the access — the index signature's value - // type (armed with undefined under noUncheckedIndexedAccess), or the - // declared fields' one common type on signature-free shapes (tsc's - // keyof check proved membership; a smuggled miss traps). The checker - // may have NARROWED this occurrence (assignment CFA on literal keys) — - // maybeNarrow bridges to the narrowed arm exactly like a field read. + // The result type of the access — the index signature's value type + // armed with undefined, or the declared fields' one common type on + // signature-free shapes (tsc's keyof check proved membership; a + // smuggled miss traps). On signature-free shapes the checker may have + // NARROWED this occurrence (assignment CFA on literal keys) — maybeNarrow + // bridges to the narrowed arm exactly like a field read. let declared: IrType | null = null; + // An index-signature read is a JavaScript property read: a missing key + // answers undefined even without noUncheckedIndexedAccess. The read keeps + // that explicit optional union, as an ordinary array read does. + let optionalRead = false; + // A read whose every consumer treats undefined like NaN (see + // nan-coded-reads.ts) is a plain number that is NaN for a missing key. + const nanCoded = + !includeUndefined && + shape.indexValue?.kind === "f64" && + lowerer.nanCodedReads?.isNumericRead(expr) === true; if (shape.indexValue) { declared = shape.indexValue; - if ( - declared.kind !== "dyn" && - (includeUndefined || lowerer.program.getCompilerOptions().noUncheckedIndexedAccess) - ) { + if (declared.kind !== "dyn" && !nanCoded) { declared = lowerer.withUndefinedArmOf(declared); if (!declared) lowerer.badType(expr, lowerer.typeOf(expr)); + optionalRead = true; } } else if ( shape.fields.length > 0 && @@ -7158,10 +7370,12 @@ export function lowerRecordKeyRead( shapeId, key, ...(overflowOnly ? { overflowOnly: true as const } : {}), + ...(nanCoded ? { missNaN: true as const } : {}), type: declared, loc, }; - return includeUndefined ? read : lowerer.maybeNarrow(read, expr); + if (nanCoded) return read; + return includeUndefined || optionalRead ? read : lowerer.maybeNarrow(read, expr); } /** ToPropertyKey for represented record keys. Missing array-derived string @@ -7269,7 +7483,8 @@ export function lowerPresenceOperand(lowerer: Lowerer, node: ts.Expression): IrE * side of `||`/`??`). JavaScript answers undefined for missing record keys * and array indices even when noUncheckedIndexedAccess is disabled. Keep * that value in an explicit union until the surrounding guard/default has - * consumed it; ordinary unchecked reads retain the typed trap. Assertions + * consumed it, including class-field and declared-only reads that otherwise + * keep their typed storage. Assertions * around the read are erased here because this context handles the missing * arm instead of consuming it as the asserted type. */ export function lowerAbsenceProbe(lowerer: Lowerer, node: ts.Expression): IrExpr | null { @@ -8067,6 +8282,8 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression): // the field's type through the emitted helper (a mismatch throws the // catchable TypeError — SEMANTICS.md). if (shape && !shape.tuple) { + const guarded = lowerGuardedRecordWrite(lowerer, expr, target); + if (guarded) return guarded; // Literal keys — string literals AND numeric literals in their // canonical string spelling (`b[1] = v` writes field/key "1", JS's // own key derivation) — name declared fields directly. A key @@ -14476,19 +14693,35 @@ export function fieldTarget( // all-unknown-fields cast — `(err as { code?: unknown }).code`): // decline, and the dyn keyed-read fallback answers. if (obj.type.kind === "union" && lowerer.armTag(obj.type.unionId, UNDEFINED_T) >= 0) { - // A nested property read such as `rows[i].value` has the same - // unchecked outer array-read issue as tuple indexing. Validate - // the record arm before fieldGet/recordGet so a missing outer - // value raises a catchable TypeError rather than reaching the - // backend with a union receiver. + // A nested property read such as `rows[i].value` or + // `table[k].value`: the outer read can miss. Validate the record + // arm before fieldGet/recordGet so a missing outer value raises + // Node's TypeError rather than reaching the backend with a union + // receiver. const present = lowerer.stripUndefinedArm(obj.type); + const parent = access.parent; + const written = + parent !== undefined && + ts.isBinaryExpression(parent) && + parent.left === access && + parent.operatorToken.kind === ts.SyntaxKind.EqualsToken; const helper = present.kind === "record" ? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(access.expression)) : null; - obj = helper - ? lowerer.checkedNarrowCall(helper, obj, present, locOf(access.expression)) - : lowerer.maybeNarrow(obj, access.expression); + obj = + (present.kind === "record" + ? lowerer.runtimeOptionalPropertyReceiver( + access.expression, + obj, + present, + access.name.text, + written ? "set" : "read", + ) + : null) ?? + (helper + ? lowerer.checkedNarrowCall(helper, obj, present, locOf(access.expression)) + : lowerer.maybeNarrow(obj, access.expression)); } if (obj.type.kind !== "record") return null; const actualShape = lowerer.shapes.get(obj.type.shapeId); @@ -14806,8 +15039,8 @@ export function fieldGetExpr( } // Overflow dot reads: exactly the bracket read with a literal key — // recordKeyGet, overflowOnly (the name declares no field by - // construction), typed as the index value armed with undefined under - // noUncheckedIndexedAccess (mirroring lowerRecordKeyRead). + // construction), typed as the index value armed with undefined + // (mirroring lowerRecordKeyRead). if (target.container === "recordOvf") { let obj = target.obj; if (obj.type.kind === "union" && ts.isPropertyAccessExpression(blame)) { @@ -14833,7 +15066,7 @@ export function fieldGetExpr( `reading '${target.field}' on a record without an index signature`, ); let t: IrType = shape.indexValue; - if (lowerer.program.getCompilerOptions().noUncheckedIndexedAccess) { + if (t.kind !== "dyn") { const armed = lowerer.withUndefinedArmOf(t); if (!armed) lowerer.badType(blame, lowerer.typeOf(blame)); t = armed; diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 367c147f8..b55b5e90d 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -2780,18 +2780,20 @@ export function lowerBindingPattern( // An UNDECLARED key of an INDEX-SIGNATURE shape (`const { m, n, p } // = ....groups` over `{ [key: string]: string }` — the groups // record, `Record` tables generally): the overflow-map - // read, exactly the dot access's recordKeyGet — a missing key - // traps when the value type carries no undefined arm (the checker - // claimed V), or binds the undefined arm (where a default applies - // like any field's). + // read, exactly the dot access's recordKeyGet — a missing key binds + // the undefined arm (where a default applies like any field's). const loc = locOf(el); + const readType = + shape.indexValue.kind === "dyn" + ? shape.indexValue + : (lowerer.withUndefinedArmOf(shape.indexValue) ?? shape.indexValue); let value: IrExpr = { kind: "recordKeyGet", obj: srcRef(), shapeId: srcType.shapeId, key: { kind: "strLit", value: propName, type: STRING, loc }, overflowOnly: true, - type: shape.indexValue, + type: readType, loc, }; if (el.initializer) value = applyBindingDefault(lowerer, el, value); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 61ccc76ce..f5c486666 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1926,6 +1926,26 @@ export class Lowerer { return fallback ?? null; } + /** The index value of a keyed read of a record's index signature that + * can answer undefined for a missing key while its checker type does not + * admit undefined, or null. A literal key naming a declared field is a + * field read. */ + optionalIndexSignatureRead(e: ts.ElementAccessExpression): IrType | null { + const receiver = panicSafe(() => this.mapTypeOf(this.typeOf(e.expression)), null); + if (receiver?.kind !== "record") return null; + const shape = this.shapes.get(receiver.shapeId); + if (!shape || shape.tuple || !shape.indexValue || shape.indexValue.kind === "dyn") return null; + const key = e.argumentExpression; + if ( + (ts.isStringLiteral(key) || ts.isNumericLiteral(key)) && + shape.fields.some((field) => field.name === key.text) + ) + return null; + const read = panicSafe(() => this.mapTypeOf(this.typeOf(e)), null); + if (read?.kind === "union" && this.armTag(read.unionId, UNDEFINED_T) >= 0) return null; + return shape.indexValue; + } + runtimeOptionalIdentifierValue( node: ts.Expression, ): { value: IrExpr; present: IrType; unionId: string } | null { @@ -2009,6 +2029,7 @@ export class Lowerer { value: IrExpr, expected: IrType, member: string, + action: "read" | "set" = "read", ): IrExpr | null { const source = this.runtimeOptionalSourceValue(node, value); if (source?.type.kind !== "union") return null; @@ -2051,7 +2072,7 @@ export class Lowerer { then: nodeThrowExpr( 1, "", - `Cannot read properties of ${unit} (reading '${member}')`, + `Cannot ${action} properties of ${unit} (${action === "read" ? "reading" : "setting"} '${member}')`, expected, loc, ), @@ -3989,6 +4010,7 @@ export class Lowerer { const t = mappedOrNull(receiver); return t?.kind === "bytes" ? t.elem : null; }, + isNumberRecordRead: (read) => this.optionalIndexSignatureRead(read)?.kind === "f64", isNumber: (node) => mappedOrNull(node)?.kind === "f64", isString: (node) => mappedOrNull(node)?.kind === "string", hasLength: (node) => { @@ -4124,8 +4146,26 @@ export class Lowerer { // Typed-array reads answer undefined for an invalid index too, unless // every consumer treats undefined like NaN. if (kind === "bytes") return !nanCoded.isNumericRead(e); + if (kind === "record") + return this.optionalIndexSignatureRead(e) !== null && !nanCoded.isNumericRead(e); return kind === "array"; }; + /** `r.name` where the name resolves to the receiver's index signature. */ + const isRecordIndexPropertyRead = (e: ts.PropertyAccessExpression): boolean => { + // A name that resolves to a declared member is not an index read, and + // only a receiver with an index signature maps to an indexed record. + if (symbolOf(e.name)) return false; + const receiverType = this.typeOf(e.expression); + if (this.checker.getIndexInfosOfType(receiverType).length === 0) return false; + const receiver = this.mapTypeOf(receiverType); + if (receiver?.kind !== "record") return false; + const shape = this.shapes.get(receiver.shapeId); + if (!shape || shape.tuple || !shape.indexValue || shape.indexValue.kind === "dyn") + return false; + if (shape.fields.some((field) => field.name === e.name.text)) return false; + const read = this.mapTypeOf(this.typeOf(e)); + return !(read?.kind === "union" && this.armTag(read.unionId, UNDEFINED_T) >= 0); + }; const isDynamicObjectEntryRead = (node: ts.Expression): boolean => { const read = peel(node); if (!ts.isElementAccessExpression(read) || !ts.isIdentifier(read.expression)) return false; @@ -4214,6 +4254,7 @@ export class Lowerer { if (assertsDefined(node)) return false; const e = peel(node); if (isIndexedRead(e)) return true; + if (ts.isPropertyAccessExpression(e) && isRecordIndexPropertyRead(e)) return true; if (ts.isPropertyAccessExpression(e) && isOptionalProcessStreamProperty(this, e)) return true; if (ts.isPropertyAccessExpression(e) && isSettledIteratorValueRead(this, e)) return true; if (ts.isPropertyAccessExpression(e) && isOsConstantsSymbol(symbolOf(e.expression), this)) @@ -4438,6 +4479,7 @@ export class Lowerer { return out; }; const scanPattern = (name: ts.BindingName, init: ts.Expression): boolean => { + if (ts.isObjectBindingPattern(name)) return scanRecordPattern(name, init); if (!ts.isArrayBindingPattern(name)) return false; const sourceType = this.mapTypeOf(this.typeOf(init)); if (sourceType?.kind !== "array") return false; @@ -4473,6 +4515,40 @@ export class Lowerer { }); return changed; }; + /** `const { a, b } = table` over an index-signature record: a name that + * is not a declared field reads the index signature and can be + * missing. */ + const scanRecordPattern = (name: ts.ObjectBindingPattern, init: ts.Expression): boolean => { + const sourceType = this.mapTypeOf(this.typeOf(init)); + if (sourceType?.kind !== "record") return false; + const shape = this.shapes.get(sourceType.shapeId); + const indexValue = shape?.indexValue; + if (!shape || shape.tuple || !indexValue || indexValue.kind === "dyn") return false; + let changed = false; + for (const el of name.elements) { + if (el.dotDotDotToken || el.initializer || !ts.isIdentifier(el.name)) continue; + const key = el.propertyName ?? el.name; + if (!ts.isIdentifier(key) && !ts.isStringLiteral(key) && !ts.isNumericLiteral(key)) + continue; + if (shape.fields.some((field) => field.name === key.text)) continue; + const symbol = symbolOf(el.name); + if (!symbol || optionalSymbols.has(symbol)) continue; + const read = this.mapTypeOf(this.typeOf(el.name)); + if (read?.kind === "union" && this.armTag(read.unionId, UNDEFINED_T) >= 0) continue; + const widened = this.withUndefinedArmOf(indexValue); + if (!widened) continue; + optionalSymbols.add(symbol); + provenance?.note("pattern-binding", el.name, init); + this.runtimeOptionalBindingTypes.set(symbol, widened); + const global = this.globalsBySymbol.get(symbol); + if (global) { + global.type = widened; + this.runtimeOptionalGlobals.add(global); + } + changed = true; + } + return changed; + }; const hofCallbackIndices = (name: string, hasInitialValue: boolean): number[] | null => { if (name === "reduce" || name === "reduceRight") return hasInitialValue ? [1] : [0, 1]; if ( diff --git a/packages/compiler/src/frontend/lowering/nan-coded-reads.ts b/packages/compiler/src/frontend/lowering/nan-coded-reads.ts index 2a537d6de..869a30f36 100644 --- a/packages/compiler/src/frontend/lowering/nan-coded-reads.ts +++ b/packages/compiler/src/frontend/lowering/nan-coded-reads.ts @@ -43,6 +43,9 @@ export interface NanCodedHost { declarationOf(symbol: ts.Symbol): ts.Node | undefined; /** The element kind of a typed-array receiver, or null. */ bytesElemOf(receiver: ts.Expression): IrBytesElem | null; + /** The read is a keyed read of a record's `number` index signature, + * which answers undefined for a missing key. */ + isNumberRecordRead(read: ts.ElementAccessExpression): boolean; /** The static IR type of the node is a plain number. */ isNumber(node: ts.Node): boolean; isString(node: ts.Expression): boolean; @@ -314,7 +317,10 @@ export class NanCodedReads { return; } if (ts.isElementAccessExpression(node) && this.isReadCandidate(node)) { - const elem = this.host.bytesElemOf(node.expression); + // A record's number values may hold a genuine NaN, like f64 elements. + const elem = + this.host.bytesElemOf(node.expression) ?? + (this.host.isNumberRecordRead(node) ? "f64" : null); if (elem) candidates.set(node, elem); } }); @@ -392,7 +398,13 @@ export class NanCodedReads { // native build of the compiler. const cached = this.symbolCache.get(node); if (cached !== undefined) return cached; - const symbol = this.host.symbolOf(node); + let symbol = this.host.symbolOf(node); + // A method read through an instance (`h.get`) can resolve to another + // symbol than its declaration name; slots and call sites key on the + // declaration's own symbol. + const decl = symbol ? this.host.declarationOf(symbol) : undefined; + if (decl && ts.isMethodDeclaration(decl) && decl.name !== node && ts.isIdentifier(decl.name)) + symbol = this.symbolOf(decl.name) ?? symbol; this.symbolCache.set(node, symbol); return symbol; } diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index bfaa13c0e..bb3cbb048 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -3003,26 +3003,30 @@ export type IrExpr = * Declared fields are tried FIRST (an emitted string-switch — field * access exactness is preserved: a declared name always answers from the * struct slot), then the overflow map on index-signature shapes. `type` - * is the CHECKER's type for the access: the index signature's value type - * (dyn for `unknown`; with noUncheckedIndexedAccess, its - * `V | undefined` union). A MISSING key produces: the undefined dyn - * singleton when `type` is dyn; the undefined arm when `type` is an - * undefined-armed union; otherwise a TRAP — the checker claimed V and no - * undefined is representable (the array OOB policy; on declared-only - * shapes tsc's keyof check makes the trap unreachable without an `as` - * smuggle). Declared-field values surface as `type`: V-typed fields read - * directly, dyn results build a dyn COPY of the field value (the dynFrom - * conversion — deep for composites, documented), union results wrap. + * is the index signature's value type armed with undefined (dyn for + * `unknown`), so a missing key reads undefined as in JavaScript, or the + * declared fields' common type on signature-free shapes. A MISSING key + * produces: the undefined dyn singleton when `type` is dyn; the undefined + * arm when `type` is an undefined-armed union; NaN with `missNaN`; + * otherwise a TRAP (declared-only shapes, where tsc's keyof check makes + * the trap unreachable without an `as` smuggle). Declared-field values + * surface as `type`: V-typed fields read directly, dyn results build a + * dyn COPY of the field value (the dynFrom conversion — deep for + * composites, documented), union results wrap. * The key and object are borrowed; refcounted results are owned (+1). * `overflowOnly` (set when the key is a LITERAL that names no declared * field): the read touches only the overflow map — declared fields need - * not surface as `type`, and the emitted helper skips the string-switch. */ + * not surface as `type`, and the emitted helper skips the string-switch. + * `missNaN` (with an f64 `type`): a missing key produces NaN instead of + * trapping, for reads whose every consumer treats undefined like NaN + * (nan-coded-reads.ts). */ | { kind: "recordKeyGet"; obj: IrExpr; shapeId: string; key: IrExpr; overflowOnly?: true; + missNaN?: true; type: IrType; loc: SrcLoc; } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5952-record-missing-keys.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5952-record-missing-keys.ts.json new file mode 100644 index 000000000..06b0e8106 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5952-record-missing-keys.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5952-record-missing-keys.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5953-nan-coded-method-returns.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5953-nan-coded-method-returns.ts.json new file mode 100644 index 000000000..7a84896f8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5953-nan-coded-method-returns.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5953-nan-coded-method-returns.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5952-record-missing-keys.ts b/tests/corpus/5952-record-missing-keys.ts new file mode 100644 index 000000000..69cc78d60 --- /dev/null +++ b/tests/corpus/5952-record-missing-keys.ts @@ -0,0 +1,127 @@ +// A keyed read of a Record or index signature that misses answers +// undefined, as in Node, at module top level and inside functions, without +// noUncheckedIndexedAccess. Static types stay what TypeScript says. +export {}; + +const kp = String(Date.now()); +const r: Record = { [kp]: 1, a: 2 }; +console.log(r["k"], r["a"], r[kp] === 1); +console.log("done"); + +function inside(): void { + const local: Record = { [kp]: 1 }; + console.log(local["k"], local[kp]); +} +inside(); + +// Bindings, reassignment, arithmetic, templates and conversions. +const v = r["missing"]; +console.log(v, typeof v, v === undefined); +let w = r["nope"]; +console.log(w); +w = 5; +console.log(w + 1); +console.log(r["x"] + 1, r["a"] + 1, `${r["x"]}`, String(r["x"]), r["x"] > 1, r["a"] > 1); +console.log(Math.max(r["a"], r["nope"]), isNaN(r["nope"]), r["nope"] == null); + +// Parameters, returns, record fields and array elements. +function take(n: number): string { + return String(n); +} +console.log(take(r["q"]), take(r["a"])); +function give(k: string): number { + return r[k]; +} +console.log(give("a"), give("zz")); +const o = { v: r["zz"] }; +console.log(JSON.stringify(o), o.v); +const arr: number[] = [r["zz"], r["a"]]; +console.log(arr.length, arr[0], arr[1]); + +// Dot reads through the index signature and destructuring. +console.log(r.zz, r.a, r.zz === undefined); +const { a, missing } = r; +console.log(a, missing); + +// Strings, booleans, arrays and unions as index values. +const s: Record = { a: "x" }; +console.log(s["b"], s["a"].toUpperCase(), s["b"]?.length); +try { + console.log(s["b"].length); +} catch (error) { + console.log((error as Error).message); +} +const b: Record = { t: true }; +console.log(b["f"], b["t"], !b["f"], b["f"] ? "y" : "n"); +const nested: Record = { a: [1] }; +console.log(nested["b"], nested["a"].length, nested["b"]?.length); +const mixed: Record = { n: 1, s: "x" }; +const m2 = mixed["q"]; +console.log(mixed["q"], typeof mixed["q"], mixed["n"], m2 === undefined); + +// Interfaces with declared fields and an index signature. +interface Bag { + name: string; + [key: string]: string; +} +const bag: Bag = { name: "n" }; +console.log(bag.name, bag["other"], bag.other); + +// Methods returning a keyed read, and loops over present and missing keys. +class Holder { + table: Record = { x: 1 }; + get(k: string): number { + return this.table[k]; + } +} +const h = new Holder(); +console.log(h.get("x"), h.get("y"), h.table["z"]); +const counts: Record = {}; +for (const word of ["a", "b", "a"]) counts[word] = (counts[word] ?? 0) + 1; +console.log(JSON.stringify(counts), counts["c"]); +let total = 0; +for (const k of ["a", "zz"]) { + console.log(k, r[k], r[k] !== undefined); + total += r[k]; +} +console.log(total); +if (r["zz"] === undefined) console.log("missing zz"); + +// Nested tables: a missing outer entry is undefined, and a member access +// on it throws Node's TypeError after the key evaluates. +const tables: Record> = { m: { one: 1 } }; +console.log(tables["m"]["one"], tables.m.one, tables["m"]["two"]); +tables["m"]["three"] = 3; +tables.m.four = 4; +console.log(JSON.stringify(tables)); +const objs: Record = { a: { b: 1 } }; +objs["a"].b = 5; +console.log(objs["a"].b, objs.a.b); +const dynamicKey = `z${kp.length > 0 ? "z" : ""}`; +for (const attempt of [ + () => objs["zz"].b, + () => tables["zz"]["q"], + () => tables[dynamicKey]["q"], + () => { + tables["zz"]["q"] = 1; + }, + () => { + objs[dynamicKey].b = 2; + }, +]) { + try { + attempt(); + } catch (error) { + console.log(error instanceof TypeError, (error as Error).message); + } +} + +// Calling a function stored under a missing key throws Node's TypeError. +const handlers: Record number> = { double: (n) => n * 2 }; +const handlerName = "double"; +console.log(handlers["double"](4), handlers[handlerName](5)); +try { + console.log(handlers["triple"](4)); +} catch (error) { + console.log(error instanceof TypeError, (error as Error).message); +} diff --git a/tests/corpus/5953-nan-coded-method-returns.ts b/tests/corpus/5953-nan-coded-method-returns.ts new file mode 100644 index 000000000..823079f03 --- /dev/null +++ b/tests/corpus/5953-nan-coded-method-returns.ts @@ -0,0 +1,44 @@ +// A method that returns a typed-array element or a numeric record entry +// answers undefined for a missing one when its caller can observe it, and +// a plain number when every caller only uses it numerically. +export {}; + +class Samples { + values = new Float64Array([1.5, 2.5]); + at(index: number): number { + return this.values[index]; + } + sum(count: number): number { + let total = 0; + for (let i = 0; i < count; i++) total += this.at(i); + return total; + } +} +const samples = new Samples(); +console.log(samples.at(0), samples.at(9)); +const missing = samples.at(9); +console.log(missing === undefined, typeof missing); +console.log(samples.sum(2), samples.sum(3)); + +class Scores { + table: Record = { ada: 3 }; + score(name: string): number { + return this.table[name]; + } + doubled(name: string): number { + return this.score(name) * 2; + } +} +const scores = new Scores(); +console.log(scores.score("ada"), scores.score("bob")); +console.log(scores.doubled("ada"), scores.doubled("bob")); + +class Readings { + data = new Float64Array(1); + read(index: number) { + return this.data[index]; + } +} +const readings = new Readings(); +const late = readings.read(5); +console.log(late, readings.read(0)); From b68f078fbe398184239576b531ee8a5c312650f4 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 20:16:35 -0500 Subject: [PATCH 017/117] Add corpus costs for the missing-key programs The shard balance test needs measured costs for the new corpus programs 5952-5954 (plain and sanitized), timed locally and scaled to the CI runners' existing entries. Fixes #964 Co-authored-by: Quim T. <26749475+espetro@users.noreply.github.com> --- tests/harness/corpus-costs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index f87883acd..a533b5564 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,9 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5952-record-missing-keys.ts": 6090, + "5953-nan-coded-method-returns.ts": 4100, + "5954-generic-optional-returns.ts": 4740, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4465,6 +4468,9 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5952-record-missing-keys.ts": 20400, + "5953-nan-coded-method-returns.ts": 15600, + "5954-generic-optional-returns.ts": 4070, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 694d67724f35792b69686c44bc6faa7fc34e9b06 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 20:47:11 -0500 Subject: [PATCH 018/117] Add corpus costs for recently added programs The shard balance test reads measured costs for corpus programs. Add plain and sanitized costs for 5950, 5951, 5955 and 5956, timed locally and scaled to the CI runners' existing entries. --- tests/harness/corpus-costs.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index f87883acd..490e47914 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,10 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5950-tuple-predicate-methods.ts": 5990, + "5951-result-never-widening.ts": 4710, + "5955-any-promise-methods.js": 3940, + "5956-erased-generic-members.ts": 6730, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4465,6 +4469,10 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5950-tuple-predicate-methods.ts": 7790, + "5951-result-never-widening.ts": 6120, + "5955-any-promise-methods.js": 5120, + "5956-erased-generic-members.ts": 8750, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From f291f1c275b91c99939152f36d56abe1bb12abc5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 20:50:59 -0500 Subject: [PATCH 019/117] Monomorphize destructured options parameters of package functions A package function that destructures its options object, such as makeClass({ Base, name }), now specializes per call site like positional parameters: each destructured name binds the static type of the matching property, so a class passed as { Base } keeps its static type and class extends Base builds a constructible subclass. Fixes #938 Co-authored-by: phall <25888173+phall1@users.noreply.github.com> --- .../frontend/lowering/generic-functions.ts | 142 +++++++++++++++++- .../compiler/src/frontend/lowering/lowerer.ts | 25 ++- .../fixtures/npm-static/class-options-cli.ts | 15 ++ .../node_modules/class-options/classes.js | 31 ++++ .../node_modules/class-options/package.json | 1 + tests/harness/npm-static.test.ts | 34 +++++ 6 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/npm-static/class-options-cli.ts create mode 100644 tests/fixtures/npm-static/node_modules/class-options/classes.js create mode 100644 tests/fixtures/npm-static/node_modules/class-options/package.json diff --git a/packages/compiler/src/frontend/lowering/generic-functions.ts b/packages/compiler/src/frontend/lowering/generic-functions.ts index 4cddcf5fd..bd785a256 100644 --- a/packages/compiler/src/frontend/lowering/generic-functions.ts +++ b/packages/compiler/src/frontend/lowering/generic-functions.ts @@ -94,6 +94,11 @@ export interface GenericFnInfo { * checker types key an instantiation, exactly the generic machinery — * the untyped params ARE the type parameters (see implicitCallInstance). */ implicitParams?: (ts.Symbol | null)[]; + /** Implicit-any monomorphization of destructured object parameters + * (implicitPatternsOf): parallel to decl.parameters, the destructured + * names where the slot binds the call site's object type. Computed on + * first use. */ + implicitPatterns?: (ImplicitPattern | null)[]; } export interface GenericInstance { @@ -1125,6 +1130,114 @@ function broadPromiseParam(lowerer: Lowerer, type: ts.Type): boolean { ); } +/** A destructured object parameter (`function f({ Base, name })`) whose + * names bind the call site argument's property types. */ +export interface ImplicitPattern { + elements: { property: string; symbol: ts.Symbol }[]; +} + +/** The destructured object parameters of a JS function-like that bind like + * implicit type parameters: every element a plain name (optionally renamed + * from an identifier or string key) with no default, no rest element, and + * no write in the body, under a broad inferred type. Parallel to + * decl.parameters. */ +export function implicitPatternsOf( + lowerer: Lowerer, + decl: ts.FunctionDeclaration | ts.MethodDeclaration | ts.FunctionExpression | ts.ArrowFunction, +): (ImplicitPattern | null)[] { + return decl.parameters.map((param): ImplicitPattern | null => { + if (!ts.isObjectBindingPattern(param.name) || !decl.body) return null; + if (param.dotDotDotToken || param.questionToken || param.initializer) return null; + const elements: ImplicitPattern["elements"] = []; + for (const element of param.name.elements) { + if (element.dotDotDotToken || element.initializer || !ts.isIdentifier(element.name)) + return null; + const key = element.propertyName ?? element.name; + if (!ts.isIdentifier(key) && !ts.isStringLiteral(key)) return null; + const symbol = lowerer.checker.getSymbolAtLocation(element.name); + if (!symbol || paramWrittenInBody(lowerer, decl.body, symbol, element.name.text)) return null; + // A JSDoc or contextual type names the properties: keep its ABI. + if ((lowerer.typeOf(element.name).flags & ts.TypeFlags.Any) === 0) return null; + elements.push({ property: key.text, symbol }); + } + return elements.length > 0 ? { elements } : null; + }); +} + +/** The type a destructured parameter takes at one call site (the object's + * own representation, a record or a checked value) and the checker type + * each destructured name binds. An object literal argument types the names + * from its property expressions, which see the enclosing instance's + * bindings (`makeClass({ Base, name })` inside a specialized + * `extend(Base, name)`); any other argument uses its checker type. Null + * when the argument lacks a destructured property, or passes a class the + * callee itself defines: each such class would instantiate the callee + * again (a static `extend` calling `makeClass({ Base: this })`). */ +function implicitPatternBinding( + lowerer: Lowerer, + callee: ts.Node, + pattern: ImplicitPattern, + arg: ts.Expression, +): { record: IrType; types: Map } | null { + let literal: ts.Expression = arg; + while (ts.isParenthesizedExpression(literal)) literal = literal.expression; + const types = new Map(); + if (ts.isObjectLiteralExpression(literal)) { + const values = new Map(); + /** Shorthand properties name the binding they read. */ + const shorthand = new Map(); + for (const property of literal.properties) { + if (ts.isShorthandPropertyAssignment(property) && ts.isIdentifier(property.name)) { + values.set(property.name.text, property.name); + const read = lowerer.checker.getShorthandAssignmentValueSymbol(property); + if (read) shorthand.set(property.name.text, read); + } else if ( + ts.isPropertyAssignment(property) && + (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) + ) + values.set(property.name.text, property.initializer); + else return null; + } + for (const element of pattern.elements) { + const value = values.get(element.property); + if (!value) return null; + const read = shorthand.get(element.property); + const type = (read && lowerer.implicitParamTypes?.get(read)) ?? lowerer.typeOf(value); + types.set(element.symbol, lowerer.checker.getBaseTypeOfLiteralType(type)); + } + // The object keeps the representation the call site lowers it to; the + // destructured names read their static types back out of it. + const lowered = tryLowerExpression(lowerer, literal); + if (lowered?.type.kind !== "record" && lowered?.type.kind !== "dyn") return null; + if (lowered.type.kind === "record") { + for (const field of lowerer.shapes.get(lowered.type.shapeId)?.fields ?? []) + if (field.type.kind === "classval" && classDefinedIn(lowerer, field.type.className, callee)) + return null; + } + return { record: lowered.type, types }; + } + const argType = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg)); + const record = lowerer.mapTypeOf(argType); + if (record?.kind !== "record") return null; + for (const element of pattern.elements) { + const property = lowerer.checker.getPropertyOfType(argType, element.property); + if (!property) return null; + types.set(element.symbol, lowerer.checker.getTypeOfSymbol(property)); + } + return { record, types }; +} + +/** The class is declared inside `scope`. */ +function classDefinedIn(lowerer: Lowerer, className: string, scope: ts.Node): boolean { + for ( + let n: ts.Node | undefined = lowerer.classes.get(className)?.decl ?? undefined; + n; + n = n.parent + ) + if (n === scope) return true; + return false; +} + /** The implicit-type-parameter slots of a JS function-like: parallel to * decl.parameters, the param SYMBOL where the slot is a bindable * implicit param (identifier-named, broad inferred/JSDoc type, not @@ -1169,6 +1282,10 @@ export function implicitAnyParamSymbolsOf( hasImplicitParams = true; return sym; }); + // Destructured object parameters monomorphize too (implicitPatternsOf); + // their slots stay null here. + if (!hasImplicitParams && isJsSourceFile(decl.getSourceFile())) + hasImplicitParams = implicitPatternsOf(lowerer, decl).some((pattern) => pattern !== null); return hasImplicitParams ? out : null; } @@ -1440,7 +1557,27 @@ export function implicitCallInstance( ): GenericInstance { const shapes: ParamShape[] = []; const argTypes = new Map(); + const patterns = (info.implicitPatterns ??= implicitPatternsOf(lowerer, info.decl)); + /** The destructured names' bound types, which the object's own + * representation does not always carry. */ + const patternKey: string[] = []; info.decl.parameters.forEach((param, i) => { + const pattern = patterns[i]; + const patternArg = call.arguments[i]; + if (pattern && patternArg && !ts.isSpreadElement(patternArg)) { + // The argument's object type binds each destructured name, so a + // class passed as `{ Base }` keeps its static class type. + const bound = implicitPatternBinding(lowerer, info.decl, pattern, patternArg); + if (bound) { + for (const [symbol, type] of bound.types) { + argTypes.set(symbol, type); + const mapped = lowerer.mapTypeOf(type); + patternKey.push(mapped ? typeKey(mapped) : "?"); + } + shapes.push({ type: bound.record, mode: "required" }); + return; + } + } const sym = info.implicitParams![i]; if (!sym) { shapes.push(lowerer.paramShape(param)); @@ -1578,7 +1715,7 @@ export function implicitCallInstance( } shapes.push({ type: bound, mode: "required" }); }); - return internImplicitInstance(lowerer, call, info, shapes, argTypes); + return internImplicitInstance(lowerer, call, info, shapes, argTypes, patternKey.join(",")); } /** The all-dyn DEFAULT instance — today's compiled body exactly: what a @@ -1611,8 +1748,9 @@ function internImplicitInstance( info: GenericFnInfo, shapes: ParamShape[], argTypes: Map, + patternKey = "", ): GenericInstance { - const key = shapes.map((s) => typeKey(s.type)).join(","); + const key = shapes.map((s) => typeKey(s.type)).join(",") + (patternKey ? `|${patternKey}` : ""); let inst = info.instances.get(key); if (inst?.implicitState === "failed") lowerer.unsupported("SC1090", blame, `the failed specialization of '${info.baseName}'`); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 61ccc76ce..7f940c692 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -341,6 +341,7 @@ import { } from "./call-signatures.js"; import { implicitAnyParamSymbolsOf, + implicitLocalFnNodeOf, type GenericFnInfo, type GenericInstance, implicitMonoFile, @@ -1525,6 +1526,28 @@ function panicSafe(query: () => T, fallback: T): T { } } +/** The function's class expressions lower once per implicit-any instance. + * A function whose only implicit slots are destructured options and that + * is bound to a variable the implicit-instance probe rejects runs as one + * shared body, so its classes keep a single name. */ +function monomorphizedImplicit( + lowerer: Lowerer, + fn: ts.FunctionDeclaration | ts.FunctionExpression | ts.ArrowFunction | ts.MethodDeclaration, +): boolean { + const slots = implicitAnyParamSymbolsOf(lowerer, fn); + if (!slots) return false; + if (slots.some((slot) => slot !== null)) return true; + let binding: ts.Node | undefined = fn.parent; + while (binding && ts.isParenthesizedExpression(binding)) binding = binding.parent; + if ( + (ts.isArrowFunction(fn) || ts.isFunctionExpression(fn)) && + binding && + ts.isVariableDeclaration(binding) + ) + return implicitLocalFnNodeOf(lowerer, binding) !== null; + return true; +} + export class Lowerer { readonly frontendServices: FrontendServices | undefined; readonly checker: ts.TypeChecker; @@ -2787,7 +2810,7 @@ export class Lowerer { if (this.localClassInstantiations.some((entry) => entry.owner === parent)) break; if ( parent.typeParameters?.length || - (implicitMonoFile(parent.getSourceFile()) && implicitAnyParamSymbolsOf(this, parent)) + (implicitMonoFile(parent.getSourceFile()) && monomorphizedImplicit(this, parent)) ) return null; } diff --git a/tests/fixtures/npm-static/class-options-cli.ts b/tests/fixtures/npm-static/class-options-cli.ts new file mode 100644 index 000000000..9d9c4f902 --- /dev/null +++ b/tests/fixtures/npm-static/class-options-cli.ts @@ -0,0 +1,15 @@ +// A package factory that receives its base class through a destructured +// options object builds subclasses of program classes that construct and +// dispatch like Node. +import { Class, extend } from "class-options/classes.js"; + +class Animal extends Class("Animal") {} +class Dog extends extend(Animal, "Dog") {} +class Puppy extends extend(Dog, "Puppy") {} + +const rex = new Dog("Rex"); +const ada = new Animal("Ada"); +const bit = new Puppy("Bit"); +console.log(rex instanceof Dog, rex instanceof Animal, ada instanceof Dog, bit instanceof Animal); +console.log(rex.describe(), ada.describe(), bit.describe()); +console.log(rex.kind, rex.value, ada.kind, bit.label); diff --git a/tests/fixtures/npm-static/node_modules/class-options/classes.js b/tests/fixtures/npm-static/node_modules/class-options/classes.js new file mode 100644 index 000000000..e2ae647f8 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/class-options/classes.js @@ -0,0 +1,31 @@ +// A class factory that takes its base and settings as one options object, +// as Effect's makeClass does: `makeClass({ Base, name })` destructures them +// and builds `class extends Base`. +function makeClass({ Base, name, tag: label }) { + return class extends Base { + constructor(value) { + super(value); + this.kind = name; + this.label = label; + } + describe() { + return `${this.label}:${this.kind}:${this.value}`; + } + // Each class passes itself back as a base: a call site must not + // specialize makeClass on the classes makeClass itself defines. + static extend(name) { + return makeClass({ Base: this, name, tag: label }); + } + }; +} +class Root { + constructor(value) { + this.value = value; + } +} +export function Class(name) { + return makeClass({ Base: Root, name, tag: "root" }); +} +export function extend(Base, name) { + return makeClass({ Base, name, tag: "sub" }); +} diff --git a/tests/fixtures/npm-static/node_modules/class-options/package.json b/tests/fixtures/npm-static/node_modules/class-options/package.json new file mode 100644 index 000000000..3e2fb2b49 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/class-options/package.json @@ -0,0 +1 @@ +{ "name": "class-options", "version": "1.0.0", "type": "module", "exports": { "./classes.js": "./classes.js" } } diff --git a/tests/harness/npm-static.test.ts b/tests/harness/npm-static.test.ts index 9324d1c7f..89bd2e0b8 100644 --- a/tests/harness/npm-static.test.ts +++ b/tests/harness/npm-static.test.ts @@ -618,6 +618,40 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { }, ); + test.each(["release", "dev"] as const)( + "a factory that destructures its base class from an options object builds static subclasses (%s)", + async (optimization) => { + const entry = join(pilotRoot, "class-options-cli.ts"); + const outDir = join(cacheDir, `class-options-${optimization}-${sanitize ? "san" : "plain"}`); + const result = await compile(entry, { + backend: "llvm", + npmStatic: ["class-options"], + sanitize, + optimization, + outDir, + outPath: join(outDir, "program"), + emitIr: true, + }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const [reference, native] = await Promise.all([ + runBinary(process.execPath, [entry]), + runBinary(result.binaryPath, []), + ]); + expect(reference.exitCode).toBe(0); + expect(native.stdout).toEqual(reference.stdout); + expect(comparableStderr(native.stderr)).toEqual(reference.stderr); + expect(native.exitCode).toBe(reference.exitCode); + // One makeClass instance per distinct base (Root, Animal, Dog) plus + // the generic one a class's own `extend` passing itself back reuses. + const ir = JSON.parse(readFileSync(result.irPath!, "utf8")) as { + functions: { name: string }[]; + }; + const instances = ir.functions.filter((fn) => /^%[\w.]*makeClass%\d+$/.test(fn.name)); + expect(instances.length).toBeLessThanOrEqual(4); + }, + ); + test.for([ ["escape-string-regexp", "escape-cli.ts"], ["slash", "slash-cli.ts"], From a5c7c09ad3f9d2a43aa61481a8af20659cb79acf Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 20:55:17 -0500 Subject: [PATCH 020/117] Add mock.timers to node:test --- .../limitations/builtin-apis/test-mocks.mdx | 3 +- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 40 +- .../generated/node-v24-backlog.json | 109 ++-- .../generated/node-v24-internal.json | 71 ++- internal/compatibility/static-support.json | 2 + .../ambient/scriptc-node-fallback.d.ts | 15 + packages/compiler/src/backend/llvm/emitter.ts | 6 +- .../compiler/src/backend/llvm/lib-dispatch.ts | 9 +- .../compiler/src/backend/llvm/lib-process.ts | 40 +- .../compiler/src/backend/llvm/lib-shared.ts | 37 ++ .../compiler/src/backend/llvm/lib-test.ts | 20 + .../src/frontend/lowering/builtins/timers.ts | 9 +- .../src/frontend/lowering/lower-calls.ts | 3 + .../src/frontend/lowering/lower-mock.ts | 154 ++++- .../src/frontend/lowering/lower-test.ts | 69 ++- .../src/frontend/lowering/lower-timers.ts | 47 +- packages/compiler/src/ir/builtin-effects.ts | 13 + .../compiler/src/ir/builtin-signatures.ts | 21 + packages/compiler/src/ir/ir.ts | 5 + packages/compiler/src/ir/runtime-features.ts | 16 + packages/compiler/src/ir/validate.ts | 7 +- .../corpus/5813-mock-timers-module.ts.json | 6 + .../corpus/5814-mock-timers-date.ts.json | 6 + .../diagnostics/mock-timers-fences.ts.json | 6 + packages/runtime/src/scr_async.c | 3 + packages/runtime/src/scr_async.h | 8 + packages/runtime/src/scr_event_target.c | 15 + packages/runtime/src/scr_event_target.h | 5 + packages/runtime/src/scr_fetch.c | 21 +- packages/runtime/src/scr_lib.c | 4 +- packages/runtime/src/scr_number.h | 4 + packages/runtime/src/scr_test.c | 524 +++++++++++++++++- packages/runtime/src/scr_test.h | 38 ++ tests/corpus/5813-mock-timers-module.ts | 91 +++ tests/corpus/5814-mock-timers-date.ts | 83 +++ tests/diagnostics/mock-timers-fences.ts | 35 ++ .../node-test/cases/mock-timers-date.ts | 197 +++++++ tests/fixtures/node-test/cases/mock-timers.ts | 348 ++++++++++++ .../__snapshots__/mock-timers-fences.ts.txt | 44 ++ 40 files changed, 2026 insertions(+), 110 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5813-mock-timers-module.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5814-mock-timers-date.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/mock-timers-fences.ts.json create mode 100644 tests/corpus/5813-mock-timers-module.ts create mode 100644 tests/corpus/5814-mock-timers-date.ts create mode 100644 tests/diagnostics/mock-timers-fences.ts create mode 100644 tests/fixtures/node-test/cases/mock-timers-date.ts create mode 100644 tests/fixtures/node-test/cases/mock-timers.ts create mode 100644 tests/harness/__snapshots__/mock-timers-fences.ts.txt diff --git a/docs/content/limitations/builtin-apis/test-mocks.mdx b/docs/content/limitations/builtin-apis/test-mocks.mdx index c9e84a80d..a0c63cd98 100644 --- a/docs/content/limitations/builtin-apis/test-mocks.mdx +++ b/docs/content/limitations/builtin-apis/test-mocks.mdx @@ -1 +1,2 @@ -- **Test mocks:** `mock.fn`, `mock.method`, `mock.restoreAll` and `mock.reset` compile, on the module's `mock` and on `t.mock`. `mock.method` mocks a function-valued field of a record, such as an object literal or an interface-typed object. Class instances, builtin objects, and object literals whose methods use `this` throw `SC2020`. Calls through the object record it as `this`, including calls of a method read off the object and called on its own, where Node records `undefined`. `object.method === mock` is `false`, because the field holds a wrapper of the mock. `mock.fn()` without an original, `mock.getter`, `mock.setter`, `mock.property`, `mock.module`, `mock.timers` and mock options throw `SC2020`. +- **Test mocks:** `mock.fn`, `mock.method`, `mock.restoreAll` and `mock.reset` compile, on the module's `mock` and on `t.mock`. `mock.method` mocks a function-valued field of a record, such as an object literal or an interface-typed object. Class instances, builtin objects, and object literals whose methods use `this` throw `SC2020`. Calls through the object record it as `this`, including calls of a method read off the object and called on its own, where Node records `undefined`. `object.method === mock` is `false`, because the field holds a wrapper of the mock. `mock.fn()` without an original, `mock.getter`, `mock.setter`, `mock.property`, `mock.module` and mock options throw `SC2020`. +- **Mock timers:** `mock.timers.enable`, `tick`, `runAll`, `reset`, `setTime` and `[Symbol.dispose]()` compile, on the module's `mock` and on `t.mock`, for the `setTimeout`, `setInterval`, `setImmediate`, `Date`, `scheduler.wait` and `AbortSignal.timeout` APIs. `enable()` takes no options or an object literal whose `apis`, when given, is an array literal. Options and `apis` lists that are not literals, and the `MockTimers` object used as a value, throw `SC2020`. As in Node, the global timer functions, `Date.now()`, `new Date()` and `scheduler.wait` are mocked, and other calls through named and namespace imports of `node:timers` and `node:timers/promises` use real timers. As in Node, once a reset gives `scheduler.wait` back, calling it throws `ERR_INVALID_THIS`. While `scheduler.wait` is mocked, calling it with a `signal` option throws an `SC2020` error. A mock timer's handle converts to a negative number, where Node's mock `Timeout` converts to `NaN`. When two trackers have timers enabled, clearing a timer through the tracker that did not create it leaves the timer queued, where Node removes the entry at the same queue position in the clearing tracker. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 93149c51c..fd99c1a78 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "a1ff929d49885bd8c92e", + "artifactVersion": "1bf81d93ee20dd4cea82", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 352c211b5..c93e45565 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -689,9 +689,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 45, + "partial": 51, "refused": 0, - "not-implemented": 72, + "not-implemented": 66, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -65550,9 +65550,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -65573,9 +65573,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -65596,9 +65596,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -65619,9 +65619,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -65642,9 +65642,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -65665,9 +65665,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index fff784adc..6aed267e8 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1091, - "verify-gap": 2238, + "audit-partial": 1097, + "verify-gap": 2232, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -66670,12 +66670,18 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.timers.enable", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -66695,12 +66701,18 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.timers.reset", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -66720,12 +66732,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.timers", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -66745,12 +66760,18 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.timers.tick", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -66770,12 +66791,18 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.timers.runAll", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -66795,12 +66822,18 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.timers.setTime", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 559bd48ca..86b66f736 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -746,9 +746,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 45, + "partial": 51, "refused": 0, - "not-implemented": 72, + "not-implemented": 66, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -90928,10 +90928,14 @@ "tests/corpus/5515-assert-deep-strict-typed-messages.ts", "tests/corpus/5810-mock-method-records.ts", "tests/corpus/5811-mock-tracker-restore.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", "tests/fixtures/node-test/cases/ctx-hooks.ts", "tests/fixtures/node-test/cases/ctx-plan.ts", "tests/fixtures/node-test/cases/mock-fn.ts", "tests/fixtures/node-test/cases/mock-method.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/fixtures/node-test/cases/mock-timers.ts", "tests/fixtures/node-test/cases/only-nested.ts", "tests/fixtures/node-test/cases/suite-variants.ts", "tests/fixtures/node-test/cases/todo-suites.ts", @@ -92562,8 +92566,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.timers.enable", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -92585,8 +92596,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.timers.reset", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -92608,8 +92626,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.timers", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -92631,8 +92653,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.timers.tick", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -92700,8 +92729,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.timers.runAll", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -92723,8 +92759,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.timers.setTime", + "tests": [ + "tests/fixtures/node-test/cases/mock-timers.ts", + "tests/fixtures/node-test/cases/mock-timers-date.ts", + "tests/corpus/5813-mock-timers-module.ts", + "tests/corpus/5814-mock-timers-date.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index d68011393..44aa67174 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -345,6 +345,8 @@ { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.diagnostic", "context.name"], "status": "partial", "evidence": ["tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.fn"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.method", "mock.reset", "mock.restoreAll"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-method.ts", "tests/corpus/5810-mock-method-records.ts", "tests/corpus/5811-mock-tracker-restore.ts", "tests/harness/node-test.test.ts"] }, + { "chapter": "test", "parent": "Class: `MockTimers`", "symbols": ["timers.enable", "timers.reset", "timers.tick", "timers.runAll", "timers.setTime"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-timers.ts", "tests/fixtures/node-test/cases/mock-timers-date.ts", "tests/corpus/5813-mock-timers-module.ts", "tests/corpus/5814-mock-timers-date.ts", "tests/harness/node-test.test.ts"] }, + { "chapter": "test", "parent": "Class: `MockTimers`", "signatures": ["`timers[Symbol.dispose]()`"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-timers-date.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockFunctionContext`", "symbols": ["calls", "ctx.callCount", "ctx.mockImplementation", "ctx.mockImplementationOnce", "ctx.resetCalls", "ctx.restore"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/fixtures/node-test/cases/mock-method.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.before", "context.after", "context.beforeEach", "context.afterEach", "context.plan", "context.fullName"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/ctx-hooks.ts", "tests/fixtures/node-test/cases/ctx-plan.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "symbols": ["describe.skip", "describe.todo", "describe.only", "suite.skip", "suite.todo", "suite.only", "it.skip", "it.todo", "it.only"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/suite-variants.ts", "tests/fixtures/node-test/cases/only-nested.ts", "tests/fixtures/node-test/cases/todo-suites.ts", "tests/harness/node-test.test.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index d87172f61..37abb2ae3 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3410,6 +3410,19 @@ declare module "node:test" { : never; reset(): void; restoreAll(): void; + readonly timers: MockTimers; + } + interface MockTimersOptions { + apis: ReadonlyArray<"setInterval" | "setTimeout" | "setImmediate" | "Date">; + now?: number | Date | undefined; + } + interface MockTimers { + enable(options?: MockTimersOptions): void; + setTime(milliseconds?: number): void; + reset(): void; + tick(milliseconds?: number): void; + runAll(): void; + [Symbol.dispose](): void; } const mock: MockTracker; /* Declared for typechecking only — every use fences (no lowering). @@ -3437,6 +3450,8 @@ declare module "node:test" { MockFunctionContext, MockFunctionCall, MockTracker, + MockTimers, + MockTimersOptions, }; export default test; } diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 2c3a71457..c4c04a68a 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -49,7 +49,7 @@ import { STRING, VOID, } from "../../ir/ir.js"; -import { moduleRuntimeFeatures } from "../../ir/runtime-features.js"; +import { moduleRuntimeFeatures, moduleUsesMockTimers } from "../../ir/runtime-features.js"; import { matchIntegerArrayForLoop, matchIntegerBytesForLoop, @@ -882,6 +882,9 @@ export class LlEmitter { /** setTimeout and friends appeared somewhere: main must run the event * loop even in programs with no async functions. */ usesTimers = false; + /** The program calls mock.timers members (moduleUsesMockTimers): timer + * calls emit scr_test.c's mock-aware entry points. */ + readonly mockTimers: boolean; /** Emitted ref-kind resolve thunks for new Promise, interned per inner * typeKey → thunk symbol. */ readonly resolveThunks = new Map(); @@ -1108,6 +1111,7 @@ export class LlEmitter { }), ); this.nullableUnions = new NullableUnions(mod); + this.mockTimers = moduleUsesMockTimers(mod); this.debug = options.debugSources === undefined ? null diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index 50804bf5a..27c8f1ff4 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -11,7 +11,12 @@ import { InternalCompilerError } from "../../errors.js"; import { MAY_THROW_LIB_FNS } from "../../ir/builtin-effects.js"; import { LlvmUnsupportedError } from "./unsupported.js"; import type { LlvmEmitterContext, LibCallExpr, LibCallPrefix, LlValue } from "./expr-context.js"; -import { ASSERT_VERDICT_LIB_FNS, LIB_FN_SYMS, USES_TIMERS_LIB_FNS } from "./lib-shared.js"; +import { + ASSERT_VERDICT_LIB_FNS, + LIB_FN_SYMS, + mockTimerSym, + USES_TIMERS_LIB_FNS, +} from "./lib-shared.js"; import { isDynUndefined } from "../../ir/runtime-features.js"; import { DYN_KIND } from "./dyn.js"; import { rawBytes } from "./lib-abi.js"; @@ -431,7 +436,7 @@ export function emitGenericLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll if (MAY_THROW_LIB_FNS.has(e.fn) && LIB_FN_SYMS[e.fn] === undefined) { throw new LlvmUnsupportedError(`libCall:${e.fn}`, e.loc); } - const sym = LIB_FN_SYMS[e.fn]; + const sym = mockTimerSym(host, e) ?? LIB_FN_SYMS[e.fn]; if (sym === undefined) throw new LlvmUnsupportedError(`libCall:${e.fn}`, e.loc); const args = READ_ONLY_STRING_LIB_FNS.has(e.fn) ? emitBorrowedInputs(host, e.args) diff --git a/packages/compiler/src/backend/llvm/lib-process.ts b/packages/compiler/src/backend/llvm/lib-process.ts index 46d08a58f..b30c65b8d 100644 --- a/packages/compiler/src/backend/llvm/lib-process.ts +++ b/packages/compiler/src/backend/llvm/lib-process.ts @@ -4,6 +4,7 @@ import { undefinedArmTag } from "../../ir/analysis.js"; import { F64, RUNTIME_ERROR_CLASSES, STRING } from "../../ir/ir.js"; import type { LlvmEmitterContext, LibCallExpr, LlValue } from "./expr-context.js"; import { f64Lit } from "./common.js"; +import { mockTimerSym } from "./lib-shared.js"; export function emitChildProcessLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { const B = host.B; @@ -372,14 +373,16 @@ export function emitAsyncContextLibCall(host: LlvmEmitterContext, e: LibCallExpr host.usesTimers = true; const cb = host.emitExpr(e.args[0]!); host.moveTemp(cb); - const sym = { - "timers.setTimeout": "scr_set_timeout", - "timers.setInterval": "scr_set_interval", - "timers.setTimeoutHandle": "scr_set_timeout_handle", - "timers.setImmediate": "scr_set_immediate", - "process.nextTick": "scr_next_tick", - "timers.queueMicrotask": "scr_queue_microtask", - }[e.fn]; + const sym = + mockTimerSym(host, e) ?? + { + "timers.setTimeout": "scr_set_timeout", + "timers.setInterval": "scr_set_interval", + "timers.setTimeoutHandle": "scr_set_timeout_handle", + "timers.setImmediate": "scr_set_immediate", + "process.nextTick": "scr_next_tick", + "timers.queueMicrotask": "scr_queue_microtask", + }[e.fn]; const rest = e.args.slice(1).map((a) => host.emitExpr(a)); const argList = [`ptr ${cb.name}`, ...rest.map((a) => `${host.llType(a.type)} ${a.name}`)].join( ", ", @@ -405,21 +408,24 @@ export function emitAsyncContextLibCall(host: LlvmEmitterContext, e: LibCallExpr // The chaining forms: bookkeep, then yield the handle itself (the // C comma expressions). const h = host.emitExpr(e.args[0]!); - const sym = { - "timers.unref": "scr_timer_unref", - "timers.ref": "scr_timer_ref", - "timers.refresh": "scr_timer_refresh", - "timers.immediateUnref": "scr_immediate_unref", - "timers.immediateRef": "scr_immediate_ref", - }[e.fn]; + const sym = + mockTimerSym(host, e) ?? + { + "timers.unref": "scr_timer_unref", + "timers.ref": "scr_timer_ref", + "timers.refresh": "scr_timer_refresh", + "timers.immediateUnref": "scr_immediate_unref", + "timers.immediateRef": "scr_immediate_ref", + }[e.fn]; host.declare(`declare void @${sym}(double)`); B.line(`call void @${sym}(double ${h.name})`); return { name: h.name, type: e.type }; } if (e.fn === "timers.clearTimeout" || e.fn === "timers.clearInterval") { const h = host.emitExpr(e.args[0]!); - host.declare(`declare void @scr_clear_interval(double)`); - B.line(`call void @scr_clear_interval(double ${h.name})`); + const sym = mockTimerSym(host, e) ?? "scr_clear_interval"; + host.declare(`declare void @${sym}(double)`); + B.line(`call void @${sym}(double ${h.name})`); return { name: "", type: e.type }; } if (e.fn === "timers.clearNoop") { diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9232cbd03..2c442756e 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -1223,10 +1223,13 @@ export const LIB_FN_SYMS: Record = { // loop gate already runs) and diagnostics_channel (scr_dc.c): all // generic shapes; the throwing members ride the pending check. "tp.setTimeout": "scr_tp_set_timeout", + "tp.schedulerWait": "scr_tp_set_timeout", "tp.setImmediate": "scr_tp_set_immediate", "tp.setTimeoutValue": "scr_tp_set_timeout_value", "tp.setImmediateValue": "scr_tp_set_immediate_value", "tp.setTimeoutSignal": "scr_tp_set_timeout_signal", + "tp.schedulerWaitValue": "scr_tp_set_timeout_value", + "tp.schedulerWaitSignal": "scr_tp_set_timeout_signal", "tp.setImmediateSignal": "scr_tp_set_immediate_signal", // stream/promises' finished form (+1 promise; may-throw pending check; // the pipeline form needs the stream-array compound and emits below). @@ -1376,6 +1379,40 @@ export const LIB_FN_SYMS: Record = { "timers.immediatePromise": "scr_immediate_promise", }; +/** The mock-aware entry points (scr_test.c) that the timer calls of a + * program using mock.timers emit in place of the loop's functions; each + * falls back to the loop's function while its API is not mocked. */ +export const MOCK_TIMER_SYMS: Readonly> = { + "timers.setTimeout": "scr_test_mt_set_timeout", + "timers.setTimeoutHandle": "scr_test_mt_set_timeout_handle", + "timers.setInterval": "scr_test_mt_set_interval", + "timers.clearTimeout": "scr_test_mt_clear_timeout", + "timers.clearInterval": "scr_test_mt_clear_interval", + "timers.unref": "scr_test_mt_unref", + "timers.ref": "scr_test_mt_ref", + "timers.refresh": "scr_test_mt_refresh", + "timers.hasRef": "scr_test_mt_has_ref", + "timers.setImmediate": "scr_test_mt_set_immediate", + "timers.clearImmediate": "scr_test_mt_clear_immediate", + "timers.immediateUnref": "scr_test_mt_immediate_unref", + "timers.immediateRef": "scr_test_mt_immediate_ref", + "timers.immediateHasRef": "scr_test_mt_immediate_has_ref", + "date.now": "scr_test_mt_date_now", + "date.newNow": "scr_test_mt_date_now", + "tp.schedulerWait": "scr_test_mt_scheduler_wait", + "tp.schedulerWaitValue": "scr_test_mt_scheduler_wait_value", + "tp.schedulerWaitSignal": "scr_tp_scheduler_wait_signal", +}; + +/** The mock-aware symbol for a timer call of a program that uses + * mock.timers, undefined for other calls and for `realTimer` calls. */ +export function mockTimerSym( + host: { readonly mockTimers: boolean }, + e: { fn: string; realTimer?: true }, +): string | undefined { + return host.mockTimers && !e.realTimer ? MOCK_TIMER_SYMS[e.fn] : undefined; +} + export const USES_TIMERS_LIB_FNS = new Set([ "process.emitWarning", // Decipheriv.setAuthTag reports DEP0182 on the next tick. diff --git a/packages/compiler/src/backend/llvm/lib-test.ts b/packages/compiler/src/backend/llvm/lib-test.ts index 79590cd9d..8ceadae2f 100644 --- a/packages/compiler/src/backend/llvm/lib-test.ts +++ b/packages/compiler/src/backend/llvm/lib-test.ts @@ -66,6 +66,26 @@ export function emitTestLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlVal return finishRuntimeCall(host, e, "scr_test_ctx_mock_restore_all", a); case "test.ctxMockReset": return finishRuntimeCall(host, e, "scr_test_ctx_mock_reset", a); + case "test.mockTimersEnable": + return finishRuntimeCall(host, e, "scr_test_mock_timers_enable", a); + case "test.mockTimersTick": + return finishRuntimeCall(host, e, "scr_test_mock_timers_tick", a); + case "test.mockTimersRunAll": + return finishRuntimeCall(host, e, "scr_test_mock_timers_run_all", a); + case "test.mockTimersReset": + return finishRuntimeCall(host, e, "scr_test_mock_timers_reset", a); + case "test.mockTimersSetTime": + return finishRuntimeCall(host, e, "scr_test_mock_timers_set_time", a); + case "test.ctxMockTimersEnable": + return finishRuntimeCall(host, e, "scr_test_ctx_mock_timers_enable", a); + case "test.ctxMockTimersTick": + return finishRuntimeCall(host, e, "scr_test_ctx_mock_timers_tick", a); + case "test.ctxMockTimersRunAll": + return finishRuntimeCall(host, e, "scr_test_ctx_mock_timers_run_all", a); + case "test.ctxMockTimersReset": + return finishRuntimeCall(host, e, "scr_test_ctx_mock_timers_reset", a); + case "test.ctxMockTimersSetTime": + return finishRuntimeCall(host, e, "scr_test_ctx_mock_timers_set_time", a); default: throw new InternalCompilerError(`unhandled test call ${e.fn}`); } diff --git a/packages/compiler/src/frontend/lowering/builtins/timers.ts b/packages/compiler/src/frontend/lowering/builtins/timers.ts index 33a907abd..98624dc4a 100644 --- a/packages/compiler/src/frontend/lowering/builtins/timers.ts +++ b/packages/compiler/src/frontend/lowering/builtins/timers.ts @@ -308,12 +308,15 @@ function lowerSchedulerCall( const promiseVoid: IrType = { kind: "promise", inner: VOID }; if (member === "scheduler.yield") return { kind: "libCall", fn: "tp.setImmediate", args: [], type: promiseVoid, loc }; + // The scheduler.wait libCalls emit timers/promises setTimeout's runtime + // calls; mock.timers mocks scheduler.wait and leaves setTimeout's named + // and namespace imports real. An omitted delay is NaN, Node's undefined. const [delayNode, optionsNode] = expr.arguments; const ms: IrExpr = delayNode ? lowerer.lowerExprExpecting(delayNode, F64) - : { kind: "numLit", value: 1, type: F64, loc }; + : { kind: "numLit", value: NaN, type: F64, loc }; if (optionsNode === undefined) - return { kind: "libCall", fn: "tp.setTimeout", args: [ms], type: promiseVoid, loc }; + return { kind: "libCall", fn: "tp.schedulerWait", args: [ms], type: promiseVoid, loc }; const { ref, signal } = timersPromisesOptions(lowerer, member, optionsNode, loc); const value: IrExpr = { kind: "intrinsic", @@ -324,7 +327,7 @@ function lowerSchedulerCall( }; return { kind: "libCall", - fn: signal === null ? "tp.setTimeoutValue" : "tp.setTimeoutSignal", + fn: signal === null ? "tp.schedulerWaitValue" : "tp.schedulerWaitSignal", args: signal === null ? [ms, value, ref] : [ms, value, ref, signal], type: promiseVoid, loc, diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 2ba83a3d5..b2d8990eb 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -13,6 +13,7 @@ import { lowerTimersMemberCall, TIMER_MODULE_MEMBERS, } from "./lower-timers.js"; +import { lowerMockTimersElementCall } from "./lower-test.js"; import { objectEnumerationReceiver } from "./object-enumeration-receiver.js"; import { InternalCompilerError } from "../../errors.js"; import { isFsStreamMember, lowerFsStreamMethodCall } from "./builtins/fs-streams.js"; @@ -1519,6 +1520,8 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { // The element spelling of an unsupported native Web method must fence // before lowering the callee into a checked-dynamic keyed read. if (ts.isElementAccessExpression(expr.expression)) { + const timersDispose = lowerMockTimersElementCall(lowerer, expr, expr.expression); + if (timersDispose) return timersDispose; const symbolMethod = lowerClassSymbolMethodCall(lowerer, expr); if (symbolMethod) return symbolMethod; lowerer.fenceUnsupportedFetchConstructorMember(expr.expression); diff --git a/packages/compiler/src/frontend/lowering/lower-mock.ts b/packages/compiler/src/frontend/lowering/lower-mock.ts index b49cd045b..2022d8232 100644 --- a/packages/compiler/src/frontend/lowering/lower-mock.ts +++ b/packages/compiler/src/frontend/lowering/lower-mock.ts @@ -32,7 +32,8 @@ import { type IrType, type SrcLoc, } from "../../ir/ir.js"; -import { countedFor, dynUndefinedExpr, numLit, varRef } from "../../ir/build.js"; +import { countedFor, dynUndefinedExpr, numLit, strLit, varRef } from "../../ir/build.js"; +import type { IrLibFn } from "../../ir/builtin-signatures.js"; import { mockType as mockHybridType } from "../mock-shapes.js"; import { locOf } from "../program.js"; import { resultIsDiscarded } from "./call-position.js"; @@ -862,6 +863,157 @@ export function lowerMockTrackerCall( }; } +const MOCK_TIMERS_HINT = + "enable, tick, runAll, reset and setTime are the supported mock.timers members"; +const MOCK_TIMERS_APIS_HINT = + "list the mocked APIs as string literals: enable({ apis: ['setTimeout', 'Date'] })"; +/** The codes scr_test.c reads for the APIs enable() mocks, in Node's + * SUPPORTED_APIS order. */ +const MOCK_TIMERS_API_CODES: Readonly> = { + setTimeout: "T", + setInterval: "I", + setImmediate: "M", + Date: "D", + "scheduler.wait": "W", + "AbortSignal.timeout": "A", +}; +/** enable() and enable({ now }) without `apis` mock every API. */ +const MOCK_TIMERS_ALL_APIS = "TIMDWA"; + +/** `mock.timers.enable(...)` and the other MockTimers members, on the + * module's `mock` (tracker null) and t.mock. enable() takes no options or + * an object literal whose `apis`, when given, is an array literal of API + * names. */ +export function lowerMockTimersCall( + lowerer: Lowerer, + call: ts.CallExpression, + member: string, + what: string, + tracker: () => MockTracker, + sym: ts.Symbol | null, +): IrExpr { + const loc = locOf(call); + const args = call.arguments; + const optionalNumber = (fallback: number): IrExpr[] => { + if (args.length > 1) + lowerer.noLowering(`${what}.${member} with ${args.length} arguments`, call); + return [args.length === 1 ? lowerer.lowerExprExpecting(args[0]!, F64) : numLit(fallback, loc)]; + }; + if (!["enable", "tick", "setTime", "runAll", "reset"].includes(member)) { + lowerer.noLowering(`${what}.${member}`, call, MOCK_TIMERS_HINT, sym); + } + // The receiver evaluates before the arguments. + const t = tracker(); + let rest: IrExpr[]; + switch (member) { + case "enable": + rest = lowerMockTimersOptions(lowerer, call, what); + break; + case "tick": + rest = optionalNumber(1); + break; + case "setTime": + rest = optionalNumber(0); + break; + default: + if (args.length > 0) { + lowerer.noLowering(`${what}.${member} with ${args.length} arguments`, call); + } + rest = []; + } + const name = member[0]!.toUpperCase() + member.slice(1); + return { + kind: "libCall", + fn: (t ? `test.ctxMockTimers${name}` : `test.mockTimers${name}`) as IrLibFn, + args: t ? [t, ...rest] : rest, + type: VOID, + loc, + }; +} + +/** enable()'s { apis, now } as the libCall's API codes, `now` and flags + * (1 = `now` given, 2 = it is a Date). */ +function lowerMockTimersOptions(lowerer: Lowerer, call: ts.CallExpression, what: string): IrExpr[] { + const loc = locOf(call); + const options = call.arguments[0]; + if (call.arguments.length > 1) { + lowerer.noLowering(`${what}.enable with ${call.arguments.length} arguments`, call); + } + if (options === undefined) { + return [strLit(MOCK_TIMERS_ALL_APIS, loc), numLit(0, loc), numLit(0, loc)]; + } + if (!ts.isObjectLiteralExpression(options)) { + lowerer.noLowering( + `${what}.enable with a non-literal options object`, + options, + MOCK_TIMERS_APIS_HINT, + ); + } + let codes = ""; + let listed = false; + let now: IrExpr = numLit(0, loc); + let flags = 0; + for (const prop of options.properties) { + // `{ apis: [...] }`, `{ "now": n }` and the `{ now }` shorthand. + const init = ts.isPropertyAssignment(prop) + ? prop.initializer + : ts.isShorthandPropertyAssignment(prop) && ts.isIdentifier(prop.name) + ? prop.name + : null; + const key = + init && prop.name && (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name)) + ? prop.name.text + : null; + if (key === "apis") { + const list = init!; + if (!ts.isArrayLiteralExpression(list)) { + lowerer.noLowering( + `${what}.enable with a non-literal apis list`, + list, + MOCK_TIMERS_APIS_HINT, + ); + } + listed = true; + for (const el of list.elements) { + if (!ts.isStringLiteralLike(el)) { + lowerer.noLowering( + `${what}.enable with a non-literal API name`, + el, + MOCK_TIMERS_APIS_HINT, + ); + } + const code = MOCK_TIMERS_API_CODES[el.text] ?? ""; + if (code === "") { + lowerer.noLowering(`${what}.enable with the ${el.text} API`, el, MOCK_TIMERS_APIS_HINT); + } + codes += code; + } + } else if (key === "now") { + const value = lowerer.lowerExpr(init!); + if (value.type.kind === "date") { + now = { kind: "libCall", fn: "date.getTime", args: [value], type: F64, loc }; + flags = 3; + } else if (value.type.kind === "f64") { + now = value; + flags = 1; + } else { + lowerer.noLowering( + `${what}.enable with a now value of this type`, + prop, + "now takes a number or a Date", + ); + } + } else { + lowerer.noLowering( + `${what}.enable with this option`, + prop, + "apis and now are the supported enable options", + ); + } + } + return [strLit(listed ? codes : MOCK_TIMERS_ALL_APIS, loc), now, numLit(flags, loc)]; +} + /** `fn.mock.calls`: a copy of the log, as Node's getter returns. Null for * other reads. */ export function lowerMockContextProperty( diff --git a/packages/compiler/src/frontend/lowering/lower-test.ts b/packages/compiler/src/frontend/lowering/lower-test.ts index 6b2563414..c616f3e73 100644 --- a/packages/compiler/src/frontend/lowering/lower-test.ts +++ b/packages/compiler/src/frontend/lowering/lower-test.ts @@ -32,12 +32,13 @@ import { lowerMockContextProperty, lowerMockFn, lowerMockMethod, + lowerMockTimersCall, lowerMockTrackerCall, type MockTracker, } from "./lower-mock.js"; const MOCK_HINT = - "mock.fn, mock.method, mock.restoreAll and mock.reset are the supported mock members"; + "mock.fn, mock.method, mock.restoreAll, mock.reset and mock.timers are the supported mock members"; /** The mock tracker members that lower, for the module's `mock` (tracker * null) and t.mock. Null for other members. */ @@ -556,6 +557,65 @@ export function lowerTestDirectCall( return lowerRegistration(lowerer, expr, "test(...)", loc, 0, null); } +/** `mock.timers` (tracker null) or `t.mock.timers` on a TestContext; + * null for other expressions. */ +function mockTimersReceiver( + lowerer: Lowerer, + expr: ts.Expression, +): { what: string; tracker: () => MockTracker } | null { + if ( + !ts.isPropertyAccessExpression(expr) || + expr.questionDotToken || + expr.name.text !== "timers" || + !lowerer.isStdlibMember(expr) + ) { + return null; + } + const owner = expr.expression; + if (ts.isIdentifier(owner)) { + const bi = lowerer.builtinImportOf(owner); + return bi && bi.module === "test" && bi.member === "mock" + ? { what: "mock.timers", tracker: () => null } + : null; + } + if ( + ts.isPropertyAccessExpression(owner) && + !owner.questionDotToken && + owner.name.text === "mock" && + lowerer.mapTypeOf(lowerer.typeOf(owner.expression))?.kind === "testCtx" && + lowerer.isStdlibMember(owner) + ) { + const testCtx = owner.expression; + return { what: "t.mock.timers", tracker: () => lowerer.lowerExpr(testCtx) }; + } + return null; +} + +/** `mock.timers[Symbol.dispose]()` and its t.mock twin: an alias of + * reset(), as in Node. Null for other element-access calls. */ +export function lowerMockTimersElementCall( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.ElementAccessExpression, +): IrExpr | null { + if (call.questionDotToken || access.questionDotToken) return null; + const timers = mockTimersReceiver(lowerer, access.expression); + if (!timers) return null; + const key = access.argumentExpression; + const isDispose = + ts.isPropertyAccessExpression(key) && + key.name.text === "dispose" && + lowerer.stdlibGlobalMember(key, "Symbol") === "dispose"; + if (!isDispose) { + lowerer.noLowering( + `${timers.what} computed member calls`, + call, + "call timers[Symbol.dispose]()", + ); + } + return lowerMockTimersCall(lowerer, call, "reset", timers.what, timers.tracker, null); +} + /** Method-position node:test calls — one entry in lower-calls.ts's * intrinsic chain: skip/todo/only twins on NAMED import bindings * (`test.skip(...)` where `test` came from `{ test }`), the TestContext @@ -634,6 +694,13 @@ export function lowerTestMethodCall( ); if (served) return served; } + // mock.timers.enable(...) and the other MockTimers members, on the + // module's `mock` and on t.mock. + const timers = mockTimersReceiver(lowerer, access.expression); + if (timers) { + const sym = lowerer.checker.getSymbolAtLocation(access.name) ?? null; + return lowerMockTimersCall(lowerer, call, member, timers.what, timers.tracker, sym); + } // t.assert.strictEqual(...) — the callee's receiver is `t.assert` on a // TestContext: Node's t.assert methods ARE the assert functions (bound // to the test for its counters — not modeled; the throw is identical), diff --git a/packages/compiler/src/frontend/lowering/lower-timers.ts b/packages/compiler/src/frontend/lowering/lower-timers.ts index 47e929b49..44b2b6a1d 100644 --- a/packages/compiler/src/frontend/lowering/lower-timers.ts +++ b/packages/compiler/src/frontend/lowering/lower-timers.ts @@ -299,6 +299,40 @@ function tolerantClearNoop(lowerer: Lowerer, expr: ts.CallExpression, loc: SrcLo return null; } +const MOCKABLE_TIMER_FNS: ReadonlySet = new Set([ + "timers.setTimeout", + "timers.setTimeoutHandle", + "timers.setInterval", + "timers.clearTimeout", + "timers.clearInterval", + "timers.setImmediate", + "timers.clearImmediate", +]); + +/** Whether a timer call's callee is an ESM named or namespace import of + * node:timers (destructured bindings included): Node's mock.timers leaves + * those bindings alone and replaces the globals. */ +function isRealTimerCallee(lowerer: Lowerer, callee: ts.Expression): boolean { + if (ts.isIdentifier(callee)) return lowerer.builtinImportOf(callee)?.module === "timers"; + if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.expression)) { + const sym = lowerer.checker.getSymbolAtLocation(callee.expression); + const decl = sym ? lowerer.checker.declarationsOf(sym)[0] : undefined; + return decl !== undefined && ts.isNamespaceImport(decl); + } + return false; +} + +/** Marks a lowered timer call `realTimer` when its callee is a binding + * mock.timers does not replace. */ +function markRealTimerCall( + lowerer: Lowerer, + expr: ts.CallExpression, + lowered: IrExpr | null, +): IrExpr | null { + if (lowered?.kind !== "libCall" || !MOCKABLE_TIMER_FNS.has(lowered.fn)) return lowered; + return isRealTimerCallee(lowerer, expr.expression) ? { ...lowered, realTimer: true } : lowered; +} + /** One timer call by MEMBER NAME — the shared lowering behind the ambient * globals, the node:timers named/destructured imports, and the namespace * form (`timers.setTimeout(...)`). Null when the member isn't a lowered @@ -308,6 +342,15 @@ export function lowerTimersMemberCall( expr: ts.CallExpression, member: string, loc: SrcLoc, +): IrExpr | null { + return markRealTimerCall(lowerer, expr, lowerTimerCall(lowerer, expr, member, loc)); +} + +function lowerTimerCall( + lowerer: Lowerer, + expr: ts.CallExpression, + member: string, + loc: SrcLoc, ): IrExpr | null { // Delayed timers share callback adaptation and the 1ms default. Trailing // arguments are captured now and delivered when the callback fires. @@ -328,10 +371,12 @@ export function lowerTimersMemberCall( expr.arguments[0]!, loc, ); + // An omitted delay is NaN, Node's undefined: the loop clamps it to + // 1ms, and mock.timers queues it to run at the next tick. const ms: IrExpr = expr.arguments.length >= 2 ? lowerer.lowerExpr(expr.arguments[1]!) - : { kind: "numLit", value: 1, type: F64, loc }; + : { kind: "numLit", value: NaN, type: F64, loc }; if (member === "setInterval") { return { kind: "libCall", fn: "timers.setInterval", args: [cb, ms], type: F64, loc }; } diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 2381413f8..480a1df82 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -16,6 +16,19 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "test.sub", "test.subEmpty", "test.suite", + // mock.timers: Node's ERR_INVALID_STATE and ERR_INVALID_ARG_VALUE, and + // the throws of the timer callbacks tick and runAll run. + "test.mockTimersEnable", + "test.mockTimersTick", + "test.mockTimersRunAll", + "test.mockTimersSetTime", + "test.ctxMockTimersEnable", + "test.ctxMockTimersTick", + "test.ctxMockTimersRunAll", + "test.ctxMockTimersSetTime", + "tp.schedulerWait", + "tp.schedulerWaitValue", + "tp.schedulerWaitSignal", "console.write", "console.label", "console.countReset", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 5e219ecf6..447974b32 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1443,6 +1443,20 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ }, "test.ctxMockRestoreAll": { argTypes: [TESTCTX_T], result: VOID }, "test.ctxMockReset": { argTypes: [TESTCTX_T], result: VOID }, + // mock.timers on the module's `mock` and on t.mock. enable takes one + // code per listed API ('T' setTimeout, 'I' setInterval), the `now` + // value and its flags (1 given, 2 from a Date). enable, tick, runAll and + // setTime throw Node's errors; tick and runAll run timer callbacks. + "test.mockTimersEnable": { argTypes: [STRING, F64, F64], result: VOID }, + "test.mockTimersTick": { argTypes: [F64], result: VOID }, + "test.mockTimersRunAll": { argTypes: [], result: VOID }, + "test.mockTimersReset": { argTypes: [], result: VOID }, + "test.mockTimersSetTime": { argTypes: [F64], result: VOID }, + "test.ctxMockTimersEnable": { argTypes: [TESTCTX_T, STRING, F64, F64], result: VOID }, + "test.ctxMockTimersTick": { argTypes: [TESTCTX_T, F64], result: VOID }, + "test.ctxMockTimersRunAll": { argTypes: [TESTCTX_T], result: VOID }, + "test.ctxMockTimersReset": { argTypes: [TESTCTX_T], result: VOID }, + "test.ctxMockTimersSetTime": { argTypes: [TESTCTX_T, F64], result: VOID }, // node:http (scr_http.c over scr_net.c). The handler and the data // listeners are program-dependent closures (null slots, checked in the // libCall case); reqHeader's result is the interned string|undefined @@ -3889,6 +3903,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * through the immediate queue (fires before due timers of later loop * turns, Node's check phase). Neither throws. */ "tp.setTimeout": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, + // scheduler.wait(delay): tp.setTimeout's promise. It throws Node's + // ERR_INVALID_THIS once mock.timers has restored the real scheduler.wait. + "tp.schedulerWait": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, "tp.setImmediate": { argTypes: [], result: { kind: "promise", inner: VOID } }, /** events.once (scr_events_emitter.c): [emitter, name, boxer, * errorBoxer, listenForError] → a pending promise of any[]; the boxers @@ -3905,6 +3922,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * AbortError (scr_event_target.c). */ "tp.setTimeoutSignal": { argTypes: [F64, null, BOOL, DYN], result: VOID }, "tp.setImmediateSignal": { argTypes: [null, BOOL, DYN], result: VOID }, + /** scheduler.wait(delay, options): tp.setTimeoutValue's and + * tp.setTimeoutSignal's shapes, with tp.schedulerWait's throws. */ + "tp.schedulerWaitValue": { argTypes: [F64, null, BOOL], result: VOID }, + "tp.schedulerWaitSignal": { argTypes: [F64, null, BOOL, DYN], result: VOID }, /** node:diagnostics_channel (scr_dc.c, linked when any dc.* appears — * the zlib gating precedent): a process-global name→channel registry; * channel values are f64 handles (type-mapper.ts maps Channel to F64, the diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index bfaa13c0e..840e58f1f 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -3556,6 +3556,11 @@ export type IrExpr = type: IrType; loc: SrcLoc; prototypeIdentityOnly?: true; + /** A timer call through an ESM named or namespace import of + * node:timers. Node's mock.timers replaces the globals and the + * module object's properties, which these bindings do not follow, + * so the call keeps the loop's timer. */ + realTimer?: true; /** An assertion call made through a node:assert Assert instance: the * instance options the runtime applies to this call. Backends set * them right before the runtime call, after its arguments are diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 80a9c9b57..dea7118e2 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -34,6 +34,9 @@ export interface RuntimeFeatures { parseArgs: boolean; fsWatch: boolean; nodeTest: boolean; + /** The program calls mock.timers members: its timer calls go through + * scr_test.c's mock-aware entry points. */ + mockTimers: boolean; dgram: boolean; http: boolean; http2: boolean; @@ -205,6 +208,7 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run parseArgs: false, fsWatch: false, nodeTest: false, + mockTimers: false, dgram: false, http: false, http2: false, @@ -252,6 +256,7 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run fn === "rl.questionAsyncSignal" || fn === "http.clientSignal" || fn === "tp.setTimeoutSignal" || + fn === "tp.schedulerWaitSignal" || fn === "tp.setImmediateSignal" || fn === "stream.addAbortSignal" || fn === "stream.addAbortSignalFn" || @@ -409,6 +414,9 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run if (fn.startsWith("test.")) { features.nodeTest = true; features.inspect = true; + if (fn.startsWith("test.mockTimers") || fn.startsWith("test.ctxMockTimers")) { + features.mockTimers = true; + } } if (fn.startsWith("dgram.") || fn.startsWith("dns.")) features.dgram = true; if (fn.startsWith("tlsca.")) features.tlsCa = true; @@ -793,6 +801,14 @@ export function moduleUsesNodeTest(mod: IrModule): boolean { return scanRuntimeFeatures(mod, "nodeTest").nodeTest; } +/** True when the module calls a mock.timers member (a test.mockTimers* or + * test.ctxMockTimers* libCall). The emitter then routes the timer calls + * through scr_test.c's mock-aware entry points; other programs keep the + * loop's timer functions. */ +export function moduleUsesMockTimers(mod: IrModule): boolean { + return scanRuntimeFeatures(mod, "mockTimers").mockTimers; +} + /** True when the module contains any dgram.* or dns.* libCall — the * link switch that pulls scr_dgram.c into the binary and has the emitted * main call scr_dgram_install (native-toolchain.ts + emitter; the scr_net gating diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index d526e7cb8..fa9a8777c 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -4116,9 +4116,12 @@ function validateFunction( e.fn === "tp.setTimeoutValue" || e.fn === "tp.setImmediateValue" || e.fn === "tp.setTimeoutSignal" || - e.fn === "tp.setImmediateSignal" + e.fn === "tp.setImmediateSignal" || + e.fn === "tp.schedulerWaitValue" || + e.fn === "tp.schedulerWaitSignal" ) { - const value = e.args[e.fn === "tp.setTimeoutValue" || e.fn === "tp.setTimeoutSignal" ? 1 : 0]; + const value = + e.args[e.fn === "tp.setImmediateValue" || e.fn === "tp.setImmediateSignal" ? 0 : 1]; if (value?.type.kind !== "promise" || !typeEquals(e.type, value.type)) { err(`libCall ${e.fn} must be the value's promise type`, e.loc); } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5813-mock-timers-module.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5813-mock-timers-module.ts.json new file mode 100644 index 000000000..bc8a46ae1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5813-mock-timers-module.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5813-mock-timers-module.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5814-mock-timers-date.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5814-mock-timers-date.ts.json new file mode 100644 index 000000000..edb0dba8c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5814-mock-timers-date.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5814-mock-timers-date.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/mock-timers-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/mock-timers-fences.ts.json new file mode 100644 index 000000000..f8800b52c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/mock-timers-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/mock-timers-fences.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index 46175cf82..f7a701b45 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -994,6 +994,9 @@ double scr_set_interval(ScrClosure *cb, double ms) { return (double)id; } +SCR_TL void (*scr_mt_abort_timeout_arm)(ScrClosure *cb, double ms) = NULL; +SCR_TL int scr_mt_wait_state = 0; + double scr_set_timeout_handle(ScrClosure *cb, double ms) { ms = scr_timer_coerce_ms(ms); unsigned long id = scr_interval_next_id++; diff --git a/packages/runtime/src/scr_async.h b/packages/runtime/src/scr_async.h index a391d2a26..7f294ca29 100644 --- a/packages/runtime/src/scr_async.h +++ b/packages/runtime/src/scr_async.h @@ -367,6 +367,14 @@ ScrPromise *scr_immediate_promise(void); void scr_clear_interval(double handle); double scr_set_timeout_handle(ScrClosure *cb, double ms); /* cb ownership moves in */ +/* Queues `cb` (moved) on the MockTimers that mocks AbortSignal.timeout + * (scr_test.c), NULL while it is not mocked. AbortSignal.timeout then + * aborts its signal from that queue instead of arming a loop timer. */ +extern SCR_TL void (*scr_mt_abort_timeout_arm)(ScrClosure *cb, double ms); +/* scheduler.wait's mock.timers state (scr_test.c): 0 real, 1 mocked, 2 the + * real one restored after a reset, which throws ERR_INVALID_THIS in Node. + * scr_tp_scheduler_wait_signal reads it. */ +extern SCR_TL int scr_mt_wait_state; void scr_timers_teardown(void); /* Timeout.unref()/ref()/hasRef(): loop-liveness bookkeeping over the timer * handle (setTimeout/setInterval's id). unref drops the timer from the diff --git a/packages/runtime/src/scr_event_target.c b/packages/runtime/src/scr_event_target.c index 68b7f6e87..e0a7c5969 100644 --- a/packages/runtime/src/scr_event_target.c +++ b/packages/runtime/src/scr_event_target.c @@ -1873,6 +1873,21 @@ ScrPromise *scr_tp_set_timeout_signal(double ms, ScrPromise *value, bool ref, Sc return scr_tp_signal(ms, value, ref, signal, false); } +ScrPromise *scr_tp_scheduler_wait_signal(double ms, ScrPromise *value, bool ref, ScrDyn *signal) { + if (scr_mt_wait_state == 2) { + static const char msg[] = "Value of \"this\" must be of type Scheduler"; + scr_throw_error_msg_code(SCR_ERR_TYPE, msg, sizeof msg - 1, "ERR_INVALID_THIS"); + return NULL; + } + if (scr_mt_wait_state == 1) { + static const char msg[] = + "scheduler.wait with a signal while mock.timers mocks it has no lowering"; + scr_throw_error_msg_code(SCR_ERR_ERROR, msg, sizeof msg - 1, "SC2020"); + return NULL; + } + return scr_tp_signal(ms, value, ref, signal, false); +} + ScrPromise *scr_tp_set_immediate_signal(ScrPromise *value, bool ref, ScrDyn *signal) { return scr_tp_signal(0, value, ref, signal, true); } diff --git a/packages/runtime/src/scr_event_target.h b/packages/runtime/src/scr_event_target.h index 6ed1475c6..c126edd54 100644 --- a/packages/runtime/src/scr_event_target.h +++ b/packages/runtime/src/scr_event_target.h @@ -89,6 +89,11 @@ ScrDyn *scr_events_add_abort_listener(ScrDyn *signal, ScrDyn *listener); * `value` is the already-resolved promise of the resolve value, borrowed. * Never throw; +1. */ ScrPromise *scr_tp_set_timeout_signal(double ms, ScrPromise *value, bool ref, ScrDyn *signal); +/* scheduler.wait(delay, { signal }) in a program that uses mock.timers: + * scr_tp_set_timeout_signal, except that it throws Node's ERR_INVALID_THIS + * once a reset restored the real scheduler.wait, and SC2020 while + * mock.timers mocks it. NULL after a throw. */ +ScrPromise *scr_tp_scheduler_wait_signal(double ms, ScrPromise *value, bool ref, ScrDyn *signal); ScrPromise *scr_tp_set_immediate_signal(ScrPromise *value, bool ref, ScrDyn *signal); /* Compiled subclasses (`class Bus extends EventTarget`, `class Ping diff --git a/packages/runtime/src/scr_fetch.c b/packages/runtime/src/scr_fetch.c index a7b540adb..f586b96f8 100644 --- a/packages/runtime/src/scr_fetch.c +++ b/packages/runtime/src/scr_fetch.c @@ -496,6 +496,15 @@ static void sf_signal_timer_fire(ScrClosure *cb) { sf_signal_release(s); } +/* The mocked AbortSignal.timeout's timer: Node's mock calls abort() on + * the signal's controller, so the reason is the AbortError. */ +static void sf_signal_mock_timer_fire(ScrClosure *cb) { + SfSignal *s = (SfSignal *)scr_box_get_ref(cb->caps[0]); + if (!s) return; + if (!s->aborted) sf_signal_abort_default(s, false); + sf_signal_release(s); +} + ScrDyn *scr_fetch_abort_timeout(ScrDyn *delay) { if (!delay || delay->kind != SCR_DYN_NUM) { if (delay) { @@ -527,13 +536,19 @@ ScrDyn *scr_fetch_abort_timeout(ScrDyn *delay) { return NULL; } SfSignal *s = sf_signal_new(); - ScrClosure *cb = scr_closure_new((void *)&sf_signal_timer_fire, 1); + bool mocked = scr_mt_abort_timeout_arm != NULL; + ScrClosure *cb = scr_closure_new( + mocked ? (void *)&sf_signal_mock_timer_fire : (void *)&sf_signal_timer_fire, 1); ScrBox *box = scr_box_new_obj(&sf_signal_retain_v, &sf_signal_release_v, NULL); scr_box_set_ref(box, sf_signal_retain(s)); cb->caps[0] = box; - s->timer_id = scr_set_timeout_handle(cb, ms); - scr_timer_unref(s->timer_id); + if (mocked) { + scr_mt_abort_timeout_arm(cb, ms); + } else { + s->timer_id = scr_set_timeout_handle(cb, ms); + scr_timer_unref(s->timer_id); + } ScrDyn *out = scr_dyn_new_handle(s, SCR_DYNH_ABORT_SIGNAL); sf_signal_release(s); return out; diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index 5f595f263..2f4ce3750 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -10171,6 +10171,8 @@ ScrStr *scr_str_from_code_point_bytes(ScrBytes *codes) { * frontend-fenced; construction, storage, getters, and ISO formatting * observe exactly this payload. */ +SCR_TL const double *scr_date_mock_now = NULL; + double scr_date_now(void) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -10861,7 +10863,7 @@ static ScrDyn *scr_native_date_invoke(void *ptr, ScrDyn *self, const char *metho ScrDyn *scr_dyn_native_date_new(const ScrDyn *arguments) { double ms; - if (arguments->v.arr.len == 0) ms = scr_date_now(); + if (arguments->v.arr.len == 0) ms = scr_date_mock_now ? *scr_date_mock_now : scr_date_now(); else { ScrDyn *value = arguments->v.arr.items[0]; if (scr_dyn_native_date_is(value)) ms = scr_dyn_native_date_value(value); diff --git a/packages/runtime/src/scr_number.h b/packages/runtime/src/scr_number.h index 50b270587..84db27075 100644 --- a/packages/runtime/src/scr_number.h +++ b/packages/runtime/src/scr_number.h @@ -91,6 +91,10 @@ ScrStr *scr_intl_num_format_en_us(double x); * mutation are frontend-fenced; construction, storage, getters, and ISO * formatting are exact over this representation. */ double scr_date_now(void); /* integer ms since epoch, like Node */ +/* The clock of the MockTimers that mocks Date (scr_test.c), NULL while + * Date is not mocked. Dynamic `new Date()` reads it; the runtime's own + * time stamps keep scr_date_now, as Node's internals keep the real Date. */ +extern SCR_TL const double *scr_date_mock_now; double scr_date_new_ms(double ms); /* TimeClip (NaN when invalid) */ double scr_date_get_time(double ms); /* Node's exact ISO 8601 UTC format (expanded ±YYYYYY years outside diff --git a/packages/runtime/src/scr_test.c b/packages/runtime/src/scr_test.c index 89301cbd3..6388857a6 100644 --- a/packages/runtime/src/scr_test.c +++ b/packages/runtime/src/scr_test.c @@ -120,6 +120,7 @@ struct ScrTestCtx { bool on_fiber; /* started on its own fiber by a concurrent parent */ ScrPromise *done; /* owned; settles when a concurrent subtest finishes */ ScrPromise *slot; /* owned; the parent waiting for its next subtest to finish */ + struct ScrMockTimers *mock_timers; /* t.mock.timers, made on first use; freed at exit */ }; static SCR_TL ScrTestCtx *scr_test_root = NULL; @@ -443,6 +444,8 @@ static bool scr_test_any_only(ScrTestCtx *parent) { } static void scr_test_run_node(ScrTestCtx *t); +typedef struct ScrMockTimers ScrMockTimers; +static void scr_mt_reset(ScrMockTimers *m); /* ── concurrency ─────────────────────────────────────────────────────── */ @@ -679,8 +682,9 @@ static void scr_test_run_node(ScrTestCtx *t) { scr_exc_clear(); } } - /* Then t.mock is reset: its mocks are restored. */ + /* Then t.mock is reset: its mocks are restored and its timers reset. */ scr_test_mocks_restore(&t->mocks, true); + scr_mt_reset(t->mock_timers); scr_test_parent_set(prev_parent); t->dur_ms = scr_now_ms() - start; if (t->mode == SCR_TEST_SKIP) { @@ -1042,16 +1046,525 @@ static void scr_test_mocks_add(ScrTestHooks *h, ScrClosure *restore /*moves*/) { h->n++; } +/* ── mock.timers ────────────────────────────────────────────────────── + * Node's MockTimers (lib/internal/test_runner/mock/mock_timers.js). The + * module's `mock` and every t.mock own one. enable() makes it the owner + * of the APIs it lists: setTimeout, setInterval, setImmediate and their + * clear functions then queue entries on it instead of arming loop timers, + * AbortSignal.timeout aborts from its queue, timers/promises + * scheduler.wait settles from it, Date.now() and new Date() read its + * clock, and tick() runs the due entries synchronously. enable() saves the owner each API had and reset() restores it, as Node + * saves and restores the functions it replaces. The queue is Node's + * binary heap (internal/priority_queue.js) with Node's comparator, so + * entries with equal, negative or NaN run times fire in Node's order. + * Mock handles are negative, which the loop's timer functions ignore. + * + * The scr_test_mt_* entry points replace the timer calls of programs + * that use mock.timers (the moduleUsesMockTimers switch), so other + * programs call the loop's timer functions directly. */ + +/* The APIs enable() mocks, in Node's SUPPORTED_APIS order. */ +enum { + SCR_MT_TIMEOUT, + SCR_MT_INTERVAL, + SCR_MT_IMMEDIATE, + SCR_MT_DATE, + SCR_MT_WAIT, + SCR_MT_ABORT, + SCR_MT_NAPIS +}; + +typedef struct { + double run_at; + double id; /* Node's #currentTimer: the tie-break between equal run times */ + double interval; /* the period of a setInterval entry */ + bool has_interval; /* false for timeouts and cleared intervals (Node's undefined) */ + ScrClosure *cb; /* owned */ + size_t pos; /* heap slot, 0 when unset (Node's priorityQueuePosition) */ + double handle; /* the negative handle the program holds */ + ScrMockTimers *owner; + int refs; /* heap slots holding the entry, plus a running callback */ +} ScrMockTimer; + +struct ScrMockTimers { + bool enabled; + char apis[16]; /* the APIs enable() listed, in order (Node's #timersInContext) */ + size_t napis; + double now; + double next_id; + ScrMockTimer **heap; /* 1-based, as Node's #heap */ + size_t size, cap; + ScrMockTimers *saved[SCR_MT_NAPIS]; /* each API's owner before enable() */ + ScrMockTimers *next_all; +}; + +/* The owner of each API: the MockTimers its calls queue on, NULL for the + * loop's timers. */ +static SCR_TL ScrMockTimers *scr_mt_owner[SCR_MT_NAPIS]; +static SCR_TL ScrMockTimers *scr_mt_module = NULL; +/* Every MockTimers, freed at exit: an owner or saved slot can still name + * one after its test ended, as Node keeps the replaced functions. */ +static SCR_TL ScrMockTimers *scr_mt_all = NULL; +static SCR_TL double scr_mt_next_handle = -1; +/* Set once a MockTimers that mocked scheduler.wait gives the real one + * back: Node restores it bound to the MockTimers, so every later call + * throws ERR_INVALID_THIS. */ +static SCR_TL bool scr_mt_wait_unbound = false; +/* Entries the program can still reach through a handle. */ +static SCR_TL ScrMockTimer **scr_mt_live = NULL; +static SCR_TL size_t scr_mt_nlive = 0, scr_mt_live_cap = 0; + +static ScrMockTimers *scr_mt_new(void) { + ScrMockTimers *m = calloc(1, sizeof *m); + if (!m) scr_test_oom(); + m->next_id = 1; + m->next_all = scr_mt_all; + scr_mt_all = m; + return m; +} + +static ScrMockTimers *scr_mt_of(ScrTestCtx *t) { + ScrMockTimers **slot = t ? &t->mock_timers : &scr_mt_module; + if (!*slot) *slot = scr_mt_new(); + return *slot; +} + +static void scr_mt_unref(ScrMockTimer *e) { + if (--e->refs > 0) return; + for (size_t i = 0; i < scr_mt_nlive; i++) { + if (scr_mt_live[i] == e) { + scr_mt_live[i] = scr_mt_live[--scr_mt_nlive]; + break; + } + } + scr_closure_release(e->cb); + free(e); +} + +static ScrMockTimer *scr_mt_find(double handle) { + if (!(handle < 0)) return NULL; + for (size_t i = 0; i < scr_mt_nlive; i++) { + if (scr_mt_live[i]->handle == handle) return scr_mt_live[i]; + } + return NULL; +} + +/* Node's compareTimersLists: (a.runAt - b.runAt) || (a.id - b.id). */ +static double scr_mt_compare(const ScrMockTimer *a, const ScrMockTimer *b) { + double d = a->run_at - b->run_at; + if (d != 0 && !isnan(d)) return d; + return a->id - b->id; +} + +static void scr_mt_percolate_down(ScrMockTimers *m, size_t pos) { + ScrMockTimer **heap = m->heap; + size_t size = m->size, hsize = size >> 1; + ScrMockTimer *item = heap[pos]; + while (pos <= hsize) { + size_t child = pos << 1, next = child + 1; + ScrMockTimer *child_item = heap[child]; + if (next <= size && scr_mt_compare(heap[next], child_item) < 0) { + child = next; + child_item = heap[next]; + } + if (scr_mt_compare(item, child_item) <= 0) break; + child_item->pos = pos; + heap[pos] = child_item; + pos = child; + } + heap[pos] = item; + item->pos = pos; +} + +static void scr_mt_percolate_up(ScrMockTimers *m, size_t pos) { + ScrMockTimer **heap = m->heap; + ScrMockTimer *item = heap[pos]; + while (pos > 1) { + size_t parent = pos >> 1; + ScrMockTimer *parent_item = heap[parent]; + if (scr_mt_compare(parent_item, item) <= 0) break; + heap[pos] = parent_item; + parent_item->pos = pos; + pos = parent; + } + heap[pos] = item; + item->pos = pos; +} + +static void scr_mt_insert(ScrMockTimers *m, ScrMockTimer *e) { + if (m->size + 2 > m->cap) { + m->cap = m->cap ? m->cap * 2 : 8; + m->heap = realloc(m->heap, m->cap * sizeof *m->heap); + if (!m->heap) scr_test_oom(); + } + e->refs++; + m->heap[++m->size] = e; + scr_mt_percolate_up(m, m->size); +} + +static void scr_mt_remove_at(ScrMockTimers *m, size_t pos) { + ScrMockTimer **heap = m->heap; + ScrMockTimer *removed = heap[pos]; + heap[pos] = heap[m->size]; + heap[m->size] = NULL; + size_t size = --m->size; + if (size > 0 && pos <= size) { + if (pos > 1 && scr_mt_compare(heap[pos >> 1], heap[pos]) > 0) scr_mt_percolate_up(m, pos); + else scr_mt_percolate_down(m, pos); + } + scr_mt_unref(removed); +} + +static ScrMockTimer *scr_mt_peek(ScrMockTimers *m) { return m->size > 0 ? m->heap[1] : NULL; } + +static void scr_mt_throw_state(const char *what) { + char msg[160]; + int len = snprintf(msg, sizeof msg, "Invalid state: %s", what); + scr_throw_error_msg_code(SCR_ERR_ERROR, msg, (size_t)len, "ERR_INVALID_STATE"); +} + +/* Node's #assertTimeArg: ERR_INVALID_ARG_VALUE('time', 'positive integer', time). */ +static bool scr_mt_time_ok(double time) { + if (!(time < 0)) return true; + char num[32]; + size_t n = scr_f64_to_str(time, num); + char msg[96]; + int len = snprintf(msg, sizeof msg, "The argument 'time' %.*s. Received 'positive integer'", + (int)n, num); + scr_throw_error_msg_code(SCR_ERR_TYPE, msg, (size_t)len, "ERR_INVALID_ARG_VALUE"); + return false; +} + +static int scr_mt_api(char code) { + switch (code) { + case 'I': + return SCR_MT_INTERVAL; + case 'M': + return SCR_MT_IMMEDIATE; + case 'D': + return SCR_MT_DATE; + case 'W': + return SCR_MT_WAIT; + case 'A': + return SCR_MT_ABORT; + default: + return SCR_MT_TIMEOUT; + } +} + +/* Node's #createTimer: the delay is used as given, except that one past + * TIMEOUT_MAX becomes 1; an omitted delay arrives as NaN (Node's + * undefined). */ +static ScrMockTimer *scr_mt_create(ScrMockTimers *m, bool is_interval, ScrClosure *cb /*moves*/, + double delay) { + if (delay > 2147483647.0) delay = 1; + ScrMockTimer *e = calloc(1, sizeof *e); + if (!e) scr_test_oom(); + e->id = m->next_id++; + e->cb = cb; + e->run_at = m->now + delay; + e->has_interval = is_interval && !isnan(delay); + e->interval = delay; + e->handle = scr_mt_next_handle--; + e->owner = m; + if (scr_mt_nlive == scr_mt_live_cap) { + scr_mt_live_cap = scr_mt_live_cap ? scr_mt_live_cap * 2 : 8; + scr_mt_live = realloc(scr_mt_live, scr_mt_live_cap * sizeof *scr_mt_live); + if (!scr_mt_live) scr_test_oom(); + } + scr_mt_live[scr_mt_nlive++] = e; + scr_mt_insert(m, e); + return e; +} + +/* Node's #clearTimer on the API's owner. A handle the owner did not + * create is left alone. */ +static void scr_mt_clear(ScrMockTimers *m, double handle) { + ScrMockTimer *e = scr_mt_find(handle); + if (!e || e->owner != m || e->pos == 0) return; + size_t pos = e->pos; + e->pos = 0; + e->has_interval = false; + scr_mt_remove_at(m, pos); +} + +static void scr_mt_tick(ScrMockTimers *m, double time) { + if (!m->enabled) { + scr_mt_throw_state("You should enable MockTimers first by calling the .enable function"); + return; + } + if (!scr_mt_time_ok(time)) return; + m->now += time; + ScrMockTimer *timer = scr_mt_peek(m); + while (timer) { + if (timer->run_at > m->now) break; + timer->refs++; + ((void (*)(ScrClosure *))timer->cb->fn)(timer->cb); + if (scr_exc_pending()) { + /* The throw leaves the entry queued, as in Node. */ + scr_mt_unref(timer); + return; + } + /* A callback that cleared its own timer already removed it. */ + ScrMockTimer *after = scr_mt_peek(m); + if (after && after->id == timer->id) { + timer->pos = 0; + scr_mt_remove_at(m, 1); + } + if (timer->has_interval) { + timer->run_at += timer->interval; + scr_mt_insert(m, timer); + } + scr_mt_unref(timer); + timer = scr_mt_peek(m); + } +} + +static void scr_mt_abort_arm(ScrClosure *cb /*moves*/, double ms) { + (void)scr_mt_create(scr_mt_owner[SCR_MT_ABORT], false, cb, ms); +} + +/* Points the Date, AbortSignal.timeout and scheduler.wait hooks at their + * owners. */ +static void scr_mt_hooks(void) { + ScrMockTimers *date = scr_mt_owner[SCR_MT_DATE]; + scr_date_mock_now = date ? &date->now : NULL; + scr_mt_abort_timeout_arm = scr_mt_owner[SCR_MT_ABORT] ? &scr_mt_abort_arm : NULL; + scr_mt_wait_state = scr_mt_owner[SCR_MT_WAIT] ? 1 : scr_mt_wait_unbound ? 2 : 0; +} + +/* Node's #toggleEnableTimers. Mocking Date while another MockTimers mocks + * it throws ERR_INVALID_STATE; the APIs listed before Date stay mocked, + * and the MockTimers stays disabled, as in Node. */ +static bool scr_mt_toggle(ScrMockTimers *m, bool activate) { + for (size_t i = 0; i < m->napis; i++) { + int api = scr_mt_api(m->apis[i]); + if (activate) { + if (api == SCR_MT_DATE && scr_mt_owner[api] != NULL) { + scr_mt_hooks(); + scr_mt_throw_state("Date is already being mocked!"); + return false; + } + m->saved[api] = scr_mt_owner[api]; + scr_mt_owner[api] = m; + } else { + scr_mt_owner[api] = m->saved[api]; + if (api == SCR_MT_WAIT && scr_mt_owner[api] == NULL) scr_mt_wait_unbound = true; + } + } + scr_mt_hooks(); + m->enabled = activate; + return true; +} + +static void scr_mt_reset(ScrMockTimers *m) { + if (!m || !m->enabled) return; + scr_mt_toggle(m, false); + m->napis = 0; + m->now = 0; + while (m->size > 0) scr_mt_remove_at(m, 1); +} + +/* enable({ apis, now }): `apis` holds one code per listed API, in order + * ('T' setTimeout, 'I' setInterval, 'M' setImmediate, 'D' Date, 'W' + * scheduler.wait, 'A' AbortSignal.timeout). flags: 1 = `now` is given, 2 = it + * came from a Date (Node then takes its time without checks). */ +static void scr_mt_enable(ScrMockTimers *m, ScrStr *apis, double now, double flags) { + if (m->enabled) { + scr_mt_throw_state("MockTimers is already enabled!"); + return; + } + bool given = ((int)flags & 1) != 0, from_date = ((int)flags & 2) != 0; + if (given && !from_date && isnan(now)) { + static const char msg[] = + "The argument 'now' epoch must be a positive integer received NaN. Received NaN"; + scr_throw_error_msg_code(SCR_ERR_TYPE, msg, sizeof msg - 1, "ERR_INVALID_ARG_VALUE"); + return; + } + if (!given || (!from_date && now == 0)) now = 0; + m->napis = apis->len < sizeof m->apis ? apis->len : sizeof m->apis; + memcpy(m->apis, apis->data, m->napis); + if (!from_date && !scr_mt_time_ok(now)) return; + m->now = now; + (void)scr_mt_toggle(m, true); +} + +void scr_test_mock_timers_enable(ScrStr *apis, double now, double flags) { + scr_mt_enable(scr_mt_of(NULL), apis, now, flags); +} +void scr_test_ctx_mock_timers_enable(ScrTestCtx *t, ScrStr *apis, double now, double flags) { + scr_mt_enable(scr_mt_of(t), apis, now, flags); +} +void scr_test_mock_timers_tick(double time) { scr_mt_tick(scr_mt_of(NULL), time); } +void scr_test_ctx_mock_timers_tick(ScrTestCtx *t, double time) { scr_mt_tick(scr_mt_of(t), time); } + +static void scr_mt_run_all(ScrMockTimers *m) { + if (!m->enabled) { + scr_mt_throw_state("You should enable MockTimers first by calling the .enable function"); + return; + } + /* Node ticks to the entry in the heap's last slot. */ + if (m->size == 0) return; + scr_mt_tick(m, m->heap[m->size]->run_at - m->now); +} +void scr_test_mock_timers_run_all(void) { scr_mt_run_all(scr_mt_of(NULL)); } +void scr_test_ctx_mock_timers_run_all(ScrTestCtx *t) { scr_mt_run_all(scr_mt_of(t)); } +void scr_test_mock_timers_reset(void) { scr_mt_reset(scr_mt_module); } +void scr_test_ctx_mock_timers_reset(ScrTestCtx *t) { scr_mt_reset(t->mock_timers); } + +/* setTime(time): Node checks the time before whether timers are enabled. */ +static void scr_mt_set_time(ScrMockTimers *m, double time) { + if (!scr_mt_time_ok(time)) return; + if (!m->enabled) { + scr_mt_throw_state("You should enable MockTimers first by calling the .enable function"); + return; + } + m->now = time; +} +void scr_test_mock_timers_set_time(double time) { scr_mt_set_time(scr_mt_of(NULL), time); } +void scr_test_ctx_mock_timers_set_time(ScrTestCtx *t, double time) { + scr_mt_set_time(scr_mt_of(t), time); +} + +/* The timer calls of a program that uses mock.timers: an owned API + * queues on its owner, else the loop's timer functions run. */ +void scr_test_mt_set_timeout(ScrClosure *cb /*moves*/, double ms) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_TIMEOUT]; + if (m) (void)scr_mt_create(m, false, cb, ms); + else scr_set_timeout(cb, ms); +} +double scr_test_mt_set_timeout_handle(ScrClosure *cb /*moves*/, double ms) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_TIMEOUT]; + return m ? scr_mt_create(m, false, cb, ms)->handle : scr_set_timeout_handle(cb, ms); +} +double scr_test_mt_set_interval(ScrClosure *cb /*moves*/, double ms) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_INTERVAL]; + return m ? scr_mt_create(m, true, cb, ms)->handle : scr_set_interval(cb, ms); +} +void scr_test_mt_clear_timeout(double handle) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_TIMEOUT]; + if (m) scr_mt_clear(m, handle); + else scr_clear_interval(handle); +} +void scr_test_mt_clear_interval(double handle) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_INTERVAL]; + if (m) scr_mt_clear(m, handle); + else scr_clear_interval(handle); +} +/* A mock Timeout's ref() and unref() return it unchanged, refresh() does + * nothing, and hasRef() is true. */ +void scr_test_mt_unref(double handle) { + if (!(handle < 0)) scr_timer_unref(handle); +} +void scr_test_mt_ref(double handle) { + if (!(handle < 0)) scr_timer_ref(handle); +} +void scr_test_mt_refresh(double handle) { + if (!(handle < 0)) scr_timer_refresh(handle); +} +bool scr_test_mt_has_ref(double handle) { return handle < 0 || scr_timer_has_ref(handle); } +/* Node's mocked setImmediate queues a timer with delay -1, so it runs + * before timers due at the same tick; its handle is a mock Timeout. */ +double scr_test_mt_set_immediate(ScrClosure *cb /*moves*/) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_IMMEDIATE]; + return m ? scr_mt_create(m, false, cb, -1)->handle : scr_set_immediate(cb); +} +void scr_test_mt_clear_immediate(double handle) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_IMMEDIATE]; + if (m) scr_mt_clear(m, handle); + else scr_clear_immediate(handle); +} +void scr_test_mt_immediate_unref(double handle) { + if (!(handle < 0)) scr_immediate_unref(handle); +} +void scr_test_mt_immediate_ref(double handle) { + if (!(handle < 0)) scr_immediate_ref(handle); +} +bool scr_test_mt_immediate_has_ref(double handle) { + return handle < 0 || scr_immediate_has_ref(handle); +} +/* timers/promises scheduler.wait(delay). Node's mock settles the result + * from an async function that awaits an inner promise the entry + * resolves, so the result settles one microtask after the entry fires. + * The entry's closure holds the result promise until it first fires. */ +static void scr_mt_wait_fire(ScrClosure *self) { + ScrPromise *p = (ScrPromise *)scr_box_get_ref(self->caps[0]); + if (!p) return; + scr_box_set_ref(self->caps[0], NULL); + scr_queue_microtask(scr_make_resolve(p, 3 /* void */)); + scr_promise_release(p); +} + +static bool scr_mt_wait_bound(void) { + if (!scr_mt_wait_unbound) return true; + static const char msg[] = "Value of \"this\" must be of type Scheduler"; + scr_throw_error_msg_code(SCR_ERR_TYPE, msg, sizeof msg - 1, "ERR_INVALID_THIS"); + return false; +} + +static ScrPromise *scr_mt_wait(ScrMockTimers *m, double ms) { + ScrPromise *p = scr_promise_new(); + ScrClosure *c = scr_closure_new((void *)&scr_mt_wait_fire, 1); + ScrBox *b = scr_box_new_obj(scr_promise_retain_v, scr_promise_release_v, scr_promise_trace_v); + scr_box_set_ref(b, scr_promise_retain(p)); + c->caps[0] = b; + (void)scr_mt_create(m, false, c, ms); + return p; +} + +ScrPromise *scr_test_mt_scheduler_wait(double ms) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_WAIT]; + if (m) return scr_mt_wait(m, ms); + return scr_mt_wait_bound() ? scr_tp_set_timeout(ms) : NULL; +} + +/* scheduler.wait(delay, { ref }): Node's mock ignores ref. */ +ScrPromise *scr_test_mt_scheduler_wait_value(double ms, ScrPromise *value, bool ref) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_WAIT]; + if (m) return scr_mt_wait(m, ms); + return scr_mt_wait_bound() ? scr_tp_set_timeout_value(ms, value, ref) : NULL; +} + +/* Date.now() and new Date() under a mocked Date read its clock. */ +double scr_test_mt_date_now(void) { + ScrMockTimers *m = scr_mt_owner[SCR_MT_DATE]; + return m ? m->now : scr_date_now(); +} + +/* Releases every MockTimers and its queued entries at exit. */ +static void scr_mt_free_all(void) { + while (scr_mt_all) { + ScrMockTimers *m = scr_mt_all; + scr_mt_all = m->next_all; + while (m->size > 0) scr_mt_remove_at(m, 1); + free(m->heap); + free(m); + } + free(scr_mt_live); + scr_mt_live = NULL; + scr_mt_nlive = scr_mt_live_cap = 0; + for (int i = 0; i < SCR_MT_NAPIS; i++) scr_mt_owner[i] = NULL; + scr_mt_hooks(); + scr_mt_module = NULL; +} + void scr_test_mock_track(ScrClosure *restore /*moves*/) { scr_test_mocks_add(&scr_test_mocks, restore); } void scr_test_mock_restore_all(void) { scr_test_mocks_restore(&scr_test_mocks, false); } -void scr_test_mock_reset(void) { scr_test_mocks_restore(&scr_test_mocks, true); } +/* reset() restores the tracker's mocks and resets its timers. */ +void scr_test_mock_reset(void) { + scr_test_mocks_restore(&scr_test_mocks, true); + scr_mt_reset(scr_mt_module); +} void scr_test_ctx_mock_track(ScrTestCtx *t, ScrClosure *restore /*moves*/) { scr_test_mocks_add(&t->mocks, restore); } void scr_test_ctx_mock_restore_all(ScrTestCtx *t) { scr_test_mocks_restore(&t->mocks, false); } -void scr_test_ctx_mock_reset(ScrTestCtx *t) { scr_test_mocks_restore(&t->mocks, true); } +void scr_test_ctx_mock_reset(ScrTestCtx *t) { + scr_test_mocks_restore(&t->mocks, true); + scr_mt_reset(t->mock_timers); +} void scr_test_ctx_plan(ScrTestCtx *t, double count) { t->plan = (int)count; } @@ -1098,7 +1611,10 @@ ScrStr *scr_test_ctx_full_name(ScrTestCtx *t) { int scr_test_exit_code(void) { /* The program is done: the module tracker's restore closures go. */ - if (scr_exit_frees()) scr_test_hooks_free(&scr_test_mocks); + if (scr_exit_frees()) { + scr_test_hooks_free(&scr_test_mocks); + scr_mt_free_all(); + } /* The runner never finished: a test awaited a promise nobody settles * and the loop exhausted (Node cancels the test and exits 1 — the * summary it prints there is not reproduced; SEMANTICS.md). The run diff --git a/packages/runtime/src/scr_test.h b/packages/runtime/src/scr_test.h index e1d97e12c..3e60f6abd 100644 --- a/packages/runtime/src/scr_test.h +++ b/packages/runtime/src/scr_test.h @@ -57,6 +57,44 @@ void scr_test_mock_reset(void); void scr_test_ctx_mock_track(ScrTestCtx *t, ScrClosure *restore); void scr_test_ctx_mock_restore_all(ScrTestCtx *t); void scr_test_ctx_mock_reset(ScrTestCtx *t); +/* mock.timers on the module's `mock` and on t.mock: enable({ apis, now }) + * (`apis` one code per listed API: 'T' setTimeout, 'I' setInterval, 'M' + * setImmediate, 'D' Date, 'W' scheduler.wait, 'A' AbortSignal.timeout; + * flags 1 = `now` given, 2 = it came from a Date), tick, runAll, reset + * and setTime. enable, tick, runAll and setTime throw Node's + * ERR_INVALID_STATE and ERR_INVALID_ARG_VALUE errors, and tick and runAll + * run the due timer callbacks, whose throws propagate. */ +void scr_test_mock_timers_enable(ScrStr *apis, double now, double flags); +void scr_test_ctx_mock_timers_enable(ScrTestCtx *t, ScrStr *apis, double now, double flags); +void scr_test_mock_timers_tick(double time); +void scr_test_ctx_mock_timers_tick(ScrTestCtx *t, double time); +void scr_test_mock_timers_run_all(void); +void scr_test_ctx_mock_timers_run_all(ScrTestCtx *t); +void scr_test_mock_timers_reset(void); +void scr_test_ctx_mock_timers_reset(ScrTestCtx *t); +void scr_test_mock_timers_set_time(double time); +void scr_test_ctx_mock_timers_set_time(ScrTestCtx *t, double time); +/* The timer calls of programs that use mock.timers (moduleUsesMockTimers): + * each queues on the API's MockTimers owner when it has one, else calls + * the loop's function of the same shape. */ +void scr_test_mt_set_timeout(ScrClosure *cb, double ms); +double scr_test_mt_set_timeout_handle(ScrClosure *cb, double ms); +double scr_test_mt_set_interval(ScrClosure *cb, double ms); +void scr_test_mt_clear_timeout(double handle); +void scr_test_mt_clear_interval(double handle); +void scr_test_mt_unref(double handle); +void scr_test_mt_ref(double handle); +void scr_test_mt_refresh(double handle); +bool scr_test_mt_has_ref(double handle); +double scr_test_mt_set_immediate(ScrClosure *cb); +void scr_test_mt_clear_immediate(double handle); +void scr_test_mt_immediate_unref(double handle); +void scr_test_mt_immediate_ref(double handle); +bool scr_test_mt_immediate_has_ref(double handle); +double scr_test_mt_date_now(void); +/* timers/promises scheduler.wait(delay) (+1 promise; NULL after a throw). */ +ScrPromise *scr_test_mt_scheduler_wait(double ms); +ScrPromise *scr_test_mt_scheduler_wait_value(double ms, ScrPromise *value, bool ref); /* Main's epilogue (emitted when moduleUsesNodeTest): 1 when any non-todo * test failed, Node's exit contract. */ int scr_test_exit_code(void); diff --git a/tests/corpus/5813-mock-timers-module.ts b/tests/corpus/5813-mock-timers-module.ts new file mode 100644 index 000000000..e9a343336 --- /dev/null +++ b/tests/corpus/5813-mock-timers-module.ts @@ -0,0 +1,91 @@ +// The module's mock.timers outside a test: a debounce and a retry loop +// driven by tick and runAll, the order due timers run in, intervals that +// clear themselves, setTime, Node's errors, and real timers made before +// enable() that keep running through the loop. +import { mock } from "node:test"; + +function debounce(fn: (value: string) => void, ms: number): (value: string) => void { + let pending: ReturnType | null = null; + return (value: string) => { + if (pending !== null) clearTimeout(pending); + pending = setTimeout(() => { + pending = null; + fn(value); + }, ms); + }; +} + +const real = setTimeout(() => console.log("real timer fired"), 1); + +mock.timers.enable({ apis: ["setTimeout", "setInterval"] }); +clearTimeout(real); // the mocked clearTimeout leaves the real timer armed + +const save = debounce((value) => console.log(`saved ${value}`), 100); +save("a"); +mock.timers.tick(50); +save("ab"); +mock.timers.tick(99); +console.log("nothing saved yet"); +save("abc"); +mock.timers.tick(100); + +let attempts = 0; +function attempt(delay: number): void { + attempts++; + console.log(`attempt ${attempts} after ${delay}ms`); + if (attempts < 4) setTimeout(() => attempt(delay * 2), delay * 2); +} +setTimeout(() => attempt(10), 10); +mock.timers.runAll(); +console.log(`runAll stopped after ${attempts} attempts`); +mock.timers.runAll(); +mock.timers.runAll(); +mock.timers.runAll(); +console.log(`attempts ${attempts}`); + +const order: string[] = []; +setTimeout(() => order.push("omitted")); +setTimeout(() => order.push("zero"), 0); +setTimeout(() => order.push("negative"), -1); +setTimeout((tag: string) => order.push(tag), 0, "zero with argument"); +mock.timers.tick(0); +console.log(order.join(", ")); + +let beats = 0; +const heartbeat = setInterval(() => { + beats++; + if (beats === 5) clearInterval(heartbeat); +}, 30); +mock.timers.tick(1000); +console.log(`beats ${beats}`); + +const handle = setTimeout(() => console.log("refreshed timer fired once"), 20); +console.log(handle.hasRef(), handle.unref().hasRef(), handle.ref().hasRef()); +handle.refresh(); +mock.timers.tick(20); +mock.timers.tick(20); + +mock.timers.setTime(1_000_000); +setTimeout(() => console.log("fires after setTime"), 1); +mock.timers.tick(1); + +for (const run of [ + () => mock.timers.enable({ apis: ["setTimeout"] }), + () => mock.timers.tick(-2), + () => mock.timers.setTime(-0.5), +]) { + try { + run(); + } catch (error) { + const e = error as { name: string; code: string; message: string }; + console.log(`${e.name} ${e.code}: ${e.message}`); + } +} + +mock.timers.reset(); +try { + mock.timers.runAll(); +} catch (error) { + console.log((error as Error).message); +} +setTimeout(() => console.log("real again after reset"), 30); diff --git a/tests/corpus/5814-mock-timers-date.ts b/tests/corpus/5814-mock-timers-date.ts new file mode 100644 index 000000000..494e3b7d8 --- /dev/null +++ b/tests/corpus/5814-mock-timers-date.ts @@ -0,0 +1,83 @@ +// The module's mock.timers for Date, setImmediate and AbortSignal.timeout: +// a cache whose entries expire by Date.now(), a batch that flushes on +// setImmediate, a request deadline from AbortSignal.timeout, and +// enable() without options, which mocks every API. +import { mock } from "node:test"; + +class TtlCache { + private entries = new Map(); + private ttl: number; + constructor(ttl: number) { + this.ttl = ttl; + } + set(key: string, value: string): void { + this.entries.set(key, { value, expires: Date.now() + this.ttl }); + } + get(key: string): string | undefined { + const entry = this.entries.get(key); + if (entry === undefined) return undefined; + if (Date.now() >= entry.expires) { + this.entries.delete(key); + return undefined; + } + return entry.value; + } +} + +mock.timers.enable({ apis: ["Date"], now: new Date("2024-05-01T12:00:00Z") }); +console.log(new Date().toISOString()); +const cache = new TtlCache(60_000); +cache.set("user", "ada"); +mock.timers.tick(59_999); +console.log(cache.get("user")); +mock.timers.tick(1); +console.log(cache.get("user")); +mock.timers.setTime(0); +console.log(Date.now(), new Date().toISOString()); +mock.timers.reset(); +console.log(Date.now() > 1_700_000_000_000); + +const batches: string[][] = []; +let pending: string[] = []; +function queue(item: string): void { + if (pending.length === 0) { + setImmediate(() => { + batches.push(pending); + pending = []; + }); + } + pending.push(item); +} + +mock.timers.enable({ apis: ["setImmediate"] }); +queue("a"); +queue("b"); +mock.timers.tick(0); +console.log(JSON.stringify(batches)); +queue("c"); +queue("d"); +console.log(JSON.stringify(pending)); +mock.timers.tick(0); +console.log(JSON.stringify(batches)); +const skipped = setImmediate(() => console.log("never")); +clearImmediate(skipped); +console.log(skipped.hasRef()); +mock.timers.runAll(); +mock.timers.reset(); + +mock.timers.enable(); +const deadline = AbortSignal.timeout(5_000); +deadline.addEventListener("abort", () => { + const reason = deadline.reason as { name: string; message: string }; + console.log(`aborted at ${Date.now()}: ${reason.name}: ${reason.message}`); +}); +mock.timers.tick(4_999); +console.log(deadline.aborted); +mock.timers.tick(1); +console.log(deadline.aborted); +mock.timers.reset(); + +const real = AbortSignal.timeout(1); +real.addEventListener("abort", () => { + console.log(`real deadline: ${(real.reason as { name: string }).name}`); +}); diff --git a/tests/diagnostics/mock-timers-fences.ts b/tests/diagnostics/mock-timers-fences.ts new file mode 100644 index 000000000..8deb95e76 --- /dev/null +++ b/tests/diagnostics/mock-timers-fences.ts @@ -0,0 +1,35 @@ +// mock.timers lowers enable(), enable({ apis, now }), tick, runAll, reset, +// setTime and [Symbol.dispose](), on the module's `mock` and on t.mock, and +// timers/promises scheduler.wait(delay) lowers. The rest is refused, each +// with a named diagnostic: an apis list or options object that is not a +// literal, and the MockTimers object used as a value. +import { mock, test } from "node:test"; +import { scheduler } from "node:timers/promises"; + +mock.timers.enable({ apis: ["setTimeout", "setInterval"], now: 10 }); // lowers +mock.timers.tick(5); // lowers +mock.timers.setTime(20); // lowers +mock.timers.runAll(); // lowers +mock.timers.reset(); // lowers + +mock.timers.enable(); // lowers +mock.timers.enable({ apis: ["Date"] }); // lowers +mock.timers.enable({ apis: ["setTimeout", "setImmediate"] }); // lowers + +const apis: ("setTimeout" | "setInterval")[] = ["setTimeout"]; +mock.timers.enable({ apis }); // apis list that is not a literal + +const options = { apis: ["setTimeout"] as const }; +mock.timers.enable(options); // options object that is not a literal + +const timers = mock.timers; // the object as a value +timers.tick(1); + +test("t.mock.timers", (t) => { + t.mock.timers.enable({ apis: ["setInterval"] }); // lowers + t.mock.timers.tick(); // lowers + t.mock.timers.enable({ apis: ["setTimeout"], now: new Date(0) }); // lowers + t.mock.timers[Symbol.dispose](); // lowers +}); + +void scheduler.wait(1); // lowers diff --git a/tests/fixtures/node-test/cases/mock-timers-date.ts b/tests/fixtures/node-test/cases/mock-timers-date.ts new file mode 100644 index 000000000..ca2714e05 --- /dev/null +++ b/tests/fixtures/node-test/cases/mock-timers-date.ts @@ -0,0 +1,197 @@ +// mock.timers for Date, setImmediate, AbortSignal.timeout and +// timers/promises scheduler.wait, enable() without apis, which mocks every +// API, and [Symbol.dispose](): Date.now() and new Date() read the mock +// clock that tick and setTime move, a mocked setImmediate runs before +// timers due at the same tick, a mocked AbortSignal.timeout aborts with +// the AbortError reason, mocking Date twice throws, and once a reset gives +// scheduler.wait back, Node's restored scheduler.wait throws +// ERR_INVALID_THIS, so its suite runs first. +import { describe, it, mock } from "node:test"; +import * as assert from "node:assert"; +import * as timersNamespace from "node:timers"; +import { setImmediate as namedSetImmediate } from "node:timers"; +import { scheduler } from "node:timers/promises"; +import * as timersPromises from "node:timers/promises"; + +type Fail = { name: string; code?: string; message: string }; +const failure = (fn: () => void): string => { + try { + fn(); + return "no throw"; + } catch (error) { + const e = error as Fail; + return `${e.name} ${e.code ?? "-"} ${e.message}`; + } +}; + +describe("scheduler.wait", () => { + it("settles from the mock queue, a microtask after tick", async (t) => { + // scheduler.wait is not in the typed apis list; enable() mocks it. + t.mock.timers.enable(); + const log: string[] = []; + const named = scheduler.wait(50).then(() => { + log.push("named"); + }); + const namespace = timersPromises.scheduler.wait(50).then(() => { + log.push("namespace"); + }); + const omitted = scheduler.wait().then(() => { + log.push("omitted"); + }); + const unref = scheduler.wait(50, { ref: false }).then(() => { + log.push("unref"); + }); + t.mock.timers.tick(50); + log.push("after tick"); + queueMicrotask(() => log.push("microtask")); + await Promise.all([named, namespace, omitted, unref]); + assert.deepStrictEqual(log, [ + "after tick", + "microtask", + "named", + "namespace", + "omitted", + "unref", + ]); + }); + + it("throws once a reset gave it back", () => { + const got = failure(() => { + void scheduler.wait(1); + }); + assert.strictEqual( + got, + 'TypeError ERR_INVALID_THIS Value of "this" must be of type Scheduler', + ); + }); +}); + +describe("Date", () => { + it("reads the mock clock", (t) => { + t.mock.timers.enable({ apis: ["Date"], now: 1000 }); + assert.strictEqual(Date.now(), 1000); + assert.strictEqual(new Date().getTime(), 1000); + assert.strictEqual(new Date(5).getTime(), 5); + assert.strictEqual(new Date() instanceof Date, true); + t.mock.timers.tick(5); + assert.strictEqual(Date.now(), 1005); + t.mock.timers.setTime(50); + assert.strictEqual(new Date().toISOString(), "1970-01-01T00:00:00.050Z"); + }); + + it("is real again after reset", (t) => { + t.mock.timers.enable({ apis: ["Date"] }); + assert.strictEqual(Date.now(), 0); + t.mock.timers.reset(); + assert.strictEqual(Date.now() > 1e12, true); + }); + + it("shares the clock with mocked timers", (t) => { + t.mock.timers.enable({ apis: ["Date", "setTimeout"], now: 100 }); + const seen: number[] = []; + setTimeout(() => seen.push(Date.now()), 25); + t.mock.timers.tick(30); + seen.push(Date.now()); + assert.deepStrictEqual(seen, [130, 130]); + }); + + it("throws when another tracker mocks Date", (t) => { + mock.timers.enable({ apis: ["Date"], now: 7 }); + const got = failure(() => t.mock.timers.enable({ apis: ["Date"] })); + assert.strictEqual(got, "Error ERR_INVALID_STATE Invalid state: Date is already being mocked!"); + assert.strictEqual(failure(() => t.mock.timers.tick(1)).includes("enable MockTimers first"), true); + assert.strictEqual(Date.now(), 7); + mock.timers.reset(); + }); +}); + +describe("setImmediate", () => { + it("runs before timers due at the same tick", (t) => { + t.mock.timers.enable({ apis: ["setImmediate", "setTimeout"] }); + const log: string[] = []; + setTimeout(() => log.push("timeout 0"), 0); + setImmediate(() => log.push("immediate")); + setImmediate((tag: string) => log.push(`immediate ${tag}`), "x"); + const cleared = setImmediate(() => log.push("cleared")); + clearImmediate(cleared); + assert.strictEqual(cleared.hasRef(), true); + assert.strictEqual(cleared.unref().hasRef(), true); + assert.strictEqual(cleared.ref().hasRef(), true); + t.mock.timers.tick(0); + log.push("tick 0"); + assert.deepStrictEqual(log, ["immediate", "immediate x", "timeout 0", "tick 0"]); + }); + + it("an immediate queued by a due timeout runs that timeout again", (t) => { + // Node removes a fired timer only when it is still first in the queue; + // the immediate's run time (now - 1) puts it first. + t.mock.timers.enable({ apis: ["setImmediate", "setTimeout"] }); + const log: string[] = []; + setTimeout(() => { + log.push("timeout"); + if (log.length === 1) setImmediate(() => log.push("immediate")); + }, 0); + t.mock.timers.tick(0); + assert.deepStrictEqual(log, ["timeout", "immediate", "timeout"]); + }); + + it("named and namespace imports keep the loop's immediates", async (t) => { + t.mock.timers.enable({ apis: ["setImmediate"] }); + const log: string[] = []; + await new Promise((resolve) => + namedSetImmediate(() => { + log.push("named"); + resolve(); + }), + ); + await new Promise((resolve) => + timersNamespace.setImmediate(() => { + log.push("namespace"); + resolve(); + }), + ); + assert.deepStrictEqual(log, ["named", "namespace"]); + }); +}); + +describe("enable() without apis", () => { + it("mocks every API", (t) => { + t.mock.timers.enable(); + const log: string[] = []; + assert.strictEqual(Date.now(), 0); + setTimeout(() => log.push(`timeout at ${Date.now()}`), 2); + setImmediate(() => log.push("immediate")); + const beat = setInterval(() => { + log.push(`interval at ${Date.now()}`); + clearInterval(beat); + }, 1); + const signal = AbortSignal.timeout(3); + signal.addEventListener("abort", () => { + const reason = signal.reason as { name: string; message: string }; + log.push(`abort ${reason.name}: ${reason.message}`); + }); + t.mock.timers.tick(3); + assert.strictEqual(signal.aborted, true); + assert.deepStrictEqual(log, [ + "immediate", + "interval at 3", + "timeout at 3", + "abort AbortError: This operation was aborted", + ]); + }); + + it("[Symbol.dispose]() resets", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + let fired = 0; + setTimeout(() => fired++, 1); + t.mock.timers[Symbol.dispose](); + assert.strictEqual(failure(() => t.mock.timers.tick(1)).includes("enable MockTimers first"), true); + assert.strictEqual(fired, 0); + }); + + it("mocks nothing with an empty apis list", (t) => { + t.mock.timers.enable({ apis: [] }); + assert.strictEqual(Date.now() > 1e12, true); + t.mock.timers.tick(1); + }); +}); diff --git a/tests/fixtures/node-test/cases/mock-timers.ts b/tests/fixtures/node-test/cases/mock-timers.ts new file mode 100644 index 000000000..1e5e5883f --- /dev/null +++ b/tests/fixtures/node-test/cases/mock-timers.ts @@ -0,0 +1,348 @@ +// mock.timers on the module's `mock` and on t.mock, for setTimeout and +// setInterval: enable({ apis, now }), tick, runAll, reset and setTime, the +// order due timers run in (equal, zero, negative, fractional and omitted +// delays), clears, handle methods, Node's errors, and the reset of +// t.mock.timers when its test ends. Node replaces the globals, so calls +// through ESM named and namespace imports of node:timers and +// node:timers/promises keep the loop's timers. +import { describe, it, mock, test } from "node:test"; +import * as assert from "node:assert"; +import * as timersNamespace from "node:timers"; +import { setTimeout as namedSetTimeout } from "node:timers"; +import { setTimeout as sleep } from "node:timers/promises"; + +type Fail = { name: string; code?: string; message: string }; +const failure = (fn: () => void): string => { + try { + fn(); + return "no throw"; + } catch (error) { + const e = error as Fail; + return `${e.name} ${e.code ?? "-"} ${e.message}`; + } +}; +const NOT_ENABLED = + "Error ERR_INVALID_STATE Invalid state: You should enable MockTimers first by calling the .enable function"; +const negative = (n: string) => + `TypeError ERR_INVALID_ARG_VALUE The argument 'time' ${n}. Received 'positive integer'`; + +describe("order", () => { + it("runs due timers by run time, then creation", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + const log: string[] = []; + setTimeout(() => log.push("omitted")); + setTimeout(() => log.push("zero"), 0); + setTimeout(() => log.push("negative"), -5); + setTimeout(() => log.push("fraction"), 0.5); + setTimeout(() => log.push("ten a"), 10); + setTimeout(() => log.push("five"), 5); + setTimeout(() => log.push("ten b"), 10); + t.mock.timers.tick(0); + log.push("tick 0"); + t.mock.timers.tick(1); + log.push("tick 1"); + t.mock.timers.tick(9); + assert.deepStrictEqual(log, [ + "omitted", + "negative", + "zero", + "tick 0", + "fraction", + "tick 1", + "five", + "ten a", + "ten b", + ]); + }); + + it("runs timers scheduled by a callback once they are due", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + const log: string[] = []; + setTimeout(() => { + log.push("outer"); + setTimeout(() => log.push("inner 0"), 0); + setTimeout(() => log.push("inner 5"), 5); + }, 10); + t.mock.timers.tick(10); + log.push("after 10"); + t.mock.timers.tick(5); + log.push("after 15"); + t.mock.timers.tick(); + assert.deepStrictEqual(log, ["outer", "inner 0", "after 10", "inner 5", "after 15"]); + }); + + it("passes the trailing arguments", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + const log: string[] = []; + setTimeout((a: string, b: number) => log.push(`${a} ${b}`), 1, "x", 2); + t.mock.timers.tick(1); + assert.deepStrictEqual(log, ["x 2"]); + }); +}); + +describe("intervals", () => { + it("repeats until cleared", (t) => { + t.mock.timers.enable({ apis: ["setInterval", "setTimeout"] }); + const log: string[] = []; + let n = 0; + const handle = setInterval(() => { + n++; + log.push(`interval ${n}`); + if (n === 3) clearInterval(handle); + }, 10); + setTimeout(() => log.push("timeout 25"), 25); + t.mock.timers.tick(100); + assert.deepStrictEqual(log, ["interval 1", "interval 2", "timeout 25", "interval 3"]); + }); + + it("fires once per elapsed period", (t) => { + t.mock.timers.enable({ apis: ["setInterval"] }); + let n = 0; + const handle = setInterval(() => n++, 3); + t.mock.timers.tick(10); + assert.strictEqual(n, 3); + clearInterval(handle); + t.mock.timers.tick(10); + assert.strictEqual(n, 3); + }); + + it("clears from another callback", (t) => { + t.mock.timers.enable({ apis: ["setInterval", "setTimeout"] }); + let n = 0; + const handle = setInterval(() => n++, 4); + setTimeout(() => clearInterval(handle), 9); + t.mock.timers.tick(20); + assert.strictEqual(n, 2); + }); + + it("leaves intervals alone when only setTimeout is mocked", async (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + let n = 0; + await new Promise((resolve) => { + const handle = setInterval(() => { + n++; + clearInterval(handle); + resolve(); + }, 5); + }); + assert.strictEqual(n, 1); + }); +}); + +describe("runAll", () => { + it("ticks to the last queued timer", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + const log: string[] = []; + setTimeout(() => { + log.push("a"); + setTimeout(() => log.push("b"), 100); + }, 10); + setTimeout(() => log.push("c"), 20); + t.mock.timers.runAll(); + log.push("first runAll"); + t.mock.timers.runAll(); + log.push("second runAll"); + t.mock.timers.runAll(); + assert.deepStrictEqual(log, ["a", "c", "first runAll", "b", "second runAll"]); + }); +}); + +describe("clock", () => { + it("starts at now and moves with setTime", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"], now: 1000 }); + const log: string[] = []; + setTimeout(() => log.push("a"), 10); + t.mock.timers.setTime(5000); + setTimeout(() => log.push("b"), 10); + t.mock.timers.tick(1); + log.push("tick 1"); + t.mock.timers.tick(9); + t.mock.timers.setTime(); + setTimeout(() => log.push("c"), 1); + t.mock.timers.tick(1); + assert.deepStrictEqual(log, ["a", "tick 1", "b", "c"]); + }); + + it("takes now from a Date", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"], now: new Date(2000) }); + const log: string[] = []; + setTimeout(() => log.push("a"), 10); + t.mock.timers.setTime(2005); + t.mock.timers.tick(4); + log.push("tick 4"); + t.mock.timers.tick(1); + assert.deepStrictEqual(log, ["tick 4", "a"]); + }); +}); + +describe("handles", () => { + it("ref, unref and refresh leave a mock timer as it is", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + let fired = 0; + const handle = setTimeout(() => fired++, 5); + assert.strictEqual(handle.hasRef(), true); + assert.strictEqual(handle.unref().hasRef(), true); + assert.strictEqual(handle.ref().hasRef(), true); + handle.refresh(); + t.mock.timers.tick(5); + t.mock.timers.tick(5); + assert.strictEqual(fired, 1); + }); + + it("clearTimeout of a mock timer", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + let fired = 0; + const handle = setTimeout(() => fired++, 5); + clearTimeout(handle); + t.mock.timers.tick(10); + assert.strictEqual(fired, 0); + }); + + it("a real timer made before enable keeps running", async (t) => { + let fired = 0; + const done = new Promise((resolve) => { + const real = setTimeout(() => { + fired++; + resolve(); + }, 5); + t.mock.timers.enable({ apis: ["setTimeout"] }); + // The mocked clearTimeout leaves the real timer armed. + clearTimeout(real); + assert.strictEqual(real.hasRef(), true); + }); + await done; + assert.strictEqual(fired, 1); + }); +}); + +describe("errors", () => { + it("throws Node's errors", (t) => { + const got: string[] = []; + got.push(failure(() => t.mock.timers.tick(1))); + got.push(failure(() => t.mock.timers.runAll())); + got.push(failure(() => t.mock.timers.setTime(-1))); + got.push(failure(() => t.mock.timers.setTime(5))); + got.push(failure(() => t.mock.timers.enable({ apis: ["setTimeout"], now: -1 }))); + got.push(failure(() => t.mock.timers.enable({ apis: ["setTimeout"], now: NaN }))); + got.push(failure(() => t.mock.timers.reset())); + t.mock.timers.enable({ apis: ["setTimeout"] }); + got.push(failure(() => t.mock.timers.enable({ apis: ["setTimeout"] }))); + got.push(failure(() => t.mock.timers.tick(-1.5))); + got.push(failure(() => t.mock.timers.tick(-Infinity))); + got.push(failure(() => t.mock.timers.tick(0))); + assert.deepStrictEqual(got, [ + NOT_ENABLED, + NOT_ENABLED, + negative("-1"), + NOT_ENABLED, + negative("-1"), + "TypeError ERR_INVALID_ARG_VALUE The argument 'now' epoch must be a positive integer received NaN. Received NaN", + "no throw", + "Error ERR_INVALID_STATE Invalid state: MockTimers is already enabled!", + negative("-1.5"), + negative("-Infinity"), + "no throw", + ]); + }); + + it("a throwing callback stays queued", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + let runs = 0; + setTimeout(() => { + runs++; + if (runs === 1) throw new Error("boom"); + }, 5); + assert.throws(() => t.mock.timers.tick(5), { message: "boom" }); + t.mock.timers.tick(0); + t.mock.timers.tick(0); + assert.strictEqual(runs, 2); + }); +}); + +describe("imports", () => { + it("globalThis.setTimeout is mocked", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + const log: string[] = []; + globalThis.setTimeout(() => log.push("timeout"), 5); + t.mock.timers.tick(5); + assert.deepStrictEqual(log, ["timeout"]); + }); + + it("named and namespace imports keep the loop's timers", async (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + const log: string[] = []; + await Promise.all([ + sleep(5).then(() => { + log.push("named promise"); + }), + new Promise((resolve) => + namedSetTimeout(() => { + log.push("named"); + resolve(); + }, 2), + ), + new Promise((resolve) => + timersNamespace.setTimeout(() => { + log.push("namespace"); + resolve(); + }, 3), + ), + ]); + t.mock.timers.tick(10); + assert.deepStrictEqual(log, ["named", "namespace", "named promise"]); + }); +}); + +describe("trackers", () => { + it("leaves t.mock.timers enabled", (t) => { + t.mock.timers.enable({ apis: ["setTimeout"] }); + setTimeout(() => { + throw new Error("never runs"); + }, 1); + }); + + it("the previous test's timers were reset", async () => { + let fired = false; + await new Promise((resolve) => + setTimeout(() => { + fired = true; + resolve(); + }, 1), + ); + assert.strictEqual(fired, true); + }); + + it("t.mock takes setTimeout over from mock and gives it back", (t) => { + const log: string[] = []; + mock.timers.enable({ apis: ["setTimeout"] }); + setTimeout(() => log.push("module"), 5); + t.mock.timers.enable({ apis: ["setTimeout"] }); + setTimeout(() => log.push("test"), 5); + mock.timers.tick(5); + log.push("module ticked"); + t.mock.timers.tick(5); + t.mock.timers.reset(); + setTimeout(() => log.push("module again"), 1); + mock.timers.tick(1); + mock.timers.reset(); + assert.deepStrictEqual(log, ["module", "module ticked", "test", "module again"]); + }); + + it("mock.reset() resets mock.timers", () => { + mock.timers.enable({ apis: ["setInterval"] }); + mock.reset(); + assert.strictEqual(failure(() => mock.timers.tick(1)), NOT_ENABLED); + }); +}); + +test("timers outside node:test bodies", () => { + // A fresh enable after reset starts the clock at 0 again. + mock.timers.enable({ apis: ["setTimeout"], now: 100 }); + mock.timers.reset(); + mock.timers.enable({ apis: ["setTimeout"] }); + const log: string[] = []; + setTimeout(() => log.push("at 1"), 1); + mock.timers.tick(1); + mock.timers.reset(); + assert.deepStrictEqual(log, ["at 1"]); +}); diff --git a/tests/harness/__snapshots__/mock-timers-fences.ts.txt b/tests/harness/__snapshots__/mock-timers-fences.ts.txt new file mode 100644 index 000000000..dba7de64c --- /dev/null +++ b/tests/harness/__snapshots__/mock-timers-fences.ts.txt @@ -0,0 +1,44 @@ +mock-timers-fences.ts:20:22 - error SC2020: 'mock.timers.enable with a non-literal apis list' is part of the standard library types but has no scriptc lowering yet + + 19 | const apis: ("setTimeout" | "setInterval")[] = ["setTimeout"]; + 20 | mock.timers.enable({ apis }); // apis list that is not a literal + | ^~~~ + 21 | + + hint: list the mocked APIs as string literals: enable({ apis: ['setTimeout', 'Date'] }) + +mock-timers-fences.ts:23:20 - error SC2020: 'mock.timers.enable with a non-literal options object' is part of the standard library types but has no scriptc lowering yet + + 22 | const options = { apis: ["setTimeout"] as const }; + 23 | mock.timers.enable(options); // options object that is not a literal + | ^~~~~~~ + 24 | + + hint: list the mocked APIs as string literals: enable({ apis: ['setTimeout', 'Date'] }) + +mock-timers-fences.ts:25:7 - error SC2020: 'MockTimers' is part of the standard library types but has no scriptc lowering yet + + 24 | + 25 | const timers = mock.timers; // the object as a value + | ^~~~~~ + 26 | timers.tick(1); + + hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) + +mock-timers-fences.ts:25:16 - error SC2020: 'MockTracker.timers' is part of the standard library types but has no scriptc lowering yet + + 24 | + 25 | const timers = mock.timers; // the object as a value + | ^~~~~~~~~~~ + 26 | timers.tick(1); + + hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) + +mock-timers-fences.ts:26:1 - error SC2020: 'MockTimers.tick' is part of the standard library types but has no scriptc lowering yet + + 25 | const timers = mock.timers; // the object as a value + 26 | timers.tick(1); + | ^~~~~~~~~~~ + 27 | + + hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) \ No newline at end of file From 39d2a05f880479d4abc05fede0cd0e1ff01db3d1 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 19:03:50 -0700 Subject: [PATCH 021/117] Renumber the array length loop corpus programs past main's numbers Co-Authored-By: Claude Opus 5.5 --- ...length-loop-resizing.ts => 5993-array-length-loop-resizing.ts} | 0 ...y-length-sparse-loops.ts => 5994-array-length-sparse-loops.ts} | 0 ...nse-loop-boundaries.ts => 5995-array-dense-loop-boundaries.ts} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/corpus/{5960-array-length-loop-resizing.ts => 5993-array-length-loop-resizing.ts} (100%) rename tests/corpus/{5961-array-length-sparse-loops.ts => 5994-array-length-sparse-loops.ts} (100%) rename tests/corpus/{5962-array-dense-loop-boundaries.ts => 5995-array-dense-loop-boundaries.ts} (100%) diff --git a/tests/corpus/5960-array-length-loop-resizing.ts b/tests/corpus/5993-array-length-loop-resizing.ts similarity index 100% rename from tests/corpus/5960-array-length-loop-resizing.ts rename to tests/corpus/5993-array-length-loop-resizing.ts diff --git a/tests/corpus/5961-array-length-sparse-loops.ts b/tests/corpus/5994-array-length-sparse-loops.ts similarity index 100% rename from tests/corpus/5961-array-length-sparse-loops.ts rename to tests/corpus/5994-array-length-sparse-loops.ts diff --git a/tests/corpus/5962-array-dense-loop-boundaries.ts b/tests/corpus/5995-array-dense-loop-boundaries.ts similarity index 100% rename from tests/corpus/5962-array-dense-loop-boundaries.ts rename to tests/corpus/5995-array-dense-loop-boundaries.ts From de4e10d542875e315668d84962700cc7dfb660fa Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 21:34:52 -0500 Subject: [PATCH 022/117] Shift the runtime in bench:runtime layouts The --layouts padding object was linked directly before the program object. The runtime is linked before the program object, so every layout moved only the program's code and left each runtime function at the same address. A change to the runtime's code size then moved its functions in all layouts at once, and the verdicts could not tell that placement change from a real one. The padding object now goes before every other input on the link line, so each layout shifts the runtime and the program code. --- scripts/bench-runtime.mjs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/scripts/bench-runtime.mjs b/scripts/bench-runtime.mjs index ff9c9d690..4e4f2c245 100644 --- a/scripts/bench-runtime.mjs +++ b/scripts/bench-runtime.mjs @@ -56,9 +56,10 @@ Each checkout must have a built CLI (packages/cli/dist/bootstrap.js) and native artifacts for this host. Without --baseline, reports absolute times only. Node is timed in the same interleaved loop as the reference to beat (--no-node skips it). ---layouts=N (macOS/Linux) links every executable N times, shifting the program -object by 0, 16, 32, ... bytes of padding, and spreads the timed runs evenly over -those layouts, so verdicts cover code-placement luck instead of one placement. +--layouts=N (macOS/Linux) links every executable N times, shifting the runtime +and program code by 0, 16, 32, ... bytes of padding, and spreads the timed runs +evenly over those layouts, so verdicts cover code-placement luck instead of one +placement. Use it for small codegen changes (e.g. --layouts=4 --runs=16). Workload names are listed in benchmarks/runtime/workloads.json; for example @@ -103,10 +104,11 @@ const work = mkdtempSync( ); /* ── code-layout perturbation ──────────────────────────────────────────── */ -// Layout k > 0 links a retained k*16-byte padding object directly before the -// program object, through a SCRIPTC_LINKER wrapper that forwards to clang (the -// default linker driver on macOS and Linux). Code after that point moves as if -// earlier code had grown; any checkout's compiler can be perturbed this way. +// Layout k > 0 links a retained k*16-byte padding object before every other +// input, through a SCRIPTC_LINKER wrapper that forwards to clang (the default +// linker driver on macOS and Linux). The runtime is linked before the program +// object, so both move as if earlier code had grown; any checkout's compiler can +// be perturbed this way. function layoutTooling() { if (layouts === 1) return null; const root = join(work, "layouts"); @@ -137,12 +139,11 @@ const args = process.argv.slice(2); const pad = process.env.SCRIPTC_BENCH_LAYOUT_PAD; let out = args; if (pad && !args.some((a) => a.startsWith("-print-prog-name"))) { - const at = args.findIndex((a) => basename(a).startsWith(".scriptc-native-program-object-")); - if (at < 0) { + if (!args.some((a) => basename(a).startsWith(".scriptc-native-program-object-"))) { process.stderr.write("bench layout wrapper: no program object on the link line\\n"); process.exit(2); } - out = ["-Wl,-u,${symbol}", ...args.slice(0, at), pad, ...args.slice(at)]; + out = ["-Wl,-u,${symbol}", pad, ...args]; } const result = spawnSync("clang", out, { stdio: "inherit" }); process.exit(result.status ?? 1); From eb0d09fb81d999a2816a3a9e5f170008a0de9082 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 19:40:45 -0700 Subject: [PATCH 023/117] Keep capture analyses linear in the size of a closure environment Three analyses did work proportional to the whole function once per captured binding, so a factory with thousands of bindings shared by its methods spent most of its compile time in them (48 s of LLVM emission at 8,000 bindings): - LazyCaptures walked the body again for every capture it checked and rebuilt a locals map for every capture of every creation site. Each function's rebound bindings are now collected in one walk and the unchanged-parameter sets are memoized. - int32-slots walked the declaring function once per box to find its initializer and scanned capture lists per member. Both are now per-function sets built on first use. - CaptureFlow scanned all capture edges, capture lists and entry copies per binding and searched statement lists per hoisted or TDZ binding. Edges are grouped by source, captures, parameters and entry copies are indexed, and hoisted and TDZ initializers are found in one pass. The results are unchanged: the candidate compiler emits byte-identical LLVM for the self-hosted compiler's source. Co-Authored-By: Claude Opus 5.5 --- .../src/backend/llvm/lazy-captures.test.ts | 2 +- .../src/backend/llvm/lazy-captures.ts | 49 ++++++--- packages/compiler/src/ir/capture-values.ts | 102 +++++++++--------- packages/compiler/src/ir/int32-slots.ts | 37 +++++-- 4 files changed, 116 insertions(+), 74 deletions(-) diff --git a/packages/compiler/src/backend/llvm/lazy-captures.test.ts b/packages/compiler/src/backend/llvm/lazy-captures.test.ts index b0a47d081..b0e5c55c5 100644 --- a/packages/compiler/src/backend/llvm/lazy-captures.test.ts +++ b/packages/compiler/src/backend/llvm/lazy-captures.test.ts @@ -47,7 +47,7 @@ function lifted(name: string, body: IrStmt[], captured = "options"): IrFunction loc, }; } -function lazy(...functions: IrFunction[]): Set { +function lazy(...functions: IrFunction[]): ReadonlySet { const map = new Map(functions.map((fn) => [fn.name, fn])); return new LazyCaptures(map).parameters(functions[0]!); } diff --git a/packages/compiler/src/backend/llvm/lazy-captures.ts b/packages/compiler/src/backend/llvm/lazy-captures.ts index 12fae0bf4..2014869af 100644 --- a/packages/compiler/src/backend/llvm/lazy-captures.ts +++ b/packages/compiler/src/backend/llvm/lazy-captures.ts @@ -26,9 +26,15 @@ function rebound(node: IrStmt | IrExpr): string | null { * closure then allocate no box. The proof follows each capture into nested * function bodies; class environments keep the eager box. */ export class LazyCaptures { - private readonly unchanged = new Map(); private readonly stable = new Map>(); private readonly once = new Map>(); + private readonly unchangedParameters = new Map>(); + /** Per function, every local rebound there or through nested captures; + * the second map counts declarations separately (see rebindings). Each + * body is walked once per map, so the queries stay linear in the IR. */ + private readonly rebound = new Map>(); + private readonly reboundAfterDeclaration = new Map>(); + private readonly pending = new Set(); private sites: Map | null = null; constructor(private readonly functions: ReadonlyMap) {} @@ -112,8 +118,11 @@ export class LazyCaptures { return sites; } - parameters(fn: IrFunction): Set { + parameters(fn: IrFunction): ReadonlySet { + const known = this.unchangedParameters.get(fn); + if (known !== undefined) return known; const result = new Set(); + this.unchangedParameters.set(fn, result); if (fn.async || fn.generator) return result; const locals = new Map(fn.locals.map((local) => [local.id, local])); for (const param of fn.params) { @@ -132,18 +141,33 @@ export class LazyCaptures { ids: ReadonlySet, declarationsBind = false, ): Set { + const all = this.reboundIn(fn, declarationsBind); const changed = new Set(); + for (const id of ids) if (all.has(id)) changed.add(id); + return changed; + } + + /** Every local rebound in `fn` or, through the closures it creates, in + * any function that captures it, directly or through further nesting. + * With `declarationsBind`, declarations are counted separately. */ + private reboundIn(fn: IrFunction, declarationsBind: boolean): ReadonlySet { + const memo = declarationsBind ? this.reboundAfterDeclaration : this.rebound; + const known = memo.get(fn); + if (known !== undefined) return known; + const changed = new Set(); + // Capture chains follow lexical nesting and cannot cycle; on malformed + // input a function reached again while its walk is pending reports + // every capture as rebound (see isUnchanged). + if (!declarationsBind) this.pending.add(fn); const nested: { target: string; local: string; source: string }[] = []; const visit = (node: IrStmt | IrExpr): boolean => { - // With `declarationsBind`, declarations are counted separately. const target = declarationsBind && node.kind === "varDecl" ? null : rebound(node); - if (target !== null && ids.has(target)) changed.add(target); + if (target !== null) changed.add(target); if (node.kind === "classRef") { - for (const id of node.captures ?? []) if (ids.has(id)) changed.add(id); + for (const id of node.captures ?? []) changed.add(id); } else if (node.kind === "closure") { const callee = this.functions.get(node.fnName); node.captures.forEach((id, index) => { - if (!ids.has(id)) return; const capture = callee?.captures?.[index]; if (!capture) changed.add(id); else nested.push({ target: node.fnName, local: capture.localId, source: id }); @@ -156,19 +180,14 @@ export class LazyCaptures { if (!changed.has(edge.source) && !this.isUnchanged(edge.target, edge.local)) changed.add(edge.source); } + if (!declarationsBind) this.pending.delete(fn); + memo.set(fn, changed); return changed; } private isUnchanged(fnName: string, localId: string): boolean { - const key = `${fnName}\0${localId}`; - const known = this.unchanged.get(key); - if (known !== undefined) return known; - // Capture chains follow lexical nesting and cannot cycle; the - // provisional entry only bounds work on malformed input. - this.unchanged.set(key, false); const fn = this.functions.get(fnName); - const result = fn !== undefined && this.rebindings(fn, new Set([localId])).size === 0; - this.unchanged.set(key, result); - return result; + if (fn === undefined || this.pending.has(fn)) return false; + return !this.reboundIn(fn, false).has(localId); } } diff --git a/packages/compiler/src/ir/capture-values.ts b/packages/compiler/src/ir/capture-values.ts index 94cff053b..d7a1516bb 100644 --- a/packages/compiler/src/ir/capture-values.ts +++ b/packages/compiler/src/ir/capture-values.ts @@ -244,8 +244,13 @@ interface FunctionFacts { classCaptured: Set; reads: Map; /** Closure capture edges: the creator's binding `source` flows into - * capture `local` of `target`. */ - edges: { target: string; index: number; source: string }[]; + * capture `local` of `target`, grouped by `source`. */ + edges: Map; + /** The function's own captures (first index of each id), class + * captures, and parameters, for constant-time membership tests. */ + captureIndex: Map; + classCaptures: Set; + params: Set; } interface CreationSite { @@ -317,7 +322,7 @@ export class CaptureFlow { ? value.fnName : null; } - const index = fn.captures?.findIndex((c) => c.localId === id) ?? -1; + const index = this.factsOf(fn).captureIndex.get(id) ?? -1; if (index < 0 || !this.stableCapture(fnName, id)) return null; let result: string | null = null; for (const site of this.sites.get(fnName) ?? []) { @@ -399,7 +404,7 @@ export class CaptureFlow { return true; }; everyStmtList(body.slice(declared + 1), { stmt: () => true, expr: count }); - const edges = facts.edges.filter((edge) => edge.source === id).length; + const edges = facts.edges.get(id)?.length ?? 0; return nodes === edges && !facts.classCaptured.has(id); } @@ -410,7 +415,7 @@ export class CaptureFlow { const local = facts.locals.get(id); const declaration = facts.declarations.get(id); if (local === undefined || local.boxed === true || local.tdz === true) return false; - if (fn.params.some((p) => p.localId === id) || declaration?.count !== 1) return false; + if (facts.params.has(id) || declaration?.count !== 1) return false; const writes = facts.writes.get(id) ?? 0; return declaration.initialized ? writes === 0 : facts.hoisted.has(id) && writes === 1; } @@ -450,8 +455,14 @@ export class CaptureFlow { tdzInits: new Map(), classCaptured: new Set(), reads: new Map(), - edges: [], + edges: new Map(), + captureIndex: new Map(), + classCaptures: new Set((fn.classCaptures ?? []).map((c) => c.localId)), + params: new Set(fn.params.map((p) => p.localId)), }; + (fn.captures ?? []).forEach((c, index) => { + if (!facts.captureIndex.has(c.localId)) facts.captureIndex.set(c.localId, index); + }); this.facts.set(fn.name, facts); const capturesIn = (e: IrExpr): Set => { const ids = new Set(); @@ -464,19 +475,17 @@ export class CaptureFlow { visitExpr(e); return ids; }; + // One pass over runs of empty declarations and closure assignments: + // each empty declaration pairs with the first later assignment of its + // binding in the same run. const findHoisted = (body: readonly IrStmt[]): void => { - body.forEach((s, i) => { - if (s.kind !== "varDecl" || s.init !== null) return; - for (let j = i + 1; j < body.length; j++) { - const next = body[j]!; - if (next.kind === "assign" && next.value.kind === "closure") { - if (next.localId === s.localId) { - facts.hoisted.set(s.localId, next); - return; - } - } else if (next.kind !== "varDecl" || next.init !== null) return; - } - }); + const pending = new Set(); + for (const s of body) { + if (s.kind === "assign" && s.value.kind === "closure") { + if (pending.delete(s.localId)) facts.hoisted.set(s.localId, s); + } else if (s.kind === "varDecl" && s.init === null) pending.add(s.localId); + else pending.clear(); + } }; const declare = (s: IrStmt & { kind: "varDecl" }, splittable: boolean): void => { const entry = facts.declarations.get(s.localId); @@ -514,9 +523,11 @@ export class CaptureFlow { let list = this.sites.get(e.fnName); if (list === undefined) this.sites.set(e.fnName, (list = [])); list.push({ owner: fn.name, captures: e.captures, adapts: e.adapts === true }); - e.captures.forEach((source, index) => - facts.edges.push({ target: e.fnName, index, source }), - ); + e.captures.forEach((source, index) => { + let edges = facts.edges.get(source); + if (edges === undefined) facts.edges.set(source, (edges = [])); + edges.push({ target: e.fnName, index, source }); + }); break; } case "classRef": @@ -535,12 +546,15 @@ export class CaptureFlow { // iteration, and statement lists inside expressions release their // locals with the enclosing frame; declarations there stay as they are. const findTdzInits = (body: readonly IrStmt[]): void => { + // The first empty declaration of each binding in this list. + const empty = new Map(); body.forEach((s, j) => { + if (s.kind === "varDecl" && s.init === null && !empty.has(s.localId)) + empty.set(s.localId, j); if (s.kind !== "assign" || s.initializes !== true) return; - const declared = body.findIndex( - (d, i) => i < j && d.kind === "varDecl" && d.localId === s.localId && d.init === null, - ); - if (declared >= 0) facts.tdzInits.set(s.localId, { body, declared, initialized: j }); + const declared = empty.get(s.localId); + if (declared !== undefined && declared < j) + facts.tdzInits.set(s.localId, { body, declared, initialized: j }); }); }; const list = (body: readonly IrStmt[], split: boolean): boolean => { @@ -591,10 +605,6 @@ export class CaptureFlow { return facts; } - private local(fn: IrFunction, id: string): IrLocal | undefined { - return this.factsOf(fn).locals.get(id); - } - /** Nothing rebinds `id` in `fnName` (declarations aside, and `ownWrites` * writes of its own body) or in any body that shares its box through * closure captures. */ @@ -610,8 +620,7 @@ export class CaptureFlow { result = (facts.writes.get(id) ?? 0) === ownWrites && !facts.classCaptured.has(id) && - facts.edges.every((edge) => { - if (edge.source !== id) return true; + (facts.edges.get(id) ?? []).every((edge) => { const capture = this.functions.get(edge.target)?.captures?.[edge.index]; return capture !== undefined && this.unchanged(edge.target, capture.localId); }); @@ -623,19 +632,18 @@ export class CaptureFlow { /** A boxed binding of `fn` itself (not a capture) whose box is filled * once, before any environment observes it, and never written again. */ stableOrigin(fn: IrFunction, id: string): boolean { - const local = this.local(fn, id); + const facts = this.factsOf(fn); + const local = facts.locals.get(id); if (local?.boxed !== true) return false; if (local.tdz === true) { - if (fn.captures?.some((c) => c.localId === id)) return false; - if (this.factsOf(fn).declarations.get(id)?.count !== 1) return false; + if (facts.captureIndex.has(id)) return false; + if (facts.declarations.get(id)?.count !== 1) return false; return this.orderedTdz(fn, id) && this.unchanged(fn.name, id, 1); } - if (fn.captures?.some((c) => c.localId === id)) return false; - if (fn.classCaptures?.some((c) => c.localId === id)) return false; - const facts = this.factsOf(fn); + if (facts.captureIndex.has(id)) return false; + if (facts.classCaptures.has(id)) return false; const declaration = facts.declarations.get(id); - if (fn.params.some((p) => p.localId === id)) - return declaration === undefined && this.unchanged(fn.name, id); + if (facts.params.has(id)) return declaration === undefined && this.unchanged(fn.name, id); if (declaration?.count !== 1) return false; if (declaration.initialized) return this.unchanged(fn.name, id); return facts.hoisted.has(id) && this.unchanged(fn.name, id, 1); @@ -654,8 +662,8 @@ export class CaptureFlow { private computeStableCapture(fnName: string, id: string): boolean { const fn = this.functions.get(fnName); - const index = fn?.captures?.findIndex((c) => c.localId === id) ?? -1; - if (fn === undefined || index < 0) return false; + const index = fn === undefined ? undefined : this.factsOf(fn).captureIndex.get(id); + if (fn === undefined || index === undefined) return false; const sites = this.sites.get(fnName); if (sites === undefined || sites.length === 0) return false; for (const site of sites) { @@ -679,7 +687,7 @@ export class CaptureFlow { const assign = init?.body[init.initialized]; return assign?.kind === "assign" ? plainLiteral(constantNumber(assign.value)) : own.literal; } - const index = fn.captures?.findIndex((c) => c.localId === id) ?? -1; + const index = this.factsOf(fn).captureIndex.get(id) ?? -1; if (index < 0 || !this.stableCapture(fnName, id)) return null; let value: number | null = null; for (const site of this.sites.get(fnName) ?? []) { @@ -715,8 +723,8 @@ export class CaptureFlow { const immutable = new Set(); for (const local of fn.locals) { if (local.boxed !== true) continue; - const capture = fn.captures?.some((c) => c.localId === local.id) === true; - const param = fn.params.some((p) => p.localId === local.id); + const capture = facts.captureIndex.has(local.id); + const param = facts.params.has(local.id); if (capture && local.mutable && this.stableCapture(fn.name, local.id)) immutable.add(local.id); if (!facts.reads.has(local.id)) continue; @@ -871,10 +879,8 @@ export class CaptureFlow { ); const pruned = dead.size === 0 ? body : prune(body, dead); const liveIds = new Set(live.map((s) => (s.kind === "varDecl" ? s.localId : ""))); - const added = locals.filter( - (local) => - liveIds.has(local.id) || !entry.some((s) => s.kind === "varDecl" && s.localId === local.id), - ); + const entryIds = new Set(entry.map((s) => (s.kind === "varDecl" ? s.localId : ""))); + const added = locals.filter((local) => liveIds.has(local.id) || !entryIds.has(local.id)); return { ...fn, locals: [...kept, ...added], body: [...live, ...pruned] }; } } diff --git a/packages/compiler/src/ir/int32-slots.ts b/packages/compiler/src/ir/int32-slots.ts index 5e868793c..78d7e9e9f 100644 --- a/packages/compiler/src/ir/int32-slots.ts +++ b/packages/compiler/src/ir/int32-slots.ts @@ -889,27 +889,44 @@ export function analyzeInt32Slots(mod: IrModule): Int32Slots { else groups.set(root, [key]); } const boxOrigin = new Map(); + // Per function, computed on first use: its capture ids and the locals an + // initialized declaration binds (one body walk each, not one per box). + const captureIds = new Map>(); + const capturedIn = (fnName: string, localId: string): boolean => { + let ids = captureIds.get(fnName); + if (ids === undefined) { + ids = new Set((functions.get(fnName)?.captures ?? []).map((c) => c.localId)); + captureIds.set(fnName, ids); + } + return ids.has(localId); + }; + const initializedDeclarations = new Map>(); + const initializedIn = (fn: IrFunction, localId: string): boolean => { + let ids = initializedDeclarations.get(fn.name); + if (ids === undefined) { + const found = new Set(); + walkFunction(fn, { + stmt: (s) => { + if (s.kind === "varDecl" && s.init) found.add(s.localId); + }, + }); + initializedDeclarations.set(fn.name, (ids = found)); + } + return ids.has(localId); + }; for (const [group, members] of groups) { if (members.some((key) => unstableBoxes.has(key))) continue; // The origin is the one member that is not a capture of its function. const origins = members.filter((key) => { const [fnName, localId] = key.split("\0") as [string, string]; - return !functions.get(fnName)?.captures?.some((c) => c.localId === localId); + return !capturedIn(fnName, localId); }); if (origins.length !== 1) continue; const [fnName, localId] = origins[0]!.split("\0") as [string, string]; const origin = functions.get(fnName)!; if (origin.params.some((p) => p.localId === localId)) { if (!slots.hasParam(fnName, localId)) continue; - } else { - let initialized = false; - walkFunction(origin, { - stmt: (s) => { - if (s.kind === "varDecl" && s.localId === localId && s.init) initialized = true; - }, - }); - if (!initialized) continue; - } + } else if (!initializedIn(origin, localId)) continue; boxOrigin.set(`param:${fnName}\0${localId}`, group); slots.addBox(group, members); // A box starts from its origin parameter's value: it can only be From 8c8ee284138995e99b6c5b81bbab03f856ae71c0 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 19:43:03 -0700 Subject: [PATCH 024/117] Compile bodies with thousands of capture boxes unoptimized Every box pointer of a captured binding is a value live from its binding to its last use. A factory whose methods share thousands of bindings hands LLVM thousands of such ranges, each crossing every call in between, in the factory and in each method that receives them, and the inliner, instruction selection and register allocation grow quadratically: Bun's large-environment AOT program (8,701 captured bindings) spent about three minutes in native code generation. A function holding at least 512 capture boxes (the self-hosted compiler's largest holds under 100) is now emitted `noinline optnone`, and its box slots are loaded and stored volatile so no IR pass promotes them, which the native helper's pipeline would otherwise still do for optnone bodies. Each use reloads its box pointer from the frame. Boxes, environments and semantics are unchanged; only those bodies' machine code is unoptimized. large-environment.ts now compiles in 16 s instead of 227 s (peak RSS 543 MB instead of 777 MB) and runs in the same 0.18 s. Corpus 5973 pins such a factory's behavior (shared mutation, per-iteration closures, a nested closure, a forward-captured read in its TDZ), and a harness test bounds compile-time growth between 500 and 4,000 bindings. Co-Authored-By: Claude Opus 5.5 --- .../compiler/src/backend/llvm/blocks.test.ts | 33 +- packages/compiler/src/backend/llvm/blocks.ts | 43 +- .../compiler/src/backend/llvm/emitter.test.ts | 55 + packages/compiler/src/backend/llvm/emitter.ts | 35 + .../corpus/5973-large-closure-environment.ts | 1859 +++++++++++++++++ .../closure-environment-scaling.test.ts | 128 ++ 6 files changed, 2151 insertions(+), 2 deletions(-) create mode 100644 tests/corpus/5973-large-closure-environment.ts create mode 100644 tests/harness/closure-environment-scaling.test.ts diff --git a/packages/compiler/src/backend/llvm/blocks.test.ts b/packages/compiler/src/backend/llvm/blocks.test.ts index c2ee90b5f..b96fc851e 100644 --- a/packages/compiler/src/backend/llvm/blocks.test.ts +++ b/packages/compiler/src/backend/llvm/blocks.test.ts @@ -1,5 +1,5 @@ import { expect, test } from "vitest"; -import { BlockBuilder } from "./blocks.js"; +import { BlockBuilder, volatileSlotAccess } from "./blocks.js"; import { f64Lit } from "./common.js"; test("entry allocations precede instructions and temporaries stay unique", () => { @@ -106,3 +106,34 @@ test("inclusive loops and nested loops keep labels separate", () => { expect(text).toContain("fcmp ole double"); expect(text.match(/alloca double/g)).toHaveLength(2); }); + +test("volatile slots render their loads and stores volatile and nothing else", () => { + const slots = new Set(["%sc_l_a_0"]); + expect(volatileSlotAccess(" %t1 = load ptr, ptr %sc_l_a_0 ; a", slots)).toBe( + " %t1 = load volatile ptr, ptr %sc_l_a_0 ; a", + ); + expect(volatileSlotAccess(" store ptr %t1, ptr %sc_l_a_0, !dbg !7", slots)).toBe( + " store volatile ptr %t1, ptr %sc_l_a_0, !dbg !7", + ); + expect(volatileSlotAccess(" store ptr null, ptr %sc_l_a_0", slots)).toBe( + " store volatile ptr null, ptr %sc_l_a_0", + ); + // Other addresses, a slot stored as a value, prefixes and other opcodes. + for (const line of [ + " %t2 = load ptr, ptr %sc_l_a_01", + " store ptr %sc_l_a_0, ptr %sc_l_b_0", + " %t3 = getelementptr inbounds ptr, ptr %sc_l_a_0, i64 1", + " call void @scr_box_release(ptr %sc_l_a_0)", + " %t4 = load volatile ptr, ptr %sc_l_a_0", + ]) + expect(volatileSlotAccess(line, slots)).toBe(line); + + const blocks = new BlockBuilder(); + blocks.volatileSlots = slots; + blocks.entryAllocas.push("%sc_l_a_0 = alloca ptr"); + blocks.line("store ptr null, ptr %sc_l_a_0"); + blocks.terminate("ret void"); + expect(blocks.render()).toBe( + "entry:\n %sc_l_a_0 = alloca ptr\n store volatile ptr null, ptr %sc_l_a_0\n ret void", + ); +}); diff --git a/packages/compiler/src/backend/llvm/blocks.ts b/packages/compiler/src/backend/llvm/blocks.ts index 5be4ef880..6d22bf3bf 100644 --- a/packages/compiler/src/backend/llvm/blocks.ts +++ b/packages/compiler/src/backend/llvm/blocks.ts @@ -31,6 +31,9 @@ export class BlockBuilder { /** Temps known to hold immortal values (temp names are only unique * within one builder). */ readonly immortalTemps = new Set(); + /** Entry slots whose loads and stores render volatile, so no LLVM pass + * promotes them to SSA values (see volatileSlotAccess). */ + volatileSlots: ReadonlySet | null = null; constructor() { this.cur = { label: "entry", lines: [], term: null }; @@ -130,9 +133,14 @@ export class BlockBuilder { } render(): string { + const slots = this.volatileSlots; return this.blocks .map((b, i) => { - const lines = i === 0 ? [...this.entryAllocas.map((l) => ` ${l}`), ...b.lines] : b.lines; + const body = + slots === null || slots.size === 0 + ? b.lines + : b.lines.map((line) => volatileSlotAccess(line, slots)); + const lines = i === 0 ? [...this.entryAllocas.map((l) => ` ${l}`), ...body] : body; // A block left unterminated is a structurally unreachable join // (every predecessor jumped elsewhere); the verifier still wants a // terminator. @@ -142,3 +150,36 @@ export class BlockBuilder { .join("\n"); } } + +/** `line` with its load or store made volatile when the address operand is + * one of `slots`. Lines are this builder's own instruction text, where the + * address is the first `ptr %name` operand after the opcode (a stored value + * precedes it without a comma). */ +export function volatileSlotAccess(line: string, slots: ReadonlySet): string { + let op = 0; + while (line.charCodeAt(op) === 32) op++; + if (line.charCodeAt(op) === 37) { + const assign = line.indexOf(" = ", op); + if (assign < 0) return line; + op = assign + 3; + } + const kind = line.startsWith("load ", op) ? 5 : line.startsWith("store ", op) ? 6 : 0; + if (kind === 0 || line.startsWith("volatile ", op + kind)) return line; + const address = line.indexOf(", ptr %", op + kind); + if (address < 0) return line; + const start = address + 6; + let end = start + 1; + while (end < line.length && isNameCode(line.charCodeAt(end))) end++; + if (!slots.has(line.slice(start, end))) return line; + return `${line.slice(0, op + kind)}volatile ${line.slice(op + kind)}`; +} + +function isNameCode(code: number): boolean { + return ( + (code >= 48 && code <= 57) || + (code >= 65 && code <= 90) || + (code >= 97 && code <= 122) || + code === 95 || + code === 46 + ); +} diff --git a/packages/compiler/src/backend/llvm/emitter.test.ts b/packages/compiler/src/backend/llvm/emitter.test.ts index 4fda0f7e0..74dc8f859 100644 --- a/packages/compiler/src/backend/llvm/emitter.test.ts +++ b/packages/compiler/src/backend/llvm/emitter.test.ts @@ -126,6 +126,61 @@ test("the shared indexed-read helpers carry an inline hint", () => { expect(define("plain")).not.toContain("inlinehint"); }); +test("bodies holding thousands of capture boxes compile unoptimized with boxes in memory", () => { + const number = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); + const read = (localId: string): IrExpr => ({ kind: "varRef", localId, type: F64, loc }); + // A declaring body with `count` boxed bindings, and a closure body that + // receives `count` of them through its environment. + const declaring = (name: string, count: number): IrFunction => { + const ids = Array.from({ length: count }, (_, i) => `${name}${i}`); + return { + name, + params: [], + returnType: F64, + locals: ids.map((id) => ({ id, name: id, type: F64, mutable: true, boxed: true as const })), + body: [ + ...ids.map((id, i): IrStmt => ({ kind: "varDecl", localId: id, init: number(i), loc })), + { kind: "return", value: read(ids[count - 1]!), loc }, + ], + loc, + }; + }; + const receiving = (name: string, count: number): IrFunction => { + const ids = Array.from({ length: count }, (_, i) => `${name}${i}`); + return { + name, + params: [], + returnType: F64, + captures: ids.map((id) => ({ localId: id, name: id, type: F64 })), + locals: ids.map((id) => ({ id, name: id, type: F64, mutable: true, boxed: true as const })), + body: [{ kind: "return", value: read(ids[0]!), loc }], + loc, + }; + }; + const module = moduleFor([]); + const llvm = emitLlvmModule({ + ...module, + functions: [ + ...module.functions, + declaring("wide", 512), + declaring("narrow", 511), + receiving("env", 512), + ], + }); + const body = (name: string): string => { + const start = llvm.split("\n").findIndex((line) => line.endsWith(`{ ; ${name}`)); + const lines = llvm.split("\n").slice(start); + return lines.slice(0, lines.indexOf("}")).join("\n"); + }; + expect(body("wide")).toMatch(/\) noinline optnone #0 \{/); + expect(body("wide")).toMatch(/store volatile ptr %[st]\d+, ptr %sc_l_wide0\b/); + expect(body("wide")).toMatch(/= load volatile ptr, ptr %sc_l_wide511\b/); + expect(body("env")).toMatch(/\) noinline optnone #0 \{/); + expect(body("env")).toMatch(/store volatile ptr %t\d+, ptr %sc_l_env0 ; captured env0/); + expect(body("narrow")).not.toContain("optnone"); + expect(body("narrow")).not.toContain("volatile"); +}); + test("throwing-call count does not multiply identical scope cleanup", () => { for (const boxed of [false, true]) { const small = emitLlvmModule(moduleFor(Array.from({ length: 4 }, call), { boxed })); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 2c3a71457..5508e61f5 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -548,10 +548,35 @@ const AWAIT_SUSPENSIONS = /@(?:scr_await_(?:void|f64|bool|str|ref|hop)\b|sc_a[wd * own fiber and promise. */ const COROUTINE_SUSPENDS = /@(?:scr_(?:await_|module_await\b|promise_await_settled\b|test_sub\b|gen_yield_|async_gen_|fiber_(?!self\b|promise\b))|sc_a[wd]_)/; +/** Captured bindings (boxes a body declares or receives) from which a + * function compiles without LLVM optimization (see boxSlotCount). */ +const UNOPTIMIZED_BOX_SLOTS = 512; /** ScrExcKind tags of a generator slot holding a number or a boolean. */ const SCR_EXC_F64 = 1; const SCR_EXC_BOOL = 2; +/** The capture boxes `fn` holds: its boxed bindings and the bindings its + * environment brings in. Each box pointer is a value from its binding (or + * function entry) to its last use, and every one of them crosses the calls + * in between. With thousands of them in one body, as in a factory whose + * returned methods share a large environment, LLVM's inliner, instruction + * selection and register allocation grow quadratically and take minutes. + * Past UNOPTIMIZED_BOX_SLOTS, which ordinary functions stay far below, the + * body is compiled `optnone` (nothing inlines into it and code generation + * takes its fast paths) and its box slots are accessed volatile, so no + * pass promotes them to values even where a pipeline runs IR passes over + * optnone bodies, as the native helper's does. Each use reloads its box + * pointer and code generation stays linear. Semantics, boxes and + * environments are unchanged; only that body's machine code is slower. */ +function boxSlotCount(fn: IrFunction): number { + const captured = new Set(); + for (const capture of fn.captures ?? []) captured.add(capture.localId); + for (const capture of fn.classCaptures ?? []) captured.add(capture.localId); + let count = 0; + for (const local of fn.locals) if (local.boxed === true || captured.has(local.id)) count++; + return count; +} + /** Whether any node of `e` names the local (reads, writes, declarations, * captures). */ function mentionsLocal(e: IrExpr, localId: string): boolean { @@ -6817,6 +6842,15 @@ export class LlEmitter { B.line(`store ptr null, ptr %${mangleLocal(local.id)}`); } } + // A body holding thousands of capture boxes compiles unoptimized, its + // box pointers kept in their slots (see boxSlotCount). + const unoptimized = this.currentCoro === null && boxSlotCount(fn) >= UNOPTIMIZED_BOX_SLOTS; + if (unoptimized) { + const slots = new Set(); + for (const local of this.currentLocals.values()) + if (local.boxed || this.captureIds.has(local.id)) slots.add(`%${mangleLocal(local.id)}`); + B.volatileSlots = slots; + } // Captured bindings come in through the environment — borrowed for the // whole call (the closure owns them): bound here, never released here. (fn.captures ?? []).forEach((c, i) => { @@ -7020,6 +7054,7 @@ export class LlEmitter { if (fn.name.startsWith("%dyn.class.protocol.fallback.")) attrs = `noinline ${attrs}`; else if (fn.name.startsWith("%dyn.class.protocol.")) attrs = `inlinehint ${attrs}`; if (fn.name.startsWith(RESULT_ENTRY_PREFIX)) attrs = `inlinehint ${attrs}`; + if (unoptimized && attrs === FN_ATTRS) attrs = `noinline optnone ${attrs}`; const debug = this.debugScope === null ? "" : ` !dbg ${this.debugScope}`; const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name); this.privateGlobalSlots.clear(); diff --git a/tests/corpus/5973-large-closure-environment.ts b/tests/corpus/5973-large-closure-environment.ts new file mode 100644 index 000000000..1ade2570c --- /dev/null +++ b/tests/corpus/5973-large-closure-environment.ts @@ -0,0 +1,1859 @@ +// One factory with 600 captured bindings (more than any ordinary function holds), +// shared by methods that read and rebind them, closures created per loop +// iteration, a nested closure, and a function declared before the bindings +// it reads. Every environment observes the same boxes: writes through one +// method are visible through the others and in later calls, and each +// factory call gets its own bindings. +function total(list: number[]): number { + let t = 0; + for (const n of list) t += n; + return t; +} +const one = Number("1"); +function make(seed: number) { + function early(): number { + return n0 + n539 + s541.length; + } + let before = "unset"; + try { + before = String(early()); + } catch (e) { + before = (e as Error).name + ": " + (e as Error).message; + } + let n0 = seed + 0; + let n1 = seed + 1; + let n2 = seed + 2; + let n3 = seed + 3; + let n4 = seed + 4; + let n5 = seed + 5; + let n6 = seed + 6; + let n7 = seed + 7; + let n8 = seed + 8; + let n9 = seed + 9; + let n10 = seed + 10; + let n11 = seed + 11; + let n12 = seed + 12; + let n13 = seed + 13; + let n14 = seed + 14; + let n15 = seed + 15; + let n16 = seed + 16; + let n17 = seed + 17; + let n18 = seed + 18; + let n19 = seed + 19; + let n20 = seed + 20; + let n21 = seed + 21; + let n22 = seed + 22; + let n23 = seed + 23; + let n24 = seed + 24; + let n25 = seed + 25; + let n26 = seed + 26; + let n27 = seed + 27; + let n28 = seed + 28; + let n29 = seed + 29; + let n30 = seed + 30; + let n31 = seed + 31; + let n32 = seed + 32; + let n33 = seed + 33; + let n34 = seed + 34; + let n35 = seed + 35; + let n36 = seed + 36; + let n37 = seed + 37; + let n38 = seed + 38; + let n39 = seed + 39; + let n40 = seed + 40; + let n41 = seed + 41; + let n42 = seed + 42; + let n43 = seed + 43; + let n44 = seed + 44; + let n45 = seed + 45; + let n46 = seed + 46; + let n47 = seed + 47; + let n48 = seed + 48; + let n49 = seed + 49; + let n50 = seed + 50; + let n51 = seed + 51; + let n52 = seed + 52; + let n53 = seed + 53; + let n54 = seed + 54; + let n55 = seed + 55; + let n56 = seed + 56; + let n57 = seed + 57; + let n58 = seed + 58; + let n59 = seed + 59; + let n60 = seed + 60; + let n61 = seed + 61; + let n62 = seed + 62; + let n63 = seed + 63; + let n64 = seed + 64; + let n65 = seed + 65; + let n66 = seed + 66; + let n67 = seed + 67; + let n68 = seed + 68; + let n69 = seed + 69; + let n70 = seed + 70; + let n71 = seed + 71; + let n72 = seed + 72; + let n73 = seed + 73; + let n74 = seed + 74; + let n75 = seed + 75; + let n76 = seed + 76; + let n77 = seed + 77; + let n78 = seed + 78; + let n79 = seed + 79; + let n80 = seed + 80; + let n81 = seed + 81; + let n82 = seed + 82; + let n83 = seed + 83; + let n84 = seed + 84; + let n85 = seed + 85; + let n86 = seed + 86; + let n87 = seed + 87; + let n88 = seed + 88; + let n89 = seed + 89; + let n90 = seed + 90; + let n91 = seed + 91; + let n92 = seed + 92; + let n93 = seed + 93; + let n94 = seed + 94; + let n95 = seed + 95; + let n96 = seed + 96; + let n97 = seed + 97; + let n98 = seed + 98; + let n99 = seed + 99; + let n100 = seed + 100; + let n101 = seed + 101; + let n102 = seed + 102; + let n103 = seed + 103; + let n104 = seed + 104; + let n105 = seed + 105; + let n106 = seed + 106; + let n107 = seed + 107; + let n108 = seed + 108; + let n109 = seed + 109; + let n110 = seed + 110; + let n111 = seed + 111; + let n112 = seed + 112; + let n113 = seed + 113; + let n114 = seed + 114; + let n115 = seed + 115; + let n116 = seed + 116; + let n117 = seed + 117; + let n118 = seed + 118; + let n119 = seed + 119; + let n120 = seed + 120; + let n121 = seed + 121; + let n122 = seed + 122; + let n123 = seed + 123; + let n124 = seed + 124; + let n125 = seed + 125; + let n126 = seed + 126; + let n127 = seed + 127; + let n128 = seed + 128; + let n129 = seed + 129; + let n130 = seed + 130; + let n131 = seed + 131; + let n132 = seed + 132; + let n133 = seed + 133; + let n134 = seed + 134; + let n135 = seed + 135; + let n136 = seed + 136; + let n137 = seed + 137; + let n138 = seed + 138; + let n139 = seed + 139; + let n140 = seed + 140; + let n141 = seed + 141; + let n142 = seed + 142; + let n143 = seed + 143; + let n144 = seed + 144; + let n145 = seed + 145; + let n146 = seed + 146; + let n147 = seed + 147; + let n148 = seed + 148; + let n149 = seed + 149; + let n150 = seed + 150; + let n151 = seed + 151; + let n152 = seed + 152; + let n153 = seed + 153; + let n154 = seed + 154; + let n155 = seed + 155; + let n156 = seed + 156; + let n157 = seed + 157; + let n158 = seed + 158; + let n159 = seed + 159; + let n160 = seed + 160; + let n161 = seed + 161; + let n162 = seed + 162; + let n163 = seed + 163; + let n164 = seed + 164; + let n165 = seed + 165; + let n166 = seed + 166; + let n167 = seed + 167; + let n168 = seed + 168; + let n169 = seed + 169; + let n170 = seed + 170; + let n171 = seed + 171; + let n172 = seed + 172; + let n173 = seed + 173; + let n174 = seed + 174; + let n175 = seed + 175; + let n176 = seed + 176; + let n177 = seed + 177; + let n178 = seed + 178; + let n179 = seed + 179; + let n180 = seed + 180; + let n181 = seed + 181; + let n182 = seed + 182; + let n183 = seed + 183; + let n184 = seed + 184; + let n185 = seed + 185; + let n186 = seed + 186; + let n187 = seed + 187; + let n188 = seed + 188; + let n189 = seed + 189; + let n190 = seed + 190; + let n191 = seed + 191; + let n192 = seed + 192; + let n193 = seed + 193; + let n194 = seed + 194; + let n195 = seed + 195; + let n196 = seed + 196; + let n197 = seed + 197; + let n198 = seed + 198; + let n199 = seed + 199; + let n200 = seed + 200; + let n201 = seed + 201; + let n202 = seed + 202; + let n203 = seed + 203; + let n204 = seed + 204; + let n205 = seed + 205; + let n206 = seed + 206; + let n207 = seed + 207; + let n208 = seed + 208; + let n209 = seed + 209; + let n210 = seed + 210; + let n211 = seed + 211; + let n212 = seed + 212; + let n213 = seed + 213; + let n214 = seed + 214; + let n215 = seed + 215; + let n216 = seed + 216; + let n217 = seed + 217; + let n218 = seed + 218; + let n219 = seed + 219; + let n220 = seed + 220; + let n221 = seed + 221; + let n222 = seed + 222; + let n223 = seed + 223; + let n224 = seed + 224; + let n225 = seed + 225; + let n226 = seed + 226; + let n227 = seed + 227; + let n228 = seed + 228; + let n229 = seed + 229; + let n230 = seed + 230; + let n231 = seed + 231; + let n232 = seed + 232; + let n233 = seed + 233; + let n234 = seed + 234; + let n235 = seed + 235; + let n236 = seed + 236; + let n237 = seed + 237; + let n238 = seed + 238; + let n239 = seed + 239; + let n240 = seed + 240; + let n241 = seed + 241; + let n242 = seed + 242; + let n243 = seed + 243; + let n244 = seed + 244; + let n245 = seed + 245; + let n246 = seed + 246; + let n247 = seed + 247; + let n248 = seed + 248; + let n249 = seed + 249; + let n250 = seed + 250; + let n251 = seed + 251; + let n252 = seed + 252; + let n253 = seed + 253; + let n254 = seed + 254; + let n255 = seed + 255; + let n256 = seed + 256; + let n257 = seed + 257; + let n258 = seed + 258; + let n259 = seed + 259; + let n260 = seed + 260; + let n261 = seed + 261; + let n262 = seed + 262; + let n263 = seed + 263; + let n264 = seed + 264; + let n265 = seed + 265; + let n266 = seed + 266; + let n267 = seed + 267; + let n268 = seed + 268; + let n269 = seed + 269; + let n270 = seed + 270; + let n271 = seed + 271; + let n272 = seed + 272; + let n273 = seed + 273; + let n274 = seed + 274; + let n275 = seed + 275; + let n276 = seed + 276; + let n277 = seed + 277; + let n278 = seed + 278; + let n279 = seed + 279; + let n280 = seed + 280; + let n281 = seed + 281; + let n282 = seed + 282; + let n283 = seed + 283; + let n284 = seed + 284; + let n285 = seed + 285; + let n286 = seed + 286; + let n287 = seed + 287; + let n288 = seed + 288; + let n289 = seed + 289; + let n290 = seed + 290; + let n291 = seed + 291; + let n292 = seed + 292; + let n293 = seed + 293; + let n294 = seed + 294; + let n295 = seed + 295; + let n296 = seed + 296; + let n297 = seed + 297; + let n298 = seed + 298; + let n299 = seed + 299; + let n300 = seed + 300; + let n301 = seed + 301; + let n302 = seed + 302; + let n303 = seed + 303; + let n304 = seed + 304; + let n305 = seed + 305; + let n306 = seed + 306; + let n307 = seed + 307; + let n308 = seed + 308; + let n309 = seed + 309; + let n310 = seed + 310; + let n311 = seed + 311; + let n312 = seed + 312; + let n313 = seed + 313; + let n314 = seed + 314; + let n315 = seed + 315; + let n316 = seed + 316; + let n317 = seed + 317; + let n318 = seed + 318; + let n319 = seed + 319; + let n320 = seed + 320; + let n321 = seed + 321; + let n322 = seed + 322; + let n323 = seed + 323; + let n324 = seed + 324; + let n325 = seed + 325; + let n326 = seed + 326; + let n327 = seed + 327; + let n328 = seed + 328; + let n329 = seed + 329; + let n330 = seed + 330; + let n331 = seed + 331; + let n332 = seed + 332; + let n333 = seed + 333; + let n334 = seed + 334; + let n335 = seed + 335; + let n336 = seed + 336; + let n337 = seed + 337; + let n338 = seed + 338; + let n339 = seed + 339; + let n340 = seed + 340; + let n341 = seed + 341; + let n342 = seed + 342; + let n343 = seed + 343; + let n344 = seed + 344; + let n345 = seed + 345; + let n346 = seed + 346; + let n347 = seed + 347; + let n348 = seed + 348; + let n349 = seed + 349; + let n350 = seed + 350; + let n351 = seed + 351; + let n352 = seed + 352; + let n353 = seed + 353; + let n354 = seed + 354; + let n355 = seed + 355; + let n356 = seed + 356; + let n357 = seed + 357; + let n358 = seed + 358; + let n359 = seed + 359; + let n360 = seed + 360; + let n361 = seed + 361; + let n362 = seed + 362; + let n363 = seed + 363; + let n364 = seed + 364; + let n365 = seed + 365; + let n366 = seed + 366; + let n367 = seed + 367; + let n368 = seed + 368; + let n369 = seed + 369; + let n370 = seed + 370; + let n371 = seed + 371; + let n372 = seed + 372; + let n373 = seed + 373; + let n374 = seed + 374; + let n375 = seed + 375; + let n376 = seed + 376; + let n377 = seed + 377; + let n378 = seed + 378; + let n379 = seed + 379; + let n380 = seed + 380; + let n381 = seed + 381; + let n382 = seed + 382; + let n383 = seed + 383; + let n384 = seed + 384; + let n385 = seed + 385; + let n386 = seed + 386; + let n387 = seed + 387; + let n388 = seed + 388; + let n389 = seed + 389; + let n390 = seed + 390; + let n391 = seed + 391; + let n392 = seed + 392; + let n393 = seed + 393; + let n394 = seed + 394; + let n395 = seed + 395; + let n396 = seed + 396; + let n397 = seed + 397; + let n398 = seed + 398; + let n399 = seed + 399; + let n400 = seed + 400; + let n401 = seed + 401; + let n402 = seed + 402; + let n403 = seed + 403; + let n404 = seed + 404; + let n405 = seed + 405; + let n406 = seed + 406; + let n407 = seed + 407; + let n408 = seed + 408; + let n409 = seed + 409; + let n410 = seed + 410; + let n411 = seed + 411; + let n412 = seed + 412; + let n413 = seed + 413; + let n414 = seed + 414; + let n415 = seed + 415; + let n416 = seed + 416; + let n417 = seed + 417; + let n418 = seed + 418; + let n419 = seed + 419; + let n420 = seed + 420; + let n421 = seed + 421; + let n422 = seed + 422; + let n423 = seed + 423; + let n424 = seed + 424; + let n425 = seed + 425; + let n426 = seed + 426; + let n427 = seed + 427; + let n428 = seed + 428; + let n429 = seed + 429; + let n430 = seed + 430; + let n431 = seed + 431; + let n432 = seed + 432; + let n433 = seed + 433; + let n434 = seed + 434; + let n435 = seed + 435; + let n436 = seed + 436; + let n437 = seed + 437; + let n438 = seed + 438; + let n439 = seed + 439; + let n440 = seed + 440; + let n441 = seed + 441; + let n442 = seed + 442; + let n443 = seed + 443; + let n444 = seed + 444; + let n445 = seed + 445; + let n446 = seed + 446; + let n447 = seed + 447; + let n448 = seed + 448; + let n449 = seed + 449; + let n450 = seed + 450; + let n451 = seed + 451; + let n452 = seed + 452; + let n453 = seed + 453; + let n454 = seed + 454; + let n455 = seed + 455; + let n456 = seed + 456; + let n457 = seed + 457; + let n458 = seed + 458; + let n459 = seed + 459; + let n460 = seed + 460; + let n461 = seed + 461; + let n462 = seed + 462; + let n463 = seed + 463; + let n464 = seed + 464; + let n465 = seed + 465; + let n466 = seed + 466; + let n467 = seed + 467; + let n468 = seed + 468; + let n469 = seed + 469; + let n470 = seed + 470; + let n471 = seed + 471; + let n472 = seed + 472; + let n473 = seed + 473; + let n474 = seed + 474; + let n475 = seed + 475; + let n476 = seed + 476; + let n477 = seed + 477; + let n478 = seed + 478; + let n479 = seed + 479; + let n480 = seed + 480; + let n481 = seed + 481; + let n482 = seed + 482; + let n483 = seed + 483; + let n484 = seed + 484; + let n485 = seed + 485; + let n486 = seed + 486; + let n487 = seed + 487; + let n488 = seed + 488; + let n489 = seed + 489; + let n490 = seed + 490; + let n491 = seed + 491; + let n492 = seed + 492; + let n493 = seed + 493; + let n494 = seed + 494; + let n495 = seed + 495; + let n496 = seed + 496; + let n497 = seed + 497; + let n498 = seed + 498; + let n499 = seed + 499; + let n500 = seed + 500; + let n501 = seed + 501; + let n502 = seed + 502; + let n503 = seed + 503; + let n504 = seed + 504; + let n505 = seed + 505; + let n506 = seed + 506; + let n507 = seed + 507; + let n508 = seed + 508; + let n509 = seed + 509; + let n510 = seed + 510; + let n511 = seed + 511; + let n512 = seed + 512; + let n513 = seed + 513; + let n514 = seed + 514; + let n515 = seed + 515; + let n516 = seed + 516; + let n517 = seed + 517; + let n518 = seed + 518; + let n519 = seed + 519; + let n520 = seed + 520; + let n521 = seed + 521; + let n522 = seed + 522; + let n523 = seed + 523; + let n524 = seed + 524; + let n525 = seed + 525; + let n526 = seed + 526; + let n527 = seed + 527; + let n528 = seed + 528; + let n529 = seed + 529; + let n530 = seed + 530; + let n531 = seed + 531; + let n532 = seed + 532; + let n533 = seed + 533; + let n534 = seed + 534; + let n535 = seed + 535; + let n536 = seed + 536; + let n537 = seed + 537; + let n538 = seed + 538; + let n539 = seed + 539; + let o540 = { x: 540 }; + let s541 = "s" + (541 + one); + let o542 = { x: 542 }; + let s543 = "s" + (543 + one); + let o544 = { x: 544 }; + let s545 = "s" + (545 + one); + let o546 = { x: 546 }; + let s547 = "s" + (547 + one); + let o548 = { x: 548 }; + let s549 = "s" + (549 + one); + let o550 = { x: 550 }; + let s551 = "s" + (551 + one); + let o552 = { x: 552 }; + let s553 = "s" + (553 + one); + let o554 = { x: 554 }; + let s555 = "s" + (555 + one); + let o556 = { x: 556 }; + let s557 = "s" + (557 + one); + let o558 = { x: 558 }; + let s559 = "s" + (559 + one); + let o560 = { x: 560 }; + let s561 = "s" + (561 + one); + let o562 = { x: 562 }; + let s563 = "s" + (563 + one); + let o564 = { x: 564 }; + let s565 = "s" + (565 + one); + let o566 = { x: 566 }; + let s567 = "s" + (567 + one); + let o568 = { x: 568 }; + let s569 = "s" + (569 + one); + let o570 = { x: 570 }; + let s571 = "s" + (571 + one); + let o572 = { x: 572 }; + let s573 = "s" + (573 + one); + let o574 = { x: 574 }; + let s575 = "s" + (575 + one); + let o576 = { x: 576 }; + let s577 = "s" + (577 + one); + let o578 = { x: 578 }; + let s579 = "s" + (579 + one); + let o580 = { x: 580 }; + let s581 = "s" + (581 + one); + let o582 = { x: 582 }; + let s583 = "s" + (583 + one); + let o584 = { x: 584 }; + let s585 = "s" + (585 + one); + let o586 = { x: 586 }; + let s587 = "s" + (587 + one); + let o588 = { x: 588 }; + let s589 = "s" + (589 + one); + let o590 = { x: 590 }; + let s591 = "s" + (591 + one); + let o592 = { x: 592 }; + let s593 = "s" + (593 + one); + let o594 = { x: 594 }; + let s595 = "s" + (595 + one); + let o596 = { x: 596 }; + let s597 = "s" + (597 + one); + let o598 = { x: 598 }; + let s599 = "s" + (599 + one); + const readers: (() => string)[] = []; + for (let i = 0; i < 3; i++) { + const label = "r" + i; + readers.push(() => label + ":" + (n539 + i) + ":" + o540.x + ":" + s541); + } + return { + before, + early, + sum(): number { + return total([ + n0, + n1, + n2, + n3, + n4, + n5, + n6, + n7, + n8, + n9, + n10, + n11, + n12, + n13, + n14, + n15, + n16, + n17, + n18, + n19, + n20, + n21, + n22, + n23, + n24, + n25, + n26, + n27, + n28, + n29, + n30, + n31, + n32, + n33, + n34, + n35, + n36, + n37, + n38, + n39, + n40, + n41, + n42, + n43, + n44, + n45, + n46, + n47, + n48, + n49, + n50, + n51, + n52, + n53, + n54, + n55, + n56, + n57, + n58, + n59, + n60, + n61, + n62, + n63, + n64, + n65, + n66, + n67, + n68, + n69, + n70, + n71, + n72, + n73, + n74, + n75, + n76, + n77, + n78, + n79, + n80, + n81, + n82, + n83, + n84, + n85, + n86, + n87, + n88, + n89, + n90, + n91, + n92, + n93, + n94, + n95, + n96, + n97, + n98, + n99, + n100, + n101, + n102, + n103, + n104, + n105, + n106, + n107, + n108, + n109, + n110, + n111, + n112, + n113, + n114, + n115, + n116, + n117, + n118, + n119, + n120, + n121, + n122, + n123, + n124, + n125, + n126, + n127, + n128, + n129, + n130, + n131, + n132, + n133, + n134, + n135, + n136, + n137, + n138, + n139, + n140, + n141, + n142, + n143, + n144, + n145, + n146, + n147, + n148, + n149, + n150, + n151, + n152, + n153, + n154, + n155, + n156, + n157, + n158, + n159, + n160, + n161, + n162, + n163, + n164, + n165, + n166, + n167, + n168, + n169, + n170, + n171, + n172, + n173, + n174, + n175, + n176, + n177, + n178, + n179, + n180, + n181, + n182, + n183, + n184, + n185, + n186, + n187, + n188, + n189, + n190, + n191, + n192, + n193, + n194, + n195, + n196, + n197, + n198, + n199, + n200, + n201, + n202, + n203, + n204, + n205, + n206, + n207, + n208, + n209, + n210, + n211, + n212, + n213, + n214, + n215, + n216, + n217, + n218, + n219, + n220, + n221, + n222, + n223, + n224, + n225, + n226, + n227, + n228, + n229, + n230, + n231, + n232, + n233, + n234, + n235, + n236, + n237, + n238, + n239, + n240, + n241, + n242, + n243, + n244, + n245, + n246, + n247, + n248, + n249, + n250, + n251, + n252, + n253, + n254, + n255, + n256, + n257, + n258, + n259, + n260, + n261, + n262, + n263, + n264, + n265, + n266, + n267, + n268, + n269, + n270, + n271, + n272, + n273, + n274, + n275, + n276, + n277, + n278, + n279, + n280, + n281, + n282, + n283, + n284, + n285, + n286, + n287, + n288, + n289, + n290, + n291, + n292, + n293, + n294, + n295, + n296, + n297, + n298, + n299, + n300, + n301, + n302, + n303, + n304, + n305, + n306, + n307, + n308, + n309, + n310, + n311, + n312, + n313, + n314, + n315, + n316, + n317, + n318, + n319, + n320, + n321, + n322, + n323, + n324, + n325, + n326, + n327, + n328, + n329, + n330, + n331, + n332, + n333, + n334, + n335, + n336, + n337, + n338, + n339, + n340, + n341, + n342, + n343, + n344, + n345, + n346, + n347, + n348, + n349, + n350, + n351, + n352, + n353, + n354, + n355, + n356, + n357, + n358, + n359, + n360, + n361, + n362, + n363, + n364, + n365, + n366, + n367, + n368, + n369, + n370, + n371, + n372, + n373, + n374, + n375, + n376, + n377, + n378, + n379, + n380, + n381, + n382, + n383, + n384, + n385, + n386, + n387, + n388, + n389, + n390, + n391, + n392, + n393, + n394, + n395, + n396, + n397, + n398, + n399, + n400, + n401, + n402, + n403, + n404, + n405, + n406, + n407, + n408, + n409, + n410, + n411, + n412, + n413, + n414, + n415, + n416, + n417, + n418, + n419, + n420, + n421, + n422, + n423, + n424, + n425, + n426, + n427, + n428, + n429, + n430, + n431, + n432, + n433, + n434, + n435, + n436, + n437, + n438, + n439, + n440, + n441, + n442, + n443, + n444, + n445, + n446, + n447, + n448, + n449, + n450, + n451, + n452, + n453, + n454, + n455, + n456, + n457, + n458, + n459, + n460, + n461, + n462, + n463, + n464, + n465, + n466, + n467, + n468, + n469, + n470, + n471, + n472, + n473, + n474, + n475, + n476, + n477, + n478, + n479, + n480, + n481, + n482, + n483, + n484, + n485, + n486, + n487, + n488, + n489, + n490, + n491, + n492, + n493, + n494, + n495, + n496, + n497, + n498, + n499, + n500, + n501, + n502, + n503, + n504, + n505, + n506, + n507, + n508, + n509, + n510, + n511, + n512, + n513, + n514, + n515, + n516, + n517, + n518, + n519, + n520, + n521, + n522, + n523, + n524, + n525, + n526, + n527, + n528, + n529, + n530, + n531, + n532, + n533, + n534, + n535, + n536, + n537, + n538, + n539, + o540.x, + s541.length, + o542.x, + s543.length, + o544.x, + s545.length, + o546.x, + s547.length, + o548.x, + s549.length, + o550.x, + s551.length, + o552.x, + s553.length, + o554.x, + s555.length, + o556.x, + s557.length, + o558.x, + s559.length, + o560.x, + s561.length, + o562.x, + s563.length, + o564.x, + s565.length, + o566.x, + s567.length, + o568.x, + s569.length, + o570.x, + s571.length, + o572.x, + s573.length, + o574.x, + s575.length, + o576.x, + s577.length, + o578.x, + s579.length, + o580.x, + s581.length, + o582.x, + s583.length, + o584.x, + s585.length, + o586.x, + s587.length, + o588.x, + s589.length, + o590.x, + s591.length, + o592.x, + s593.length, + o594.x, + s595.length, + o596.x, + s597.length, + o598.x, + s599.length, + ]); + }, + bump(): void { + n0 += 1; + n1 += 1; + n2 += 1; + n3 += 1; + n4 += 1; + n5 += 1; + n6 += 1; + n7 += 1; + n8 += 1; + n9 += 1; + n10 += 1; + n11 += 1; + n12 += 1; + n13 += 1; + n14 += 1; + n15 += 1; + n16 += 1; + n17 += 1; + n18 += 1; + n19 += 1; + n20 += 1; + n21 += 1; + n22 += 1; + n23 += 1; + n24 += 1; + n25 += 1; + n26 += 1; + n27 += 1; + n28 += 1; + n29 += 1; + n30 += 1; + n31 += 1; + n32 += 1; + n33 += 1; + n34 += 1; + n35 += 1; + n36 += 1; + n37 += 1; + n38 += 1; + n39 += 1; + n40 += 1; + n41 += 1; + n42 += 1; + n43 += 1; + n44 += 1; + n45 += 1; + n46 += 1; + n47 += 1; + n48 += 1; + n49 += 1; + n50 += 1; + n51 += 1; + n52 += 1; + n53 += 1; + n54 += 1; + n55 += 1; + n56 += 1; + n57 += 1; + n58 += 1; + n59 += 1; + n60 += 1; + n61 += 1; + n62 += 1; + n63 += 1; + n64 += 1; + n65 += 1; + n66 += 1; + n67 += 1; + n68 += 1; + n69 += 1; + n70 += 1; + n71 += 1; + n72 += 1; + n73 += 1; + n74 += 1; + n75 += 1; + n76 += 1; + n77 += 1; + n78 += 1; + n79 += 1; + n80 += 1; + n81 += 1; + n82 += 1; + n83 += 1; + n84 += 1; + n85 += 1; + n86 += 1; + n87 += 1; + n88 += 1; + n89 += 1; + n90 += 1; + n91 += 1; + n92 += 1; + n93 += 1; + n94 += 1; + n95 += 1; + n96 += 1; + n97 += 1; + n98 += 1; + n99 += 1; + n100 += 1; + n101 += 1; + n102 += 1; + n103 += 1; + n104 += 1; + n105 += 1; + n106 += 1; + n107 += 1; + n108 += 1; + n109 += 1; + n110 += 1; + n111 += 1; + n112 += 1; + n113 += 1; + n114 += 1; + n115 += 1; + n116 += 1; + n117 += 1; + n118 += 1; + n119 += 1; + n120 += 1; + n121 += 1; + n122 += 1; + n123 += 1; + n124 += 1; + n125 += 1; + n126 += 1; + n127 += 1; + n128 += 1; + n129 += 1; + n130 += 1; + n131 += 1; + n132 += 1; + n133 += 1; + n134 += 1; + n135 += 1; + n136 += 1; + n137 += 1; + n138 += 1; + n139 += 1; + n140 += 1; + n141 += 1; + n142 += 1; + n143 += 1; + n144 += 1; + n145 += 1; + n146 += 1; + n147 += 1; + n148 += 1; + n149 += 1; + n150 += 1; + n151 += 1; + n152 += 1; + n153 += 1; + n154 += 1; + n155 += 1; + n156 += 1; + n157 += 1; + n158 += 1; + n159 += 1; + n160 += 1; + n161 += 1; + n162 += 1; + n163 += 1; + n164 += 1; + n165 += 1; + n166 += 1; + n167 += 1; + n168 += 1; + n169 += 1; + n170 += 1; + n171 += 1; + n172 += 1; + n173 += 1; + n174 += 1; + n175 += 1; + n176 += 1; + n177 += 1; + n178 += 1; + n179 += 1; + n180 += 1; + n181 += 1; + n182 += 1; + n183 += 1; + n184 += 1; + n185 += 1; + n186 += 1; + n187 += 1; + n188 += 1; + n189 += 1; + n190 += 1; + n191 += 1; + n192 += 1; + n193 += 1; + n194 += 1; + n195 += 1; + n196 += 1; + n197 += 1; + n198 += 1; + n199 += 1; + n200 += 1; + n201 += 1; + n202 += 1; + n203 += 1; + n204 += 1; + n205 += 1; + n206 += 1; + n207 += 1; + n208 += 1; + n209 += 1; + n210 += 1; + n211 += 1; + n212 += 1; + n213 += 1; + n214 += 1; + n215 += 1; + n216 += 1; + n217 += 1; + n218 += 1; + n219 += 1; + n220 += 1; + n221 += 1; + n222 += 1; + n223 += 1; + n224 += 1; + n225 += 1; + n226 += 1; + n227 += 1; + n228 += 1; + n229 += 1; + n230 += 1; + n231 += 1; + n232 += 1; + n233 += 1; + n234 += 1; + n235 += 1; + n236 += 1; + n237 += 1; + n238 += 1; + n239 += 1; + n240 += 1; + n241 += 1; + n242 += 1; + n243 += 1; + n244 += 1; + n245 += 1; + n246 += 1; + n247 += 1; + n248 += 1; + n249 += 1; + n250 += 1; + n251 += 1; + n252 += 1; + n253 += 1; + n254 += 1; + n255 += 1; + n256 += 1; + n257 += 1; + n258 += 1; + n259 += 1; + n260 += 1; + n261 += 1; + n262 += 1; + n263 += 1; + n264 += 1; + n265 += 1; + n266 += 1; + n267 += 1; + n268 += 1; + n269 += 1; + n270 += 1; + n271 += 1; + n272 += 1; + n273 += 1; + n274 += 1; + n275 += 1; + n276 += 1; + n277 += 1; + n278 += 1; + n279 += 1; + n280 += 1; + n281 += 1; + n282 += 1; + n283 += 1; + n284 += 1; + n285 += 1; + n286 += 1; + n287 += 1; + n288 += 1; + n289 += 1; + n290 += 1; + n291 += 1; + n292 += 1; + n293 += 1; + n294 += 1; + n295 += 1; + n296 += 1; + n297 += 1; + n298 += 1; + n299 += 1; + n300 += 1; + n301 += 1; + n302 += 1; + n303 += 1; + n304 += 1; + n305 += 1; + n306 += 1; + n307 += 1; + n308 += 1; + n309 += 1; + n310 += 1; + n311 += 1; + n312 += 1; + n313 += 1; + n314 += 1; + n315 += 1; + n316 += 1; + n317 += 1; + n318 += 1; + n319 += 1; + n320 += 1; + n321 += 1; + n322 += 1; + n323 += 1; + n324 += 1; + n325 += 1; + n326 += 1; + n327 += 1; + n328 += 1; + n329 += 1; + n330 += 1; + n331 += 1; + n332 += 1; + n333 += 1; + n334 += 1; + n335 += 1; + n336 += 1; + n337 += 1; + n338 += 1; + n339 += 1; + n340 += 1; + n341 += 1; + n342 += 1; + n343 += 1; + n344 += 1; + n345 += 1; + n346 += 1; + n347 += 1; + n348 += 1; + n349 += 1; + n350 += 1; + n351 += 1; + n352 += 1; + n353 += 1; + n354 += 1; + n355 += 1; + n356 += 1; + n357 += 1; + n358 += 1; + n359 += 1; + n360 += 1; + n361 += 1; + n362 += 1; + n363 += 1; + n364 += 1; + n365 += 1; + n366 += 1; + n367 += 1; + n368 += 1; + n369 += 1; + n370 += 1; + n371 += 1; + n372 += 1; + n373 += 1; + n374 += 1; + n375 += 1; + n376 += 1; + n377 += 1; + n378 += 1; + n379 += 1; + n380 += 1; + n381 += 1; + n382 += 1; + n383 += 1; + n384 += 1; + n385 += 1; + n386 += 1; + n387 += 1; + n388 += 1; + n389 += 1; + n390 += 1; + n391 += 1; + n392 += 1; + n393 += 1; + n394 += 1; + n395 += 1; + n396 += 1; + n397 += 1; + n398 += 1; + n399 += 1; + n400 += 1; + n401 += 1; + n402 += 1; + n403 += 1; + n404 += 1; + n405 += 1; + n406 += 1; + n407 += 1; + n408 += 1; + n409 += 1; + n410 += 1; + n411 += 1; + n412 += 1; + n413 += 1; + n414 += 1; + n415 += 1; + n416 += 1; + n417 += 1; + n418 += 1; + n419 += 1; + n420 += 1; + n421 += 1; + n422 += 1; + n423 += 1; + n424 += 1; + n425 += 1; + n426 += 1; + n427 += 1; + n428 += 1; + n429 += 1; + n430 += 1; + n431 += 1; + n432 += 1; + n433 += 1; + n434 += 1; + n435 += 1; + n436 += 1; + n437 += 1; + n438 += 1; + n439 += 1; + n440 += 1; + n441 += 1; + n442 += 1; + n443 += 1; + n444 += 1; + n445 += 1; + n446 += 1; + n447 += 1; + n448 += 1; + n449 += 1; + n450 += 1; + n451 += 1; + n452 += 1; + n453 += 1; + n454 += 1; + n455 += 1; + n456 += 1; + n457 += 1; + n458 += 1; + n459 += 1; + n460 += 1; + n461 += 1; + n462 += 1; + n463 += 1; + n464 += 1; + n465 += 1; + n466 += 1; + n467 += 1; + n468 += 1; + n469 += 1; + n470 += 1; + n471 += 1; + n472 += 1; + n473 += 1; + n474 += 1; + n475 += 1; + n476 += 1; + n477 += 1; + n478 += 1; + n479 += 1; + n480 += 1; + n481 += 1; + n482 += 1; + n483 += 1; + n484 += 1; + n485 += 1; + n486 += 1; + n487 += 1; + n488 += 1; + n489 += 1; + n490 += 1; + n491 += 1; + n492 += 1; + n493 += 1; + n494 += 1; + n495 += 1; + n496 += 1; + n497 += 1; + n498 += 1; + n499 += 1; + n500 += 1; + n501 += 1; + n502 += 1; + n503 += 1; + n504 += 1; + n505 += 1; + n506 += 1; + n507 += 1; + n508 += 1; + n509 += 1; + n510 += 1; + n511 += 1; + n512 += 1; + n513 += 1; + n514 += 1; + n515 += 1; + n516 += 1; + n517 += 1; + n518 += 1; + n519 += 1; + n520 += 1; + n521 += 1; + n522 += 1; + n523 += 1; + n524 += 1; + n525 += 1; + n526 += 1; + n527 += 1; + n528 += 1; + n529 += 1; + n530 += 1; + n531 += 1; + n532 += 1; + n533 += 1; + n534 += 1; + n535 += 1; + n536 += 1; + n537 += 1; + n538 += 1; + n539 += 1; + o540 = { x: o540.x + 1 }; + s541 += "!"; + o542 = { x: o542.x + 1 }; + s543 += "!"; + o544 = { x: o544.x + 1 }; + s545 += "!"; + o546 = { x: o546.x + 1 }; + s547 += "!"; + o548 = { x: o548.x + 1 }; + s549 += "!"; + o550 = { x: o550.x + 1 }; + s551 += "!"; + o552 = { x: o552.x + 1 }; + s553 += "!"; + o554 = { x: o554.x + 1 }; + s555 += "!"; + o556 = { x: o556.x + 1 }; + s557 += "!"; + o558 = { x: o558.x + 1 }; + s559 += "!"; + o560 = { x: o560.x + 1 }; + s561 += "!"; + o562 = { x: o562.x + 1 }; + s563 += "!"; + o564 = { x: o564.x + 1 }; + s565 += "!"; + o566 = { x: o566.x + 1 }; + s567 += "!"; + o568 = { x: o568.x + 1 }; + s569 += "!"; + o570 = { x: o570.x + 1 }; + s571 += "!"; + o572 = { x: o572.x + 1 }; + s573 += "!"; + o574 = { x: o574.x + 1 }; + s575 += "!"; + o576 = { x: o576.x + 1 }; + s577 += "!"; + o578 = { x: o578.x + 1 }; + s579 += "!"; + o580 = { x: o580.x + 1 }; + s581 += "!"; + o582 = { x: o582.x + 1 }; + s583 += "!"; + o584 = { x: o584.x + 1 }; + s585 += "!"; + o586 = { x: o586.x + 1 }; + s587 += "!"; + o588 = { x: o588.x + 1 }; + s589 += "!"; + o590 = { x: o590.x + 1 }; + s591 += "!"; + o592 = { x: o592.x + 1 }; + s593 += "!"; + o594 = { x: o594.x + 1 }; + s595 += "!"; + o596 = { x: o596.x + 1 }; + s597 += "!"; + o598 = { x: o598.x + 1 }; + s599 += "!"; + }, + readers, + nested(): () => string { + let calls = 0; + return () => { + calls++; + n0 += 10; + return calls + "/" + n0 + "/" + s599; + }; + }, + }; +} +const a = make(0); +const b = make(100); +console.log(a.before); +console.log(a.sum(), b.sum(), a.early()); +a.bump(); +a.bump(); +console.log(a.sum(), b.sum(), a.early()); +console.log(a.readers.map((r) => r()).join(" ")); +const next = a.nested(); +console.log(next(), next(), a.sum()); +b.bump(); +console.log(b.readers.map((r) => r()).join(" "), b.early()); diff --git a/tests/harness/closure-environment-scaling.test.ts b/tests/harness/closure-environment-scaling.test.ts new file mode 100644 index 000000000..c6f3a09fe --- /dev/null +++ b/tests/harness/closure-environment-scaling.test.ts @@ -0,0 +1,128 @@ +/* Compile time stays linear in the size of a closure environment. A factory + * whose methods share thousands of captured bindings (the shape of Bun's + * large-environment AOT program) used to take minutes: capture analyses + * walked the whole body once per binding, and LLVM received every box + * pointer as a value live across the entire function. Behavior of such a + * program is pinned by corpus 5973; this test bounds how compile time grows + * between two generated sizes. */ +import { execFile } from "node:child_process"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { promisify } from "node:util"; +import { expect, test } from "vitest"; + +const execFileAsync = promisify(execFile); +const repoRoot = join(import.meta.dirname, "../.."); +const sanitize = process.env["SCRIPTC_SAN"] === "1"; + +/** `n` number bindings plus n/20 objects and strings, all captured by a + * reader and a writer method, and the output the program prints. */ +function program(n: number): { source: string; expected: string } { + const lines = [ + `function total(list: number[]): number {`, + ` let t = 0;`, + ` for (const v of list) t += v;`, + ` return t;`, + `}`, + `const one = Number("1");`, + `function make() {`, + ]; + const reads: string[] = []; + const writes: string[] = []; + let sum = 0; + let bumped = 0; + for (let i = 0; i < n; i++) { + lines.push(` let n${i} = ${i} + 0.5;`); + reads.push(`n${i}`); + writes.push(`n${i} += 1;`); + sum += i + 0.5; + bumped += i + 1.5; + } + for (let i = n; i < n + n / 10; i++) { + if (i % 2 === 0) { + lines.push(` let o${i} = { x: ${i} };`); + reads.push(`o${i}.x`); + writes.push(`o${i} = { x: o${i}.x + 1 };`); + sum += i; + bumped += i + 1; + } else { + lines.push(` let s${i} = "s" + (${i} + one);`); + reads.push(`s${i}.length`); + writes.push(`s${i} += "!";`); + const length = `s${i + 1}`.length; + sum += length; + bumped += length + 1; + } + } + lines.push( + ` return {`, + ` sum(): number {`, + ` return total([${reads.join(", ")}]);`, + ` },`, + ` bump(): void {`, + ...writes.map((write) => ` ${write}`), + ` },`, + ` };`, + `}`, + `const a = make();`, + `const b = make();`, + `a.bump();`, + `console.log(a.sum(), b.sum());`, + ); + return { source: lines.join("\n") + "\n", expected: `${bumped} ${sum}\n` }; +} + +/** Milliseconds from the end of the frontend load to the finished + * executable (SCRIPTC_TIMING phases): lowering, IR passes, LLVM emission, + * native code generation and the link, without process and tsgo startup. */ +async function compileTime(dir: string, n: number): Promise { + const { source, expected } = program(n); + const entry = join(dir, `env${n}.ts`); + const binary = join(dir, `env${n}`); + writeFileSync(entry, source); + const { stderr } = await execFileAsync( + process.execPath, + [ + join(repoRoot, "packages/cli/dist/main.js"), + "build", + entry, + "-o", + binary, + ...(sanitize ? ["--sanitize"] : []), + ], + { + env: { ...process.env, SCRIPTC_TIMING: "1", SCRIPTC_NO_CACHE: "1" }, + maxBuffer: 16 * 1024 * 1024, + }, + ); + const phases = new Map(); + for (const line of stderr.split("\n")) { + if (!line.startsWith("scriptc timing ")) continue; + const { phase, total_ms } = JSON.parse(line.slice("scriptc timing ".length)) as { + phase: string; + total_ms: number; + }; + phases.set(phase, total_ms); + } + const loaded = phases.get("frontend-load"); + const complete = phases.get("complete"); + if (loaded === undefined || complete === undefined) throw new Error(stderr); + const run = await execFileAsync(binary, [], { encoding: "utf8" }); + expect(run.stdout).toBe(expected); + return complete - loaded; +} + +test("compile time grows linearly with a shared closure environment", async () => { + const dir = mkdtempSync(join(tmpdir(), "scriptc-closure-scaling-")); + try { + const small = await compileTime(dir, 500); + const large = await compileTime(dir, 4000); + // Eight times the bindings. Linear growth stays at or below 8x (fixed + // costs keep it near 5x); the quadratic analyses and code generation + // measured 24x at these sizes, and every doubling beyond adds 4x. + expect(large / small, `${small.toFixed(0)} ms -> ${large.toFixed(0)} ms`).toBeLessThan(16); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}, 300_000); From cf872eaba51a4fb060bdc4bf2f474a4431b5e5df Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 19:43:56 -0700 Subject: [PATCH 025/117] Convert only int32 loop counters from their low half A uint32 counter converted through `uitofp i32` folds an inlined callee's index conversion, but the zero extension it adds on x86-64 slowed loops that only convert the counter for a cold fallback. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/backend/llvm/expr-primitives.ts | 10 +++++----- packages/compiler/src/backend/llvm/integer-values.ts | 7 +------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index 664689e91..e237f8f13 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -67,18 +67,18 @@ export function emitLiteralExpr( const uint32 = integerSlot.type === "i32" ? integer : B.tmp(); if (integerSlot.type !== "i32") B.line(`${uint32} = trunc ${integerSlot.type} ${integer} to i32`); - // A counter whose range fits 32 bits converts from its low half, so - // LLVM folds a later `fptosi` of the double (an inlined callee's + // An int32 counter (a dense array loop's) converts from its low half, + // so LLVM folds a later `fptosi` of the double (an inlined callee's // index) back to the integer. Otherwise a 64-bit induction value is // a safe integer, so its sign bit is clear and the signed conversion // is exact: one cvtsi2sd instead of x86-64's multi-instruction - // unsigned 64-bit conversion. + // unsigned 64-bit conversion. (A uint32 counter would fold through + // `uitofp i32` too, but the zero extension it adds on x86-64 cost + // more in loops that never convert the double than it saved.) const range = integerSlot.range; const signedConversion = integerSlot.signed === true || integerSlot.type === "i64"; if (range && range.min >= -2147483648 && range.max <= 2147483647) B.line(`${number} = sitofp i32 ${uint32} to double`); - else if (range && range.min >= 0 && range.max <= 4294967295) - B.line(`${number} = uitofp i32 ${uint32} to double`); else B.line( `${number} = ${signedConversion ? "sitofp" : "uitofp"} ${integerSlot.type} ${integer} to double`, diff --git a/packages/compiler/src/backend/llvm/integer-values.ts b/packages/compiler/src/backend/llvm/integer-values.ts index 53e07462e..63e279d04 100644 --- a/packages/compiler/src/backend/llvm/integer-values.ts +++ b/packages/compiler/src/backend/llvm/integer-values.ts @@ -93,16 +93,11 @@ export function integerNumber( // `x | 0`), while a 64-bit source is not known to convert exactly. So a // counter written `i = (i + 1) | 0` stays an integer instead of taking a // double round trip on every iteration. - // A uint32 (an array index counter) converts from its low half unsigned, - // which LLVM likewise folds back through a later `fptosi` to i64. const int32 = range.min >= -2147483648 && range.max <= 2147483647; - const unsigned = !int32 && range.min >= 0 && range.max <= 4294967295; host.B.line( int32 ? `${number} = sitofp i32 ${uint32} to double` - : unsigned - ? `${number} = uitofp i32 ${uint32} to double` - : `${number} = sitofp i64 ${name} to double`, + : `${number} = sitofp i64 ${name} to double`, ); return { name: number, type, uint32, integer: { name, type: "i64", signed: true, range } }; } From 1e5079a23ab3354f3d67cc76624774050104de30 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 19:44:08 -0700 Subject: [PATCH 026/117] Format the array length loop changes and record their order baselines Co-Authored-By: Claude Opus 5.5 --- .../backend/llvm/dense-array-loops.test.ts | 28 +++++++++++++---- .../src/backend/llvm/dense-array-loops.ts | 5 +--- .../src/ir/array-length-stability.test.ts | 30 +++++++++++++------ .../compiler/src/ir/integer-ranges.test.ts | 25 ++++++++++++++-- .../5993-array-length-loop-resizing.ts.json | 6 ++++ .../5994-array-length-sparse-loops.ts.json | 6 ++++ .../5995-array-dense-loop-boundaries.ts.json | 6 ++++ 7 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5993-array-length-loop-resizing.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5994-array-length-sparse-loops.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5995-array-dense-loop-boundaries.ts.json diff --git a/packages/compiler/src/backend/llvm/dense-array-loops.test.ts b/packages/compiler/src/backend/llvm/dense-array-loops.test.ts index d9e18d7ef..405ad67e7 100644 --- a/packages/compiler/src/backend/llvm/dense-array-loops.test.ts +++ b/packages/compiler/src/backend/llvm/dense-array-loops.test.ts @@ -1,6 +1,10 @@ import { expect, test } from "vitest"; import { BOOL, F64, arrayOf, type IrExpr, type IrLocal, type IrStmt } from "../../ir/ir.js"; -import { countedDenseShape, matchDenseArrayLoop, type DenseLoopShape } from "./dense-array-loops.js"; +import { + countedDenseShape, + matchDenseArrayLoop, + type DenseLoopShape, +} from "./dense-array-loops.js"; const loc = { file: "dense-array-loops.ts", start: 0, end: 0 }; const ARR = arrayOf(F64); @@ -16,9 +20,15 @@ const method = ( receiver: string, name: Extract["method"], args: IrExpr[] = [], -): IrExpr => ({ kind: "arrIntrinsic", method: name, receiver: arr(receiver), args, type: F64, loc }); -const read = (receiver: string, index = ref("i")): IrExpr => - method(receiver, "getNumber", [index]); +): IrExpr => ({ + kind: "arrIntrinsic", + method: name, + receiver: arr(receiver), + args, + type: F64, + loc, +}); +const read = (receiver: string, index = ref("i")): IrExpr => method(receiver, "getNumber", [index]); const write = (receiver: string, value: IrExpr, index = ref("i")): IrStmt => ({ kind: "arraySet", arr: arr(receiver), @@ -49,7 +59,11 @@ function loop(body: IrStmt[]): IrStmt & { kind: "for" } { body, }; } -const shape: DenseLoopShape = { counter: "i", length: arr("a"), range: { min: 0, max: 4294967294 } }; +const shape: DenseLoopShape = { + counter: "i", + length: arr("a"), + range: { min: 0, max: 4294967294 }, +}; const match = (body: IrStmt[], initialized = new Set(["a", "b"])) => matchDenseArrayLoop(loop(body), shape, locals, new Set(), initialized); @@ -73,7 +87,9 @@ test("loops that may resize, rebind or move storage keep the ordinary copy only" expect(match([{ kind: "exprStmt", expr: method("a", "push", [num(1)]), loc }])).toBeNull(); expect(match([write("a", num(0), ref("unknown"))])).toBeNull(); expect( - match([{ kind: "exprStmt", expr: { kind: "call", callee: "f", args: [], type: F64, loc }, loc }]), + match([ + { kind: "exprStmt", expr: { kind: "call", callee: "f", args: [], type: F64, loc }, loc }, + ]), ).toBeNull(); // A nested loop would be duplicated too. expect(match([{ kind: "exprStmt", expr: read("a"), loc }, loop([])])).toBeNull(); diff --git a/packages/compiler/src/backend/llvm/dense-array-loops.ts b/packages/compiler/src/backend/llvm/dense-array-loops.ts index 5009e6c82..271a5ddf8 100644 --- a/packages/compiler/src/backend/llvm/dense-array-loops.ts +++ b/packages/compiler/src/backend/llvm/dense-array-loops.ts @@ -137,10 +137,7 @@ export function matchDenseArrayLoop( if (s.kind === "assign" || s.kind === "varDecl") disturbed.add(s.localId); if (s.kind === "arraySet") { access(s.arr, s.index); - if ( - s.arr.kind === "varRef" && - (s.index.kind !== "varRef" || s.index.localId !== counter) - ) + if (s.arr.kind === "varRef" && (s.index.kind !== "varRef" || s.index.localId !== counter)) disturbed.add(s.arr.localId); } return everyStmtChild(s, expr, stmt); diff --git a/packages/compiler/src/ir/array-length-stability.test.ts b/packages/compiler/src/ir/array-length-stability.test.ts index 87e510a3f..44e461ca2 100644 --- a/packages/compiler/src/ir/array-length-stability.test.ts +++ b/packages/compiler/src/ir/array-length-stability.test.ts @@ -1,6 +1,14 @@ import { expect, test } from "vitest"; import { findUnaliasedLocalArrays, preservesArrayLength } from "./array-length-stability.js"; -import { BOOL, F64, arrayOf, type IrExpr, type IrFunction, type IrLocal, type IrStmt } from "./ir.js"; +import { + BOOL, + F64, + arrayOf, + type IrExpr, + type IrFunction, + type IrLocal, + type IrStmt, +} from "./ir.js"; const loc = { file: "array-length-stability.ts", start: 0, end: 0 }; const ARR = arrayOf(F64); @@ -11,7 +19,14 @@ const method = ( receiver: string, name: Extract["method"], args: IrExpr[] = [], -): IrExpr => ({ kind: "arrIntrinsic", method: name, receiver: arr(receiver), args, type: F64, loc }); +): IrExpr => ({ + kind: "arrIntrinsic", + method: name, + receiver: arr(receiver), + args, + type: F64, + loc, +}); const length = (receiver: string): IrExpr => method(receiver, "length"); const read = (receiver: string, index: IrExpr): IrExpr => method(receiver, "getNumber", [index]); const plus = (left: IrExpr, right: IrExpr): IrExpr => ({ @@ -74,9 +89,9 @@ test("resizing methods, length stores, calls and escapes refuse the proof", () = expect(preserves([{ kind: "arraySetLength", arr: arr("a"), length: num(0), loc }])).toBe(false); expect(preserves([{ kind: "arrayDelete", arr: arr("a"), index: ref("i"), loc }])).toBe(false); expect(preserves([stmt({ kind: "call", callee: "f", args: [], type: F64, loc })])).toBe(false); - expect( - preserves([stmt({ kind: "call", callee: "f", args: [arr("a")], type: F64, loc })]), - ).toBe(false); + expect(preserves([stmt({ kind: "call", callee: "f", args: [arr("a")], type: F64, loc })])).toBe( + false, + ); expect(preserves([{ kind: "varDecl", localId: "b", init: arr("a"), loc }])).toBe(false); expect(preserves([{ kind: "assign", localId: "a", value: arr("b"), loc }])).toBe(false); }); @@ -119,10 +134,7 @@ test("fresh local arrays read only as receivers have no alias", () => { expect(findUnaliasedLocalArrays(fn(body, ["out"])).size).toBe(0); const copied = [...body, { kind: "varDecl", localId: "b", init: arr("out"), loc } as IrStmt]; expect(findUnaliasedLocalArrays(fn(copied)).has("out")).toBe(false); - const passed = [ - ...body, - stmt({ kind: "call", callee: "g", args: [arr("out")], type: F64, loc }), - ]; + const passed = [...body, stmt({ kind: "call", callee: "g", args: [arr("out")], type: F64, loc })]; expect(findUnaliasedLocalArrays(fn(passed)).has("out")).toBe(false); const rebound = [...body, { kind: "assign", localId: "out", value: arr("a"), loc } as IrStmt]; expect(findUnaliasedLocalArrays(fn(rebound)).has("out")).toBe(false); diff --git a/packages/compiler/src/ir/integer-ranges.test.ts b/packages/compiler/src/ir/integer-ranges.test.ts index 0d0762d16..8e1c97f66 100644 --- a/packages/compiler/src/ir/integer-ranges.test.ts +++ b/packages/compiler/src/ir/integer-ranges.test.ts @@ -800,11 +800,25 @@ test("an array length bounds while and for counters even when the body resizes t // let i = 0; while (i < items.length) { observe(i); items.push(i); i++; } observe(i); const ARR = { kind: "array", elem: F64 } as const; const items: IrExpr = { loc, kind: "varRef", localId: "items", type: ARR }; - const length: IrExpr = { loc, kind: "arrIntrinsic", method: "length", receiver: items, args: [], type: F64 }; + const length: IrExpr = { + loc, + kind: "arrIntrinsic", + method: "length", + receiver: items, + args: [], + type: F64, + }; const push: IrStmt = { loc, kind: "exprStmt", - expr: { loc, kind: "arrIntrinsic", method: "push", receiver: items, args: [ref("i")], type: F64 }, + expr: { + loc, + kind: "arrIntrinsic", + method: "push", + receiver: items, + args: [ref("i")], + type: F64, + }, }; const bump: IrStmt = { loc, @@ -815,7 +829,12 @@ test("an array length bounds while and for counters even when the body resizes t after = ref("i"); const f = fn([ { loc, kind: "assign", localId: "i", value: num(0) }, - { loc, kind: "while", cond: condition("<", ref("i"), length), body: [observe(inside), push, bump] }, + { + loc, + kind: "while", + cond: condition("<", ref("i"), length), + body: [observe(inside), push, bump], + }, observe(after), ]); f.locals.push( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5993-array-length-loop-resizing.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5993-array-length-loop-resizing.ts.json new file mode 100644 index 000000000..e4cf027ce --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5993-array-length-loop-resizing.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5993-array-length-loop-resizing.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5994-array-length-sparse-loops.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5994-array-length-sparse-loops.ts.json new file mode 100644 index 000000000..6289e8a21 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5994-array-length-sparse-loops.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5994-array-length-sparse-loops.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5995-array-dense-loop-boundaries.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5995-array-dense-loop-boundaries.ts.json new file mode 100644 index 000000000..d0afcf505 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5995-array-dense-loop-boundaries.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5995-array-dense-loop-boundaries.ts" + ], + "diags": [] +} From 84b74c02690cba2ad61fcf6d48a86bb450a37e31 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 21:50:39 -0500 Subject: [PATCH 027/117] Keep declared methods of function-local classes after a computed-key write observedPrototypeMethod skipped classPrototypeData for function-local classes, which also marks such a class as needing prototype data, so its instances got no prototype behind their property bag. A function-local class value's prototype holds only methods the program replaced there, so reads of a marked method name on its instances now check for the property, own or inherited, and otherwise use the declared method, as for generic class instances. The prototype data is built again, so a method replaced on the class's prototype stays visible. --- .../src/frontend/lowering/class-callbacks.ts | 2 +- .../lowering/class-dynamic-dispatch.ts | 1 + .../src/frontend/lowering/class-prototypes.ts | 15 +++-- .../5942-local-class-observed-methods.ts.json | 6 ++ .../5942-local-class-observed-methods.ts | 63 +++++++++++++++++++ tests/harness/corpus-costs.json | 2 + 6 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json create mode 100644 tests/corpus/5942-local-class-observed-methods.ts diff --git a/packages/compiler/src/frontend/lowering/class-callbacks.ts b/packages/compiler/src/frontend/lowering/class-callbacks.ts index 15e24f4a0..e96b7d6d9 100644 --- a/packages/compiler/src/frontend/lowering/class-callbacks.ts +++ b/packages/compiler/src/frontend/lowering/class-callbacks.ts @@ -49,7 +49,7 @@ function observedSlot(lowerer: Lowerer, receiver: IrExpr, name: string, loc: Src const info = receiver.type.kind === "object" ? lowerer.classes.get(receiver.type.className) : undefined; return info - ? observedPrototypeMethod(lowerer, info, name, loc) + ? observedPrototypeMethod(lowerer, info, name, loc, receiver) : lowerer.prototypeMethodAccesses.has(name); } diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index e6038a9c6..0f56f37d7 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -2423,6 +2423,7 @@ export class ClassDynamicDispatch { info, dispatch.source.method, loc, + receiver, ); const bag = this.readPropertyBagOrEmpty(lowerer, value, loc); dispatch.callback.body.unshift({ diff --git a/packages/compiler/src/frontend/lowering/class-prototypes.ts b/packages/compiler/src/frontend/lowering/class-prototypes.ts index f5280aaea..1db709e91 100644 --- a/packages/compiler/src/frontend/lowering/class-prototypes.ts +++ b/packages/compiler/src/frontend/lowering/class-prototypes.ts @@ -232,8 +232,8 @@ export function classPrototypeData( /** Whether reads of method `name` on instances of `info` use the observed * prototype slot: the census marked the name and the class has prototype * data that holds the method. Classes without prototype data (generic - * instantiations, mixins and their subclasses) check for an own property - * and otherwise use the declared method. */ + * instantiations, mixins and their subclasses) and function-local classes + * check for the property and otherwise use the declared method. */ export function observedPrototypeMethod( lowerer: Lowerer, info: ClassInfo, @@ -241,10 +241,13 @@ export function observedPrototypeMethod( loc: SrcLoc, receiver?: IrExpr, ): boolean { - return ( - lowerer.prototypeMethodAccesses.has(name) && - (info.localClass !== undefined || classPrototypeData(lowerer, info, loc, receiver) !== null) - ); + if (!lowerer.prototypeMethodAccesses.has(name)) return false; + // Building the data also marks a function-local class whose instances + // need it. That class value's prototype holds only methods the program + // replaced there, so its reads check for the key (own or inherited) and + // otherwise use the declared method. + const data = classPrototypeData(lowerer, info, loc, receiver); + return data !== null && info.localClass === undefined; } export function hasClassPrototypeData(info: ClassInfo): boolean { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json new file mode 100644 index 000000000..89502dd27 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5942-local-class-observed-methods.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5942-local-class-observed-methods.ts b/tests/corpus/5942-local-class-observed-methods.ts new file mode 100644 index 000000000..7445b322a --- /dev/null +++ b/tests/corpus/5942-local-class-observed-methods.ts @@ -0,0 +1,63 @@ +// After a write with a computed string key, calls of every method name +// check the receiver for the property. Instances of function-local +// classes keep their declared methods, see own-property replacements, and +// see methods the program replaces on the class's prototype. +function write(target: object, key: string, value: unknown): void { + (target as any)[key] = value; +} + +function makeCounter(start: number) { + class Counter { + n: number; + constructor() { + this.n = start; + } + bump(): number { + return ++this.n; + } + label(): string { + return `counter ${this.n}`; + } + } + return new Counter(); +} + +function run(start: number): string { + class Step { + value = start; + next(): number { + this.value *= 2; + return this.value; + } + twice(): number { + this.next(); + return this.next(); + } + } + const step = new Step(); + return `${typeof step.next} ${step.twice()} ${step.next()}`; +} + +function makePatched(start: number) { + class Patched { + n = start; + bump(): number { + return ++this.n; + } + } + Patched.prototype.bump = function (this: Patched) { + this.n += 10; + return this.n; + }; + return new Patched(); +} + +const counter = makeCounter(5); +write({}, "other", 1); +console.log(typeof counter.bump, counter.bump(), counter.label()); +const bump = counter.bump; +console.log(bump.call(counter)); +write(counter, "label", () => "replaced"); +console.log(counter.label(), makeCounter(1).label()); +console.log(run(1), run(10)); +console.log(makePatched(1).bump()); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index f87883acd..9f26f6c74 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,7 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5942-local-class-observed-methods.ts": 5063, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4465,6 +4466,7 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5942-local-class-observed-methods.ts": 6212, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 3d2c834125fadb8e5a9e0a3e1614662a6a773d5a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 21:55:00 -0500 Subject: [PATCH 028/117] Add corpus costs for the mock programs The corpus programs 5810 to 5814 had no measured cost, which put the measured share of the corpus below shard.test.ts's 0.9 floor. Their plain and SCRIPTC_SAN=1 costs are cold local timings scaled to the CI runner by programs with recorded costs: 1440, 1441, 1442 and 1463, and 5133 for 5814's sanitized run, which links the AbortSignal runtime. --- tests/harness/corpus-costs.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index f87883acd..dda7a63c0 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,11 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5810-mock-method-records.ts": 3976, + "5811-mock-tracker-restore.ts": 3698, + "5812-dyn-box-async-fields.ts": 3522, + "5813-mock-timers-module.ts": 3766, + "5814-mock-timers-date.ts": 3760, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4465,6 +4470,11 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5810-mock-method-records.ts": 6363, + "5811-mock-tracker-restore.ts": 4503, + "5812-dyn-box-async-fields.ts": 5278, + "5813-mock-timers-module.ts": 4227, + "5814-mock-timers-date.ts": 17708, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 43fb6124388ba2c6d386ec14b6b662ae8acdd210 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 19:58:21 -0700 Subject: [PATCH 029/117] Compile CommonJS requires placed after code that can reach them, and JSON requires A top-level require binding that earlier code could reach was refused (SC1013). The reachability scan now follows Node's evaluation order: hoisted functions and classes run only when reachable code names them, a class statement runs only its heritage, computed keys, decorators and static initializers, timer and promise callbacks run after the module body, and publishing a value through module.exports, exports.n, Object.defineProperty(exports, ...) or F.prototype.m runs nothing until reachable code reads it back. This admits the export-first layouts of semver, glob@7, fs.realpath, on-finished, readable-stream and tsc-emitted CommonJS. A const or let binding that code can still reach before its require now compiles with an initialization flag set right after the require and a module.tdzCheck before the outermost expression of every reference that can run earlier, so an early read throws Node's ReferenceError before any argument evaluates. A reference whose lowering leaves no expression to check, a var binding (Node reads undefined there) and createRequire bindings keep SC1013. require() of a JSON document now answers one parsed object per document, created in the requiring module's %init prelude unless another module already created it, so repeated requires return the same object and mutations are visible to every requirer. Require bindings of JSON documents are ordinary storage, so destructuring (nested patterns, defaults, missing keys) copies at the require as in Node. Nested destructuring of a builtin require binds the members of the sub-module the key names (const { types: { isPromise } } = require('util')). Co-Authored-By: Claude Opus 5.5 --- .../lowering/builtins/module-bindings.ts | 43 +- .../src/frontend/lowering/json-require.ts | 140 ++++ .../src/frontend/lowering/lower-calls.ts | 5 + .../src/frontend/lowering/lower-modules.ts | 10 +- .../src/frontend/lowering/lower-stmts.ts | 155 +++-- .../compiler/src/frontend/lowering/lowerer.ts | 16 + .../lowering/require-initialization.ts | 262 ++++++++ .../compiler/src/frontend/program-analysis.ts | 14 +- packages/compiler/src/frontend/program.ts | 604 ++++++++++++++++-- .../corpus/6140-cjs-require-tdz-throws/lib.js | 8 + .../6140-cjs-require-tdz-throws/main.js | 15 + .../6140-cjs-require-tdz-throws/package.json | 1 + .../6141-cjs-require-tdz-checked/counter.js | 14 + .../6141-cjs-require-tdz-checked/lib.js | 8 + .../6141-cjs-require-tdz-checked/main.js | 49 ++ .../6141-cjs-require-tdz-checked/package.json | 1 + .../comparator.js | 37 ++ .../6142-cjs-require-published-early/debug.js | 10 + .../6142-cjs-require-published-early/glob.js | 20 + .../helpers.js | 10 + .../6142-cjs-require-published-early/main.js | 13 + .../package.json | 1 + .../parse-options.js | 8 + tests/corpus/6143-cjs-require-json/counter.js | 14 + tests/corpus/6143-cjs-require-json/data.json | 7 + tests/corpus/6143-cjs-require-json/list.json | 1 + tests/corpus/6143-cjs-require-json/main.js | 27 + .../corpus/6143-cjs-require-json/package.json | 1 + .../6144-cjs-require-builtin-nested/main.js | 15 + .../package.json | 1 + .../cjs-require-tdz-unchecked/lib.js | 8 + .../cjs-require-tdz-unchecked/main.js | 8 + .../cjs-require-tdz-unchecked/package.json | 3 + tests/diagnostics/cjs-require-tdz/main.js | 13 +- .../cjs-require-tdz-unchecked/main.js.txt | 6 + .../__snapshots__/cjs-require-tdz/main.js.txt | 10 +- 36 files changed, 1417 insertions(+), 141 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/json-require.ts create mode 100644 packages/compiler/src/frontend/lowering/require-initialization.ts create mode 100644 tests/corpus/6140-cjs-require-tdz-throws/lib.js create mode 100644 tests/corpus/6140-cjs-require-tdz-throws/main.js create mode 100644 tests/corpus/6140-cjs-require-tdz-throws/package.json create mode 100644 tests/corpus/6141-cjs-require-tdz-checked/counter.js create mode 100644 tests/corpus/6141-cjs-require-tdz-checked/lib.js create mode 100644 tests/corpus/6141-cjs-require-tdz-checked/main.js create mode 100644 tests/corpus/6141-cjs-require-tdz-checked/package.json create mode 100644 tests/corpus/6142-cjs-require-published-early/comparator.js create mode 100644 tests/corpus/6142-cjs-require-published-early/debug.js create mode 100644 tests/corpus/6142-cjs-require-published-early/glob.js create mode 100644 tests/corpus/6142-cjs-require-published-early/helpers.js create mode 100644 tests/corpus/6142-cjs-require-published-early/main.js create mode 100644 tests/corpus/6142-cjs-require-published-early/package.json create mode 100644 tests/corpus/6142-cjs-require-published-early/parse-options.js create mode 100644 tests/corpus/6143-cjs-require-json/counter.js create mode 100644 tests/corpus/6143-cjs-require-json/data.json create mode 100644 tests/corpus/6143-cjs-require-json/list.json create mode 100644 tests/corpus/6143-cjs-require-json/main.js create mode 100644 tests/corpus/6143-cjs-require-json/package.json create mode 100644 tests/corpus/6144-cjs-require-builtin-nested/main.js create mode 100644 tests/corpus/6144-cjs-require-builtin-nested/package.json create mode 100644 tests/diagnostics/cjs-require-tdz-unchecked/lib.js create mode 100644 tests/diagnostics/cjs-require-tdz-unchecked/main.js create mode 100644 tests/diagnostics/cjs-require-tdz-unchecked/package.json create mode 100644 tests/harness/__snapshots__/cjs-require-tdz-unchecked/main.js.txt diff --git a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts index 3fa6eb0c9..0ccd304b5 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts @@ -34,21 +34,48 @@ export function builtinImportOf( // binding (`const { readFileSync } = require("fs")`, renames via // `{ readFileSync: rf }`) keys the same tables. if (ts.isBindingElement(decl) && decl.name !== undefined && ts.isIdentifier(decl.name)) { - const varDecl = decl.parent?.parent; + // A NESTED pattern names a member of a sub-module (`const { types: { + // isPromise } } = require("util")`): util.types IS the util/types + // module object, so each level composes the module name. + const path: string[] = []; + let pattern: ts.Node | undefined = decl.parent; + let varDecl = pattern?.parent; + while ( + pattern !== undefined && + ts.isObjectBindingPattern(pattern) && + varDecl !== undefined && + ts.isBindingElement(varDecl) + ) { + const key = varDecl.propertyName; + if (varDecl.initializer !== undefined || key === undefined || !ts.isIdentifier(key)) { + return null; + } + path.unshift(key.text); + pattern = varDecl.parent; + varDecl = pattern?.parent; + } if ( - ts.isObjectBindingPattern(decl.parent) && + pattern !== undefined && + ts.isObjectBindingPattern(pattern) && + varDecl !== undefined && ts.isVariableDeclaration(varDecl) && varDecl.initializer !== undefined ) { const spec = requireSpecOf(varDecl.initializer); - const module = + let module = spec !== null ? canonicalBuiltinModule(spec) - : // The one-hop alias twin: `const crypto = require('crypto'); - // const { createSign } = crypto;` — test/common's idiom. The - // destructure re-binds module members under local names, so the - // bindings key the same tables as the direct-require form. - builtinNamespaceDestructureModuleOf(lowerer, varDecl); + : path.length > 0 + ? null + : // The one-hop alias twin: `const crypto = require('crypto'); + // const { createSign } = crypto;` — test/common's idiom. The + // destructure re-binds module members under local names, so the + // bindings key the same tables as the direct-require form. + builtinNamespaceDestructureModuleOf(lowerer, varDecl); + for (const key of path) { + if (module === null) break; + module = canonicalBuiltinModule(`${module}/${key}`); + } if (module === null) return null; const member = decl.propertyName && ts.isIdentifier(decl.propertyName) diff --git a/packages/compiler/src/frontend/lowering/json-require.ts b/packages/compiler/src/frontend/lowering/json-require.ts new file mode 100644 index 000000000..7c688dcda --- /dev/null +++ b/packages/compiler/src/frontend/lowering/json-require.ts @@ -0,0 +1,140 @@ +/* CommonJS require() of JSON modules. Node parses the document at the + * first require and caches the resulting object: every later require, from + * any module, answers that same object, so a mutation through one requirer + * is visible to all of them. The document is data known at build time, so + * the object bakes from the parsed text (comptimeValueToIr, as JSON import + * declarations do) into one global per document. The parse has no + * observable effect, so each requiring module creates the object in its + * %init prelude unless an earlier module already did, and every require + * call of the document reads the shared global. A require binding of a + * JSON module is ordinary storage holding that object — destructuring + * copies its properties at the require, exactly like Node. ES-module JSON + * imports keep their own record (Node's ESM loader caches separately). */ +import * as ts from "../ts7/adapter.js"; +import type { Lowerer } from "./lowerer.js"; +import { PoisonError } from "./lowerer.js"; +import type { FileParts } from "./lower-modules.js"; +import { isCjsJsFile, locOf, requireSpecOf, resolveImport } from "../program.js"; +import { createRequireCalleeFileOf } from "./builtins/module-bindings.js"; +import { invalidJsonModuleDiag } from "../../diagnostics/diagnostic.js"; +import { BOOL, type IrExpr, type IrGlobal, type IrType } from "../../ir/ir.js"; + +/** One required JSON document: its shared global, the run-once flag, and + * the parsed value with the type it bakes to. */ +export interface JsonRequireModule { + global: IrGlobal; + loadedId: string; + parsed: unknown; + type: IrType; +} + +/** The JSON document a CommonJS `require("…")` call loads, or null. */ +export function jsonRequireTarget( + lowerer: Lowerer, + call: ts.Expression | undefined, +): ts.SourceFile | null { + if (call === undefined || !ts.isCallExpression(call)) return null; + const spec = requireSpecOf(call); + if (spec === null || !ts.isIdentifier(call.expression)) return null; + const sf = call.getSourceFile(); + if (!isCjsJsFile(sf, lowerer.program)) return null; + if (createRequireCalleeFileOf(lowerer, call.expression) !== null) return null; + const target = resolveImport(lowerer.program, sf, spec, "require"); + return target !== null && target.fileName.endsWith(".json") ? target : null; +} + +/** A declaration whose initializer is a require() of a JSON document. */ +export function isJsonRequireDecl(lowerer: Lowerer, decl: ts.VariableDeclaration): boolean { + return jsonRequireTarget(lowerer, decl.initializer) !== null; +} + +/** Registers the shared global of every JSON document a CommonJS module of + * the program requires, and the guarded creation in each requiring + * module's %init prelude. */ +export function collectJsonRequires(lowerer: Lowerer, parts: FileParts[]): void { + for (const fp of parts) { + const sf = fp.sf; + if (sf.isDeclarationFile || !isCjsJsFile(sf, lowerer.program)) continue; + if (!sf.text.includes(".json")) continue; + const calls: ts.CallExpression[] = []; + ts.walkPreorder(sf, (node) => { + if (ts.isCallExpression(node) && requireSpecOf(node) !== null) calls.push(node); + return undefined; + }); + const created = new Set(); + for (const call of calls) { + const jsonSf = jsonRequireTarget(lowerer, call); + if (jsonSf === null) continue; + try { + let mod = lowerer.jsonRequireModules.get(jsonSf.fileName); + if (mod === undefined) { + const tsType = lowerer.typeOf(call); + const mapped = lowerer.mapTypeOf(tsType); + if (!mapped || !lowerer.comptimeBakeable(mapped)) lowerer.badType(call, tsType); + let parsed: unknown; + try { + parsed = JSON.parse(jsonSf.text); + } catch (e) { + lowerer.pushDiag( + invalidJsonModuleDiag( + jsonSf.fileName, + e instanceof Error ? e.message : String(e), + locOf(call), + ), + ); + throw new PoisonError(); + } + const id = `%g.jsonRequire.${lowerer.jsonRequireModules.size}`; + const global: IrGlobal = { id, name: "%json", type: mapped, mutable: true }; + const loadedId = `${id}%loaded`; + lowerer.globalsList.push(global, { + id: loadedId, + name: "%loaded", + type: BOOL, + mutable: true, + }); + mod = { global, loadedId, parsed, type: mapped }; + lowerer.jsonRequireModules.set(jsonSf.fileName, mod); + } + lowerer.jsonRequireCalls.set(call, mod); + if (created.has(mod)) continue; + created.add(mod); + const loc = locOf(call); + const value = lowerer.comptimeValueToIr(mod.parsed, mod.type, "$", call); + const actions = lowerer.jsonInitActions.get(sf) ?? []; + lowerer.jsonInitActions.set(sf, actions); + actions.push({ + kind: "if", + cond: { + kind: "unary", + op: "!", + operand: { kind: "varRef", localId: mod.loadedId, type: BOOL, loc }, + type: BOOL, + loc, + }, + then: [ + { + kind: "assign", + localId: mod.loadedId, + value: { kind: "boolLit", value: true, type: BOOL, loc }, + loc, + }, + { kind: "assign", localId: mod.global.id, value, loc }, + ], + else_: null, + loc, + }); + } catch (e) { + if (!(e instanceof PoisonError)) throw e; + // diagnostic already recorded + } + } + } +} + +/** A require() call of a JSON document: the shared object. */ +export function lowerJsonRequireCall(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null { + const mod = lowerer.jsonRequireCalls.get(call); + if (mod === undefined) return null; + return { kind: "varRef", localId: mod.global.id, type: mod.global.type, loc: locOf(call) }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 2ba83a3d5..4acba2066 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -58,6 +58,7 @@ import { } from "../../ir/ir.js"; import { lowerProtocolMethodCall } from "./class-protocol-dispatch.js"; import { isJsSourceFile, locOf, requireSpecOf } from "../program.js"; +import { lowerJsonRequireCall } from "./json-require.js"; import { lowerAssertInstanceCall } from "./assert-instances.js"; import { isGenericCallableMemberType, typeKey } from "../type-mapper.js"; import { dynFallbackType, jsFuncNameOf, newFnCtx, staticImportNamespaceType } from "./lowerer.js"; @@ -221,6 +222,10 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { if (object) return object; } + // require() of a JSON document: the shared parsed object. + const json = lowerJsonRequireCall(lowerer, expr); + if (json) return json; + // A call whose chain ROOTS at an ambient-undefined name (`declare // const value: Y | undefined; value?.foo("a")`, `declare function // chain...; chain(o).mapValues(f).value()`, a trap binding's read): diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index d18c4f547..81ded6a58 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -35,6 +35,8 @@ import { withClassInitFlag, withCycleInitFlags, } from "./cycle-initialization.js"; +import { markRequireEarlyBindings } from "./require-initialization.js"; +import { collectJsonRequires, isJsonRequireDecl } from "./json-require.js"; import { invalidJsonModuleDiag, unsupportedPackageImportDiag, @@ -409,6 +411,7 @@ export function collectProgram(lowerer: Lowerer, parts: FileParts[]): void { for (const fp of parts) lowerer.collectGlobals(fp.sf, fp.topStmts); lowerer.collectNpmImports(parts); lowerer.collectJsonImports(parts); + collectJsonRequires(lowerer, parts); } finally { lowerer.diagSink = null; } @@ -416,6 +419,7 @@ export function collectProgram(lowerer: Lowerer, parts: FileParts[]): void { for (const fp of parts) lowerer.collectGlobals(fp.sf, fp.topStmts); lowerer.collectNpmImports(parts); lowerer.collectJsonImports(parts); + collectJsonRequires(lowerer, parts); } for (const decl of computed) { const symbol = declSymbolOf(lowerer, decl); @@ -493,6 +497,7 @@ export function collectProgram(lowerer: Lowerer, parts: FileParts[]): void { lowerer.collecting = wasCollecting; } markCycleEarlyBindings(lowerer); + markRequireEarlyBindings(lowerer); } export function collectNpmImports(lowerer: Lowerer, parts: FileParts[]): void { @@ -1532,8 +1537,9 @@ export function collectGlobals( isRequireStatement(stmt) && !( ts.isVariableStatement(stmt) && - stmt.declarationList.declarations.some((decl) => - isNativeFfiRequire(lowerer, decl.initializer), + stmt.declarationList.declarations.some( + (decl) => + isNativeFfiRequire(lowerer, decl.initializer) || isJsonRequireDecl(lowerer, decl), ) ) ) { diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 367c147f8..8e43f1a42 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -10,6 +10,8 @@ import { InternalCompilerError } from "../../errors.js"; * flow (if/while/for/for-of/do, switch, try/catch, abrupt completions), * explicit resource management, and blocked-binding poisoning. */ import * as ts from "../ts7/adapter.js"; +import { requireInitFlagStmt } from "./require-initialization.js"; +import { isJsonRequireDecl } from "./json-require.js"; import { bindingSource } from "../binding-source.js"; import type { Lowerer } from "./lowerer.js"; import { @@ -1512,81 +1514,96 @@ export function lowerVarStatement(lowerer: Lowerer, stmt: ts.VariableStatement): const isLet = (list.flags & ts.NodeFlags.Let) !== 0 || (list.flags & ts.NodeFlags.BlockScoped) === 0; return list.declarations.flatMap((decl) => { - // The canonical ESM bridge to a compiled program module. Like a - // top-level CommonJS require declaration, the binding is alias - // plumbing while the dependency evaluates at this statement's - // exact position through its run-once initializer. - if (isConst && createRequireProgramModuleDecl(lowerer, decl.name, decl.initializer)) { - if (!ts.isSourceFile(stmt.parent)) { - lowerer.unsupported( - "SC1090", - decl, - "createRequire program-module bindings outside the module's top level (move the binding to the top of the file; side-effect-only requires may remain nested)", - ); - } - const target = createRequireProgramModuleOf(lowerer, decl.initializer)!; - const init = lowerer.requireInitStmt(target.spec, decl); - return init ? [init] : []; - } - // CommonJS require declarations (JS files): at the module's top - // level the BINDINGS are alias plumbing (no storage; - // resolveValueSymbol routes the reads), but the require itself is - // Node's inline module evaluation — a relative require lowers to the - // required module's guarded %init call at exactly this position - // (first require runs the body, later ones are cache hits; builtins - // load nothing). Binding requires anywhere else would need lazily- - // initialized alias storage this model doesn't represent; named - // fence. - if ( - decl.initializer !== undefined && - requireSpecOf(decl.initializer) !== null && - !isNativeFfiRequire(lowerer, decl.initializer) && - isJsSourceFile(decl.getSourceFile()) - ) { - const spec = requireSpecOf(decl.initializer)!; - if (lowerer.externalTypes.has(spec)) lowerer.externalHostFence(spec, decl, false); - if (ts.isSourceFile(stmt.parent)) { - const init = lowerer.requireInitStmt(spec, decl); - return init ? [init] : []; - } - // A nested BUILTIN require (`get inFreeBSDJail() { const { execSync } - // = require('child_process'); ... }` — test/common's lazy-getter - // idiom): builtins load nothing, so the statement is PURE alias - // plumbing wherever it sits — the bindings resolve through the - // same routing top-level requires use, and no statement remains. - // Relative requires keep the fence: their module-init-at-position - // semantics needs storage this model doesn't represent. - if (canonicalBuiltinModule(spec) !== null) { - return []; - } + const lowered = lowerVarDeclarator(lowerer, stmt, decl, isConst, isLet); + // A require binding earlier code can read is initialized from here on + // (require-initialization.ts). + const initialized = requireInitFlagStmt(lowerer, decl); + return initialized ? [...lowered, initialized] : lowered; + }); +} + +function lowerVarDeclarator( + lowerer: Lowerer, + stmt: ts.VariableStatement, + decl: ts.VariableDeclaration, + isConst: boolean, + isLet: boolean, +): IrStmt[] { + // The canonical ESM bridge to a compiled program module. Like a + // top-level CommonJS require declaration, the binding is alias + // plumbing while the dependency evaluates at this statement's + // exact position through its run-once initializer. + if (isConst && createRequireProgramModuleDecl(lowerer, decl.name, decl.initializer)) { + if (!ts.isSourceFile(stmt.parent)) { lowerer.unsupported( "SC1090", decl, - "require() with bindings outside the module's top level (move it to the top of the file)", + "createRequire program-module bindings outside the module's top level (move the binding to the top of the file; side-effect-only requires may remain nested)", ); } - // `const { NGHTTP2_CANCEL } = http2.constants` — a destructure over - // the baked constants table: alias plumbing, no storage (uses read - // their literals via builtinConstantBindingOf; collectGlobals skipped - // the globals by the same test). - if (lowerer.builtinConstantsDestructureDecl(decl.name, decl.initializer)) return []; - if (ts.isArrayBindingPattern(decl.name) || ts.isObjectBindingPattern(decl.name)) { - // `const { createSign } = crypto` over a builtin NAMESPACE binding: - // alias plumbing (builtinImportOf routes the reads) — no statement. - if (builtinNamespaceDestructureModuleOf(lowerer, decl) !== null) return []; - return lowerer.lowerDestructuringDecl(decl, isLet); + const target = createRequireProgramModuleOf(lowerer, decl.initializer)!; + const init = lowerer.requireInitStmt(target.spec, decl); + return init ? [init] : []; + } + // CommonJS require declarations (JS files): at the module's top + // level the BINDINGS are alias plumbing (no storage; + // resolveValueSymbol routes the reads), but the require itself is + // Node's inline module evaluation — a relative require lowers to the + // required module's guarded %init call at exactly this position + // (first require runs the body, later ones are cache hits; builtins + // load nothing). Binding requires anywhere else would need lazily- + // initialized alias storage this model doesn't represent; named + // fence. + if ( + decl.initializer !== undefined && + requireSpecOf(decl.initializer) !== null && + !isNativeFfiRequire(lowerer, decl.initializer) && + !isJsonRequireDecl(lowerer, decl) && + isJsSourceFile(decl.getSourceFile()) + ) { + const spec = requireSpecOf(decl.initializer)!; + if (lowerer.externalTypes.has(spec)) lowerer.externalHostFence(spec, decl, false); + if (ts.isSourceFile(stmt.parent)) { + const init = lowerer.requireInitStmt(spec, decl); + return init ? [init] : []; } - // STORED protocol values with statically closed representations: - // numeric value iterators retain source/cursor/done hidden locals; a - // matchAll drain retains its companion index array so a later - // for-of can serve `m.index`. Both are const-only interceptions. - const numericIterator = lowerNumericIteratorDecl(lowerer, decl, isConst); - if (numericIterator) return numericIterator; - const drained = lowerMatchAllDrainDecl(lowerer, decl, isConst); - if (drained) return drained; - const lowered = lowerer.lowerVarDecl(decl, isLet); - return lowered ? [lowered] : []; - }); + // A nested BUILTIN require (`get inFreeBSDJail() { const { execSync } + // = require('child_process'); ... }` — test/common's lazy-getter + // idiom): builtins load nothing, so the statement is PURE alias + // plumbing wherever it sits — the bindings resolve through the + // same routing top-level requires use, and no statement remains. + // Relative requires keep the fence: their module-init-at-position + // semantics needs storage this model doesn't represent. + if (canonicalBuiltinModule(spec) !== null) { + return []; + } + lowerer.unsupported( + "SC1090", + decl, + "require() with bindings outside the module's top level (move it to the top of the file)", + ); + } + // `const { NGHTTP2_CANCEL } = http2.constants` — a destructure over + // the baked constants table: alias plumbing, no storage (uses read + // their literals via builtinConstantBindingOf; collectGlobals skipped + // the globals by the same test). + if (lowerer.builtinConstantsDestructureDecl(decl.name, decl.initializer)) return []; + if (ts.isArrayBindingPattern(decl.name) || ts.isObjectBindingPattern(decl.name)) { + // `const { createSign } = crypto` over a builtin NAMESPACE binding: + // alias plumbing (builtinImportOf routes the reads) — no statement. + if (builtinNamespaceDestructureModuleOf(lowerer, decl) !== null) return []; + return lowerer.lowerDestructuringDecl(decl, isLet); + } + // STORED protocol values with statically closed representations: + // numeric value iterators retain source/cursor/done hidden locals; a + // matchAll drain retains its companion index array so a later + // for-of can serve `m.index`. Both are const-only interceptions. + const numericIterator = lowerNumericIteratorDecl(lowerer, decl, isConst); + if (numericIterator) return numericIterator; + const drained = lowerMatchAllDrainDecl(lowerer, decl, isConst); + if (drained) return drained; + const lowered = lowerer.lowerVarDecl(decl, isLet); + return lowered ? [lowered] : []; } /** The numeric indexed source of a built-in value-iterator expression: diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 3217802ad..98ae29209 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -10,6 +10,12 @@ import { refuseUncheckedCycleReads, type CycleInitFlag, } from "./cycle-initialization.js"; +import { isJsonRequireDecl, type JsonRequireModule } from "./json-require.js"; +import { + checkRequireBindingAccesses, + type EarlyReference, + type RequireInitFlag, +} from "./require-initialization.js"; import { identityPreservingWidening } from "./coercions/identity.js"; import { scanDivergences } from "./divergences.js"; import { checkedClassAssertion } from "./class-assertions.js"; @@ -2414,6 +2420,10 @@ export class Lowerer { * prepended by lowerFileInit so the bindings are live before any * top-level statement runs. */ readonly jsonInitActions = new Map(); + /** CommonJS require() of JSON documents: the shared object per document + * and the calls reading it (json-require.ts). */ + readonly jsonRequireModules = new Map(); + readonly jsonRequireCalls = new Map(); /** Dynamic `import("literal")` resolutions, keyed * `fileName\u0000specifier` (collectDynamicImports fills it during npm * collection; lowerDynamicImportCall reads it per site). */ @@ -2581,6 +2591,10 @@ export class Lowerer { * by class name (cycle-initialization.ts). */ readonly classInitFlags = new Map(); readonly cycleInitDeclarations = new Map(); + /** CommonJS require declarations whose bindings code running before the + * require can read, and those references (require-initialization.ts). */ + readonly requireInitFlags = new Map(); + readonly requireEarlyReferences: EarlyReference[] = []; get ctx(): FnCtx { const top = this.fnStack[this.fnStack.length - 1]; @@ -3421,6 +3435,7 @@ export class Lowerer { return null; const directSpec = requireSpecOf(decl.initializer); if (directSpec !== null) { + if (isJsonRequireDecl(this, decl)) return null; return ( resolveImport(this.program, decl.getSourceFile(), directSpec, "require") ?? npmStaticDepSf7(this.program, decl.getSourceFile(), directSpec, "require") @@ -6203,6 +6218,7 @@ export class Lowerer { // slots), uniformly across params/locals/globals/fields/body types so // every producer and consumer agrees. Programs with no unregistered // reference are untouched — byte-stability holds. + checkRequireBindingAccesses(this, functions); const module: IrModule | null = this.diags.length > 0 ? null diff --git a/packages/compiler/src/frontend/lowering/require-initialization.ts b/packages/compiler/src/frontend/lowering/require-initialization.ts new file mode 100644 index 000000000..5375f3792 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/require-initialization.ts @@ -0,0 +1,262 @@ +/* CommonJS require bindings read before their require ran. A top-level + * `const x = require("./dep")` binds x AT the require: Node throws "Cannot + * access 'x' before initialization" when code that runs earlier (a hoisted + * function called above the require, say) reads it. The lowering keeps + * require bindings as module aliases, so the reads themselves cannot + * observe the order. When preflight finds code that can reach a binding + * before its require (requireEarlyReference), the declaration gets a BOOL + * initialization flag, set right after the require evaluated the module, + * and every reference that can run earlier checks it first — the same + * module.tdzCheck the import-cycle bindings use. A reference whose lowering + * leaves no expression to check keeps the SC1013 fence. */ +import * as ts from "../ts7/adapter.js"; +import type { Lowerer } from "./lowerer.js"; +import { + inDeferredPosition, + isCjsJsFile, + locOf, + requireEarlyReference, + requireSpecOf, +} from "../program.js"; +import { unsupportedDiag } from "../../diagnostics/diagnostic.js"; +import { + BOOL, + STRING, + VOID, + type IrExpr, + type IrFunction, + type IrStmt, + type SrcLoc, +} from "../../ir/ir.js"; +import { mapExprChildren, mapStmtChildren } from "../../ir/traverse.js"; + +/** One flagged require declaration. */ +export interface RequireInitFlag { + flagId: string; + /** The binding names, by symbol. */ + names: Map; +} + +/** A reference that can run before its require: the identifier, the + * outermost expression whose evaluation starts with reading it, and the + * body of the innermost function holding it (null at the top level). */ +export interface EarlyReference { + flag: RequireInitFlag; + name: string; + ref: SrcLoc; + chain: SrcLoc; + body: SrcLoc | null; + node: ts.Identifier; +} + +function boundNames(name: ts.BindingName): ts.Identifier[] { + if (ts.isIdentifier(name)) return [name]; + const out: ts.Identifier[] = []; + for (const el of name.elements) { + if (ts.isOmittedExpression(el) || el.name === undefined) continue; + out.push(...boundNames(el.name)); + } + return out; +} + +/** The outermost node whose evaluation begins by evaluating `ref`: member + * reads, calls and constructions through it, and the transparent wrappers + * around them. */ +function chainOf(ref: ts.Identifier): ts.Node { + let node: ts.Node = ref; + for (;;) { + const parent = node.parent; + if (parent === undefined) return node; + if ( + ((ts.isPropertyAccessExpression(parent) || + ts.isElementAccessExpression(parent) || + ts.isCallExpression(parent) || + ts.isNewExpression(parent)) && + parent.expression === node) || + (ts.isTaggedTemplateExpression(parent) && parent.tag === node) || + ts.isParenthesizedExpression(parent) || + ts.isNonNullExpression(parent) || + (ts.isAsExpression(parent) && parent.expression === node) || + (ts.isSatisfiesExpression(parent) && parent.expression === node) + ) { + node = parent; + continue; + } + return node; + } +} + +function enclosingBody(node: ts.Node): ts.Node | null { + for (let p = node.parent; p !== undefined && !ts.isSourceFile(p); p = p.parent) { + if (ts.isFunctionLike(p)) { + const body = (p as { body?: ts.Node }).body; + if (body !== undefined) return body; + } + if (ts.isPropertyDeclaration(p) && p.initializer !== undefined) return p.initializer; + } + return null; +} + +/** Registers a flag for every top-level const/let require declaration of a + * CommonJS module whose bindings earlier code can reach, and collects the + * references that can run before the require. Runs once per lowering pass, + * after global collection. */ +export function markRequireEarlyBindings(lowerer: Lowerer): void { + for (const sf of lowerer.moduleOrder) { + if (sf.isDeclarationFile || !isCjsJsFile(sf, lowerer.program)) continue; + const declared: { decl: ts.VariableDeclaration; stmt: ts.VariableStatement }[] = []; + for (const stmt of sf.statements) { + if (!ts.isVariableStatement(stmt)) continue; + if ((stmt.declarationList.flags & (ts.NodeFlags.Const | ts.NodeFlags.Let)) === 0) continue; + for (const decl of stmt.declarationList.declarations) { + if (decl.initializer === undefined || requireSpecOf(decl.initializer) === null) continue; + if (requireEarlyReference(lowerer.program, decl) === null) continue; + declared.push({ decl, stmt }); + } + } + if (declared.length === 0) continue; + const rawTag = lowerer.fileTag.get(sf) ?? ""; + const tag = rawTag === "" ? "e." : rawTag.replace(/^%/, ""); + const bySymbol = new Map(); + for (const { decl } of declared) { + const flagId = `%g.${tag}%required.${decl.getStart(sf)}`; + lowerer.globalsList.push({ id: flagId, name: "%initialized", type: BOOL, mutable: true }); + const flag: RequireInitFlag = { flagId, names: new Map() }; + for (const id of boundNames(decl.name)) { + const symbol = lowerer.checker.getSymbolAtLocation(id); + if (symbol === undefined) continue; + flag.names.set(symbol, id.text); + bySymbol.set(symbol, { flag, decl }); + } + lowerer.requireInitFlags.set(decl, flag); + } + const names = new Set(); + for (const { flag } of bySymbol.values()) for (const n of flag.names.values()) names.add(n); + const idents: ts.Identifier[] = []; + ts.walkPreorder(sf, (node) => { + if (ts.isIdentifier(node) && names.has(node.text)) idents.push(node); + return undefined; + }); + lowerer.checker.prefetchSymbolNodesExact(idents); + for (const id of idents) { + const parent = id.parent; + const symbol = + parent !== undefined && ts.isShorthandPropertyAssignment(parent) && parent.name === id + ? lowerer.checker.getShorthandAssignmentValueSymbol(parent) + : lowerer.checker.getSymbolAtLocation(id); + const owner = symbol === undefined ? undefined : bySymbol.get(symbol); + if (owner === undefined) continue; + if (boundNames(owner.decl.name).includes(id)) continue; + // Code after the require runs after it, except inside functions. + if (id.getStart(sf) >= owner.decl.getEnd() && !inDeferredPosition(id)) continue; + const body = enclosingBody(id); + lowerer.requireEarlyReferences.push({ + flag: owner.flag, + name: owner.flag.names.get(symbol!)!, + ref: locOf(id), + chain: locOf(chainOf(id)), + body: body === null ? null : locOf(body), + node: id, + }); + } + } +} + +/** The statement marking a flagged require declaration initialized, placed + * right after its require evaluated the module. */ +export function requireInitFlagStmt(lowerer: Lowerer, decl: ts.VariableDeclaration): IrStmt | null { + const flag = lowerer.requireInitFlags.get(decl); + if (flag === undefined) return null; + const loc = locOf(decl); + return { + kind: "assign", + localId: flag.flagId, + value: { kind: "boolLit", value: true, type: BOOL, loc }, + loc, + }; +} + +const within = (inner: SrcLoc, outer: SrcLoc): boolean => + inner.file === outer.file && outer.start <= inner.start && inner.end <= outer.end; + +/** Inserts the initialization check before the outermost expression built + * for each early reference, and refuses a reference whose lowered code + * holds no expression for it. */ +export function checkRequireBindingAccesses(lowerer: Lowerer, functions: IrFunction[]): void { + const refs = lowerer.requireEarlyReferences; + if (refs.length === 0) return; + const byFile = new Map(); + for (const r of refs) { + const list = byFile.get(r.ref.file); + if (list) list.push(r); + else byFile.set(r.ref.file, [r]); + } + const covered = new Set(); + const loweredBodies = new Set(); + const claimed = new Set(); + const check = (r: EarlyReference, loc: SrcLoc): IrStmt => ({ + kind: "exprStmt", + expr: { + kind: "intrinsic", + name: "module.tdzCheck", + args: [ + { kind: "varRef", localId: r.flag.flagId, type: BOOL, loc }, + { kind: "strLit", value: r.name, type: STRING, loc }, + ], + type: VOID, + loc, + }, + loc, + }); + const note = (loc: SrcLoc | undefined): EarlyReference[] => { + if (loc === undefined) return []; + const list = byFile.get(loc.file); + if (list === undefined) return []; + const mine: EarlyReference[] = []; + for (const r of list) { + if (r.body !== null && !loweredBodies.has(r) && within(loc, r.body)) loweredBodies.add(r); + if (!claimed.has(r) && within(r.ref, loc) && within(loc, r.chain)) mine.push(r); + } + return mine; + }; + const rewriteExpr = (e: IrExpr): IrExpr => { + const mine = note(e.loc); + for (const r of mine) claimed.add(r); + const out = mapExprChildren(e, rewriteExpr, rewriteStmt); + for (const r of mine) { + claimed.delete(r); + covered.add(r); + } + if (mine.length === 0) return out; + const flags = new Set(); + const stmts: IrStmt[] = []; + for (const r of mine) { + if (flags.has(r.flag.flagId)) continue; + flags.add(r.flag.flagId); + stmts.push(check(r, e.loc)); + } + return { kind: "seqExpr", stmts, result: out, type: out.type, loc: out.loc }; + }; + const rewriteStmt = (s: IrStmt): IrStmt => { + note(s.loc); + return mapStmtChildren(s, rewriteExpr, rewriteStmt); + }; + for (const fn of functions) fn.body = fn.body.map(rewriteStmt); + if (lowerer.remainder) return; + const reported = new Set(); + for (const r of refs) { + if (covered.has(r)) continue; + // A function body that never lowered never runs. + if (r.body !== null && !loweredBodies.has(r)) continue; + const key = `${r.ref.file}:${r.ref.start}`; + if (reported.has(key)) continue; + reported.add(key); + lowerer.pushDiag( + unsupportedDiag( + "SC1013", + r.ref, + `reading require() binding '${r.name}' where it can run before the require (this use has no checked form for Node's ReferenceError — move the require above the code that can run first)`, + ), + ); + } +} diff --git a/packages/compiler/src/frontend/program-analysis.ts b/packages/compiler/src/frontend/program-analysis.ts index 0ecf09e6a..e49b9307e 100644 --- a/packages/compiler/src/frontend/program-analysis.ts +++ b/packages/compiler/src/frontend/program-analysis.ts @@ -1,4 +1,9 @@ -import type { ExportDeclaration, SourceFile, VariableDeclaration } from "./ts7/ast-types.js"; +import type { + ExportDeclaration, + Identifier, + SourceFile, + VariableDeclaration, +} from "./ts7/ast-types.js"; import type { ModuleSourceCandidates } from "./module-source-candidates.js"; import type { CycleEarlyBinding } from "./program.js"; @@ -20,6 +25,11 @@ export class ProgramAnalysis { readonly exactCycleMembers = new Set(); cycleEarlyBindings: EarlyBindingsMemo | null = null; moduleEarlyBindings: EarlyBindingsMemo | null = null; + /** Top-level require declarations: the first reference to their bindings + * that code running before the require can reach (requireEarlyReference). */ + readonly requireEarlyReferences = new Map(); + /** Per file: the first top-level statement that can run user code. */ + readonly requireFirstRunnable = new Map(); clear(): void { this.createRequireReasons.clear(); @@ -29,5 +39,7 @@ export class ProgramAnalysis { this.exactCycleMembers.clear(); this.cycleEarlyBindings = null; this.moduleEarlyBindings = null; + this.requireEarlyReferences.clear(); + this.requireFirstRunnable.clear(); } } diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index 3a4ec1647..82b2cb5e0 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -1312,6 +1312,476 @@ export function bindingEarlyUse7( return hit; } +/** The first reference to a top-level require declaration's bindings that + * code running before the require completes can reach, or null when no + * earlier code can run or reach one. Memoized per program: preflight + * decides the fence and the lowering places the initialization checks + * from the same answer. */ +function requireEarlyReference7( + program: ts.Program, + decl: ts.VariableDeclaration, +): ts.Identifier | null { + const memo = program.analysis.requireEarlyReferences; + const cached = memo.get(decl); + if (cached !== undefined) return cached; + let found: ts.Identifier | null = null; + const stmt = decl.parent?.parent; + const sf = decl.getSourceFile(); + if (stmt !== undefined && ts.isVariableStatement(stmt) && ts.isSourceFile(stmt.parent)) { + const stmts = sf.statements; + const k = stmts.indexOf(stmt); + const declarations = stmt.declarationList.declarations; + // Earlier declarators run too: `const x = read(), dep = require('./dep')`. + const precedingDecls = declarations.slice(0, declarations.indexOf(decl)); + let firstRunnable = program.analysis.requireFirstRunnable.get(sf); + if (firstRunnable === undefined) { + firstRunnable = stmts.findIndex((s) => !purePrefixStmt7(program, s)); + program.analysis.requireFirstRunnable.set(sf, firstRunnable); + } + const prefixCanRun = + (firstRunnable >= 0 && firstRunnable < k) || precedingDecls.some((d) => !purePrefixDecl7(d)); + if (prefixCanRun) found = requireBindingEarlyUse7(program, sf, k, decl, precedingDecls); + } + memo.set(decl, found); + return found; +} + +/** The CommonJS twin of bindingEarlyUse7 for a top-level require binding: + * the first reference to one of `decl`'s bindings that code running before + * the require completes can reach, or null. It follows Node's evaluation + * order instead of the conservative "every earlier statement" scan: + * - hoisted functions and classes, and the function and class values a + * var stored before the require, run only when reachable code names + * them; a class statement runs only its heritage, computed keys, + * decorators and static initializers; + * - callbacks handed to timers, microtasks and promise reactions run after + * the module body, hence after the require; + * - publishing a value (`module.exports = f`, `exports.n = f`, + * `Object.defineProperty(exports, "n", { get })`, `F.prototype.m = f`) + * runs nothing. The published value becomes reachable only when + * reachable code reads it back: an `exports.n` read reaches the values + * published as `n`, any other read of the export object reaches all of + * them, and naming `F` reaches what was stored on `F`. No other module + * can read this module's exports before its body completes: require + * cycles keep their SC1016 fence and a compiled module graph has no + * reflective exports object. + * Every other function-like met in reachable code counts as reachable + * because it may be handed to a callee. */ +export function requireBindingEarlyUse7( + program: ts.Program, + sf: ts.SourceFile, + k: number, + decl: ts.VariableDeclaration, + precedingDecls: readonly ts.VariableDeclaration[], +): ts.Identifier | null { + const checker = program.getTypeChecker(); + const bindings = new Set(); + for (const id of boundNames7(decl.name)) { + const sym = checker.getSymbolAtLocation(id); + if (sym) bindings.add(sym); + } + if (bindings.size === 0) return null; + const stmts = sf.statements; + const cjs = isCjsJsFile7(sf, program); + const symbolOf = (id: ts.Identifier): ts.Symbol | undefined => { + const parent = id.parent; + if (parent !== undefined && ts.isShorthandPropertyAssignment(parent) && parent.name === id) { + return checker.getShorthandAssignmentValueSymbol(parent); + } + return checker.getSymbolAtLocation(id); + }; + // Stored callables and the scans that skip them. + const units = new Map(); + const stored = new Set(); + const addUnit = (name: ts.Identifier, node: ts.Node): void => { + const sym = checker.getSymbolAtLocation(name); + if (sym === undefined) return; + stored.add(node); + const list = units.get(sym); + if (list) list.push(node); + else units.set(sym, [node]); + }; + const storedCallables = (e: ts.Expression, out: ts.Node[]): void => { + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (ts.isArrowFunction(e) || ts.isFunctionExpression(e) || ts.isClassExpression(e)) { + out.push(e); + } else if (ts.isObjectLiteralExpression(e)) { + for (const p of e.properties) { + if ( + (ts.isMethodDeclaration(p) || + ts.isGetAccessorDeclaration(p) || + ts.isSetAccessorDeclaration(p)) && + !ts.isComputedPropertyName(p.name) + ) { + out.push(p); + } else if (ts.isPropertyAssignment(p) && !ts.isComputedPropertyName(p.name)) { + storedCallables(p.initializer, out); + } + } + } + }; + stmts.forEach((s, i) => { + if ((ts.isFunctionDeclaration(s) || ts.isClassDeclaration(s)) && s.name !== undefined) { + addUnit(s.name, s); + } else if (i < k && ts.isVariableStatement(s)) { + for (const d of s.declarationList.declarations) { + if (!ts.isIdentifier(d.name) || d.initializer === undefined) continue; + const out: ts.Node[] = []; + storedCallables(d.initializer, out); + for (const node of out) addUnit(d.name, node); + } + } + }); + // Callbacks that only run as later jobs never run before the require: + // the timers, microtasks and promise reactions. (Event listeners can run + // synchronously from an emit, so they keep the conservative rule.) + const laterJob = (callee: ts.Expression): boolean => { + while (ts.isParenthesizedExpression(callee)) callee = callee.expression; + const name = ts.isIdentifier(callee) + ? callee.text + : ts.isPropertyAccessExpression(callee) + ? callee.name.text + : null; + return ( + name !== null && + (LATER_JOB_BUILTINS7.has(name) || name === "nextTick") && + laterJobCallee7(checker, callee) + ); + }; + if (!hasTopLevelAwait7(sf)) { + const callbacks = (e: ts.Expression): void => { + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (ts.isArrowFunction(e) || ts.isFunctionExpression(e)) stored.add(e); + }; + for (const s of stmts.slice(0, k)) { + ts.walkPreorder(s, (node) => { + if ((ts.isCallExpression(node) || ts.isNewExpression(node)) && laterJob(node.expression)) { + for (const arg of node.arguments ?? []) callbacks(arg); + } + return undefined; + }); + } + } + const isWrapperName = (e: ts.Node, name: string): e is ts.Identifier => + ts.isIdentifier(e) && e.text === name && !sourceBinding7(program, e); + /** `this` at the module's top level: the original export object. */ + const isModuleThis = (e: ts.Node): boolean => { + if (e.kind !== ts.SyntaxKind.ThisKeyword) return false; + for (let p = e.parent; p !== undefined && !ts.isSourceFile(p); p = p.parent) { + if (ts.isFunctionLike(p) && !ts.isArrowFunction(p)) return false; + if (ts.isClassExpression(p) || ts.isClassDeclaration(p)) return false; + } + return true; + }; + const isExportObject = (e: ts.Expression): boolean => + isWrapperName(e, "exports") || + isModuleThis(e) || + (isModuleExportsAccess(e) && isWrapperName(e.expression, "module")); + // Published values: by export name ("*" for a whole replacement), and by + // the stored callable whose properties hold them. + const exportLinks = new Map(); + const ownerLinks = new Map(); + const reachedKeys = new Set(); + const reachedUnits = new Set(); + const work: ts.Node[] = []; + let hit: ts.Identifier | null = null; + const reachUnit = (node: ts.Node): void => { + if (reachedUnits.has(node)) return; + reachedUnits.add(node); + work.push(node); + }; + const reachSymbol = (sym: ts.Symbol): void => { + for (const node of units.get(sym) ?? []) reachUnit(node); + for (const node of ownerLinks.get(sym) ?? []) reachUnit(node); + }; + let allReached = false; + const reachKey = (key: string | null): void => { + if (key === null) { + allReached = true; + for (const list of exportLinks.values()) for (const node of list) reachUnit(node); + return; + } + reachedKeys.add(key); + for (const name of [key, "*"]) for (const node of exportLinks.get(name) ?? []) reachUnit(node); + }; + const keyReached = (key: string): boolean => + allReached || reachedKeys.has(key) || (key === "*" && reachedKeys.size > 0); + /** A read of the export object: which published names it can observe. */ + const exportRead = (node: ts.Expression): void => { + let use: ts.Node = node; + while (ts.isParenthesizedExpression(use.parent)) use = use.parent; + const parent = use.parent; + // A truthiness test reads no member (tsc's `this && this.__helper`). + if ( + ts.isBinaryExpression(parent) && + parent.left === use && + parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken + ) { + return; + } + if (ts.isTypeOfExpression(parent)) return; + if (ts.isPropertyAccessExpression(parent) && parent.expression === use) { + reachKey(parent.name.text); + return; + } + if ( + ts.isElementAccessExpression(parent) && + parent.expression === use && + ts.isStringLiteralLike(parent.argumentExpression) + ) { + reachKey(parent.argumentExpression.text); + return; + } + reachKey(null); + }; + const scan = (root: ts.Node): void => { + ts.walkPreorder(root, (n) => { + if (hit !== null) return "stop"; + if (n !== root && stored.has(n)) { + if (ts.isClassExpression(n) || ts.isClassDeclaration(n)) { + for (const part of classSyncParts7(n)) scan(part); + } + return "skip"; + } + // A self-require answers this module's partially built exports. + if (cjs && ts.isCallExpression(n)) { + const spec = requireSpecOf7(n); + if (spec !== null && resolveImport7(program, sf, spec, "require") === sf) reachKey(null); + } + if (cjs && n.kind === ts.SyntaxKind.ThisKeyword && isModuleThis(n)) { + exportRead(n as ts.Expression); + return undefined; + } + if (!ts.isIdentifier(n)) return undefined; + if (inTypePosition7(n)) return undefined; + const named = n.parent; + if ( + (ts.isPropertyAccessExpression(named) || + ts.isPropertyAssignment(named) || + ts.isMethodDeclaration(named) || + ts.isGetAccessorDeclaration(named) || + ts.isSetAccessorDeclaration(named) || + ts.isPropertyDeclaration(named)) && + named.name === n + ) { + return undefined; + } + if (cjs && isWrapperName(n, "exports")) { + exportRead(n); + return undefined; + } + if (cjs && isWrapperName(n, "module")) { + const parent = n.parent; + if (ts.isPropertyAccessExpression(parent) && parent.expression === n) { + if (parent.name.text === "exports") exportRead(parent); + return "skip"; + } + reachKey(null); + return undefined; + } + const sym = symbolOf(n); + if (sym === undefined) return undefined; + if (bindings.has(sym)) { + hit = n; + return "stop"; + } + reachSymbol(sym); + return undefined; + }); + }; + /** Links a published value: evaluating it reads identifiers, but the + * callables it names run only once they are read back. */ + const publish = (value: ts.Expression, link: (node: ts.Node) => void): void => { + while (ts.isParenthesizedExpression(value)) value = value.expression; + if (ts.isIdentifier(value)) { + const sym = symbolOf(value); + if (sym !== undefined && bindings.has(sym)) { + hit = value; + return; + } + if (sym !== undefined) { + // What was stored on the value stays reachable through it. + for (const node of [...(units.get(sym) ?? []), ...(ownerLinks.get(sym) ?? [])]) link(node); + } + return; + } + if (ts.isFunctionExpression(value) || ts.isArrowFunction(value)) { + link(value); + return; + } + if (ts.isClassExpression(value)) { + for (const part of classSyncParts7(value)) scan(part); + link(value); + return; + } + if (ts.isObjectLiteralExpression(value)) { + for (const p of value.properties) { + if (ts.isShorthandPropertyAssignment(p)) { + const sym = checker.getShorthandAssignmentValueSymbol(p); + if (sym !== undefined && bindings.has(sym)) hit = p.name as ts.Identifier; + else if (sym !== undefined) { + for (const node of [...(units.get(sym) ?? []), ...(ownerLinks.get(sym) ?? [])]) { + link(node); + } + } + } else if (ts.isPropertyAssignment(p) && !ts.isComputedPropertyName(p.name)) { + publish(p.initializer, link); + } else if ( + (ts.isMethodDeclaration(p) || + ts.isGetAccessorDeclaration(p) || + ts.isSetAccessorDeclaration(p)) && + !ts.isComputedPropertyName(p.name) + ) { + link(p); + } else scan(p); + } + return; + } + if ( + ts.isStringLiteralLike(value) || + ts.isNumericLiteral(value) || + value.kind === ts.SyntaxKind.TrueKeyword || + value.kind === ts.SyntaxKind.FalseKeyword || + value.kind === ts.SyntaxKind.NullKeyword || + (ts.isVoidExpression(value) && ts.isNumericLiteral(value.expression)) + ) { + return; + } + scan(value); + // Whatever an arbitrary expression evaluates to is opaque: treat it as + // reachable through the target too (scan already reached its parts). + }; + /** Where a publication stores: an export name, or a stored callable. */ + type Target = { kind: "key"; key: string } | { kind: "owner"; owner: ts.Symbol }; + const targetOf = (left: ts.Expression): Target | null => { + if (isModuleExportsAccess(left) && isWrapperName(left.expression, "module")) { + return { kind: "key", key: "*" }; + } + const names: string[] = []; + let e: ts.Expression = left; + for (;;) { + if (ts.isPropertyAccessExpression(e) && !e.questionDotToken) { + if (isExportObject(e)) break; + names.unshift(e.name.text); + e = e.expression; + } else if ( + ts.isElementAccessExpression(e) && + !e.questionDotToken && + ts.isStringLiteralLike(e.argumentExpression) + ) { + names.unshift(e.argumentExpression.text); + e = e.expression; + } else break; + } + if (names.length === 0) return null; + if (isExportObject(e)) return { kind: "key", key: names[0]! }; + if (ts.isIdentifier(e)) { + const sym = symbolOf(e); + if (sym !== undefined && units.has(sym) && !bindings.has(sym)) + return { kind: "owner", owner: sym }; + } + return null; + }; + const linkTo = (target: Target, node: ts.Node): void => { + if (target.kind === "key") { + if (keyReached(target.key)) reachUnit(node); + const list = exportLinks.get(target.key); + if (list) list.push(node); + else exportLinks.set(target.key, [node]); + } else { + if ((units.get(target.owner) ?? []).some((u) => reachedUnits.has(u))) reachUnit(node); + if ((units.get(target.owner) ?? []).includes(node)) return; + const list = ownerLinks.get(target.owner); + if (list === undefined) ownerLinks.set(target.owner, [node]); + else if (!list.includes(node)) list.push(node); + } + }; + /** A top-level publication statement, handled in place; false for any + * other statement. */ + const publication = (s: ts.Statement): boolean => { + if (!cjs || !ts.isExpressionStatement(s)) return false; + const e = s.expression; + if (ts.isBinaryExpression(e) && e.operatorToken.kind === ts.SyntaxKind.EqualsToken) { + const targets: Target[] = []; + let value: ts.Expression = e; + while ( + ts.isBinaryExpression(value) && + value.operatorToken.kind === ts.SyntaxKind.EqualsToken + ) { + const target = targetOf(value.left); + if (target === null) return false; + targets.push(target); + value = value.right; + } + publish(value, (node) => { + for (const t of targets) linkTo(t, node); + }); + return true; + } + // Object.defineProperty(exports, "name", { get() {...}, value: f, ... }) + if ( + ts.isCallExpression(e) && + ts.isPropertyAccessExpression(e.expression) && + isWrapperName(e.expression.expression, "Object") && + e.expression.name.text === "defineProperty" && + e.arguments.length === 3 + ) { + const [recv, key, desc] = e.arguments as unknown as [ + ts.Expression, + ts.Expression, + ts.Expression, + ]; + if (!isExportObject(recv) || !ts.isStringLiteralLike(key)) return false; + if (!ts.isObjectLiteralExpression(desc)) return false; + const keyTarget: Target = { kind: "key", key: key.text }; + const link = (node: ts.Node): void => linkTo(keyTarget, node); + for (const p of desc.properties) { + if ( + (ts.isMethodDeclaration(p) || ts.isPropertyAssignment(p)) && + ts.isIdentifier(p.name) && + (p.name.text === "get" || p.name.text === "set") + ) { + if (ts.isMethodDeclaration(p)) link(p); + else publish(p.initializer, link); + } else if ( + ts.isPropertyAssignment(p) && + ts.isIdentifier(p.name) && + p.name.text === "value" + ) { + publish(p.initializer, link); + } else scan(p); + } + return true; + } + return false; + }; + const drain = (): void => { + while (hit === null && work.length > 0) { + const unit = work.pop()!; + checker.prefetchSymbolRoots([unit]); + scan(unit); + } + }; + const roots = stmts.slice(0, k); + checker.prefetchSymbolRoots([...roots, ...precedingDecls]); + for (const s of roots) { + if (hit !== null) break; + if (ts.isFunctionDeclaration(s)) continue; + if (ts.isClassDeclaration(s)) { + for (const part of classSyncParts7(s)) scan(part); + } else if (!publication(s)) { + scan(s); + } + drain(); + } + for (const d of precedingDecls) { + if (hit !== null) break; + scan(d); + drain(); + } + return hit; +} + /** Bare `require("...")` EXPRESSION STATEMENTS anywhere below the top * level of a file — inside top-level ifs/blocks/loops and inside function * bodies (the lazy-require idiom). No bindings, pure side-effect loads. */ @@ -4049,10 +4519,37 @@ function preflight7(load: LoadResult): { { const jsRequireFile = isJsSourceFileName(sf.fileName); const stmts = sf.statements; - let firstRunnable = -1; - stmts.forEach((s, i) => { - if (firstRunnable < 0 && !purePrefixStmt7(program, s)) firstRunnable = i; - }); + // A binding that code running before the require can reach. Node + // initializes it AT the require: a const/let read earlier throws + // ReferenceError, which the lowering reproduces with an + // initialization check at every reference that can run early + // (require-initialization.ts). A var reads undefined there, which + // module aliases cannot represent; createRequire bindings have no + // checked form either. + const earlyRequireFence = ( + req: { decl: ts.VariableDeclaration | null }, + bindingKind: RequireCallBindingKind7, + loc: { file: string; start: number; end: number }, + ): boolean => { + const early = req.decl !== null ? requireEarlyReference7(program, req.decl) : null; + if ( + early === null || + (bindingKind !== "createRequire" && + ((req.decl!.parent?.flags ?? 0) & (ts.NodeFlags.Const | ts.NodeFlags.Let)) !== 0) + ) { + return false; + } + diags.push( + unsupportedDiag( + "SC1013", + loc, + bindingKind === "createRequire" + ? `createRequire() binding '${early.text}' below code that can reach it (Node throws ReferenceError on any earlier access, which is not modeled — move the require above the code that can run first)` + : `var require() binding '${early.text}' below code that can reach it (Node reads undefined before the require runs, which is not modeled — declare it with const or let, or move the require above the code that can run first)`, + ), + ); + return true; + }; for (let k = 0; k < stmts.length; k++) { const stmt = stmts[k]!; for (const req of requiresOf7(stmt)) { @@ -4072,24 +4569,62 @@ function preflight7(load: LoadResult): { if (load.externalTypes.has(req.spec)) { continue; } + // A JSON document: the require answers its cached parsed object + // (json-require.ts), an ordinary value the binding stores, so + // every destructuring form lowers as usual. No module edge. + const jsonDep = resolveImport7(program, sf, req.spec, "require"); + if (jsonDep !== null && jsonDep.fileName.endsWith(".json")) { + if (bindingKind === "createRequire") continue; + if (ts.isVariableStatement(stmt) && requiresOf7(stmt).length > 1) { + const others = requiresOf7(stmt).some((r) => { + const d = resolveImport7(program, sf, r.spec, "require"); + return d === null || !d.fileName.endsWith(".json"); + }); + if (others) { + diags.push( + unsupportedDiag( + "SC1012", + loc, + "require() of a JSON module declared together with other require() bindings", + ), + ); + continue; + } + } + earlyRequireFence(req, bindingKind, loc); + continue; + } if (req.decl && ts.isArrayBindingPattern(req.decl.name)) { diags.push(unsupportedDiag("SC1012", loc, "array-destructuring require() bindings")); continue; } if (req.decl && ts.isObjectBindingPattern(req.decl.name)) { - const bad = req.decl.name.elements.find( - (e) => - e.name === undefined || - !ts.isIdentifier(e.name) || - e.initializer !== undefined || - e.dotDotDotToken !== undefined, - ); - if (bad) { + // A nested pattern of a builtin binds members of the sub-module + // its key names (`const { types: { isPromise } } = + // require("util")` — util.types IS util/types). + const builtin = canonicalBuiltinModule(req.spec); + const plainElements = ( + pattern: ts.ObjectBindingPattern, + module: string | null, + ): boolean => + pattern.elements.every((e) => { + if (e.initializer !== undefined || e.dotDotDotToken !== undefined) return false; + if (e.name !== undefined && ts.isIdentifier(e.name)) return true; + if (module === null || e.name === undefined || !ts.isObjectBindingPattern(e.name)) + return false; + const key = e.propertyName; + if (key === undefined || !ts.isIdentifier(key)) return false; + const sub = canonicalBuiltinModule(`${module}/${key.text}`); + return sub !== null && plainElements(e.name, sub); + }); + if (!plainElements(req.decl.name, builtin)) { diags.push( unsupportedDiag( "SC1012", loc, - "require() destructuring with defaults, rest, or nested patterns", + builtin !== null + ? "require() destructuring with defaults, rest, or nested patterns other than builtin sub-modules" + : "require() destructuring with defaults, rest, or nested patterns of program modules (JSON documents and builtin sub-modules destructure fully)", ), ); continue; @@ -4132,38 +4667,7 @@ function preflight7(load: LoadResult): { continue; } } - if (dep && dep.fileName.endsWith(".json")) { - if (bindingKind === "createRequire") continue; - diags.push(unsupportedDiag("SC1012", loc, "require() of JSON modules")); - continue; - } - // Earlier declarators run too: `const x = read(), dep = - // require('./dep')` must not lose the guard merely because both - // initializers share one VariableStatement. - const precedingDecls = - req.decl && ts.isVariableStatement(stmt) - ? stmt.declarationList.declarations.slice( - 0, - stmt.declarationList.declarations.indexOf(req.decl), - ) - : []; - const prefixCanRun = - (firstRunnable >= 0 && firstRunnable < k) || - precedingDecls.some((decl) => !purePrefixDecl7(decl)); - const tdzName = - prefixCanRun && req.decl - ? bindingEarlyUse7(program, sf, k, req.decl, precedingDecls) - : null; - if (tdzName !== null) { - diags.push( - unsupportedDiag( - "SC1013", - loc, - `require() below code that can reach its binding '${tdzName}' (Node initializes the binding AT the require and throws ReferenceError on any earlier access, which is not modeled — move the require above the code that can run first)`, - ), - ); - continue; - } + if (earlyRequireFence(req, bindingKind, loc)) continue; if (dep) deps.push({ dep }); } } @@ -4191,11 +4695,9 @@ function preflight7(load: LoadResult): { } const projectDep = resolveImport7(program, sf, spec, "require"); if (projectDep !== null) { - if (projectDep.fileName.endsWith(".json")) { - if (bindingKind === "createRequire") continue; - diags.push(unsupportedDiag("SC1012", loc, "require() of JSON modules")); - continue; - } + // A bare require of a JSON document only parses it: nothing to + // evaluate (json-require.ts creates the cached object). + if (projectDep.fileName.endsWith(".json")) continue; deps.push({ dep: projectDep }); continue; } @@ -4930,6 +5432,8 @@ export { resolveImport7 as resolveImport, resolveNpmImport7 as resolveNpmImport, locOf7 as locOf, + requireEarlyReference7 as requireEarlyReference, + inDeferredPosition7 as inDeferredPosition, }; /** True for JavaScript source files (.js/.mjs/.cjs) — the files whose diff --git a/tests/corpus/6140-cjs-require-tdz-throws/lib.js b/tests/corpus/6140-cjs-require-tdz-throws/lib.js new file mode 100644 index 000000000..2a9669e12 --- /dev/null +++ b/tests/corpus/6140-cjs-require-tdz-throws/lib.js @@ -0,0 +1,8 @@ +'use strict'; + +/** @param {string} who */ +function greet(who) { + return `hello ${who}`; +} + +module.exports = { greet }; diff --git a/tests/corpus/6140-cjs-require-tdz-throws/main.js b/tests/corpus/6140-cjs-require-tdz-throws/main.js new file mode 100644 index 000000000..13163137e --- /dev/null +++ b/tests/corpus/6140-cjs-require-tdz-throws/main.js @@ -0,0 +1,15 @@ +// @exit: 1 +// A hoisted function called above the require reads the binding before +// the require ran: Node throws "Cannot access 'greet' before +// initialization" there, uncaught, and nothing after it runs. +'use strict'; + +console.log('start'); +console.log('boot', helper()); +const { greet } = require('./lib.js'); + +function helper() { + return greet('early'); +} + +console.log('unreachable', helper()); diff --git a/tests/corpus/6140-cjs-require-tdz-throws/package.json b/tests/corpus/6140-cjs-require-tdz-throws/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/corpus/6140-cjs-require-tdz-throws/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/corpus/6141-cjs-require-tdz-checked/counter.js b/tests/corpus/6141-cjs-require-tdz-checked/counter.js new file mode 100644 index 000000000..24ef13e5d --- /dev/null +++ b/tests/corpus/6141-cjs-require-tdz-checked/counter.js @@ -0,0 +1,14 @@ +'use strict'; + +class Counter { + /** @param {number} start */ + constructor(start) { + this.value = start; + } + next() { + this.value += 1; + return this.value; + } +} + +module.exports = Counter; diff --git a/tests/corpus/6141-cjs-require-tdz-checked/lib.js b/tests/corpus/6141-cjs-require-tdz-checked/lib.js new file mode 100644 index 000000000..aa15c97d6 --- /dev/null +++ b/tests/corpus/6141-cjs-require-tdz-checked/lib.js @@ -0,0 +1,8 @@ +'use strict'; + +/** @param {string} who */ +function greet(who) { + return `hello ${who}`; +} + +module.exports = { greet, answer: 42 }; diff --git a/tests/corpus/6141-cjs-require-tdz-checked/main.js b/tests/corpus/6141-cjs-require-tdz-checked/main.js new file mode 100644 index 000000000..917eb7874 --- /dev/null +++ b/tests/corpus/6141-cjs-require-tdz-checked/main.js @@ -0,0 +1,49 @@ +// Require bindings that code running before the require can read. Every +// read that happens before the require throws Node's ReferenceError for +// the local binding name, before any argument of the access evaluates; +// the same reads succeed once the require ran. +'use strict'; + +/** + * @param {string} label + * @param {() => unknown} read + */ +function attempt(label, read) { + try { + console.log(label, 'ok', read()); + } catch (e) { + if (!(e instanceof ReferenceError)) throw e; + console.log(label, e.name, e.message); + } +} + +/** @param {string} s */ +function note(s) { + console.log('evaluated', s); + return s; +} + +const later = [() => greet('later'), () => new Counter(5).next()]; + +attempt('call', () => greet('a')); +attempt('call-arguments', () => greet(note('argument'))); +attempt('member', () => lib.greet('b')); +attempt('construct', () => new Counter(1).next()); +attempt('builtin', () => path.join('a', 'b')); +attempt('value', () => answer + 1); +attempt('renamed', () => hello('c')); + +const { greet } = require('./lib.js'); +const lib = require('./lib.js'); +const Counter = require('./counter.js'); +const path = require('path'); +const { answer, greet: hello } = require('./lib.js'); + +attempt('call', () => greet('a')); +attempt('call-arguments', () => greet(note('argument'))); +attempt('member', () => lib.greet('b')); +attempt('construct', () => new Counter(1).next()); +attempt('builtin', () => path.join('a', 'b')); +attempt('value', () => answer + 1); +attempt('renamed', () => hello('c')); +for (const read of later) console.log('later', read()); diff --git a/tests/corpus/6141-cjs-require-tdz-checked/package.json b/tests/corpus/6141-cjs-require-tdz-checked/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/corpus/6141-cjs-require-tdz-checked/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/corpus/6142-cjs-require-published-early/comparator.js b/tests/corpus/6142-cjs-require-published-early/comparator.js new file mode 100644 index 000000000..2b2ea6146 --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/comparator.js @@ -0,0 +1,37 @@ +'use strict'; + +// The semver layout: the class and its export come first, the requires its +// methods use come after. Publishing the class runs none of its methods, so +// no read can happen before the requires ran. +const ANY = Symbol('ANY'); + +class Comparator { + static get ANY() { + return ANY; + } + + static describe() { + return `Comparator(${typeof parseOptions})`; + } + + /** + * @param {string} text + * @param {{ loose?: boolean }} [options] + */ + constructor(text, options) { + this.mode = parseOptions(options); + this.text = text.trim(); + debug('comparator', this.text, this.mode); + } + + /** @param {string} other */ + test(other) { + return path.basename(other) === this.text; + } +} + +module.exports = Comparator; + +const parseOptions = require('./parse-options.js'); +const { debug } = require('./debug.js'); +const path = require('path'); diff --git a/tests/corpus/6142-cjs-require-published-early/debug.js b/tests/corpus/6142-cjs-require-published-early/debug.js new file mode 100644 index 000000000..30451569b --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/debug.js @@ -0,0 +1,10 @@ +'use strict'; + +console.log('debug: init'); + +/** @param {...unknown} args */ +function debug(...args) { + console.log('debug:', args.join(' ')); +} + +module.exports = { debug }; diff --git a/tests/corpus/6142-cjs-require-published-early/glob.js b/tests/corpus/6142-cjs-require-published-early/glob.js new file mode 100644 index 000000000..3d2907f00 --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/glob.js @@ -0,0 +1,20 @@ +'use strict'; + +// The glob@7 layout with var: export first, then var requires, a runnable +// statement between them, and properties stored on the exported function. +module.exports = glob; +glob.sync = globSync; + +var parseOptions = require('./parse-options.js'); +var mode = parseOptions({ loose: true }); +var helpers = require('./helpers.js'); + +/** @param {string} pattern */ +function glob(pattern) { + return `${mode}:${helpers.normalize(pattern)}`; +} + +/** @param {string} pattern */ +function globSync(pattern) { + return helpers.normalize(pattern).toUpperCase(); +} diff --git a/tests/corpus/6142-cjs-require-published-early/helpers.js b/tests/corpus/6142-cjs-require-published-early/helpers.js new file mode 100644 index 000000000..206ca7785 --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/helpers.js @@ -0,0 +1,10 @@ +'use strict'; + +console.log('helpers: init'); + +/** @param {string} s */ +function normalize(s) { + return s.replace(/\/+/g, '/'); +} + +module.exports = { normalize }; diff --git a/tests/corpus/6142-cjs-require-published-early/main.js b/tests/corpus/6142-cjs-require-published-early/main.js new file mode 100644 index 000000000..9182f1cf5 --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/main.js @@ -0,0 +1,13 @@ +// CommonJS modules that export first and require afterwards: code that can +// reach the bindings only runs after the module finished, so they compile +// without a fence and behave exactly as under Node. +'use strict'; + +console.log('main: start'); +const Comparator = require('./comparator.js'); +const glob = require('./glob.js'); + +const c = new Comparator(' a.txt ', { loose: true }); +console.log(c.mode, c.text, c.test('/x/a.txt'), Comparator.ANY.toString()); +console.log(new Comparator('b').mode, Comparator.describe()); +console.log(glob('a//b'), glob.sync('c//d')); diff --git a/tests/corpus/6142-cjs-require-published-early/package.json b/tests/corpus/6142-cjs-require-published-early/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/corpus/6142-cjs-require-published-early/parse-options.js b/tests/corpus/6142-cjs-require-published-early/parse-options.js new file mode 100644 index 000000000..0872049ea --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/parse-options.js @@ -0,0 +1,8 @@ +'use strict'; + +/** @param {{ loose?: boolean } | undefined} options */ +function parseOptions(options) { + return options && options.loose ? 'loose' : 'strict'; +} + +module.exports = parseOptions; diff --git a/tests/corpus/6143-cjs-require-json/counter.js b/tests/corpus/6143-cjs-require-json/counter.js new file mode 100644 index 000000000..b794d1d4c --- /dev/null +++ b/tests/corpus/6143-cjs-require-json/counter.js @@ -0,0 +1,14 @@ +'use strict'; + +// A second requirer: it receives the same cached object and mutates it. +const data = require('./data.json'); + +console.log('counter: sees', data.count); +data.count += 1; + +function bump() { + data.count += 100; + data.tags.push('bumped'); +} + +module.exports = { bump }; diff --git a/tests/corpus/6143-cjs-require-json/data.json b/tests/corpus/6143-cjs-require-json/data.json new file mode 100644 index 000000000..b1cf3d3bc --- /dev/null +++ b/tests/corpus/6143-cjs-require-json/data.json @@ -0,0 +1,7 @@ +{ + "name": "fixture-data", + "version": "1.2.3", + "count": 41, + "tags": ["native", "json"], + "nested": { "flag": true, "ratio": 0.5 } +} diff --git a/tests/corpus/6143-cjs-require-json/list.json b/tests/corpus/6143-cjs-require-json/list.json new file mode 100644 index 000000000..98ace19c0 --- /dev/null +++ b/tests/corpus/6143-cjs-require-json/list.json @@ -0,0 +1 @@ +[3, 1, 2] diff --git a/tests/corpus/6143-cjs-require-json/main.js b/tests/corpus/6143-cjs-require-json/main.js new file mode 100644 index 000000000..b67c39f3e --- /dev/null +++ b/tests/corpus/6143-cjs-require-json/main.js @@ -0,0 +1,27 @@ +// require() of a JSON document: Node parses it at the first require and +// caches the object, so every require of the document, from any module, +// returns the same object and a mutation is visible to all requirers. +// Destructuring copies the properties at the require. +'use strict'; + +const data = require('./data.json'); +const { count, nested: { flag, ratio }, tags: [firstTag] } = require('./data.json'); +const version = require('./data.json').version; + +console.log(data.name, version, data.count, count, flag, ratio, firstTag); +console.log('same object', require('./data.json') === data); + +const { bump } = require('./counter.js'); +console.log('after counter', data.count, count); +bump(); +console.log('after bump', data.count, data.tags.join(','), count); + +function load() { + return require('./data.json'); +} +console.log('lazy same object', load() === data, load().count); +load().nested.flag = false; +console.log('flag', data.nested.flag, flag); + +const list = require('./list.json'); +console.log(list.length, list.slice().sort().join(','), require('./list.json') === list); diff --git a/tests/corpus/6143-cjs-require-json/package.json b/tests/corpus/6143-cjs-require-json/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/corpus/6143-cjs-require-json/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/corpus/6144-cjs-require-builtin-nested/main.js b/tests/corpus/6144-cjs-require-builtin-nested/main.js new file mode 100644 index 000000000..305876762 --- /dev/null +++ b/tests/corpus/6144-cjs-require-builtin-nested/main.js @@ -0,0 +1,15 @@ +// Nested destructuring of a builtin require (undici's `const { types: { +// isPromise } } = require('util')`): util.types IS the util/types module, +// so the nested pattern binds that module's members. +'use strict'; + +const { + types: { isPromise, isPromise: promiseCheck }, + format, +} = require('util'); +const { promises: { readFile } } = require('fs'); +const { posix: { join } } = require('path'); + +console.log(isPromise(Promise.resolve(1)), isPromise({}), promiseCheck(Promise.reject(new Error('x')).catch(() => {}))); +console.log(format('%s=%d', 'a', 1), join('a', 'b', '..', 'c')); +readFile(__filename, 'utf8').then((text) => console.log('read', text.includes('isPromise'))); diff --git a/tests/corpus/6144-cjs-require-builtin-nested/package.json b/tests/corpus/6144-cjs-require-builtin-nested/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/corpus/6144-cjs-require-builtin-nested/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/diagnostics/cjs-require-tdz-unchecked/lib.js b/tests/diagnostics/cjs-require-tdz-unchecked/lib.js new file mode 100644 index 000000000..2a9669e12 --- /dev/null +++ b/tests/diagnostics/cjs-require-tdz-unchecked/lib.js @@ -0,0 +1,8 @@ +'use strict'; + +/** @param {string} who */ +function greet(who) { + return `hello ${who}`; +} + +module.exports = { greet }; diff --git a/tests/diagnostics/cjs-require-tdz-unchecked/main.js b/tests/diagnostics/cjs-require-tdz-unchecked/main.js new file mode 100644 index 000000000..52b12fcb4 --- /dev/null +++ b/tests/diagnostics/cjs-require-tdz-unchecked/main.js @@ -0,0 +1,8 @@ +// A const require binding read by a statement above the require that +// lowers to no expression: publishing the binding as an export is module +// plumbing, so no initialization check can run where Node throws +// "Cannot access 'greet' before initialization". The read keeps SC1013. +'use strict'; + +module.exports = { greet }; +const { greet } = require('./lib.js'); diff --git a/tests/diagnostics/cjs-require-tdz-unchecked/package.json b/tests/diagnostics/cjs-require-tdz-unchecked/package.json new file mode 100644 index 000000000..5bbefffba --- /dev/null +++ b/tests/diagnostics/cjs-require-tdz-unchecked/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/tests/diagnostics/cjs-require-tdz/main.js b/tests/diagnostics/cjs-require-tdz/main.js index a571b4524..c2b5a945c 100644 --- a/tests/diagnostics/cjs-require-tdz/main.js +++ b/tests/diagnostics/cjs-require-tdz/main.js @@ -1,14 +1,15 @@ -// A require whose binding IS reachable from code above it: Node would -// throw "Cannot access 'greet' before initialization" at the helper() -// call (the const initializes AT the require), an ordering the compiled -// aliasing does not model — the require keeps a named SC1013 fence. +// A var require binding that code above the require can reach: Node reads +// undefined there (the var is hoisted, the require has not run), a value +// the compiled module alias cannot hold — the require keeps a named SC1013 +// fence. A const or let binding compiles with an initialization check +// instead (tests/corpus/6141-cjs-require-tdz-checked). 'use strict'; console.log('boot', helper()); -const { greet } = require('./lib.js'); +var lib = require('./lib.js'); function helper() { - return greet('early'); + return lib.greet('early'); } console.log(helper()); diff --git a/tests/harness/__snapshots__/cjs-require-tdz-unchecked/main.js.txt b/tests/harness/__snapshots__/cjs-require-tdz-unchecked/main.js.txt new file mode 100644 index 000000000..eda869e9a --- /dev/null +++ b/tests/harness/__snapshots__/cjs-require-tdz-unchecked/main.js.txt @@ -0,0 +1,6 @@ +cjs-require-tdz-unchecked/main.js:7:20 - error SC1013: reading require() binding 'greet' where it can run before the require (this use has no checked form for Node's ReferenceError — move the require above the code that can run first) is not supported yet + + 6 | + 7 | module.exports = { greet }; + | ^~~~~ + 8 | const { greet } = require('./lib.js'); \ No newline at end of file diff --git a/tests/harness/__snapshots__/cjs-require-tdz/main.js.txt b/tests/harness/__snapshots__/cjs-require-tdz/main.js.txt index 6316ce98b..295f7cd0c 100644 --- a/tests/harness/__snapshots__/cjs-require-tdz/main.js.txt +++ b/tests/harness/__snapshots__/cjs-require-tdz/main.js.txt @@ -1,6 +1,6 @@ -cjs-require-tdz/main.js:8:7 - error SC1013: require() below code that can reach its binding 'greet' (Node initializes the binding AT the require and throws ReferenceError on any earlier access, which is not modeled — move the require above the code that can run first) is not supported yet +cjs-require-tdz/main.js:9:5 - error SC1013: var require() binding 'lib' below code that can reach it (Node reads undefined before the require runs, which is not modeled — declare it with const or let, or move the require above the code that can run first) is not supported yet - 7 | console.log('boot', helper()); - 8 | const { greet } = require('./lib.js'); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 9 | \ No newline at end of file + 8 | console.log('boot', helper()); + 9 | var lib = require('./lib.js'); + | ^~~~~~~~~~~~~~~~~~~~~~~~~ + 10 | \ No newline at end of file From e0998f017285eeb8839426f49dd15119491c8229 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 22:25:55 -0500 Subject: [PATCH 030/117] Prove generic classes acyclic like other classes Each instantiation of a generic class names the generic class as its base, and the generic class has no constructor function. The cycle analysis treated a base without a constructor function as one whose constructor let `this` escape, so every store in an instantiation's constructor counted as a write after construction. A generic class could not be declared Acyclic, and its constructor-only references were never treated as immutable. A program class without a constructor function runs no code at construction, so it now lets nothing escape. Runtime classes keep the conservative answer. --- .../src/backend/cycle-analysis.test.ts | 13 +++++++++++ .../compiler/src/backend/cycle-mutability.ts | 9 ++++++-- tests/corpus/4642-acyclic-contract.ts | 22 +++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/backend/cycle-analysis.test.ts b/packages/compiler/src/backend/cycle-analysis.test.ts index 5fb408403..8972b9e70 100644 --- a/packages/compiler/src/backend/cycle-analysis.test.ts +++ b/packages/compiler/src/backend/cycle-analysis.test.ts @@ -513,6 +513,19 @@ test("a subclass constructor runs after its base constructor's escape", () => { checkExact(mod, ["object:Base", "object:Sub"], ["link"]); }); +test("a base without a constructor function lets nothing escape", () => { + // Instantiations of a generic class name the generic class as their base, + // which has no constructor function of its own. + const mod = module(); + mod.classes = [ + { name: "Chain", fields: [{ name: "next", type: link }], loc }, + { name: "Chain%0", base: "Chain", fields: [{ name: "next", type: link }], loc }, + ]; + mod.unions = [{ id: "link", arms: [obj("Chain%0"), { kind: "nullT" }] }]; + mod.functions.push(ctor("Chain%0", [setThis("Chain%0", "next", link)])); + checkExact(mod, []); +}); + test("field reads of this inside the constructor do not escape", () => { const read: IrStmt = { kind: "fieldSet", diff --git a/packages/compiler/src/backend/cycle-mutability.ts b/packages/compiler/src/backend/cycle-mutability.ts index 24d3c470f..c7d476527 100644 --- a/packages/compiler/src/backend/cycle-mutability.ts +++ b/packages/compiler/src/backend/cycle-mutability.ts @@ -216,8 +216,13 @@ export function computeCycleMutability( escapePoints.set(name, point); return point; }; - const escapes = (name: string): boolean => - escapePoint(name) < (fnByName.get(`%${name}.constructor`)?.body.length ?? 1); + const escapes = (name: string): boolean => { + const fn = fnByName.get(`%${name}.constructor`); + // A program class without a constructor function runs no code at construction. Generic + // classes are such bases: their instantiations name them as their base. + if (fn === undefined && classByName.get(name)?.runtime !== true) return false; + return escapePoint(name) < (fn?.body.length ?? 1); + }; const ancestorEscaped = (name: string): boolean => { for (let c = classByName.get(name)?.base; c !== undefined; c = classByName.get(c)?.base) if (escapes(c)) return true; diff --git a/tests/corpus/4642-acyclic-contract.ts b/tests/corpus/4642-acyclic-contract.ts index dffbba761..bbd256fe1 100644 --- a/tests/corpus/4642-acyclic-contract.ts +++ b/tests/corpus/4642-acyclic-contract.ts @@ -50,6 +50,16 @@ interface Point extends Acyclic { type Segment = Acyclic<{ readonly from: Point; readonly to: Point; readonly label: string }>; +// A generic class is acyclic like any other class. +class Chain implements Acyclic { + readonly value: T; + readonly next: Chain | undefined; + constructor(value: T, next: Chain | undefined) { + this.value = value; + this.next = next; + } +} + function build(depth: number): Tree { return depth === 0 ? new Tree(null, null, 1) : new Tree(build(depth - 1), build(depth - 1), depth); } @@ -74,3 +84,15 @@ const slots: Record = { a: new Slot() }; for (let i = 0; i < 3; i++) slots["a"]!.index = (slots["a"]!.index + 2) | 0; slots["b"] = new Slot(); console.log(Object.keys(slots).join(","), slots["a"]!.index, slots["b"]!.index); + +let numbers: Chain | undefined = undefined; +let words: Chain | undefined = undefined; +for (let i = 0; i < 1000; i++) { + numbers = new Chain(i, numbers); + words = new Chain(`w${i % 7}`, words); +} +let chained = 0; +for (let c = numbers; c !== undefined; c = c.next) chained += c.value; +let longest = ""; +for (let c = words; c !== undefined; c = c.next) if (c.value > longest) longest = c.value; +console.log(chained, longest); From 82c699b437b6157b7f819ea3e1df56a5df7e46bd Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 22:40:13 -0500 Subject: [PATCH 031/117] Add DisposableStack new DisposableStack() compiles to a native stack handle. use, adopt, defer, move, dispose, disposed and [Symbol.dispose] are members of its dynamic view, and the stack works with `using`. Disposal runs the resources in reverse order, calls use() resources' dispose methods with the resource as `this`, and raises a SuppressedError chain when more than one disposal throws; a single failure is rethrown as thrown. Calls on a disposed stack throw Node's ReferenceError, and invalid receivers, resources and callbacks throw Node's TypeErrors. use() of a class instance registers a function that calls the class's [Symbol.dispose] method, and returns the instance at its static type; use() of a union that includes class instances is refused. The stack is collected with its callbacks when a callback captures the stack. x instanceof DisposableStack compiles. Handles can expose symbol-keyed members through a new symbol_get hook. --- .../language-features/resource-disposal.mdx | 2 +- .../compiler/src/backend/llvm/lib-dispatch.ts | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 3 + .../lowering/builtins/disposable-stack.ts | 136 +++++++ .../src/frontend/lowering/lower-calls.ts | 2 + .../src/frontend/lowering/lower-exprs.ts | 5 + .../compiler/src/frontend/lowering/lowerer.ts | 2 + packages/compiler/src/frontend/type-mapper.ts | 8 +- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 7 + packages/compiler/src/ir/runtime-features.ts | 3 +- .../corpus/5858-disposable-stack.ts.json | 6 + .../corpus/5859-disposable-stack-js.js.json | 6 + packages/runtime/src/scr_dyn.h | 18 + packages/runtime/src/scr_json.c | 12 +- packages/runtime/src/scr_symbol.c | 368 ++++++++++++++++++ tests/corpus/5858-disposable-stack.ts | 157 ++++++++ tests/corpus/5859-disposable-stack-js.js | 77 ++++ tests/harness/corpus-costs.json | 4 + 19 files changed, 811 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5858-disposable-stack.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5859-disposable-stack-js.js.json create mode 100644 tests/corpus/5858-disposable-stack.ts create mode 100644 tests/corpus/5859-disposable-stack-js.js diff --git a/docs/content/limitations/language-features/resource-disposal.mdx b/docs/content/limitations/language-features/resource-disposal.mdx index 5163d5322..d3df4138e 100644 --- a/docs/content/limitations/language-features/resource-disposal.mdx +++ b/docs/content/limitations/language-features/resource-disposal.mdx @@ -1 +1 @@ -- **Resource disposal:** Top-level and switch-clause `using` declarations, and `DisposableStack` constructors are unsupported. Block- and function-scoped `using` and `await using` support compiled classes with zero-parameter disposal methods, object literals and other `Disposable`- or `AsyncDisposable`-typed values, and supported FileHandle, timer, immediate, child-process, and readline handles. A class instance reached through a `Disposable`- or `unknown`-typed value throws an SC2020 error when its declaration runs; declare the variable with the class type. Array `for (using ... of ...)` loops also compile. `SuppressedError` values expose `error` and `suppressed`; `extends SuppressedError` and casting `unknown` to `SuppressedError` are unsupported (narrow with `instanceof`). +- **Resource disposal:** Top-level and switch-clause `using` declarations, and `AsyncDisposableStack`, are unsupported. Block- and function-scoped `using` and `await using` support compiled classes with zero-parameter disposal methods, object literals and other `Disposable`- or `AsyncDisposable`-typed values, and supported FileHandle, timer, immediate, child-process, and readline handles. A class instance reached through a `Disposable`- or `unknown`-typed value throws an SC2020 error when its declaration runs; declare the variable with the class type. Array `for (using ... of ...)` loops also compile. `SuppressedError` values expose `error` and `suppressed`; `extends SuppressedError` and casting `unknown` to `SuppressedError` are unsupported (narrow with `instanceof`). `DisposableStack` supports `use`, `adopt`, `defer`, `move`, `dispose`, `disposed` and `[Symbol.dispose]`, and works with `using`; `use` accepts class instances, object literals and other `Disposable`-typed values, and refuses unions that include class instances (narrow the value first). Disposal runs in reverse order and raises Node's `SuppressedError` chain when more than one callback throws. diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index 50804bf5a..b5c524da8 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -680,6 +680,7 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { case "events": case "blob": case "record": + case "disposable": return host.emitGenericLibCall(e); case "test": return emitTestLibCall(host, e); diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9232cbd03..e5d16d85d 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -1324,6 +1324,9 @@ export const LIB_FN_SYMS: Record = { "dyn.reflectGet": "scr_dyn_reflect_get", "dyn.usingMethod": "scr_dyn_using_method", "dyn.usingDispose": "scr_dyn_using_dispose", + "disposable.stackNew": "scr_disposable_stack_new", + "disposable.stackIs": "scr_disposable_stack_is", + "disposable.stackUseCallback": "scr_disposable_stack_use_callback", "dyn.reflectSet": "scr_dyn_reflect_set", "dyn.reflectDefine": "scr_dyn_reflect_define", "dyn.abstractEq": "scr_dyn_abstract_eq", diff --git a/packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts b/packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts new file mode 100644 index 000000000..469a66ace --- /dev/null +++ b/packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts @@ -0,0 +1,136 @@ +import * as ts from "../../ts7/adapter.js"; +import { type Lowerer } from "../lowerer.js"; +import { locOf } from "../../program.js"; +import { newFnCtx } from "../function-context.js"; +import { BOOL, DYN, VOID, type IrExpr, type IrType } from "../../../ir/ir.js"; +import { varRef } from "../../../ir/build.js"; + +/** Whether `node`'s static type is the standard library's DisposableStack. */ +function isStdlibDisposableStack(lowerer: Lowerer, node: ts.Expression): boolean { + const type = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(node)); + for (const symbol of [type.getSymbol(), type.getAliasSymbol()]) { + if (symbol?.name === "DisposableStack" && lowerer.isStdlibSymbol(symbol)) return true; + } + return false; +} + +/** `new DisposableStack()`: a native stack handle (scr_symbol.c). Its + * members are function values and getters of the handle, reached through + * the checked-dynamic method and property paths. Null for other + * constructors. */ +export function lowerDisposableStackNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr | null { + if (!ts.isIdentifier(expr.expression) || expr.expression.text !== "DisposableStack") return null; + const symbol = lowerer.resolveValueSymbol(expr.expression); + if (!symbol || !lowerer.isStdlibSymbol(symbol)) return null; + if ((expr.arguments ?? []).length !== 0) return null; + return { kind: "libCall", fn: "disposable.stackNew", args: [], type: DYN, loc: locOf(expr) }; +} + +/** `x instanceof DisposableStack`, or null when the right side is not the + * standard library's DisposableStack. */ +export function lowerDisposableStackInstanceOf( + lowerer: Lowerer, + expr: ts.BinaryExpression, +): IrExpr | null { + if (!lowerer.isStdlibGlobal(expr.right, "DisposableStack")) return null; + const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); + return { kind: "libCall", fn: "disposable.stackIs", args: [value], type: BOOL, loc: locOf(expr) }; +} + +/** `stack.use(value)` where `value` is a class instance. The dyn view of a + * class instance has no methods, so the stack receives a function that + * calls the class's [Symbol.dispose] method on the value, and the call + * answers the value at its static type. Other values take the + * checked-dynamic method path, which reads the value's [Symbol.dispose]. + * Null when the call is not that form. */ +export function lowerDisposableStackUseCall( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.PropertyAccessExpression, +): IrExpr | null { + if (call.questionDotToken || access.questionDotToken) return null; + if (access.name.text !== "use" || call.arguments.length !== 1) return null; + const argNode = call.arguments[0]!; + if (ts.isSpreadElement(argNode)) return null; + if (!isStdlibDisposableStack(lowerer, access.expression)) return null; + const valueT = lowerer.mapTypeOf(lowerer.typeOf(argNode)); + if (valueT?.kind === "union") { + const arms = lowerer.unions.get(valueT.unionId)?.arms ?? []; + if (arms.some((arm) => arm.kind === "object")) { + lowerer.unsupported( + "SC1090", + argNode, + "DisposableStack.use on a union with class instances (narrow the value to the class first)", + ); + } + } + if (valueT?.kind !== "object") return null; + const loc = locOf(call); + const className = valueT.className; + const info = lowerer.classes.get(className); + if (!info) lowerer.flushDeferredClass(className); + const found = info ? lowerer.findMethodOn(info, "sym:dispose") : null; + if (!found) return null; + if (found.sig.params.length !== 0) { + lowerer.unsupported("SC1090", argNode, "[Symbol.dispose] methods with parameters"); + } + const stack = lowerer.lowerExpr(access.expression); + const value = lowerer.lowerExpr(argNode); + const key = `disposableStack.use:${className}`; + let helper = lowerer.valueHelpers.get(key); + if (!helper) { + helper = `%disposableStack.use.${lowerer.valueHelpers.size}`; + lowerer.valueHelpers.set(key, helper); + const context = newFnCtx(false, null, null, VOID); + lowerer.fnStack.push(context); + try { + const param = lowerer.declareHiddenLocal("value", valueT); + const self = varRef(param.id, valueT, loc); + lowerer.liftedFns.push({ + name: helper, + params: [{ localId: param.id, name: "value", type: valueT }], + returnType: VOID, + locals: context.locals, + body: [ + { + kind: "exprStmt", + expr: lowerer.accessorCall(className, "sym:dispose", self, [], found.sig.ret, loc), + loc, + }, + ], + loc, + }); + } finally { + lowerer.fnStack.pop(); + } + } + const stackLocal = lowerer.declareHiddenLocal("%disposableStack", DYN); + const valueLocal = lowerer.declareHiddenLocal("%disposableValue", valueT); + const fnT: IrType = { kind: "func", params: [valueT], ret: VOID }; + const dispose: IrExpr = { kind: "closure", fnName: helper, captures: [], type: fnT, loc }; + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: stackLocal.id, init: stack, loc }, + { kind: "varDecl", localId: valueLocal.id, init: value, loc }, + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "disposable.stackUseCallback", + args: [ + varRef(stackLocal.id, DYN, loc), + lowerer.coerceToExpected(varRef(valueLocal.id, valueT, loc), DYN), + lowerer.coerceToExpected(dispose, DYN), + ], + type: BOOL, + loc, + }, + loc, + }, + ], + result: varRef(valueLocal.id, valueT, loc), + type: valueT, + loc, + }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 2ba83a3d5..b71510ebf 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -106,6 +106,7 @@ import { } from "./builtins/module-resolution.js"; import { lowerCipherMethodCall, lowerCryptoHashMethodCall } from "./builtins/crypto.js"; import { lowerErrorIsErrorCall } from "./builtins/errors.js"; +import { lowerDisposableStackUseCall } from "./builtins/disposable-stack.js"; import { lowerDirentMethodCall, lowerFileHandleMethodCall, @@ -1379,6 +1380,7 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { lowerer.fenceStaticResponseMember(expr.expression, "call") ?? lowerer.fenceStaticHeadersMember(expr.expression, "call") ?? lowerer.fenceStaticReadableStreamMember(expr.expression, "call") ?? + lowerDisposableStackUseCall(lowerer, expr, expr.expression) ?? lowerer.lowerStdlibMethodCall(expr, expr.expression) ?? // Dyn receivers (JSON.parse-derived `unknown`/`any` values) — diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 08e12518b..1a4126672 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -2,6 +2,7 @@ import { guardNullProto, nullProtoRecordShape, recordNullProtoTest } from "./nul import { lowerProtocolPropertyRead } from "./class-protocol-dispatch.js"; import { generatorDrain } from "./iterator-adapters.js"; import { lowerEventObjectProperty, lowerEventObjectPropertyWrite } from "./lower-event-target.js"; +import { lowerDisposableStackInstanceOf } from "./builtins/disposable-stack.js"; import { lowerEventStaticProperty } from "./builtins/numbers.js"; import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js"; import { isOptionalProcessStreamProperty } from "./builtins/process.js"; @@ -11972,6 +11973,10 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); return { kind: "libCall", fn: "dyn.nativeUrlIs", args: [value], type: BOOL, loc }; } + { + const stack = lowerDisposableStackInstanceOf(lowerer, expr); + if (stack) return stack; + } if (lowerer.isStdlibGlobal(expr.right, "DataView")) { const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); return { kind: "libCall", fn: "dyn.dataViewIs", args: [value], type: BOOL, loc }; diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index d4cf82752..e17e4ccdc 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -417,6 +417,7 @@ import { lowerTracingChannelMethodCall, lowerTracingChannelProperty, } from "./builtins/async-context.js"; +import { lowerDisposableStackNew } from "./builtins/disposable-stack.js"; import { lowerErrorCodeProperty } from "./builtins/errors.js"; import { lowerProcessProperty, @@ -11063,6 +11064,7 @@ export class Lowerer { lowerLifetimeRegionNew(this, expr) ?? lowerInternTableNew(this, expr) ?? lowerAbortControllerNew(this, expr) ?? + lowerDisposableStackNew(this, expr) ?? lowerEventTargetNew(this, expr) ?? lowerFetchWebNew(this, expr) ?? lowerResponseNew(this, expr) ?? diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 54fb8f70e..e78ae59cc 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -2377,9 +2377,13 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // representation and consumed by the console method lowerings. The // stdlib Disposable (events.addAbortListener's result) and // AsyncDisposable are checked objects carrying their Symbol.dispose or - // Symbol.asyncDispose method. + // Symbol.asyncDispose method. A DisposableStack is a native handle whose + // methods are function values of its checked-dynamic view. if ( - (psym?.name === "Console" || psym?.name === "Disposable" || psym?.name === "AsyncDisposable") && + (psym?.name === "Console" || + psym?.name === "Disposable" || + psym?.name === "AsyncDisposable" || + psym?.name === "DisposableStack") && checker .declarationsOf(psym) .some((d) => ts.isInterfaceDeclaration(d) && ctx.isStdlibFile(d.getSourceFile())) diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 2381413f8..13e78ec10 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -39,6 +39,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "dyn.reflectGet", "dyn.usingMethod", "dyn.usingDispose", + "disposable.stackUseCallback", "dyn.reflectSet", "dyn.reflectDefine", "dyn.abstractEq", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 5e219ecf6..b9e692975 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3210,6 +3210,13 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * `await using`. Both throw Node's TypeErrors or the method's error. */ "dyn.usingMethod": { argTypes: [DYN, BOOL], result: DYN }, "dyn.usingDispose": { argTypes: [DYN, DYN], result: DYN }, + /** DisposableStack (scr_symbol.c): a new stack handle; whether a value is + * one; and `stack.use(value)` for a class instance, registering the + * compiler's disposal function for it. The last throws Node's + * ReferenceError on a disposed stack. */ + "disposable.stackNew": { argTypes: [], result: DYN }, + "disposable.stackIs": { argTypes: [DYN], result: BOOL }, + "disposable.stackUseCallback": { argTypes: [DYN, DYN, DYN], result: BOOL }, "dyn.reflectSet": { argTypes: [DYN, DYN, DYN, DYN], result: BOOL }, "dyn.reflectDefine": { argTypes: [DYN, DYN, DYN], result: BOOL }, "dyn.abstractEq": { argTypes: [DYN, DYN], result: BOOL }, diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 80a9c9b57..94c3331ce 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -377,7 +377,8 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run fn.startsWith("sym.") || fn === "util.isDeepStrictEqual" || fn === "dyn.usingMethod" || - fn === "dyn.usingDispose" + fn === "dyn.usingDispose" || + fn.startsWith("disposable.") ) features.symbol = true; if (fn === "process.hrtimeValue") features.bigint = true; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5858-disposable-stack.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5858-disposable-stack.ts.json new file mode 100644 index 000000000..316261387 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5858-disposable-stack.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5858-disposable-stack.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5859-disposable-stack-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5859-disposable-stack-js.js.json new file mode 100644 index 000000000..f35375f63 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5859-disposable-stack-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5859-disposable-stack-js.js" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 375ced573..392670bef 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -168,6 +168,7 @@ typedef enum { SCR_DYNH_DECIPHER, /* node:crypto Decipheriv (scr_cipher.c) */ SCR_DYNH_NET_SOCKET_ADDRESS, /* net.SocketAddress (scr_net.c) */ SCR_DYNH_NET_BLOCK_LIST, /* net.BlockList (scr_net.c) */ + SCR_DYNH_DISPOSABLE_STACK, /* DisposableStack (scr_symbol.c) */ SCR_DYNH_COUNT, } ScrDynHandleTag; @@ -619,6 +620,19 @@ ScrDyn *scr_dyn_symbol_key_get(const ScrDyn *value, const ScrDyn *key, bool opti * and return NULL with the exception pending. */ ScrDyn *scr_dyn_using_method(const ScrDyn *value, bool async); ScrDyn *scr_dyn_using_dispose(const ScrDyn *method, const ScrDyn *value); +/* DisposableStack (scr_symbol.c). scr_disposable_stack_new answers a new + * stack (+1). The use, adopt and defer calls borrow their operands, throw + * Node's ReferenceError on a disposed stack and Node's TypeError on an + * invalid resource or callback, and return false with the exception + * pending. scr_disposable_stack_use_callback registers `dispose(value)` + * with the error texts of use(); the compiler passes it the disposal of a + * class instance, whose dyn view has no methods. The stack's other members + * are function values and getters of its dyn handle. */ +ScrDyn *scr_disposable_stack_new(void); +bool scr_disposable_stack_is(const ScrDyn *value); +bool scr_disposable_stack_use(const ScrDyn *stack, const ScrDyn *value); +bool scr_disposable_stack_use_callback(const ScrDyn *stack, const ScrDyn *value, const ScrDyn *dispose); +bool scr_disposable_stack_adopt(const ScrDyn *stack, const ScrDyn *value, const ScrDyn *on_dispose); void scr_dyn_symbol_key_set(ScrDyn *value, ScrDyn *key, ScrDyn *stored); void scr_dyn_symbol_key_placeholder(ScrDyn *value, ScrDyn *key); bool scr_dyn_has_key_computed(const ScrDyn *value, const ScrDyn *key); @@ -1129,6 +1143,10 @@ typedef struct ScrDynHandleOps { /* The view has no properties, so util.inspect prints it in full at any * depth, as Node prints `{}`. */ bool inspect_view_empty; + /* A symbol-keyed READ (`stack[Symbol.dispose]`, the `using` method + * lookup): +1 value, or NULL when the class has no member for `key` + * (the read answers undefined). NULL hook = no symbol-keyed members. */ + ScrDyn *(*symbol_get)(void *h, const ScrDyn *key); } ScrDynHandleOps; ScrDyn *scr_dyn_native_handle_iterator(ScrDyn *source, unsigned selection); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index cdfb3d0f9..99920dacd 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -3840,7 +3840,7 @@ ScrDyn *scr_dyn_new_handle(void *h, ScrDynHandleTag tag) { d->v.handle.ptr = scr_dyn_handle_ops(tag)->retain(h); d->v.handle.tag = tag; d->v.handle.traced = tag == SCR_DYNH_WEAK_MAP || tag == SCR_DYNH_WEAK_SET || - tag == SCR_DYNH_WORKER || tag == SCR_DYNH_MESSAGE_PORT || + tag == SCR_DYNH_WORKER || tag == SCR_DYNH_MESSAGE_PORT || tag == SCR_DYNH_DISPOSABLE_STACK || ((tag == SCR_DYNH_SET || tag == SCR_DYNH_MAP) && ((ScrMap *)h)->traced != 0); return d; @@ -4820,6 +4820,11 @@ ScrDyn *scr_dyn_symbol_key_get(const ScrDyn *value, const ScrDyn *key, bool opti } bool builtin = scr_iterator_symbol && key->v.symbol.value == scr_iterator_symbol->v.symbol.value && scr_builtin_iterable(value); if (builtin && value->kind != SCR_DYN_ARR) return scr_builtin_iterator_method(value); + if (value->kind == SCR_DYN_HANDLE) { + const ScrDynHandleOps *ops = scr_dyn_handle_ops(value->v.handle.tag); + ScrDyn *member = ops->symbol_get ? ops->symbol_get(value->v.handle.ptr, key) : NULL; + if (member || scr_exc_pending()) return member; + } ScrDyn *receiver = scr_dyn_symbol_receiver(value); if (!receiver) return scr_exc_pending() ? NULL : scr_dyn_retain(scr_dyn_undefined()); ScrDynEntry *entry = scr_dyn_symbol_entry(receiver, key, false); @@ -5343,7 +5348,7 @@ ScrStr *scr_dyn_object_tag(const ScrDyn *d) { d->v.handle.tag == SCR_DYNH_WEAK_MAP || d->v.handle.tag == SCR_DYNH_WEAK_SET || d->v.handle.tag == SCR_DYNH_SET || d->v.handle.tag == SCR_DYNH_MAP || d->v.handle.tag == SCR_DYNH_REGEXP || d->v.handle.tag == SCR_DYNH_DATE || d->v.handle.tag == SCR_DYNH_BLOB || - d->v.handle.tag == SCR_DYNH_FILE) { + d->v.handle.tag == SCR_DYNH_FILE || d->v.handle.tag == SCR_DYNH_DISPOSABLE_STACK) { ScrJsonBuf b; scr_jb_init(&b); scr_jb_puts(&b, "[object "); @@ -5928,7 +5933,8 @@ ScrStr *scr_dyn_to_string(const ScrDyn *d, const ScrStr *enc) { if ((d->v.handle.tag >= SCR_DYNH_ABORT_SIGNAL && d->v.handle.tag <= SCR_DYNH_ABORT_CONTROLLER) || d->v.handle.tag == SCR_DYNH_EVENT_TARGET || d->v.handle.tag == SCR_DYNH_CUSTOM_EVENT || d->v.handle.tag == SCR_DYNH_ARRAY_BUFFER || d->v.handle.tag == SCR_DYNH_SHARED_ARRAY_BUFFER || d->v.handle.tag == SCR_DYNH_SET || d->v.handle.tag == SCR_DYNH_MAP || - d->v.handle.tag == SCR_DYNH_BLOB || d->v.handle.tag == SCR_DYNH_FILE) { + d->v.handle.tag == SCR_DYNH_BLOB || d->v.handle.tag == SCR_DYNH_FILE || + d->v.handle.tag == SCR_DYNH_DISPOSABLE_STACK) { ScrJsonBuf b; scr_jb_init(&b); scr_jb_puts(&b, "[object "); diff --git a/packages/runtime/src/scr_symbol.c b/packages/runtime/src/scr_symbol.c index a29a28ad2..ebfb56291 100644 --- a/packages/runtime/src/scr_symbol.c +++ b/packages/runtime/src/scr_symbol.c @@ -457,3 +457,371 @@ ScrDyn *scr_dyn_using_dispose(const ScrDyn *method, const ScrDyn *value) { scr_dyn_release(result); return scr_dyn_retain(scr_dyn_undefined()); } + +/* ── DisposableStack ─────────────────────────────────────────────────── + * The stack is a collector-headered object behind a traced dyn handle: its + * resources hold callbacks that can capture the stack itself. Each entry + * records how disposal calls it: `use` calls the value's dispose method + * with the value as `this`, `adopt` calls the callback with the value, and + * `defer` calls the callback with no arguments. Disposal runs the entries + * in reverse order; each later failure becomes a SuppressedError over the + * error so far, and a single failure is rethrown as it was thrown. */ +enum { SCR_DS_USE, SCR_DS_ADOPT, SCR_DS_DEFER }; + +typedef struct { + ScrDyn *value; /* the resource (use, adopt); NULL for defer */ + ScrDyn *method; + unsigned kind; + /* Which members the last trace visited: the collector frees those + * itself, and gcfree must not read them afterwards. */ + bool value_traced, method_traced; +} ScrDisposableResource; + +typedef struct { + size_t rc; + bool disposed; + ScrDisposableResource *items; + size_t len, cap; +} ScrDisposableStack; + +static bool scr_ds_traced(const ScrDyn *value) { + return value && value->kind > SCR_DYN_STR && value->kind != SCR_DYN_UNDEF; +} + +static void scr_ds_trace(void *ptr, ScrTraceVisit visit, void *ctx) { + ScrDisposableStack *s = ptr; + for (size_t i = 0; i < s->len; i++) { + ScrDisposableResource *r = &s->items[i]; + r->value_traced = scr_ds_traced(r->value); + r->method_traced = scr_ds_traced(r->method); + if (r->value_traced) visit(r->value, ctx); + if (r->method_traced) visit(r->method, ctx); + } +} + +/* The collector frees traced members itself; the rest are released here. */ +static void scr_ds_gcfree(void *ptr) { + ScrDisposableStack *s = ptr; + for (size_t i = 0; i < s->len; i++) { + if (!s->items[i].value_traced) scr_dyn_release(s->items[i].value); + if (!s->items[i].method_traced) scr_dyn_release(s->items[i].method); + } + free(s->items); + scr_obj_free_note(); + scr_cyc_free(ptr); +} + +static void scr_ds_destroy(void *ptr) { + ScrDisposableStack *s = ptr; + for (size_t i = 0; i < s->len; i++) { + scr_dyn_release(s->items[i].value); + scr_dyn_release(s->items[i].method); + } + s->len = 0; + scr_ds_gcfree(ptr); +} + +static void *scr_ds_retain(void *ptr) { + ((ScrDisposableStack *)ptr)->rc++; + return ptr; +} + +static void scr_ds_release(void *ptr) { + ScrDisposableStack *s = ptr; + if (!s) return; + if (--s->rc == 0) { + scr_cyc_dead(s); + scr_rc_destroy(s, scr_ds_destroy); + } else scr_cyc_released(s); +} + +static void scr_ds_push(ScrDisposableStack *s, ScrDyn *value, ScrDyn *method, unsigned kind) { + if (s->len == s->cap) { + size_t cap = s->cap ? s->cap * 2 : 4; + ScrDisposableResource *items = realloc(s->items, cap * sizeof *items); + if (!items) scr_trap("scriptc: out of memory\n"); + s->items = items; + s->cap = cap; + } + s->items[s->len++] = (ScrDisposableResource){value, method, kind, false, false}; +} + +/* V8's rendering of a value in a TypeError: primitives by ToString, + * arrays as [object Array], other objects as #. */ +static void scr_ds_put_value(ScrJsonBuf *b, const ScrDyn *value) { + switch (value->kind) { + case SCR_DYN_UNDEF: scr_jb_puts(b, "undefined"); return; + case SCR_DYN_NULL: scr_jb_puts(b, "null"); return; + case SCR_DYN_BOOL: + case SCR_DYN_NUM: + case SCR_DYN_STR: + case SCR_DYN_BIGINT: { + ScrStr *text = scr_dyn_to_string(value, NULL); + if (text) scr_jb_write(b, text->data, text->len); + scr_str_release(text); + return; + } + case SCR_DYN_SYMBOL: { + ScrStr *text = value->v.symbol.render(value->v.symbol.value); + scr_jb_write(b, text->data, text->len); + scr_str_release(text); + return; + } + case SCR_DYN_ARR: scr_jb_puts(b, "[object Array]"); return; + case SCR_DYN_HANDLE: + scr_jb_puts(b, "#<"); + scr_jb_puts(b, scr_dyn_handle_cls(value)); + scr_jb_putc(b, '>'); + return; + default: scr_jb_puts(b, "#"); return; + } +} + +static ScrDisposableStack *scr_ds_of(const ScrDyn *value) { + return value && value->kind == SCR_DYN_HANDLE && value->v.handle.tag == SCR_DYNH_DISPOSABLE_STACK + ? value->v.handle.ptr : NULL; +} + +bool scr_disposable_stack_is(const ScrDyn *value) { return scr_ds_of(value) != NULL; } + +/* The receiver of DisposableStack.prototype., or NULL with Node's + * TypeError (an incompatible receiver) or ReferenceError (a disposed + * stack, when `live` is required) pending. */ +static ScrDisposableStack *scr_ds_receiver(const ScrDyn *self, const char *name, bool getter, bool live) { + ScrDisposableStack *s = scr_ds_of(self); + ScrJsonBuf message; + if (!s) { + scr_jb_init(&message); + scr_jb_puts(&message, getter ? "Method get DisposableStack.prototype." : "Method DisposableStack.prototype."); + scr_jb_puts(&message, name); + scr_jb_puts(&message, " called on incompatible receiver "); + scr_ds_put_value(&message, self); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&message)); + return NULL; + } + if (live && s->disposed) { + scr_jb_init(&message); + scr_jb_puts(&message, "Cannot call DisposableStack.prototype."); + scr_jb_puts(&message, name); + scr_jb_puts(&message, " on an already-disposed DisposableStack"); + scr_throw_error(SCR_ERR_REFERENCE, scr_jb_finish(&message)); + return NULL; + } + return s; +} + +static bool scr_ds_callable(const ScrDyn *value) { + if (scr_using_typeof_is(value, "function", 8)) return true; + ScrJsonBuf message; + scr_jb_init(&message); + scr_ds_put_value(&message, value); + scr_jb_puts(&message, " is not a function"); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&message)); + return false; +} + +bool scr_disposable_stack_use(const ScrDyn *stack, const ScrDyn *value) { + ScrDisposableStack *s = scr_ds_receiver(stack, "use", false, true); + if (!s) return false; + if (value->kind == SCR_DYN_NULL || value->kind == SCR_DYN_UNDEF) return true; + ScrDyn *method = scr_dyn_using_method(value, false); + if (!method) return false; + scr_ds_push(s, scr_dyn_retain((ScrDyn *)value), method, SCR_DS_USE); + return true; +} + +bool scr_disposable_stack_use_callback(const ScrDyn *stack, const ScrDyn *value, const ScrDyn *dispose) { + ScrDisposableStack *s = scr_ds_receiver(stack, "use", false, true); + if (!s) return false; + scr_ds_push(s, scr_dyn_retain((ScrDyn *)value), scr_dyn_retain((ScrDyn *)dispose), SCR_DS_ADOPT); + return true; +} + +bool scr_disposable_stack_adopt(const ScrDyn *stack, const ScrDyn *value, const ScrDyn *on_dispose) { + ScrDisposableStack *s = scr_ds_receiver(stack, "adopt", false, true); + if (!s || !scr_ds_callable(on_dispose)) return false; + scr_ds_push(s, scr_dyn_retain((ScrDyn *)value), scr_dyn_retain((ScrDyn *)on_dispose), SCR_DS_ADOPT); + return true; +} + +static bool scr_disposable_stack_defer(const ScrDyn *stack, const ScrDyn *on_dispose) { + ScrDisposableStack *s = scr_ds_receiver(stack, "defer", false, true); + if (!s || !scr_ds_callable(on_dispose)) return false; + scr_ds_push(s, NULL, scr_dyn_retain((ScrDyn *)on_dispose), SCR_DS_DEFER); + return true; +} + +/* DisposeResources over the stack's entries: NULL with the disposal error + * pending, or undefined (+1). */ +static ScrDyn *scr_ds_dispose(ScrDisposableStack *s) { + if (s->disposed) return scr_dyn_retain(scr_dyn_undefined()); + s->disposed = true; + ScrDisposableResource *items = s->items; + size_t len = s->len; + s->items = NULL; + s->len = s->cap = 0; + ScrCaught *error = NULL; + for (size_t i = len; i-- > 0;) { + ScrDisposableResource *r = &items[i]; + ScrDyn *result; + if (r->kind == SCR_DS_USE) { + result = scr_dyn_using_dispose(r->method, r->value); + } else { + scr_dyn_this_push_dyn(scr_dyn_undefined()); + result = r->kind == SCR_DS_ADOPT ? scr_dyn_call(r->method, &r->value, 1, "onDispose") + : scr_dyn_call(r->method, NULL, 0, "onDispose"); + scr_dyn_this_pop(); + } + if (result) { + scr_dyn_release(result); + } else { + if (error) scr_exc_suppress(error); + error = scr_exc_take(); + } + scr_dyn_release(r->value); + scr_dyn_release(r->method); + } + free(items); + if (!error) return scr_dyn_retain(scr_dyn_undefined()); + scr_rethrow(error); + scr_caught_release(error); + return NULL; +} + +static SCR_TL ScrDyn *scr_ds_method_values[6]; +static const char *const scr_ds_method_names[] = {"use", "adopt", "defer", "move", "dispose", "disposed"}; +static const uint32_t scr_ds_method_lengths[] = {1, 2, 1, 0, 0, 0}; +enum { SCR_DS_M_USE, SCR_DS_M_ADOPT, SCR_DS_M_DEFER, SCR_DS_M_MOVE, SCR_DS_M_DISPOSE, SCR_DS_M_DISPOSED }; + +static ScrDisposableStack *scr_ds_alloc(void); +static ScrDyn *scr_ds_box(ScrDisposableStack *s); + +static ScrDyn *scr_ds_method_call(ScrClosure *clo, ScrDyn *const *args, size_t argc) { + unsigned index = (unsigned)scr_box_get_f64(clo->caps[0]); + ScrDyn *self = scr_dyn_this_get(); + const ScrDyn *arg0 = argc > 0 ? args[0] : scr_dyn_undefined(); + const ScrDyn *arg1 = argc > 1 ? args[1] : scr_dyn_undefined(); + ScrDyn *out = NULL; + switch (index) { + case SCR_DS_M_USE: + if (scr_disposable_stack_use(self, arg0)) out = scr_dyn_retain((ScrDyn *)arg0); + break; + case SCR_DS_M_ADOPT: + if (scr_disposable_stack_adopt(self, arg0, arg1)) out = scr_dyn_retain((ScrDyn *)arg0); + break; + case SCR_DS_M_DEFER: + if (scr_disposable_stack_defer(self, arg0)) out = scr_dyn_retain(scr_dyn_undefined()); + break; + case SCR_DS_M_MOVE: { + /* The new stack takes the entries; this one becomes disposed. */ + ScrDisposableStack *s = scr_ds_receiver(self, "move", false, true); + if (!s) break; + ScrDisposableStack *moved = scr_ds_alloc(); + moved->items = s->items; + moved->len = s->len; + moved->cap = s->cap; + s->items = NULL; + s->len = s->cap = 0; + s->disposed = true; + out = scr_ds_box(moved); + scr_ds_release(moved); + break; + } + default: { + ScrDisposableStack *s = scr_ds_receiver(self, "dispose", false, false); + if (s) out = scr_ds_dispose(s); + break; + } + } + scr_dyn_release(self); + return out; +} + +/* The function value of method `index` (+1), cached per thread. */ +static ScrDyn *scr_ds_method_value(unsigned index) { + if (!scr_ds_method_values[index]) { + ScrClosure *clo = scr_closure_new(NULL, 1); + clo->caps[0] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(clo->caps[0], (double)index); + scr_ds_method_values[index] = scr_dyn_new_func(clo, scr_ds_method_call, scr_ds_method_lengths[index], + "", scr_ds_method_names[index]); + } + return scr_dyn_retain(scr_ds_method_values[index]); +} + +static ScrDyn *scr_ds_get(void *ptr, const char *key, size_t len) { + ScrDisposableStack *s = ptr; + if (len == 8 && memcmp(key, "disposed", 8) == 0) return scr_dyn_new_bool(s->disposed); + for (unsigned i = 0; i < SCR_DS_M_DISPOSED; i++) { + if (strlen(scr_ds_method_names[i]) == len && memcmp(key, scr_ds_method_names[i], len) == 0) + return scr_ds_method_value(i); + } + return NULL; +} + +static bool scr_ds_set(void *ptr, const char *key, size_t len, const ScrDyn *value) { + (void)ptr; + (void)key; + (void)len; + (void)value; + return false; +} + +/* [Symbol.dispose] is the dispose method itself, as in Node. */ +static ScrDyn *scr_ds_symbol_get(void *ptr, const ScrDyn *key) { + (void)ptr; + if (key->kind != SCR_DYN_SYMBOL) return NULL; + ScrStr *name = scr_str_new("dispose", 7); + ScrSym *dispose = scr_sym_well_known(name); + scr_str_release(name); + bool match = key->v.symbol.value == dispose; + scr_sym_release(dispose); + return match ? scr_ds_method_value(SCR_DS_M_DISPOSE) : NULL; +} + +static ScrDyn *scr_ds_inspect_view(void *ptr) { + (void)ptr; + return scr_dyn_new_obj(); +} + +static void scr_ds_teardown(void) { + for (size_t i = 0; i < sizeof scr_ds_method_values / sizeof scr_ds_method_values[0]; i++) { + scr_dyn_release(scr_ds_method_values[i]); + scr_ds_method_values[i] = NULL; + } +} + +static const ScrDynHandleOps scr_ds_ops = { + .cls = "DisposableStack", + .retain = scr_ds_retain, + .release = scr_ds_release, + .get = scr_ds_get, + .set = scr_ds_set, + .inspect_view = scr_ds_inspect_view, + .json_empty_object = true, + .inspect_view_empty = true, + .symbol_get = scr_ds_symbol_get, +}; + +static ScrDisposableStack *scr_ds_alloc(void) { + static SCR_TL bool installed; + if (!installed) { + installed = true; + scr_dyn_handle_install(SCR_DYNH_DISPOSABLE_STACK, &scr_ds_ops); + scr_atexit(scr_ds_teardown); + } + static ScrCycType cyc_type = {&scr_ds_trace, &scr_ds_gcfree, SCR_CYC_KIND_NONE, 0}; + ScrDisposableStack *s = scr_cyc_alloc(sizeof *s, &cyc_type); + s->rc = 1; + scr_obj_alloc_note(); + return s; +} + +static ScrDyn *scr_ds_box(ScrDisposableStack *s) { return scr_dyn_new_handle(s, SCR_DYNH_DISPOSABLE_STACK); } + +ScrDyn *scr_disposable_stack_new(void) { + ScrDisposableStack *s = scr_ds_alloc(); + ScrDyn *out = scr_ds_box(s); + scr_ds_release(s); + return out; +} diff --git a/tests/corpus/5858-disposable-stack.ts b/tests/corpus/5858-disposable-stack.ts new file mode 100644 index 000000000..749730997 --- /dev/null +++ b/tests/corpus/5858-disposable-stack.ts @@ -0,0 +1,157 @@ +// DisposableStack: use, adopt, defer, move and dispose with class instances, +// object literals and callbacks; LIFO disposal; SuppressedError chains; +// Node's ReferenceError and TypeError texts; using over a stack; inspection; +// and stacks whose callbacks capture the stack. Node.js prints the same. +const log: string[] = []; +class Resource { + readonly name: string; + constructor(name: string) { + this.name = name; + } + [Symbol.dispose](): void { + log.push("dispose " + this.name); + } +} +class Failing { + readonly name: string; + constructor(name: string) { + this.name = name; + } + [Symbol.dispose](): void { + throw new Error("fail " + this.name); + } +} +function scope(): void { + using stack = new DisposableStack(); + const a = stack.use(new Resource("a")); + log.push("got " + a.name); + stack.defer(() => log.push("deferred")); + const n = stack.adopt(42, (v) => log.push("adopted " + v)); + const r = stack.adopt(new Resource("adopted-res"), (v) => log.push("adopt " + v.name)); + stack.use({ [Symbol.dispose]() { log.push("literal"); } }); + stack.use(null); + stack.use(undefined); + log.push("n=" + n + " r=" + r.name + " disposed=" + stack.disposed); +} +scope(); +console.log(log.join("\n")); +log.length = 0; + +const outer = new DisposableStack(); +outer.use(new Resource("x")); +const moved = outer.move(); +console.log(outer.disposed, moved.disposed, outer instanceof DisposableStack, moved instanceof DisposableStack); +moved.dispose(); +moved.dispose(); +console.log(log.join(","), moved.disposed); +log.length = 0; + +function attempt(label: string, f: () => void): void { + try { + f(); + console.log(label, "ok"); + } catch (e) { + if (e instanceof SuppressedError) { + const chain: string[] = []; + let cur: unknown = e; + while (cur instanceof SuppressedError) { + chain.push((cur.error as Error).message); + cur = cur.suppressed; + } + chain.push(cur instanceof Error ? cur.message : String(cur)); + console.log(label, "SuppressedError", e.message, chain.join(" <- ")); + } else if (e instanceof Error) { + console.log(label, e.name, e.message); + } else { + console.log(label, "thrown", e); + } + } +} +attempt("three failures", () => { + const s = new DisposableStack(); + s.use(new Failing("one")); + s.defer(() => { throw new Error("two"); }); + s.use(new Failing("three")); + s.dispose(); +}); +attempt("single", () => { + const s = new DisposableStack(); + s.use(new Resource("before")); + s.defer(() => { throw new RangeError("only"); }); + s.dispose(); +}); +console.log(log.join(",")); +attempt("thrown value", () => { + const s = new DisposableStack(); + s.defer(() => { throw 7; }); + s.dispose(); +}); +attempt("using body error", () => { + using s = new DisposableStack(); + s.defer(() => { throw new Error("disposal"); }); + throw new Error("body"); +}); +const done = new DisposableStack(); +done.dispose(); +attempt("use after dispose", () => { done.use(new Resource("late")); }); +attempt("defer after dispose", () => done.defer(() => {})); +attempt("adopt after dispose", () => { done.adopt(1, () => {}); }); +attempt("move after dispose", () => { done.move(); }); +attempt("dispose twice", () => done.dispose()); +attempt("use non-object", () => { new DisposableStack().use(5 as unknown as Disposable); }); +attempt("use missing method", () => { new DisposableStack().use({} as unknown as Disposable); }); +attempt("defer non-function", () => new DisposableStack().defer(3 as unknown as () => void)); +attempt("adopt non-function", () => { new DisposableStack().adopt(1, "x" as unknown as () => void); }); +const reentrant = new DisposableStack(); +reentrant.defer(() => { + console.log("inside disposed", reentrant.disposed); + attempt("defer during dispose", () => reentrant.defer(() => {})); +}); +reentrant.dispose(); +const shown = new DisposableStack(); +console.log(shown, String(shown), Object.prototype.toString.call(shown), typeof shown, JSON.stringify(shown)); +const self = new DisposableStack(); +self.defer(() => console.log("self disposed", self.disposed)); +self[Symbol.dispose](); +const nested = new DisposableStack(); +const inner = nested.use(new DisposableStack()); +inner.defer(() => console.log("inner via outer")); +nested.dispose(); +console.log(inner.disposed); +class Base { + readonly name: string; + constructor(name: string) { + this.name = name; + } + [Symbol.dispose](): void { + console.log("base dispose", this.name); + } +} +class Derived extends Base { + override [Symbol.dispose](): void { + console.log("derived dispose", this.name); + } +} +class Plain extends Base {} +const inherit = new DisposableStack(); +const items: Base[] = [new Derived("d"), new Plain("p"), new Base("b")]; +for (const item of items) inherit.use(item); +const back = inherit.use(new Derived("returned")); +console.log(back.name, back instanceof Derived); +inherit.dispose(); +// A stack whose callback captures the stack is collected without disposal. +for (let i = 0; i < 3; i++) { + const cyc = new DisposableStack(); + cyc.defer(() => console.log("never", cyc.disposed)); +} +const holder = { stack: new DisposableStack() }; +console.log(holder, [holder.stack]); +function make(): DisposableStack { + const st = new DisposableStack(); + st.defer(() => console.log("made stack disposed")); + return st; +} +{ + using made = make(); + console.log("in block", made.disposed); +} diff --git a/tests/corpus/5859-disposable-stack-js.js b/tests/corpus/5859-disposable-stack-js.js new file mode 100644 index 000000000..491beee16 --- /dev/null +++ b/tests/corpus/5859-disposable-stack-js.js @@ -0,0 +1,77 @@ +// DisposableStack from JavaScript: untyped resources and callbacks, methods +// detached from the stack, and Node's TypeError and ReferenceError texts for +// invalid receivers, resources and callbacks. Node.js prints the same. +const attempt = (label, f) => { + try { + console.log(label, f()); + } catch (e) { + console.log(label, e.name + ": " + e.message); + } +}; +const s = new DisposableStack(); +attempt("use number", () => s.use(5)); +attempt("use empty object", () => s.use({})); +attempt("use null", () => s.use(null)); +attempt("use undefined", () => s.use(undefined)); +for (const v of ["x", 5, {}, [], null, undefined, true, Symbol("q"), 1n, new Map()]) { + attempt("defer", () => s.defer(v)); +} +attempt("adopt", () => s.adopt(1, 2)); +const { defer, use, dispose, move } = s; +attempt("detached defer", () => defer(() => {})); +attempt("use on object", () => use.call({}, null)); +attempt("dispose on number", () => dispose.call(5)); +attempt("move on string", () => move.call("x")); +console.log(s.defer.length, s.use.length, s.adopt.length, s.move.length, s.dispose.length); +console.log(s.defer.name, s[Symbol.dispose].name, s[Symbol.dispose] === s.dispose); +console.log(typeof s.disposed, s.disposed, JSON.stringify(s), String(s), s); + +const order = []; +const resource = (name) => ({ + [Symbol.dispose]() { + order.push("dispose " + name); + }, +}); +const stack = new DisposableStack(); +console.log(stack.use(resource("a")) !== null, stack.adopt(7, (v) => order.push("adopt " + v))); +stack.defer(() => order.push("defer")); +stack.use(resource("b")); +const moved = stack.move(); +moved.defer(() => order.push("after move")); +console.log(stack.disposed, moved.disposed, moved instanceof DisposableStack); +moved[Symbol.dispose](); +console.log(order.join(", ")); +console.log(moved.dispose(), moved.disposed); +attempt("use after dispose", () => moved.use(null)); +attempt("adopt after dispose", () => moved.adopt(1, () => {})); + +const failing = new DisposableStack(); +failing.defer(() => { + throw new Error("one"); +}); +failing.defer(() => { + throw new TypeError("two"); +}); +failing.defer(() => { + throw "three"; +}); +try { + failing.dispose(); +} catch (e) { + console.log(e.name, e.message, e.error.name, e.suppressed.error.message, e.suppressed.suppressed); +} +const getterResource = { + get [Symbol.dispose]() { + console.log("getter read"); + return () => console.log("getter resource disposed"); + }, +}; +const g = new DisposableStack(); +g.use(getterResource); +console.log("after use"); +g.dispose(); +{ + using scoped = new DisposableStack(); + scoped.defer(() => console.log("scope exit")); + console.log("in scope"); +} diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index ecd7f5d9b..ceab551f3 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,8 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5858-disposable-stack.ts": 3050, + "5859-disposable-stack-js.js": 3100, "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, @@ -4468,6 +4470,8 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5858-disposable-stack.ts": 3750, + "5859-disposable-stack-js.js": 3600, "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, From 32061e8ba3c5ad4e3cf16b213ba0d9c56131be03 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 22:45:32 -0500 Subject: [PATCH 032/117] Add Float16Array Float16Array is a native typed-array kind with IEEE 754 binary16 storage. Stores round the number to nearest-even in one step from the double, as Node does, including overflow to Infinity, subnormals, -0 and NaN; reads widen exactly. The runtime converts with integer operations, so no target needs half-precision hardware or compiler-rt support. Construction, element reads and writes, ArrayBuffer views, fill, set, subarray, slice, both sort orders, constructor values and checked-dynamic storage work as for the other typed arrays. Math.f16round, DataView.prototype.getFloat16 and setFloat16, and util.types.isFloat16Array compile. --- .../arraybuffers-and-typed-arrays.mdx | 2 +- .../ambient/scriptc-node-fallback.d.ts | 1 + .../compiler/src/backend/llvm/byte-numbers.ts | 11 +- packages/compiler/src/backend/llvm/common.ts | 1 + .../compiler/src/backend/llvm/expr-bytes.ts | 29 ++++- .../src/backend/llvm/lib-filesystem.ts | 10 ++ .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../lowering/containers/array-pipelines.ts | 1 + .../src/frontend/lowering/containers/bytes.ts | 6 +- .../src/frontend/lowering/lower-assert.ts | 1 + .../src/frontend/lowering/nan-coded-reads.ts | 1 + .../frontend/lowering/narrowing-stability.ts | 1 + .../src/frontend/lowering/surfaces.ts | 3 + packages/compiler/src/frontend/type-mapper.ts | 1 + packages/compiler/src/ir/analysis.ts | 1 + packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 2 + packages/compiler/src/ir/byte-numbers.ts | 3 + packages/compiler/src/ir/int32-slots.ts | 1 + packages/compiler/src/ir/ir.ts | 24 +++- .../tests/corpus/5900-float16-array.ts.json | 6 + .../corpus/5901-float16-array-js.js.json | 6 + packages/runtime/src/scr_array.c | 37 +++++- packages/runtime/src/scr_assert.c | 3 +- packages/runtime/src/scr_bytes.c | 79 +++++++++++- packages/runtime/src/scr_bytes.h | 15 ++- packages/runtime/src/scr_dyn_invoke.c | 6 +- packages/runtime/src/scr_json.c | 18 +-- tests/corpus/5900-float16-array.ts | 94 ++++++++++++++ tests/corpus/5901-float16-array-js.js | 95 ++++++++++++++ tests/diagnostics/dataview.ts | 4 +- tests/diagnostics/es2025-fences.ts | 13 +- tests/harness/__snapshots__/dataview.ts.txt | 19 +-- .../__snapshots__/es2025-fences.ts.txt | 118 ++++++------------ tests/harness/corpus-costs.json | 4 + 35 files changed, 489 insertions(+), 129 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5900-float16-array.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5901-float16-array-js.js.json create mode 100644 tests/corpus/5900-float16-array.ts create mode 100644 tests/corpus/5901-float16-array-js.js diff --git a/docs/content/limitations/builtin-apis/arraybuffers-and-typed-arrays.mdx b/docs/content/limitations/builtin-apis/arraybuffers-and-typed-arrays.mdx index 81dfded25..59a61518d 100644 --- a/docs/content/limitations/builtin-apis/arraybuffers-and-typed-arrays.mdx +++ b/docs/content/limitations/builtin-apis/arraybuffers-and-typed-arrays.mdx @@ -1 +1 @@ -- **ArrayBuffers and typed arrays:** Fixed-length ArrayBuffers support shared typed-array and DataView storage. Resizing, transferring, Float16 arrays, and BigInt arrays are unsupported. Numeric typed arrays and Buffers preserve their kind and shared storage through `unknown`, including when nested in records and arrays. Numeric typed-array constructors can be stored and used with `new`, including constructors read from an array's `constructor` property. JavaScript numeric-array parameters and returns preserve typed-array storage. `Buffer.from`, `Buffer.allocUnsafe`, and `Buffer.concat` return views into a per-thread pool of `Buffer.poolSize` bytes (64 KiB by default) when the size is below `Buffer.poolSize >>> 1`, as in Node; a pool slab stays in memory while any of its Buffers does. Node's own startup code allocates from the first slab, so the `byteOffset` of Buffers in that slab differs from Node's. Buffers returned by other Node APIs, such as `fs.readFileSync` and `zlib`, own their `ArrayBuffer`, where Node allocates small ones from the pool. +- **ArrayBuffers and typed arrays:** Fixed-length ArrayBuffers support shared typed-array and DataView storage. Resizing, transferring, and BigInt arrays are unsupported. `Float16Array` stores IEEE 754 half-precision values, rounding each stored number to nearest-even as Node does; `Math.f16round`, `DataView.prototype.getFloat16` and `setFloat16`, and `util.types.isFloat16Array` compile. Numeric typed arrays and Buffers preserve their kind and shared storage through `unknown`, including when nested in records and arrays. Numeric typed-array constructors can be stored and used with `new`, including constructors read from an array's `constructor` property. JavaScript numeric-array parameters and returns preserve typed-array storage. `Buffer.from`, `Buffer.allocUnsafe`, and `Buffer.concat` return views into a per-thread pool of `Buffer.poolSize` bytes (64 KiB by default) when the size is below `Buffer.poolSize >>> 1`, as in Node; a pool slab stays in memory while any of its Buffers does. Node's own startup code allocates from the first slab, so the `byteOffset` of Buffers in that slab differs from Node's. Buffers returned by other Node APIs, such as `fs.readFileSync` and `zlib`, own their `ArrayBuffer`, where Node allocates small ones from the pool. diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index d87172f61..064dccc77 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3250,6 +3250,7 @@ declare module "util/types" { export function isInt8Array(value: unknown): value is Int8Array; export function isInt16Array(value: unknown): value is Int16Array; export function isInt32Array(value: unknown): value is Int32Array; + export function isFloat16Array(value: unknown): value is Float16Array; export function isFloat32Array(value: unknown): value is Float32Array; export function isFloat64Array(value: unknown): value is Float64Array; export function isMap(value: unknown): value is Map; diff --git a/packages/compiler/src/backend/llvm/byte-numbers.ts b/packages/compiler/src/backend/llvm/byte-numbers.ts index d12ef08b9..c51d03744 100644 --- a/packages/compiler/src/backend/llvm/byte-numbers.ts +++ b/packages/compiler/src/backend/llvm/byte-numbers.ts @@ -182,7 +182,11 @@ export function emitByteNumber( const integerType = bits <= 32 ? "i32" : "i64"; if (spec.write) { let raw: string; - if (spec.floating) { + if (spec.floating && bits === 16) { + host.declare(`declare zeroext i16 @scr_f16_from_f64(double)`); + raw = B.tmp(); + B.line(`${raw} = call zeroext i16 @scr_f16_from_f64(double ${value!.name})`); + } else if (spec.floating) { let stored = value!.name; if (bits === 32) { stored = B.tmp(); @@ -228,7 +232,10 @@ export function emitByteNumber( const raw = endianBits(host, loaded, spec.width, little); fastResult = B.tmp(); if (spec.floating) { - if (bits === 32) { + if (bits === 16) { + host.declare(`declare double @scr_f16_to_f64(i16 zeroext)`); + B.line(`${fastResult} = call double @scr_f16_to_f64(i16 zeroext ${raw})`); + } else if (bits === 32) { const float = B.tmp(); B.line(`${float} = bitcast i32 ${raw} to float`); B.line(`${fastResult} = fpext float ${float} to double`); diff --git a/packages/compiler/src/backend/llvm/common.ts b/packages/compiler/src/backend/llvm/common.ts index 0a473e65b..8a8778919 100644 --- a/packages/compiler/src/backend/llvm/common.ts +++ b/packages/compiler/src/backend/llvm/common.ts @@ -159,6 +159,7 @@ export const BYTES_ELEM_NUM: Record = { u16: 6, i16: 7, u8c: 8, + f16: 9, }; /** The payload marker of an ABSENT record field slot (IR fieldAbsent): the diff --git a/packages/compiler/src/backend/llvm/expr-bytes.ts b/packages/compiler/src/backend/llvm/expr-bytes.ts index 89a482b52..ac025df09 100644 --- a/packages/compiler/src/backend/llvm/expr-bytes.ts +++ b/packages/compiler/src/backend/llvm/expr-bytes.ts @@ -44,6 +44,7 @@ const DV_GET_KIND: Record = { dvGetFloat64: 7, dvGetBigUint64Number: 8, dvGetBigInt64Number: 9, + dvGetFloat16: 10, }; const DV_SET_KIND: Record = { @@ -55,6 +56,7 @@ const DV_SET_KIND: Record = { dvSetInt32: 5, dvSetFloat32: 6, dvSetFloat64: 7, + dvSetFloat16: 10, }; export function emitIntegerLoopIndex(host: LlvmEmitterContext, expr: IrExpr): string | null { @@ -273,7 +275,7 @@ function emitSharedOrLocalLoad( idx: string, ): LlValue { const B = host.B; - const floating = elem === "f32" || elem === "f64"; + const floating = elem === "f16" || elem === "f32" || elem === "f64"; const fn = floating ? "scr_bytes_shared_get_f64" : "scr_bytes_shared_get_int"; const ret = floating ? "double" : "i32"; host.declare(`declare ${ret} @${fn}(ptr, ${host.sizeType})`); @@ -314,6 +316,16 @@ function emitBytesLoadAt( const B = host.B; const data = host.emitBytesData(receiver); const p = B.tmp(); + if (elem === "f16") { + // Half-precision bits widen exactly; the runtime converts them. + host.declare(`declare double @scr_f16_to_f64(i16 zeroext)`); + const raw = B.tmp(); + const out = B.tmp(); + B.line(`${p} = getelementptr inbounds i16, ptr ${data}, ${host.sizeType} ${idx}`); + B.line(`${raw} = load i16, ptr ${p}, align 1`); + B.line(`${out} = call double @scr_f16_to_f64(i16 zeroext ${raw})`); + return { name: out, type: F64 }; + } if (BYTES_ELEMENT_SIZE[elem] < 4) { const bits = BYTES_ELEMENT_SIZE[elem] * 8; const signed = elem === "i8" || elem === "i16"; @@ -472,10 +484,19 @@ export function emitBytesSet( B.line(`${stored} = fptoui double ${clamped} to i32`); } else stored = - elem === "f32" || elem === "f64" ? null : host.emitToUint32(value.name, expr, value.uint32); + elem === "f16" || elem === "f32" || elem === "f64" + ? null + : host.emitToUint32(value.name, expr, value.uint32); const data = host.emitBytesData(receiver); const p = B.tmp(); - if (BYTES_ELEMENT_SIZE[elem] < 4) { + if (elem === "f16") { + // One round-to-nearest-even step from the double, in the runtime. + host.declare(`declare zeroext i16 @scr_f16_from_f64(double)`); + const narrowed = B.tmp(); + B.line(`${narrowed} = call zeroext i16 @scr_f16_from_f64(double ${value.name})`); + B.line(`${p} = getelementptr inbounds i16, ptr ${data}, ${host.sizeType} ${idx}`); + B.line(`store i16 ${narrowed}, ptr ${p}, align 1`); + } else if (BYTES_ELEMENT_SIZE[elem] < 4) { const bits = BYTES_ELEMENT_SIZE[elem] * 8; const byte = B.tmp(); B.line(`${byte} = trunc i32 ${stored!} to i${bits}`); @@ -882,6 +903,7 @@ export function emitBytesIntrinsic( case "dvGetInt16": case "dvGetUint32": case "dvGetInt32": + case "dvGetFloat16": case "dvGetFloat32": case "dvGetFloat64": case "dvGetBigUint64Number": @@ -912,6 +934,7 @@ export function emitBytesIntrinsic( case "dvSetInt16": case "dvSetUint32": case "dvSetInt32": + case "dvSetFloat16": case "dvSetFloat32": case "dvSetFloat64": { // DataView setters: [offset, value, littleEndian?] — void; throw diff --git a/packages/compiler/src/backend/llvm/lib-filesystem.ts b/packages/compiler/src/backend/llvm/lib-filesystem.ts index 1083c69d5..d15bf39e7 100644 --- a/packages/compiler/src/backend/llvm/lib-filesystem.ts +++ b/packages/compiler/src/backend/llvm/lib-filesystem.ts @@ -1037,6 +1037,16 @@ export function emitPrimitiveLibCall(host: LlvmEmitterContext, e: LibCallExpr): B.line(`${t} = sitofp i32 ${product} to double`); return { name: t, type: e.type, uint32: product }; } + if (e.fn === "math.f16round") { + const v = host.emitExpr(e.args[0]!); + host.declare(`declare zeroext i16 @scr_f16_from_f64(double)`); + host.declare(`declare double @scr_f16_to_f64(i16 zeroext)`); + const narrowed = B.tmp(); + const t = B.tmp(); + B.line(`${narrowed} = call zeroext i16 @scr_f16_from_f64(double ${v.name})`); + B.line(`${t} = call double @scr_f16_to_f64(i16 zeroext ${narrowed})`); + return { name: t, type: e.type }; + } if (e.fn === "math.fround") { const v = host.emitExpr(e.args[0]!); const narrowed = B.tmp(); diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9232cbd03..7b3566383 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -65,6 +65,7 @@ export const LIB_FN_SYMS: Record = { "arrayBuffer.viewU8": "scr_array_buffer_view_u8", "arrayBuffer.viewU32": "scr_array_buffer_view_u32", "arrayBuffer.viewI32": "scr_array_buffer_view_i32", + "arrayBuffer.viewF16": "scr_array_buffer_view_f16", "arrayBuffer.viewF32": "scr_array_buffer_view_f32", "arrayBuffer.viewF64": "scr_array_buffer_view_f64", "arrayBuffer.viewDV": "scr_array_buffer_view_dv", diff --git a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts index 0ceb4d677..cf45a7575 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts @@ -108,6 +108,7 @@ const PURE_MATH = new Set([ "math.exp", "math.expm1", "math.floor", + "math.f16round", "math.fround", "math.imul", "math.log", diff --git a/packages/compiler/src/frontend/lowering/containers/bytes.ts b/packages/compiler/src/frontend/lowering/containers/bytes.ts index b9400cbbd..7a19927de 100644 --- a/packages/compiler/src/frontend/lowering/containers/bytes.ts +++ b/packages/compiler/src/frontend/lowering/containers/bytes.ts @@ -151,7 +151,7 @@ function lowerBytesSortCall( /* ── typed arrays / Buffer ─────────────────────────────────────────────── */ /** The typed-array constructors with a runtime representation, by lib - * interface name. Other flavors (Float16Array, BigInt64Array, ...) fall through + * interface name. Other flavors (BigInt64Array, BigUint64Array) fall through * to the generic stdlib-constructor fence. DataView is handled separately. */ const BYTES_CTORS: Record = { Uint8Array: "u8", @@ -161,6 +161,7 @@ const BYTES_CTORS: Record = { Int16Array: "i16", Uint32Array: "u32", Int32Array: "i32", + Float16Array: "f16", Float32Array: "f32", Float64Array: "f64", }; @@ -397,6 +398,7 @@ function lowerArrayBufferView( u8: "arrayBuffer.viewU8", u32: "arrayBuffer.viewU32", i32: "arrayBuffer.viewI32", + f16: "arrayBuffer.viewF16", f32: "arrayBuffer.viewF32", f64: "arrayBuffer.viewF64", dv: "arrayBuffer.viewDV", @@ -1220,6 +1222,7 @@ const DV_GETTERS: Record = new Set([ "Int8Array", "Int16Array", "Int32Array", + "Float16Array", "Float32Array", "Float64Array", "BigInt64Array", diff --git a/packages/compiler/src/frontend/lowering/nan-coded-reads.ts b/packages/compiler/src/frontend/lowering/nan-coded-reads.ts index 2a537d6de..f7023cc52 100644 --- a/packages/compiler/src/frontend/lowering/nan-coded-reads.ts +++ b/packages/compiler/src/frontend/lowering/nan-coded-reads.ts @@ -191,6 +191,7 @@ const TYPED_ARRAYS = new Set([ "Uint16Array", "Int32Array", "Uint32Array", + "Float16Array", "Float32Array", "Float64Array", ]); diff --git a/packages/compiler/src/frontend/lowering/narrowing-stability.ts b/packages/compiler/src/frontend/lowering/narrowing-stability.ts index 9c7850ceb..4ae8eec67 100644 --- a/packages/compiler/src/frontend/lowering/narrowing-stability.ts +++ b/packages/compiler/src/frontend/lowering/narrowing-stability.ts @@ -834,6 +834,7 @@ const INERT_CONSTRUCTORS = new Set([ "Int16Array", "Uint32Array", "Int32Array", + "Float16Array", "Float32Array", "Float64Array", "BigInt64Array", diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 4c74e8b6a..91059ce0d 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -664,6 +664,7 @@ export const STDLIB_SURFACE = { cosh: ISL_N1, exp: ISL_N1, expm1: ISL_N1, + f16round: ISL_N1, fround: ISL_N1, hypot: ISL_N2, imul: ISL_N2, @@ -751,6 +752,7 @@ export const STATIC_MATH_FNS: Record([ "math.sign", "math.exp", "math.expm1", + "math.f16round", "math.fround", "math.log", "math.log1p", diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 2381413f8..5dd4f9956 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -73,6 +73,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "arrayBuffer.viewU8", "arrayBuffer.viewU32", "arrayBuffer.viewI32", + "arrayBuffer.viewF16", "arrayBuffer.viewF32", "arrayBuffer.viewF64", "arrayBuffer.viewDV", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 5e219ecf6..a2849a244 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -644,6 +644,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "math.sign": { argTypes: [F64], result: F64 }, "math.exp": { argTypes: [F64], result: F64 }, "math.expm1": { argTypes: [F64], result: F64 }, + "math.f16round": { argTypes: [F64], result: F64 }, "math.fround": { argTypes: [F64], result: F64 }, "math.sqrt": { argTypes: [F64], result: F64 }, "math.log": { argTypes: [F64], result: F64 }, @@ -3159,6 +3160,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "arrayBuffer.viewU8": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, "arrayBuffer.viewU32": { argTypes: [DYN, DYN, DYN], result: bytesOf("u32") }, "arrayBuffer.viewI32": { argTypes: [DYN, DYN, DYN], result: bytesOf("i32") }, + "arrayBuffer.viewF16": { argTypes: [DYN, DYN, DYN], result: bytesOf("f16") }, "arrayBuffer.viewF32": { argTypes: [DYN, DYN, DYN], result: bytesOf("f32") }, "arrayBuffer.viewF64": { argTypes: [DYN, DYN, DYN], result: bytesOf("f64") }, "arrayBuffer.viewDV": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, diff --git a/packages/compiler/src/ir/byte-numbers.ts b/packages/compiler/src/ir/byte-numbers.ts index a6a079af6..89ffaaa98 100644 --- a/packages/compiler/src/ir/byte-numbers.ts +++ b/packages/compiler/src/ir/byte-numbers.ts @@ -25,6 +25,7 @@ const FORMATS: Readonly> = { i16: { width: 2, signed: true, floating: false }, u32: { width: 4, signed: false, floating: false }, i32: { width: 4, signed: true, floating: false }, + f16: { width: 2, signed: false, floating: true }, f32: { width: 4, signed: false, floating: true }, f64: { width: 8, signed: false, floating: true }, u64: { width: 8, signed: false, floating: false }, @@ -38,6 +39,7 @@ const VIEW_FORMATS: Readonly> = { dvGetInt16: "i16", dvGetUint32: "u32", dvGetInt32: "i32", + dvGetFloat16: "f16", dvGetFloat32: "f32", dvGetFloat64: "f64", dvGetBigUint64Number: "u64", @@ -48,6 +50,7 @@ const VIEW_FORMATS: Readonly> = { dvSetInt16: "i16", dvSetUint32: "u32", dvSetInt32: "i32", + dvSetFloat16: "f16", dvSetFloat32: "f32", dvSetFloat64: "f64", }; diff --git a/packages/compiler/src/ir/int32-slots.ts b/packages/compiler/src/ir/int32-slots.ts index 5e868793c..a6a10eaa7 100644 --- a/packages/compiler/src/ir/int32-slots.ts +++ b/packages/compiler/src/ir/int32-slots.ts @@ -336,6 +336,7 @@ const BOUNDARY_KINDS = new Set([ * property, except literal-keyed `dyn.keySet`/`dyn.keyDelete`. */ const DYN_READ_ONLY = new Set([ "arrayBuffer.new", + "arrayBuffer.viewF16", "arrayBuffer.viewF32", "arrayBuffer.viewF64", "arrayBuffer.viewI16", diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index bfaa13c0e..90c9bd618 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -26,9 +26,19 @@ export interface SrcLoc { /* ── types ─────────────────────────────────────────────────────────────── */ -/** Numeric typed-array element kinds with a native representation. Float16 - * and BigInt typed arrays remain frontend-fenced. */ -export type IrBytesElem = "u8" | "u8c" | "i8" | "u16" | "i16" | "u32" | "i32" | "f32" | "f64"; +/** Numeric typed-array element kinds with a native representation. BigInt + * typed arrays remain frontend-fenced. */ +export type IrBytesElem = + | "u8" + | "u8c" + | "i8" + | "u16" + | "i16" + | "u32" + | "i32" + | "f16" + | "f32" + | "f64"; export const BYTES_ELEMENT_SIZE: Record = { u8: 1, @@ -38,13 +48,14 @@ export const BYTES_ELEMENT_SIZE: Record = { i16: 2, u32: 4, i32: 4, + f16: 2, f32: 4, f64: 8, }; /** Integer element kinds: a valid element read is never NaN. */ export function isIntegerBytesElem(elem: IrBytesElem): boolean { - return elem !== "f32" && elem !== "f64"; + return elem !== "f16" && elem !== "f32" && elem !== "f64"; } export const BYTES_ELEMENT_NAME: Record = { @@ -55,6 +66,7 @@ export const BYTES_ELEMENT_NAME: Record = { i16: "Int16Array", u32: "Uint32Array", i32: "Int32Array", + f16: "Float16Array", f32: "Float32Array", f64: "Float64Array", }; @@ -2227,6 +2239,7 @@ export type IrBytesIntrinsicMethod = | "dvGetInt16" | "dvGetUint32" | "dvGetInt32" + | "dvGetFloat16" | "dvGetFloat32" | "dvGetFloat64" | "dvGetBigUint64Number" @@ -2237,6 +2250,7 @@ export type IrBytesIntrinsicMethod = | "dvSetInt16" | "dvSetUint32" | "dvSetInt32" + | "dvSetFloat16" | "dvSetFloat32" | "dvSetFloat64"; @@ -2268,6 +2282,7 @@ export const MAY_THROW_BYTES_METHODS: ReadonlySet = new "dvGetInt16", "dvGetUint32", "dvGetInt32", + "dvGetFloat16", "dvGetFloat32", "dvGetFloat64", "dvGetBigUint64Number", @@ -2278,6 +2293,7 @@ export const MAY_THROW_BYTES_METHODS: ReadonlySet = new "dvSetInt16", "dvSetUint32", "dvSetInt32", + "dvSetFloat16", "dvSetFloat32", "dvSetFloat64", ]); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5900-float16-array.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5900-float16-array.ts.json new file mode 100644 index 000000000..47cf8723f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5900-float16-array.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5900-float16-array.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5901-float16-array-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5901-float16-array-js.js.json new file mode 100644 index 000000000..148849dca --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5901-float16-array-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5901-float16-array-js.js" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_array.c b/packages/runtime/src/scr_array.c index eba0367f7..ef64be56d 100644 --- a/packages/runtime/src/scr_array.c +++ b/packages/runtime/src/scr_array.c @@ -3111,6 +3111,11 @@ static double scr_bytes_sort_load(const ScrBytes *b, size_t i) { memcpy(&v, at, sizeof v); return v; } + case SCR_BYTES_F16: { + uint16_t v; + memcpy(&v, at, sizeof v); + return scr_f16_to_f64(v); + } case SCR_BYTES_F32: { float v; memcpy(&v, at, sizeof v); @@ -3151,6 +3156,11 @@ static void scr_bytes_sort_store(ScrBytes *b, size_t i, double value) { memcpy(at, &v, sizeof v); break; } + case SCR_BYTES_F16: { + uint16_t v = scr_f16_from_f64(value); + memcpy(at, &v, sizeof v); + break; + } case SCR_BYTES_F32: { float v = (float)value; memcpy(at, &v, sizeof v); @@ -3263,6 +3273,18 @@ static int scr_bytes_f32_key(const uint8_t *at, int32_t order, uint32_t *key) { return 0; } +/* Float16 keys use the low 16 bits of a 32-bit key; a descending order + * complements all 32, which keeps the order of keys. */ +static int scr_bytes_f16_key(const uint8_t *at, int32_t order, uint32_t *key) { + uint16_t bits; + memcpy(&bits, at, sizeof bits); + if ((bits & 0x7fff) > 0x7c00) return order ? 2 : 1; + if (order && bits == 0x8000) return 2; + uint32_t k = (bits & 0x8000) ? (uint16_t)~bits : (uint32_t)bits | 0x8000; + *key = k ^ (order < 0 ? ~UINT32_C(0) : 0); + return 0; +} + static int scr_bytes_f64_key(const uint8_t *at, int32_t order, uint64_t *key) { double v; uint64_t bits; @@ -3323,6 +3345,9 @@ static bool scr_bytes_sort_refused(const ScrBytes *b, int32_t order) { if (b->elem == SCR_BYTES_F32) { uint32_t key; if (scr_bytes_f32_key(data + i * 4, order, &key)) return true; + } else if (b->elem == SCR_BYTES_F16) { + uint32_t key; + if (scr_bytes_f16_key(data + i * 2, order, &key)) return true; } else if (b->elem == SCR_BYTES_F64) { uint64_t key; if (scr_bytes_f64_key(data + i * 8, order, &key)) return true; @@ -3353,7 +3378,7 @@ bool scr_bytes_sort_numeric(ScrBytes *b, int32_t order) { size_t width = scr_bytes_elem_size(b->elem); uint8_t *data = b->data; /* Integer elements have no NaN or -0: every order is a value order. */ - if (width == 1 || (width == 2 && n >= SCR_BYTES_COUNT_SORT)) { + if (width == 1 || (width == 2 && b->elem != SCR_BYTES_F16 && n >= SCR_BYTES_COUNT_SORT)) { scr_bytes_count_sort(b, order < 0); return true; } @@ -3392,13 +3417,23 @@ bool scr_bytes_sort_numeric(ScrBytes *b, int32_t order) { uint32_t bits_ = (k_ & SCR_SORT_SIGN32) ? k_ & ~SCR_SORT_SIGN32 : ~k_; \ memcpy(data + (i) * 4, &bits_, 4); \ } while (0) +#define SCR_BYTES_READ32_F16(i, key) scr_bytes_f16_key(data + (i) * 2, order, (key)) +#define SCR_BYTES_WRITE32_F16(i, key) \ + do { \ + uint16_t k_ = (uint16_t)((key) ^ flip32); \ + uint16_t bits_ = (k_ & 0x8000) ? (uint16_t)(k_ & 0x7fff) : (uint16_t)~k_; \ + memcpy(data + (i) * 2, &bits_, 2); \ + } while (0) if (b->elem == SCR_BYTES_F32) SCR_BYTES_KEYS32(F32); + else if (b->elem == SCR_BYTES_F16) SCR_BYTES_KEYS32(F16); else SCR_BYTES_KEYS32(INT); #undef SCR_BYTES_KEYS32 #undef SCR_BYTES_READ32_INT #undef SCR_BYTES_WRITE32_INT #undef SCR_BYTES_READ32_F32 #undef SCR_BYTES_WRITE32_F32 +#undef SCR_BYTES_READ32_F16 +#undef SCR_BYTES_WRITE32_F16 free(keys); return true; } diff --git a/packages/runtime/src/scr_assert.c b/packages/runtime/src/scr_assert.c index 9e2e79418..5a4769038 100644 --- a/packages/runtime/src/scr_assert.c +++ b/packages/runtime/src/scr_assert.c @@ -791,7 +791,7 @@ static bool scr_assert_loose_error(const ScrDyn *a, const ScrDyn *b) { } static bool scr_assert_loose_float_elem(ScrBytesElem elem) { - return elem == SCR_BYTES_F32 || elem == SCR_BYTES_F64; + return elem == SCR_BYTES_F16 || elem == SCR_BYTES_F32 || elem == SCR_BYTES_F64; } /* Typed arrays and Buffers: the same tag (a Buffer is a Uint8Array here), @@ -1305,6 +1305,7 @@ static const char *scr_assert_cf_bytes_class(ScrBytesElem elem) { switch (elem) { case SCR_BYTES_U8: return "Uint8Array"; case SCR_BYTES_U32: return "Uint32Array"; + case SCR_BYTES_F16: return "Float16Array"; case SCR_BYTES_F32: return "Float32Array"; case SCR_BYTES_I32: return "Int32Array"; case SCR_BYTES_F64: return "Float64Array"; diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index df5b8a3c0..f8b9f4479 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -87,10 +87,60 @@ static void scr_bytes_oom(void) { scr_trap("scriptc: out of memory\n"); } +uint16_t scr_f16_from_f64(double value) { + uint64_t bits; + memcpy(&bits, &value, sizeof bits); + uint16_t sign = (uint16_t)((bits >> 48) & 0x8000); + uint64_t magnitude = bits & UINT64_C(0x7fffffffffffffff); + if (magnitude >= UINT64_C(0x7ff0000000000000)) { + if (magnitude == UINT64_C(0x7ff0000000000000)) return sign | 0x7c00; + return sign | 0x7e00 | (uint16_t)((magnitude >> 42) & 0x3ff); + } + int exponent = (int)(magnitude >> 52) - 1023; + if (exponent > 15) return sign | 0x7c00; + uint64_t fraction = magnitude & ((UINT64_C(1) << 52) - 1); + uint64_t significand = exponent == -1023 ? fraction : fraction | (UINT64_C(1) << 52); + if (exponent == -1023) exponent = -1022; + int biased = exponent + 15; + /* Normal results keep 10 of the 52 fraction bits; subnormal results + * shift further, by how far the exponent is below the normal range. */ + int shift = biased >= 1 ? 42 : 42 + (1 - biased); + if (shift >= 54) return sign; + uint64_t q = significand >> shift; + uint64_t rest = significand & ((UINT64_C(1) << shift) - 1); + uint64_t half = UINT64_C(1) << (shift - 1); + if (rest > half || (rest == half && (q & 1))) q++; + if (biased < 1) return sign | (uint16_t)q; /* a carry into 0x400 is the smallest normal */ + if (q == 2048) { + q = 1024; + biased++; + } + if (biased >= 31) return sign | 0x7c00; + return sign | (uint16_t)(biased << 10) | (uint16_t)(q & 0x3ff); +} + +double scr_f16_to_f64(uint16_t h) { + uint64_t sign = (uint64_t)(h >> 15) << 63; + unsigned exponent = (h >> 10) & 0x1f, fraction = h & 0x3ff; + uint64_t bits; + if (exponent == 0) { + double v = (double)fraction * 5.9604644775390625e-8; /* fraction * 2^-24, exact */ + memcpy(&bits, &v, sizeof bits); + bits |= sign; + } else if (exponent == 31) { + bits = sign | UINT64_C(0x7ff0000000000000) | ((uint64_t)fraction << 42); + } else { + bits = sign | ((uint64_t)(exponent - 15 + 1023) << 52) | ((uint64_t)fraction << 42); + } + double out; + memcpy(&out, &bits, sizeof out); + return out; +} + size_t scr_bytes_elem_size(ScrBytesElem elem) { switch (elem) { case SCR_BYTES_U8: case SCR_BYTES_U8C: case SCR_BYTES_I8: return 1; - case SCR_BYTES_U16: case SCR_BYTES_I16: return 2; + case SCR_BYTES_U16: case SCR_BYTES_I16: case SCR_BYTES_F16: return 2; case SCR_BYTES_U32: case SCR_BYTES_I32: case SCR_BYTES_F32: return 4; case SCR_BYTES_F64: return 8; } @@ -106,6 +156,7 @@ const char *scr_bytes_elem_name(ScrBytesElem elem) { case SCR_BYTES_I16: return "Int16Array"; case SCR_BYTES_U32: return "Uint32Array"; case SCR_BYTES_I32: return "Int32Array"; + case SCR_BYTES_F16: return "Float16Array"; case SCR_BYTES_F32: return "Float32Array"; case SCR_BYTES_F64: return "Float64Array"; } @@ -329,6 +380,11 @@ static double scr_bytes_decode(ScrBytesElem elem, const uint8_t *p) { memcpy(&v, p, 4); return (double)v; } + case SCR_BYTES_F16: { + uint16_t v; + memcpy(&v, p, 2); + return scr_f16_to_f64(v); + } case SCR_BYTES_F32: { float v; memcpy(&v, p, 4); @@ -368,6 +424,11 @@ static void scr_bytes_encode(ScrBytesElem elem, uint8_t *p, double v) { memcpy(p, &u, 4); break; } + case SCR_BYTES_F16: { + uint16_t h = scr_f16_from_f64(v); + memcpy(p, &h, 2); + break; + } case SCR_BYTES_F32: { float f = (float)v; /* round-to-nearest-even, exactly Float32Array */ memcpy(p, &f, 4); @@ -511,6 +572,13 @@ static void scr_bytes_read_numbers(double *out, const uint8_t *src, ScrBytesElem SCR_READ_NUMBERS(SCR_BYTES_I32, int32_t); SCR_READ_NUMBERS(SCR_BYTES_F32, float); SCR_READ_NUMBERS(SCR_BYTES_F64, double); + case SCR_BYTES_F16: + for (size_t i = 0; i < count; i++) { + uint16_t value; + memcpy(&value, src + i * sizeof value, sizeof value); + out[i] = scr_f16_to_f64(value); + } + return; } #undef SCR_READ_NUMBERS } @@ -535,6 +603,9 @@ static void scr_bytes_write_numbers(uint8_t *dst, ScrBytesElem elem, const doubl case SCR_BYTES_U32: case SCR_BYTES_I32: { SCR_WRITE_NUMBERS(uint32_t, scr_numeric_to_u32(src[i])); } + case SCR_BYTES_F16: { + SCR_WRITE_NUMBERS(uint16_t, scr_f16_from_f64(src[i])); + } case SCR_BYTES_F32: { SCR_WRITE_NUMBERS(float, (float)src[i]); } @@ -936,6 +1007,7 @@ static size_t scr_dataview_get_size(ScrDataViewGet kind) { return 1; case SCR_DV_U16: case SCR_DV_I16: + case SCR_DV_F16: return 2; case SCR_DV_U32: case SCR_DV_I32: @@ -974,6 +1046,8 @@ double scr_dataview_get(const ScrBytes *b, double byte_off, ScrDataViewGet kind, return (double)(int16_t)u; case SCR_DV_I32: return (double)(int32_t)u; + case SCR_DV_F16: + return scr_f16_to_f64((uint16_t)u); case SCR_DV_F32: { uint32_t bits = (uint32_t)u; float f; @@ -1018,6 +1092,9 @@ void scr_dataview_set(ScrBytes *b, double byte_off, double value, ScrDataViewGet case SCR_DV_I32: u = (uint64_t)scr_bytes_to_u32(value); break; + case SCR_DV_F16: + u = scr_f16_from_f64(value); + break; case SCR_DV_F32: { float f = (float)value; uint32_t bits; diff --git a/packages/runtime/src/scr_bytes.h b/packages/runtime/src/scr_bytes.h index b56f9477d..93a80a7eb 100644 --- a/packages/runtime/src/scr_bytes.h +++ b/packages/runtime/src/scr_bytes.h @@ -20,7 +20,8 @@ * Elements are scalars only and the backing edge is acyclic by * construction (owners point at nothing): never part of a cycle, no * trace. Element reads widen to double; writes coerce JS-exactly (ToUint8 - * / ToUint32 modular truncation, double→float rounding for f32). + * / ToUint32 modular truncation, double→float rounding for f32, one + * double→binary16 rounding for f16). * Out-of-bounds typed ELEMENT reads trap like arrays; invalid writes are * ignored as in JavaScript. The Node-shaped operations * (construction lengths, set(), the read/write numeric families, the @@ -37,7 +38,16 @@ typedef enum ScrBytesElem { SCR_BYTES_U16, /* Uint16Array */ SCR_BYTES_I16, /* Int16Array */ SCR_BYTES_U8C, /* Uint8ClampedArray */ + SCR_BYTES_F16, /* Float16Array (IEEE 754 binary16 storage) */ } ScrBytesElem; +#define SCR_BYTES_ELEM_COUNT 10 + +/* Float16Array's element conversions: one round-to-nearest-even step from + * the double (Float16Array stores, Math.f16round and DataView.setFloat16 + * all round this way), and the exact widening back. NaN keeps its sign and + * top payload bits with the quiet bit set. */ +uint16_t scr_f16_from_f64(double value); +double scr_f16_to_f64(uint16_t bits); typedef struct ScrSharedBytes ScrSharedBytes; @@ -148,6 +158,7 @@ ScrBytes *scr_array_buffer_view_i16(ScrDyn *, ScrDyn *, ScrDyn *); ScrBytes *scr_array_buffer_view_u8(ScrDyn *, ScrDyn *, ScrDyn *); ScrBytes *scr_array_buffer_view_u32(ScrDyn *, ScrDyn *, ScrDyn *); ScrBytes *scr_array_buffer_view_i32(ScrDyn *, ScrDyn *, ScrDyn *); +ScrBytes *scr_array_buffer_view_f16(ScrDyn *, ScrDyn *, ScrDyn *); ScrBytes *scr_array_buffer_view_f32(ScrDyn *, ScrDyn *, ScrDyn *); ScrBytes *scr_array_buffer_view_f64(ScrDyn *, ScrDyn *, ScrDyn *); ScrBytes *scr_array_buffer_view_dv(ScrDyn *, ScrDyn *, ScrDyn *); @@ -205,7 +216,7 @@ ScrBytes *scr_dataview_new(ScrBytes *src, double byte_off, bool has_len, double * with the exception pending). */ typedef enum ScrDataViewGet { SCR_DV_U8, SCR_DV_I8, SCR_DV_U16, SCR_DV_I16, SCR_DV_U32, SCR_DV_I32, - SCR_DV_F32, SCR_DV_F64, SCR_DV_BIGU64, SCR_DV_BIGI64, + SCR_DV_F32, SCR_DV_F64, SCR_DV_BIGU64, SCR_DV_BIGI64, SCR_DV_F16, } ScrDataViewGet; double scr_dataview_get(const ScrBytes *b, double byte_off, ScrDataViewGet kind, bool le); diff --git a/packages/runtime/src/scr_dyn_invoke.c b/packages/runtime/src/scr_dyn_invoke.c index 72d277271..59cf34a10 100644 --- a/packages/runtime/src/scr_dyn_invoke.c +++ b/packages/runtime/src/scr_dyn_invoke.c @@ -1520,7 +1520,7 @@ static ScrDyn *scr_dyn_invoke_impl( if (recv->kind == SCR_DYN_BYTES) { ScrBytes *bytes = recv->v.bytes; if (bytes->is_data_view) { - static const char *const kinds[] = { "Uint8", "Int8", "Uint16", "Int16", "Uint32", "Int32", "Float32", "Float64", "BigUint64", "BigInt64" }; + static const char *const kinds[] = { "Uint8", "Int8", "Uint16", "Int16", "Uint32", "Int32", "Float32", "Float64", "BigUint64", "BigInt64", "Float16" }; const bool get = !strncmp(method, "get", 3); const bool set = !strncmp(method, "set", 3); for (size_t kind = 0; (get || set) && kind < sizeof kinds / sizeof kinds[0]; kind++) { @@ -1537,7 +1537,7 @@ static ScrDyn *scr_dyn_invoke_impl( } const bool le = argc > (get ? 1 : 2) && scr_dyn_truthy(args[get ? 1 : 2]); if (get) { - if (kind >= SCR_DV_BIGU64) { + if (kind == SCR_DV_BIGU64 || kind == SCR_DV_BIGI64) { ScrBigInt *value = scr_bigint_dataview_get(bytes, offset, kind == SCR_DV_BIGI64, le); if (scr_exc_pending()) return NULL; ScrDyn *result = scr_dyn_new_bigint(value); @@ -1547,7 +1547,7 @@ static ScrDyn *scr_dyn_invoke_impl( double value = scr_dataview_get(bytes, offset, (ScrDataViewGet)kind, le); return scr_exc_pending() ? NULL : scr_dyn_new_num(value); } - if (kind >= SCR_DV_BIGU64) { + if (kind == SCR_DV_BIGU64 || kind == SCR_DV_BIGI64) { ScrBigInt *value = scr_dyn_bigint_coerce(argc > 1 ? args[1] : scr_dyn_undefined()); if (scr_exc_pending()) return NULL; scr_bigint_dataview_set(bytes, offset, value, le); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index cdfb3d0f9..b5ae62668 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -3113,6 +3113,7 @@ bool scr_dyn_util_type_is(const ScrDyn *value, const ScrStr *probe) { if (PROBE("isInt8Array")) return scr_dyn_typed_array_is(value, SCR_BYTES_I8); if (PROBE("isInt16Array")) return scr_dyn_typed_array_is(value, SCR_BYTES_I16); if (PROBE("isInt32Array")) return scr_dyn_typed_array_is(value, SCR_BYTES_I32); + if (PROBE("isFloat16Array")) return scr_dyn_typed_array_is(value, SCR_BYTES_F16); if (PROBE("isFloat32Array")) return scr_dyn_typed_array_is(value, SCR_BYTES_F32); if (PROBE("isFloat64Array")) return scr_dyn_typed_array_is(value, SCR_BYTES_F64); if (PROBE("isMap")) return value->kind == SCR_DYN_HANDLE && value->v.handle.tag == SCR_DYNH_MAP; @@ -3139,7 +3140,7 @@ bool scr_dyn_util_type_is(const ScrDyn *value, const ScrStr *probe) { * anonymous with length zero. Keep their native closure identity intact. */ ScrDyn *scr_dyn_util_type_value(const ScrDyn *value, const ScrStr *probe) { static const char *const named[] = { "isDataView", "isTypedArray", "isUint8Array", "isUint8ClampedArray", "isUint16Array", "isUint32Array", - "isInt8Array", "isInt16Array", "isInt32Array", "isFloat32Array", "isFloat64Array" }; + "isInt8Array", "isInt16Array", "isInt32Array", "isFloat16Array", "isFloat32Array", "isFloat64Array" }; const char *name = ""; if (probe->len == 17 && memcmp(probe->data, "isArrayBufferView", 17) == 0) name = "isView"; for (size_t i = 0; i < sizeof named / sizeof named[0]; i++) @@ -3158,16 +3159,16 @@ ScrBytes *scr_dyn_bytes_unbox(const ScrDyn *d) { /* Numeric typed-array constructor values share native function identity. * The cache owns one reference until runtime cleanup; arbitrary strings or * functions cannot impersonate one of these constructors. */ -static SCR_TL ScrDyn *scr_bytes_ctors[9]; +static SCR_TL ScrDyn *scr_bytes_ctors[SCR_BYTES_ELEM_COUNT]; static void scr_bytes_ctors_cleanup(void) { - for (size_t i = 0; i < 9; i++) { + for (size_t i = 0; i < SCR_BYTES_ELEM_COUNT; i++) { scr_dyn_release(scr_bytes_ctors[i]); scr_bytes_ctors[i] = NULL; } } static ScrDyn *scr_bytes_ctor_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) { (void)args; (void)argc; - for (size_t i = 0; i < 9; i++) { + for (size_t i = 0; i < SCR_BYTES_ELEM_COUNT; i++) { if (!scr_bytes_ctors[i] || scr_bytes_ctors[i]->v.fn.clo != closure) continue; ScrJsonBuf message; scr_jb_init(&message); @@ -3183,7 +3184,7 @@ static ScrDyn *scr_dyn_fn_properties(const ScrDyn *function); static ScrDyn *scr_bytes_constructor_for(ScrBytesElem elem) { if (!scr_bytes_ctors[elem]) { bool initialized = false; - for (size_t i = 0; i < 9; i++) if (scr_bytes_ctors[i]) initialized = true; + for (size_t i = 0; i < SCR_BYTES_ELEM_COUNT; i++) if (scr_bytes_ctors[i]) initialized = true; if (!initialized) scr_atexit(scr_bytes_ctors_cleanup); scr_bytes_ctors[elem] = scr_dyn_new_func(scr_closure_new(NULL, 0), scr_bytes_ctor_call, 3, "typed-array-constructor", scr_bytes_elem_name(elem)); @@ -3196,7 +3197,7 @@ static ScrDyn *scr_bytes_constructor_for(ScrBytesElem elem) { return scr_dyn_retain(scr_bytes_ctors[elem]); } ScrDyn *scr_bytes_constructor(const ScrStr *name) { - for (size_t i = 0; i < 9; i++) { + for (size_t i = 0; i < SCR_BYTES_ELEM_COUNT; i++) { const char *candidate = scr_bytes_elem_name((ScrBytesElem)i); if (strlen(candidate) == name->len && memcmp(candidate, name->data, name->len) == 0) return scr_bytes_constructor_for((ScrBytesElem)i); @@ -3263,7 +3264,7 @@ bool scr_bytes_instanceof(const ScrDyn *value, const ScrDyn *callee) { } if (scr_array_buffer_ctor && callee->v.fn.clo == scr_array_buffer_ctor->v.fn.clo) return scr_array_buffer_is(value); if (scr_array_ctor && callee->v.fn.clo == scr_array_ctor->v.fn.clo) return value->kind == SCR_DYN_ARR || scr_dyn_ref_is_array(value); - for (size_t i = 0; i < 9; i++) { + for (size_t i = 0; i < SCR_BYTES_ELEM_COUNT; i++) { if (scr_bytes_ctors[i] && callee->v.fn.clo == scr_bytes_ctors[i]->v.fn.clo) return scr_dyn_typed_array_is(value, (int)i); } @@ -3276,7 +3277,7 @@ ScrDyn *scr_bytes_construct(const ScrDyn *callee, const ScrDyn *args, const ScrS return scr_array_ctor_call(callee->v.fn.clo, args->v.arr.items, args->v.arr.len); if (callee->kind == SCR_DYN_FUNC && scr_array_buffer_ctor && callee->v.fn.clo == scr_array_buffer_ctor->v.fn.clo) return scr_array_buffer_new(args->v.arr.len ? args->v.arr.items[0] : scr_dyn_undefined()); - for (size_t i = 0; i < 9; i++) { + for (size_t i = 0; i < SCR_BYTES_ELEM_COUNT; i++) { if (callee->kind != SCR_DYN_FUNC || !scr_bytes_ctors[i] || callee->v.fn.clo != scr_bytes_ctors[i]->v.fn.clo) continue; const ScrDyn *input = args->v.arr.len > 0 ? args->v.arr.items[0] : scr_dyn_undefined(); const ScrDyn *offset = args->v.arr.len > 1 ? args->v.arr.items[1] : scr_dyn_undefined(); @@ -12245,6 +12246,7 @@ SCR_ARRAY_BUFFER_VIEW(i16, SCR_BYTES_I16) SCR_ARRAY_BUFFER_VIEW(u8, SCR_BYTES_U8) SCR_ARRAY_BUFFER_VIEW(u32, SCR_BYTES_U32) SCR_ARRAY_BUFFER_VIEW(i32, SCR_BYTES_I32) +SCR_ARRAY_BUFFER_VIEW(f16, SCR_BYTES_F16) SCR_ARRAY_BUFFER_VIEW(f32, SCR_BYTES_F32) SCR_ARRAY_BUFFER_VIEW(f64, SCR_BYTES_F64) #undef SCR_ARRAY_BUFFER_VIEW diff --git a/tests/corpus/5900-float16-array.ts b/tests/corpus/5900-float16-array.ts new file mode 100644 index 000000000..bcf57ea8d --- /dev/null +++ b/tests/corpus/5900-float16-array.ts @@ -0,0 +1,94 @@ +// Float16Array: construction from lengths, arrays, typed arrays and ArrayBuffer +// views; round-to-nearest-even stores with overflow, NaN, -0 and subnormals; +// fill, set, subarray, slice and both sort orders; DataView getFloat16 and +// setFloat16 in both byte orders; Math.f16round; util.types and instanceof; +// structuredClone, assert and Buffer views. Node.js prints the same. +import { types } from "node:util"; +import assert from "node:assert"; +const show = (label: string, a: Float16Array): void => console.log(label, a.length, Array.from(a).join(",")); +const a = new Float16Array(6); +a[0] = 1.5; +a[1] = 65519; +a[2] = 65520; +a[3] = 0.1; +a[4] = -0; +a[5] = 5.960464477539063e-8 / 2; +show("rounding", a); +const b = new Float16Array([NaN, Infinity, -Infinity, 1e-8, 2049, 2051, 4097, -1e6]); +show("specials", b); +console.log(Object.is(a[4], -0), a[6], a.length, a.byteLength, Number.isNaN(b[0])); +const c = Float16Array.from([3.14159, 2.71828, 1.41421]); +show("from", c); +const e = new Float16Array(c); +e[0] = 100; +show("copy", e); +show("source untouched", c); +const f32 = new Float32Array([1 / 3, 2 / 3]); +show("from f32", new Float16Array(f32)); +const buf = new ArrayBuffer(8); +const view = new Float16Array(buf, 2, 2); +view[0] = 1; +view[1] = -2; +console.log("view bytes", Array.from(new Uint8Array(buf)).join(","), new Uint16Array(buf)[1]); +const g = new Float16Array(5); +g.fill(0.3); +show("fill", g); +g.set([1.1, 2.2], 3); +show("set", g); +show("subarray", g.subarray(1, 4)); +show("slice", g.slice(-2)); +const h = new Float16Array([3, -0, 0, NaN, -1, 2.5, -Infinity, 0.1]); +show("sort", h.slice().sort()); +show("sort desc", h.slice().sort((x, y) => y - x)); +show("toSorted", h.toSorted()); +let sum = 0; +for (const v of c) sum += v; +console.log("for-of", sum, h.join("|"), String(c), Object.prototype.toString.call(c)); +const dv = new DataView(new ArrayBuffer(8)); +dv.setFloat16(0, 3.14159); +dv.setFloat16(2, 3.14159, true); +dv.setFloat16(4, -65504); +dv.setFloat16(6, NaN, true); +console.log("dataview", dv.getFloat16(0), dv.getFloat16(2, true), dv.getFloat16(4), dv.getFloat16(6, true), dv.getUint16(0), dv.getUint16(2)); +try { + dv.getFloat16(7); +} catch (err) { + console.log((err as Error).name, (err as Error).message); +} +console.log("f16round", Math.f16round(1.337), Math.f16round(65520), Math.f16round(-0), Math.f16round(5e-8), Math.f16round(2 ** -25), Math.f16round(1.0009765625 + 2 ** -12)); +console.log("types", types.isFloat16Array(a), types.isFloat32Array(a), types.isTypedArray(a), a instanceof Float16Array); +const u: unknown = a; +console.log("unknown", u instanceof Float16Array, u instanceof Float32Array); +const big = new Float16Array(1000); +for (let i = 0; i < big.length; i++) big[i] = Math.sin(i) * 1000; +let acc = 0; +for (let i = 0; i < big.length; i++) acc += big[i]!; +console.log("loop", acc, big[999]); +const f = new Float16Array([1.5, NaN, -0, 65504]); +const clone = structuredClone(f); +clone[0] = 2; +console.log(clone[0], f[0], clone.length); +assert.deepStrictEqual(new Float16Array([NaN, 1]), new Float16Array([NaN, 1])); +try { + assert.deepStrictEqual(new Float16Array([0]), new Float16Array([-0])); +} catch (e) { + console.log("deepStrictEqual -0", (e as Error).name); +} +assert.deepEqual(new Float16Array([0]), new Float16Array([-0])); +const raw = Buffer.from(f.buffer); +console.log(raw.length, raw.readUInt16LE(0), raw.readUInt16LE(6)); +const fromBuf = new Float16Array(f.buffer, 2, 1); +console.log(Number.isNaN(fromBuf[0])); +const list: Float16Array[] = [f, new Float16Array(2)]; +const m = new Map([["a", f]]); +console.log(list.length, m.get("a")![3], list[1]!.length); +const Ctor = Float16Array; +const x = new Ctor(3); +x[1] = 0.2; +console.log(x.length, x[1]); +const y = new Float16Array([1, 2]); +const D = y.constructor as Float16ArrayConstructor; +const z = new D(2); +console.log(z.length, z instanceof Float16Array); +const unknownView: unknown = new Float16Array([7]); +console.log(unknownView instanceof Float16Array); diff --git a/tests/corpus/5901-float16-array-js.js b/tests/corpus/5901-float16-array-js.js new file mode 100644 index 000000000..8c0f6f7bc --- /dev/null +++ b/tests/corpus/5901-float16-array-js.js @@ -0,0 +1,95 @@ +// Float16Array from JavaScript: construction from lengths, arrays, typed +// arrays and ArrayBuffer views; round-to-nearest-even stores with overflow, +// NaN, -0 and subnormals; fill, set, subarray, slice and both sort orders; +// DataView getFloat16 and setFloat16 in both byte orders; Math.f16round; +// util.types and instanceof; structuredClone, assert and Buffer views. +// Node.js prints the same. +import { types } from "node:util"; +import assert from "node:assert"; +const show = (label , a ) => console.log(label, a.length, Array.from(a).join(",")); +const a = new Float16Array(6); +a[0] = 1.5; +a[1] = 65519; +a[2] = 65520; +a[3] = 0.1; +a[4] = -0; +a[5] = 5.960464477539063e-8 / 2; +show("rounding", a); +const b = new Float16Array([NaN, Infinity, -Infinity, 1e-8, 2049, 2051, 4097, -1e6]); +show("specials", b); +console.log(Object.is(a[4], -0), a[6], a.length, a.byteLength, Number.isNaN(b[0])); +const c = Float16Array.from([3.14159, 2.71828, 1.41421]); +show("from", c); +const e = new Float16Array(c); +e[0] = 100; +show("copy", e); +show("source untouched", c); +const f32 = new Float32Array([1 / 3, 2 / 3]); +show("from f32", new Float16Array(f32)); +const buf = new ArrayBuffer(8); +const view = new Float16Array(buf, 2, 2); +view[0] = 1; +view[1] = -2; +console.log("view bytes", Array.from(new Uint8Array(buf)).join(","), new Uint16Array(buf)[1]); +const g = new Float16Array(5); +g.fill(0.3); +show("fill", g); +g.set([1.1, 2.2], 3); +show("set", g); +show("subarray", g.subarray(1, 4)); +show("slice", g.slice(-2)); +const h = new Float16Array([3, -0, 0, NaN, -1, 2.5, -Infinity, 0.1]); +show("sort", h.slice().sort()); +show("sort desc", h.slice().sort((x, y) => y - x)); +show("toSorted", h.toSorted()); +let sum = 0; +for (const v of c) sum += v; +console.log("for-of", sum, h.join("|"), String(c), Object.prototype.toString.call(c)); +const dv = new DataView(new ArrayBuffer(8)); +dv.setFloat16(0, 3.14159); +dv.setFloat16(2, 3.14159, true); +dv.setFloat16(4, -65504); +dv.setFloat16(6, NaN, true); +console.log("dataview", dv.getFloat16(0), dv.getFloat16(2, true), dv.getFloat16(4), dv.getFloat16(6, true), dv.getUint16(0), dv.getUint16(2)); +try { + dv.getFloat16(7); +} catch (err) { + console.log((err ).name, (err ).message); +} +console.log("f16round", Math.f16round(1.337), Math.f16round(65520), Math.f16round(-0), Math.f16round(5e-8), Math.f16round(2 ** -25), Math.f16round(1.0009765625 + 2 ** -12)); +console.log("types", types.isFloat16Array(a), types.isFloat32Array(a), types.isTypedArray(a), a instanceof Float16Array); +const u = a; +console.log("unknown", u instanceof Float16Array, u instanceof Float32Array); +const big = new Float16Array(1000); +for (let i = 0; i < big.length; i++) big[i] = Math.sin(i) * 1000; +let acc = 0; +for (let i = 0; i < big.length; i++) acc += big[i] ; +console.log("loop", acc, big[999]); +const f = new Float16Array([1.5, NaN, -0, 65504]); +const clone = structuredClone(f); +clone[0] = 2; +console.log(clone[0], f[0], clone.length); +assert.deepStrictEqual(new Float16Array([NaN, 1]), new Float16Array([NaN, 1])); +try { + assert.deepStrictEqual(new Float16Array([0]), new Float16Array([-0])); +} catch (e) { + console.log("deepStrictEqual -0", (e ).name); +} +assert.deepEqual(new Float16Array([0]), new Float16Array([-0])); +const raw = Buffer.from(f.buffer); +console.log(raw.length, raw.readUInt16LE(0), raw.readUInt16LE(6)); +const fromBuf = new Float16Array(f.buffer, 2, 1); +console.log(Number.isNaN(fromBuf[0])); +const list = [f, new Float16Array(2)]; +const m = new Map ([["a", f]]); +console.log(list.length, m.get("a") [3], list[1] .length); +const Ctor = Float16Array; +const x = new Ctor(3); +x[1] = 0.2; +console.log(x.length, x[1]); +const y = new Float16Array([1, 2]); +const D = y.constructor ; +const z = new D(2); +console.log(z.length, z instanceof Float16Array); +const unknownView = new Float16Array([7]); +console.log(unknownView instanceof Float16Array); diff --git a/tests/diagnostics/dataview.ts b/tests/diagnostics/dataview.ts index 01255b47c..c20193279 100644 --- a/tests/diagnostics/dataview.ts +++ b/tests/diagnostics/dataview.ts @@ -1,6 +1,8 @@ -// Stored ArrayBuffers and DataViews lower; Float16 accessors remain unsupported. +// Stored ArrayBuffers and DataViews lower, Float16 accessors included; +// detached accessor methods remain unsupported. const buffer = new ArrayBuffer(16); const view = new DataView(buffer); view.setFloat16(0, 1.5); console.log(view.getFloat16(0)); +const getter = view.getFloat16; // End of the diagnostic fixture. diff --git a/tests/diagnostics/es2025-fences.ts b/tests/diagnostics/es2025-fences.ts index 2df12226f..067da192e 100644 --- a/tests/diagnostics/es2025-fences.ts +++ b/tests/diagnostics/es2025-fences.ts @@ -1,9 +1,8 @@ // The es2025-lib surface WITHOUT a lowering fences by name: resizable // ArrayBuffers and transfer, SharedArrayBuffer.grow, Atomics.waitAsync, -// Float16Array and its Math/DataView companions, first-class iterator -// objects, and the unlowered forms of the implemented statics -// (Promise.try with fewer arguments than parameters, groupBy's -// literal-union keys, a set-like non-Set argument). +// first-class iterator objects, and the unlowered forms of the +// implemented statics (Promise.try with fewer arguments than parameters, +// groupBy's literal-union keys, a set-like non-Set argument). // Resizable ArrayBuffer + transfer (ES2024). const ab = new ArrayBuffer(8, { maxByteLength: 16 }); @@ -22,12 +21,6 @@ sab.grow(16); const ia = new Int32Array(4); const waited = Atomics.waitAsync(ia, 0, 0, 1); -// Float16 (ES2025): the typed array, Math.f16round, DataView accessors. -const f16 = new Float16Array(4); -console.log(Math.f16round(1.337)); -const dv = new DataView(new Uint8Array(8).buffer); -dv.setFloat16(0, 1.5); - // First-class iterator objects. const it = Iterator.from([1, 2, 3].values()); diff --git a/tests/harness/__snapshots__/dataview.ts.txt b/tests/harness/__snapshots__/dataview.ts.txt index f09051126..4f1401ca3 100644 --- a/tests/harness/__snapshots__/dataview.ts.txt +++ b/tests/harness/__snapshots__/dataview.ts.txt @@ -1,17 +1,8 @@ -dataview.ts:4:1 - error SC2020: 'DataView.setFloat16' is part of the standard library types but has no scriptc lowering yet +dataview.ts:7:16 - error SC2020: 'DataView.getFloat16' is part of the standard library types but has no scriptc lowering yet - 3 | const view = new DataView(buffer); - 4 | view.setFloat16(0, 1.5); - | ^~~~~~~~~~~~~~~ - 5 | console.log(view.getFloat16(0)); - - hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) - -dataview.ts:5:13 - error SC2020: 'DataView.getFloat16' is part of the standard library types but has no scriptc lowering yet - - 4 | view.setFloat16(0, 1.5); - 5 | console.log(view.getFloat16(0)); - | ^~~~~~~~~~~~~~~ - 6 | // End of the diagnostic fixture. + 6 | console.log(view.getFloat16(0)); + 7 | const getter = view.getFloat16; + | ^~~~~~~~~~~~~~~ + 8 | // End of the diagnostic fixture. hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) \ No newline at end of file diff --git a/tests/harness/__snapshots__/es2025-fences.ts.txt b/tests/harness/__snapshots__/es2025-fences.ts.txt index e1761f73a..e2dc5f40f 100644 --- a/tests/harness/__snapshots__/es2025-fences.ts.txt +++ b/tests/harness/__snapshots__/es2025-fences.ts.txt @@ -1,125 +1,89 @@ -es2025-fences.ts:9:12 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:8:12 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet - 8 | // Resizable ArrayBuffer + transfer (ES2024). - 9 | const ab = new ArrayBuffer(8, { maxByteLength: 16 }); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 10 | ab.resize(16); + 7 | // Resizable ArrayBuffer + transfer (ES2024). + 8 | const ab = new ArrayBuffer(8, { maxByteLength: 16 }); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 9 | ab.resize(16); hint: fixed-length ArrayBuffers accept a byte length; resizable storage is not supported yet -es2025-fences.ts:15:27 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:14:27 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet - 14 | // fixed-length new Uint8Array(new ArrayBuffer(8)) lowers). - 15 | const rz = new Uint8Array(new ArrayBuffer(8, { maxByteLength: 16 })); + 13 | // fixed-length new Uint8Array(new ArrayBuffer(8)) lowers). + 14 | const rz = new Uint8Array(new ArrayBuffer(8, { maxByteLength: 16 })); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 16 | + 15 | hint: fixed-length ArrayBuffers accept a byte length; resizable storage is not supported yet -es2025-fences.ts:18:13 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:17:13 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet - 17 | // SharedArrayBuffer growth. - 18 | const sab = new SharedArrayBuffer(8, { maxByteLength: 16 }); + 16 | // SharedArrayBuffer growth. + 17 | const sab = new SharedArrayBuffer(8, { maxByteLength: 16 }); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 19 | sab.grow(16); + 18 | sab.grow(16); hint: fixed-length ArrayBuffers accept a byte length; resizable storage is not supported yet -es2025-fences.ts:23:7 - error SC2009: values of type '{ async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }' cannot be compiled: the union shape is supported, but its arm '{ async: false; value: "not-equal" | "timed-out"; }' does not compile +es2025-fences.ts:22:7 - error SC2009: values of type '{ async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }' cannot be compiled: the union shape is supported, but its arm '{ async: false; value: "not-equal" | "timed-out"; }' does not compile - 22 | const ia = new Int32Array(4); - 23 | const waited = Atomics.waitAsync(ia, 0, 0, 1); + 21 | const ia = new Int32Array(4); + 22 | const waited = Atomics.waitAsync(ia, 0, 0, 1); | ^~~~~~ - 24 | + 23 | hint: the outer shape is supported — the named component is the blocker; restate it inside the compilable set (number, string, boolean, arrays, Maps, Sets, RegExp, functions, classes, records, unions of those, and 'unknown') -es2025-fences.ts:23:16 - error SC2020: 'Atomics.waitAsync' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:22:16 - error SC2020: 'Atomics.waitAsync' is part of the standard library types but has no scriptc lowering yet - 22 | const ia = new Int32Array(4); - 23 | const waited = Atomics.waitAsync(ia, 0, 0, 1); + 21 | const ia = new Int32Array(4); + 22 | const waited = Atomics.waitAsync(ia, 0, 0, 1); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 24 | + 23 | hint: use integer load, store, exchange, compareExchange, add, sub, and, or, xor, wait or notify -es2025-fences.ts:26:7 - error SC2020: 'Float16Array' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:25:7 - error SC2020: 'IteratorObject' is part of the standard library types but has no scriptc lowering yet - 25 | // Float16 (ES2025): the typed array, Math.f16round, DataView accessors. - 26 | const f16 = new Float16Array(4); - | ^~~ - 27 | console.log(Math.f16round(1.337)); - - hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) - -es2025-fences.ts:26:13 - error SC2020: 'new Float16Array' is part of the standard library types but has no scriptc lowering yet - - 25 | // Float16 (ES2025): the typed array, Math.f16round, DataView accessors. - 26 | const f16 = new Float16Array(4); - | ^~~~~~~~~~~~~~~~~~~ - 27 | console.log(Math.f16round(1.337)); - - hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) - -es2025-fences.ts:27:13 - error SC2020: 'Math.f16round' is part of the standard library types but has no scriptc lowering yet - - 26 | const f16 = new Float16Array(4); - 27 | console.log(Math.f16round(1.337)); - | ^~~~~~~~~~~~~ - 28 | const dv = new DataView(new Uint8Array(8).buffer); - - hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) - -es2025-fences.ts:29:1 - error SC2020: 'DataView.setFloat16' is part of the standard library types but has no scriptc lowering yet - - 28 | const dv = new DataView(new Uint8Array(8).buffer); - 29 | dv.setFloat16(0, 1.5); - | ^~~~~~~~~~~~~ - 30 | - - hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) - -es2025-fences.ts:32:7 - error SC2020: 'IteratorObject' is part of the standard library types but has no scriptc lowering yet - - 31 | // First-class iterator objects. - 32 | const it = Iterator.from([1, 2, 3].values()); + 24 | // First-class iterator objects. + 25 | const it = Iterator.from([1, 2, 3].values()); | ^~ - 33 | + 26 | hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) -es2025-fences.ts:32:12 - error SC2020: 'Iterator.from' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:25:12 - error SC2020: 'Iterator.from' is part of the standard library types but has no scriptc lowering yet - 31 | // First-class iterator objects. - 32 | const it = Iterator.from([1, 2, 3].values()); + 24 | // First-class iterator objects. + 25 | const it = Iterator.from([1, 2, 3].values()); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 33 | + 26 | hint: first-class iterator objects have no lowering — iterator helpers compile as one chain on an array iterator, consumed in place: arr.values().map(f).take(n).toArray() -es2025-fences.ts:35:27 - error SC2020: 'Promise.try over a callback of type '(a: number, b?: number | undefined) => number' with 1 argument' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:28:27 - error SC2020: 'Promise.try over a callback of type '(a: number, b?: number | undefined) => number' with 1 argument' is part of the standard library types but has no scriptc lowering yet - 34 | // Promise.try with fewer arguments than the callback's parameters. - 35 | const tried = Promise.try((a: number, b?: number) => a + (b ?? 0), 1); + 27 | // Promise.try with fewer arguments than the callback's parameters. + 28 | const tried = Promise.try((a: number, b?: number) => a + (b ?? 0), 1); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 36 | + 29 | hint: pass one argument per callback parameter: Promise.try((a, b) => a + b, 1, 2) -es2025-fences.ts:38:17 - error SC2020: 'Object.groupBy at this result type' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:31:17 - error SC2020: 'Object.groupBy at this result type' is part of the standard library types but has no scriptc lowering yet - 37 | // Object.groupBy at a literal-union key type (a fixed-field record). - 38 | const grouped = Object.groupBy([1, 2, 3], (n) => (n % 2 === 0 ? "even" : "odd")); + 30 | // Object.groupBy at a literal-union key type (a fixed-field record). + 31 | const grouped = Object.groupBy([1, 2, 3], (n) => (n % 2 === 0 ? "even" : "odd")); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 39 | + 32 | hint: a string-keyed result (Partial>) is the supported form — a literal-union key type makes a fixed-field record: widen the callback's key type to string (numbers stringify like JS property keys) -es2025-fences.ts:43:19 - error SC2020: 'Set.prototype.union over a set-like argument of type '{ size: number; has: (x: number) => x is 1; keys: () => ArrayIterator; }'' is part of the standard library types but has no scriptc lowering yet +es2025-fences.ts:36:19 - error SC2020: 'Set.prototype.union over a set-like argument of type '{ size: number; has: (x: number) => x is 1; keys: () => ArrayIterator; }'' is part of the standard library types but has no scriptc lowering yet - 42 | const like = { size: 1, has: (x: number) => x === 1, keys: () => [1].values() }; - 43 | const u = s.union(like); + 35 | const like = { size: 1, has: (x: number) => x === 1, keys: () => [1].values() }; + 36 | const u = s.union(like); | ^~~~ - 44 | + 37 | hint: only a real Set or Map lowers (the argument's has/size/keys must be the builtins) — build one first: new Set(...) \ No newline at end of file diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index ecd7f5d9b..2b83e3de9 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,8 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5900-float16-array.ts": 3000, + "5901-float16-array-js.js": 2900, "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, @@ -4468,6 +4470,8 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5900-float16-array.ts": 3750, + "5901-float16-array-js.js": 3700, "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, From ed817c017dbe4660e381cb9edc079d073ecdd3ac Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 22:50:45 -0500 Subject: [PATCH 033/117] Name the rejected value in the Object prototype TypeError Object.setPrototypeOf and Object.create threw "Object prototype may only be an Object or null" without the value Node appends. The message now ends with the value's string form, as in Node: "...: 7", "...: undefined", "...: Symbol(tag)". A prototype or receiver that is a valid object of a kind these functions do not handle yet (a function or Map prototype for Object.create, a Map prototype or receiver for Object.setPrototypeOf) threw the same TypeError. It now throws an Error that says the operation is not supported for that value. --- ...5913-prototype-type-error-messages.ts.json | 6 +++ packages/runtime/src/scr_json.c | 42 ++++++++++++++----- .../5913-prototype-type-error-messages.ts | 39 +++++++++++++++++ tests/harness/corpus-costs.json | 6 +++ 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5913-prototype-type-error-messages.ts.json create mode 100644 tests/corpus/5913-prototype-type-error-messages.ts diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5913-prototype-type-error-messages.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5913-prototype-type-error-messages.ts.json new file mode 100644 index 000000000..f7e3d10b9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5913-prototype-type-error-messages.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5913-prototype-type-error-messages.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index cdfb3d0f9..958112b66 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1729,13 +1729,40 @@ static bool scr_dyn_typed_ref_prototype(const ScrDyn *value) { return view && (view->kind == SCR_DYN_OBJ || view->kind == SCR_DYN_ARR); } +/* True when `prototype` is null or an object or function, the values + * Object.create and Object.setPrototypeOf accept. Otherwise throws Node's + * TypeError, whose message ends with the value's string form. */ +static bool scr_dyn_prototype_valid(const ScrDyn *prototype) { + if (scr_dyn_is_object(prototype) || scr_dyn_is_callable(prototype)) return true; + if (scr_exc_pending()) return false; + ScrStr *text = prototype->kind == SCR_DYN_SYMBOL + ? prototype->v.symbol.render(prototype->v.symbol.value) : scr_dyn_string_coerce_js(prototype); + if (!text) return false; + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_puts(&b, "Object prototype may only be an Object or null: "); + scr_jb_put_str(&b, text); + scr_str_release(text); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&b)); + return false; +} + +/* A valid receiver or prototype whose kind this operation does not handle. */ +static void scr_dyn_prototype_unsupported(const char *operation) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_puts(&b, operation); + scr_jb_puts(&b, " with this value is not supported yet"); + scr_throw_error(SCR_ERR_ERROR, scr_jb_finish(&b)); +} + ScrDyn *scr_dyn_obj_create(ScrDyn *prototype) { + if (!scr_dyn_prototype_valid(prototype)) return NULL; if (prototype != scr_builtin_object_prototype && scr_dyn_class_reflection_fence(prototype)) return NULL; bool typed = scr_dyn_typed_ref_prototype(prototype); if (scr_exc_pending()) return NULL; if (prototype->kind != SCR_DYN_OBJ && prototype->kind != SCR_DYN_ARR && prototype->kind != SCR_DYN_NULL && !typed) { - static const char message[] = "Object prototype may only be an Object or null"; - scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + scr_dyn_prototype_unsupported("Object.create"); return NULL; } ScrDyn *object = prototype->kind == SCR_DYN_NULL ? scr_dyn_new_obj_null_proto() : scr_dyn_new_obj(); @@ -1786,12 +1813,7 @@ ScrDyn *scr_dyn_set_prototype(ScrDyn *object, ScrDyn *prototype) { * only check. */ if (object->kind == SCR_DYN_BOOL || object->kind == SCR_DYN_NUM || object->kind == SCR_DYN_STR || object->kind == SCR_DYN_BIGINT || object->kind == SCR_DYN_SYMBOL) { - bool valid = scr_dyn_is_object(prototype) || scr_dyn_is_callable(prototype); - if (scr_exc_pending()) return NULL; - if (valid) return scr_dyn_retain(object); - static const char message[] = "Object prototype may only be an Object or null"; - scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); - return NULL; + return scr_dyn_prototype_valid(prototype) ? scr_dyn_retain(object) : NULL; } if (scr_dyn_class_reflection_fence(object) || scr_dyn_class_reflection_fence(prototype)) return NULL; if (object->kind == SCR_DYN_TYPED_REF) { @@ -1821,12 +1843,12 @@ ScrDyn *scr_dyn_set_prototype(ScrDyn *object, ScrDyn *prototype) { scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); return NULL; } + if (!scr_dyn_prototype_valid(prototype)) return NULL; bool typed = scr_dyn_typed_ref_prototype(prototype); if (scr_exc_pending()) return NULL; if ((object->kind != SCR_DYN_OBJ && object->kind != SCR_DYN_ARR) || (prototype->kind != SCR_DYN_OBJ && prototype->kind != SCR_DYN_ARR && prototype->kind != SCR_DYN_FUNC && prototype->kind != SCR_DYN_NULL && !typed)) { - static const char message[] = "Object prototype may only be an Object or null"; - scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + scr_dyn_prototype_unsupported("Object.setPrototypeOf"); return NULL; } for (const ScrDyn *current = scr_dyn_chain_link(prototype); current;) { diff --git a/tests/corpus/5913-prototype-type-error-messages.ts b/tests/corpus/5913-prototype-type-error-messages.ts new file mode 100644 index 000000000..cb78e4cb1 --- /dev/null +++ b/tests/corpus/5913-prototype-type-error-messages.ts @@ -0,0 +1,39 @@ +// Object.setPrototypeOf and Object.create reject a prototype that is +// neither an object nor null with Node's TypeError, whose message ends with +// the value's string form: numbers as String(n) (-0 as 0), bigints without +// the n suffix, symbols as Symbol(description), and the empty string as +// nothing. + +function message(run: () => unknown): string { + try { + run(); + return "no error"; + } catch (error) { + return `${error instanceof TypeError} ${(error as Error).message}`; + } +} + +const prototypes: [string, unknown][] = [ + ["number", 7], + ["fraction", 1.5], + ["negative zero", -0], + ["nan", NaN], + ["string", "proto"], + ["empty string", ""], + ["boolean", true], + ["undefined", undefined], + ["bigint", 10n], + ["symbol", Symbol("tag")], +]; + +for (const [label, prototype] of prototypes) { + const invalid = prototype as object | null; + const target: unknown = JSON.parse('{"own":1}'); + console.log(label, "object receiver |", message(() => Object.setPrototypeOf(target, invalid))); + console.log(label, "primitive receiver |", message(() => Object.setPrototypeOf(5, invalid))); + console.log(label, "create |", message(() => Object.create(invalid))); +} + +const valid: unknown = JSON.parse('{"own":1}'); +console.log("null prototype |", message(() => Object.setPrototypeOf(valid, null))); +console.log("object prototype |", message(() => Object.create({ inherited: true }))); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index ecd7f5d9b..a653b9bae 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,9 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5910-set-prototype-of-primitive-object-kinds.ts": 2719, + "5911-dyn-class-to-primitive.ts": 2850, + "5913-prototype-type-error-messages.ts": 2484, "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, @@ -4468,6 +4471,9 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5910-set-prototype-of-primitive-object-kinds.ts": 5033, + "5911-dyn-class-to-primitive.ts": 4732, + "5913-prototype-type-error-messages.ts": 4068, "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, From aa19f948c5f3d5b5f9a4d916715ab7f842bc27e0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 23:19:15 -0500 Subject: [PATCH 034/117] Settle async generator completions on Node's microtask turns An async generator that fell off its end, with a return type other than void, settled its last next() one microtask turn after Node, so for await loops over it also ended a turn late. The appended implicit return now marks the completion as settled, like a bare `return;`. return() at a suspended yield ran the generator's finally blocks before awaiting the return value. The request now awaits the value first and resumes the body on the next turn, and the completion that follows settles without a further turn, also when a finally block yields or awaits first. An explicit `return x` reached during that unwind still takes its own turn to await x. Array.fromAsync accepts typed async generator sources: each next() result is awaited and its value used as is, a throwing or rejecting mapping function closes the generator, and a rejected next() rejects the result on the turn Node rejects it. --- .../language-features/async-iteration.mdx | 2 +- packages/compiler/src/backend/llvm/emitter.ts | 6 + .../lowering/containers/array-from-async.ts | 203 +++++++++++++++--- .../src/frontend/lowering/function-returns.ts | 8 +- .../src/frontend/lowering/lower-generators.ts | 2 +- .../5904-async-generator-completion.ts.json | 6 + .../5905-array-from-async-generator.ts.json | 6 + ...5906-array-from-async-generator-js.js.json | 6 + packages/runtime/src/scr_async.c | 69 +++++- packages/runtime/src/scr_generator.h | 2 + .../corpus/5904-async-generator-completion.ts | 188 ++++++++++++++++ .../corpus/5905-array-from-async-generator.ts | 61 ++++++ .../5906-array-from-async-generator-js.js | 60 ++++++ tests/harness/corpus-costs.json | 6 + 14 files changed, 590 insertions(+), 35 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5904-async-generator-completion.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5905-array-from-async-generator.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5906-array-from-async-generator-js.js.json create mode 100644 tests/corpus/5904-async-generator-completion.ts create mode 100644 tests/corpus/5905-array-from-async-generator.ts create mode 100644 tests/corpus/5906-array-from-async-generator-js.js diff --git a/docs/content/limitations/language-features/async-iteration.mdx b/docs/content/limitations/language-features/async-iteration.mdx index ee570f17d..f18377299 100644 --- a/docs/content/limitations/language-features/async-iteration.mdx +++ b/docs/content/limitations/language-features/async-iteration.mdx @@ -1 +1 @@ -- **Async iteration:** Async `yield*` delegation, stored Web or Node iterator handles, and general structural async-iterator objects are unsupported. Typed async generators support lazy execution, `await`, direct `yield`, queued `.next()`/`.return()`/`.throw()` requests, and `for await`. `for await` also accepts Node `Readable` streams, Web `ReadableStream` values, and compiled class iterators whose zero-parameter `next()` returns a promise of a `{ value, done? }` record. Abrupt completion runs cleanup, including literal `destroyOnReturn` and `preventCancel` options. The `node:timers/promises` `setInterval(delay, value)` iterator compiles without AbortSignal options. `Array.fromAsync` accepts arrays of values or of promises with an optional mapping function; async generator sources, a `thisArg`, and arrays that mix values and promises are unsupported. +- **Async iteration:** Async `yield*` delegation, stored Web or Node iterator handles, and general structural async-iterator objects are unsupported. Typed async generators support lazy execution, `await`, direct `yield`, queued `.next()`/`.return()`/`.throw()` requests, and `for await`. `for await` also accepts Node `Readable` streams, Web `ReadableStream` values, and compiled class iterators whose zero-parameter `next()` returns a promise of a `{ value, done? }` record. Abrupt completion runs cleanup, including literal `destroyOnReturn` and `preventCancel` options. The `node:timers/promises` `setInterval(delay, value)` iterator compiles without AbortSignal options. `Array.fromAsync` accepts arrays of values or of promises and typed async generators, with an optional mapping function; a `thisArg` and arrays that mix values and promises are unsupported. diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 2c3a71457..e2b1102c1 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -8919,6 +8919,12 @@ export class LlEmitter { // own turn is the await (nothing runs in between). const genSettles = this.currentAsyncGenerator && (s.awaited === true || this.finallyStack.length > 0); + // A completion turn that awaits x replaces a return() request's + // already-taken await. + if (this.currentAsyncGenerator && !genSettles) { + this.declare(`declare void @scr_async_gen_return_awaits()`); + B.line(`call void @scr_async_gen_return_awaits()`); + } if (this.currentAsyncGenerator && s.awaited !== true && this.finallyStack.length > 0) { if (this.wasi) this.emitWasiSuspend(null); else { diff --git a/packages/compiler/src/frontend/lowering/containers/array-from-async.ts b/packages/compiler/src/frontend/lowering/containers/array-from-async.ts index 43e8b4959..db60cdf1b 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-from-async.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-from-async.ts @@ -17,9 +17,10 @@ import { locOf } from "../../program.js"; import { arrayValueRead, arrayValueStore, arrayValueType } from "../array-values.js"; import { newFnCtx } from "../function-context.js"; import { lowerArrayCallback } from "./callback-arguments.js"; +import { extractIteratorValue, resultRecordOf, type GenType } from "../lower-generators.js"; -/** `Array.fromAsync(source, mapFn?)` over an array, as an async helper - * with the spec's loop: +/** `Array.fromAsync(source, mapFn?)` over an array or an async generator, + * as an async helper with the spec's loop: * * const out = []; let k = 0; * for await (const v of source) out.push(mapFn ? await mapFn(v, k++) : v); @@ -29,9 +30,10 @@ import { lowerArrayCallback } from "./callback-arguments.js"; * awaited (a promise element through its promise, any other value as one * resolved promise), and the iterator result is awaited again, which the * helper spells as the same microtask hops the `for await` array loop - * takes. A throwing or rejecting mapFn, and a rejected element, close the - * iterator before the returned promise rejects. Null when this is not an - * `Array.fromAsync` call. */ + * takes. An async generator is driven directly: each next() result is + * awaited once and its value is used as is. A throwing or rejecting mapFn, + * and a rejected array element, close the iterator before the returned + * promise rejects. Null when this is not an `Array.fromAsync` call. */ export function lowerArrayFromAsyncCall( lowerer: Lowerer, call: ts.CallExpression, @@ -54,23 +56,18 @@ export function lowerArrayFromAsyncCall( lowerer.badType(call, lowerer.typeOf(call)); const outT = resultT.inner; const source = lowerer.lowerExpr(args[0]!); - if (source.type.kind !== "array") { - if (source.type.kind === "generator" && source.type.async) { - // An async generator's completion settles one microtask later here - // than in Node, which would reorder the returned promise. - lowerer.noLowering( - "Array.fromAsync over an async generator", - args[0]!, - "collect its values with for await", - ); - } + let step: SourceStep; + if (source.type.kind === "array") { + step = arraySourceStep(lowerer, args[0]!, source.type.elem); + } else if (source.type.kind === "generator" && source.type.async) { + step = generatorSourceStep(lowerer, args[0]!, source.type); + } else { lowerer.noLowering( `Array.fromAsync over a value of type '${lowerer.checker.typeToString(lowerer.typeOf(args[0]!))}'`, args[0]!, - "an array is the supported source", + "an array or an async generator is the supported source", ); } - const step = arraySourceStep(lowerer, args[0]!, source.type.elem); let mapper: (IrExpr & { type: IrType & { kind: "func" } }) | null = null; if (args[1]) { const callback = lowerArrayCallback(lowerer, args[1], [step.valueT], outT); @@ -207,19 +204,173 @@ function nonThenable(lowerer: Lowerer, type: IrType): boolean { ); } +interface SourceStep { + /** The value each step hands to the mapping function. */ + valueT: IrType; + loop(source: IrExpr, append: (value: IrExpr) => IrStmt[], loc: SrcLoc): IrStmt[]; +} + +/** The async generator loop: each next() result is awaited, `done` ends + * the loop, and the value goes to the mapping function as is (no further + * await, unlike the async-from-sync array form). A mapping function that + * throws or rejects closes the generator by awaiting return(); a failure + * of that close is dropped, so the mapping error rejects the result. A + * rejected next() does not close the generator and rejects the result on + * the turn Node rejects it. */ +function generatorSourceStep(lowerer: Lowerer, node: ts.Expression, genT: GenType): SourceStep { + if (genT.yieldT.kind === "void") { + lowerer.noLowering("Array.fromAsync over an async generator that never yields", node); + } + if (genT.nextT.kind !== "undefinedT" && genT.nextT.kind !== "dyn") { + lowerer.noLowering( + `Array.fromAsync over an async generator whose yields expect .next(value) ('${lowerer.fmt(genT.nextT)}')`, + node, + ); + } + const recT = resultRecordOf(lowerer, genT); + const promiseT: IrType = { kind: "promise", inner: recT }; + const fieldT = lowerer.shapes.get(recT.shapeId)!.fields.find((f) => f.name === "value")!.type; + return { + valueT: genT.yieldT, + loop(source, append, loc) { + const g = lowerer.declareHiddenLocal("%fromAsyncGenerator", genT); + const needsClose = lowerer.declareHiddenLocal("%fromAsyncNeedsClose", BOOL); + needsClose.mutable = true; + const p = lowerer.declareHiddenLocal("%fromAsyncNext", promiseT); + const r = lowerer.declareHiddenLocal("%fromAsyncResult", recT); + r.mutable = true; + const nextError = lowerer.declareHiddenLocal("%fromAsyncNextError", CAUGHT); + const closeError = lowerer.declareHiddenLocal("%fromAsyncCloseError", CAUGHT); + const gRef = varRef(g.id, genT, loc); + const rRef = varRef(r.id, recT, loc); + const read: IrExpr = { + kind: "recordGet", + obj: rRef, + shapeId: recT.shapeId, + field: "value", + type: fieldT, + loc, + }; + const value = extractIteratorValue(lowerer, genT.yieldT, fieldT, read, loc); + if (!value) { + lowerer.noLowering( + `Array.fromAsync over an async generator yielding '${lowerer.fmt(genT.yieldT)}'`, + node, + ); + } + const setClose = (on: boolean): IrStmt => ({ + kind: "assign", + localId: needsClose.id, + value: boolLit(on, loc), + loc, + }); + const loop: IrStmt = { + kind: "while", + cond: boolLit(true, loc), + body: [ + { + kind: "varDecl", + localId: p.id, + init: { kind: "genResume", mode: "next", gen: gRef, arg: null, type: promiseT, loc }, + loc, + }, + { kind: "varDecl", localId: r.id, init: null, loc }, + // A rejected next() rejects the result two reactions later, as + // the rejected array element does. + { + kind: "tryCatch", + tryBody: [ + { + kind: "assign", + localId: r.id, + value: { kind: "awaitExpr", value: varRef(p.id, promiseT, loc), type: recT, loc }, + loc, + }, + ], + catchBody: [hop(loc), hop(loc), { kind: "rethrow", localId: nextError.id, loc }], + catchLocalId: nextError.id, + finallyBody: null, + loc, + }, + { + kind: "if", + cond: { + kind: "recordGet", + obj: rRef, + shapeId: recT.shapeId, + field: "done", + type: BOOL, + loc, + }, + then: [{ kind: "break", loc }], + else_: null, + loc, + }, + setClose(true), + ...append(value!), + setClose(false), + ], + loc, + }; + const stmts: IrStmt[] = [ + { kind: "varDecl", localId: g.id, init: source, loc }, + { kind: "varDecl", localId: needsClose.id, init: boolLit(false, loc), loc }, + { + kind: "tryCatch", + tryBody: [loop], + catchBody: null, + catchLocalId: null, + finallyBody: [ + { + kind: "if", + cond: varRef(needsClose.id, BOOL, loc), + then: [closeGenerator(gRef, promiseT, recT, closeError.id, loc)], + else_: null, + loc, + }, + ], + loc, + }, + ]; + return stmts; + }, + }; +} + +/** Await `gen.return()`, dropping a failure of the close. */ +function closeGenerator( + gen: IrExpr, + promiseT: IrType, + recT: IrType, + errorLocalId: string, + loc: SrcLoc, +): IrStmt { + return { + kind: "tryCatch", + tryBody: [ + { + kind: "exprStmt", + expr: { + kind: "awaitExpr", + value: { kind: "genResume", mode: "return", gen, arg: null, type: promiseT, loc }, + type: recT, + loc, + }, + loc, + }, + ], + catchBody: [], + catchLocalId: errorLocalId, + finallyBody: null, + loc, + }; +} + /** The `for await` array loop (lowerForOf's async-from-sync form): two * hops per element that is not a promise, the element's own await plus * one hop for a promise element, two hops before the final done result, * and one hop to close the iterator when the body completes abruptly. */ -function arraySourceStep( - lowerer: Lowerer, - node: ts.Expression, - elem: IrType, -): { - /** The awaited value each element hands to the mapping function. */ - valueT: IrType; - loop(source: IrExpr, append: (value: IrExpr) => IrStmt[], loc: SrcLoc): IrStmt[]; -} { +function arraySourceStep(lowerer: Lowerer, node: ts.Expression, elem: IrType): SourceStep { const yieldedT = arrayValueType(lowerer, elem); let promiseTag: number | null = null; let valueT = yieldedT; diff --git a/packages/compiler/src/frontend/lowering/function-returns.ts b/packages/compiler/src/frontend/lowering/function-returns.ts index 38c728027..d3c5eb1ba 100644 --- a/packages/compiler/src/frontend/lowering/function-returns.ts +++ b/packages/compiler/src/frontend/lowering/function-returns.ts @@ -59,6 +59,11 @@ export function appendImplicitUndefinedReturn( ): void { if (bodyReturn.kind === "void") return; if (!bodyMayFallThrough(body)) return; + // An async generator that falls off its end completes without awaiting + // anything: its request settles as the body returns, where `return x` + // takes a turn to await x. + let settled = false; + if (lowerer.ctx.isAsync === true && lowerer.ctx.generator) settled = true; // A DYN body that can complete without returning (a JS function whose // guarded return may not run — mustSucceed's `if (typeof fn === // 'function') return fn.apply(...)`): JS completes with undefined — @@ -67,6 +72,7 @@ export function appendImplicitUndefinedReturn( body.push({ kind: "return", value: dynUndefinedExpr(loc), + ...(settled ? { awaited: true as const } : {}), loc, }); return; @@ -74,7 +80,7 @@ export function appendImplicitUndefinedReturn( if (bodyReturn.kind === "union") { const value = lowerer.wrappedUndefined(bodyReturn, loc); if (value) { - body.push({ kind: "return", value, loc }); + body.push({ kind: "return", value, ...(settled ? { awaited: true as const } : {}), loc }); return; } // no undefined arm: the trap below stands in, exactly like non-unions diff --git a/packages/compiler/src/frontend/lowering/lower-generators.ts b/packages/compiler/src/frontend/lowering/lower-generators.ts index c61920c60..2eda4c4ce 100644 --- a/packages/compiler/src/frontend/lowering/lower-generators.ts +++ b/packages/compiler/src/frontend/lowering/lower-generators.ts @@ -32,7 +32,7 @@ export type GenType = IrType & { kind: "generator" }; /** The interned IteratorResult record of a generator type (never null for * a MAPPED generator — mapType required it to intern). */ -function resultRecordOf(lowerer: Lowerer, genT: GenType): IrType & { kind: "record" } { +export function resultRecordOf(lowerer: Lowerer, genT: GenType): IrType & { kind: "record" } { const rec = genResultRecord(genT.yieldT, genT.retT, lowerer.shapes, lowerer.unions); if (!rec) throw new InternalCompilerError("lowerer bug: mapped generator without a result record"); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5904-async-generator-completion.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5904-async-generator-completion.ts.json new file mode 100644 index 000000000..dd2338a5b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5904-async-generator-completion.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5904-async-generator-completion.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5905-array-from-async-generator.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5905-array-from-async-generator.ts.json new file mode 100644 index 000000000..dd9276926 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5905-array-from-async-generator.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5905-array-from-async-generator.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5906-array-from-async-generator-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5906-array-from-async-generator-js.js.json new file mode 100644 index 000000000..fc7977463 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5906-array-from-async-generator-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5906-array-from-async-generator-js.js" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index 46175cf82..e6a18072d 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -4860,6 +4860,13 @@ struct ScrGen { ScrExcCell async_error; bool settle_queued; bool success_hop_done; + /* A return() request at a yield: the queued job resumes the body after + * the return value's await (return_queued), and the body's completion, + * on that request or a later one, settles without another turn + * (return_awaited). An explicit `return x` during the unwind clears it, + * since that return takes its own turn to await x. */ + bool return_queued; + bool return_awaited; #ifdef SCR_WORKERS bool context_abandoned; #endif @@ -5261,6 +5268,8 @@ void scr_coro_yield_ref(ScrFiber *self, void *v, void (*release)(void *)) { scr_gen_slot_ref(&self->gen->out, v, release); } +void scr_async_gen_return_awaits(void) { scr_gen_self()->return_awaited = false; } + void scr_async_gen_hop_done(void) { ScrGen *g = scr_gen_self(); if (!g->is_async) { @@ -5540,6 +5549,21 @@ static void scr_async_gen_capture_caller_error(ScrGen *g) { if (cell->kind != SCR_EXC_NONE) scr_gen_exc_move(&g->async_error, cell); } +/* Whether the body's latest stop settles its request without a further + * turn: a yield whose await already supplied the value, or a completion + * after a return() request's await. */ +static bool scr_async_gen_settles_now(ScrGen *g) { + if (g->success_hop_done) { + g->success_hop_done = false; + return true; + } + if (g->return_awaited && g->state == SCR_GEN_DONE) { + g->return_awaited = false; + return true; + } + return false; +} + static void scr_async_gen_run_active(ScrGen *g, ScrAsyncGenRequest *req) { const bool was_done = g->state == SCR_GEN_DONE; if (req->mode == SCR_AG_NEXT) { @@ -5551,6 +5575,13 @@ static void scr_async_gen_run_active(ScrGen *g, ScrAsyncGenRequest *req) { scr_gen_slot_reset(&g->ret); g->ret = req->arg; memset(&req->arg, 0, sizeof req->arg); + if (g->state == SCR_GEN_SUSPENDED) { + /* At a yield, AsyncGeneratorYield awaits the return value before + * the body resumes, so finally blocks run one turn later. */ + g->return_queued = true; + scr_async_gen_schedule_settle(g); + return; + } scr_gen_resume_return(g); } else { scr_gen_exc_move(scr_exc_current_cell(), &req->thrown); @@ -5565,18 +5596,39 @@ static void scr_async_gen_run_active(ScrGen *g, ScrAsyncGenRequest *req) { if (g->state == SCR_GEN_AWAITING) return; /* next() on an already-completed generator produces its undefined done - * result immediately. Yield, body return, and return(value) all pass - * through AsyncGeneratorYield's successful Await step. */ + * result immediately. A yield and return(value) on an unstarted or + * completed generator pass through an Await step; a body that falls off + * its end, or whose `return x` already awaited x, marks its completion + * as settled. */ if (was_done && req->mode == SCR_AG_NEXT) { scr_async_gen_finish_active(g, false); - } else if (g->success_hop_done) { - g->success_hop_done = false; + } else if (scr_async_gen_settles_now(g)) { scr_async_gen_finish_active(g, false); } else { scr_async_gen_schedule_settle(g); } } +/* The return() request's await has taken its turn: resume the body with + * the return completion. */ +static void scr_async_gen_resume_returning(ScrGen *g) { + g->return_queued = false; + g->return_awaited = true; + scr_gen_resume_return(g); + scr_async_gen_capture_caller_error(g); + if (g->async_error.kind != SCR_EXC_NONE) { + scr_async_gen_finish_active(g, true); + } else if (g->state == SCR_GEN_AWAITING) { + return; + } else if (scr_async_gen_settles_now(g)) { + scr_async_gen_finish_active(g, false); + } else { + scr_async_gen_schedule_settle(g); + return; + } + scr_async_gen_start_queued(g); +} + static void scr_async_gen_start_queued(ScrGen *g) { /* Keep the object alive while an immediately-settled request releases * its own retain and the loop inspects the next queue node. */ @@ -5687,6 +5739,12 @@ static void scr_async_gen_job(ScrGen *g) { fputs("scriptc: internal error: invalid async generator settlement job\n", stderr); abort(); } + if (g->return_queued) { + scr_gen_retain(g); + scr_async_gen_resume_returning(g); + scr_gen_release(g); + return; + } scr_async_gen_finish_active(g, false); scr_async_gen_start_queued(g); } @@ -5704,8 +5762,7 @@ static void scr_async_gen_resume_ready(ScrGen *g) { scr_async_gen_finish_active(g, true); scr_async_gen_start_queued(g); } else if (g->state != SCR_GEN_AWAITING) { - if (g->success_hop_done) { - g->success_hop_done = false; + if (scr_async_gen_settles_now(g)) { scr_async_gen_finish_active(g, false); scr_async_gen_start_queued(g); } else { diff --git a/packages/runtime/src/scr_generator.h b/packages/runtime/src/scr_generator.h index f528b8b8f..2c2c0e953 100644 --- a/packages/runtime/src/scr_generator.h +++ b/packages/runtime/src/scr_generator.h @@ -133,6 +133,8 @@ void scr_gen_yield_f64(double v); void scr_gen_yield_bool(bool v); void scr_gen_yield_ref(void *v, void (*release)(void *)); /* moves */ void scr_async_gen_hop_done(void); +/* An async generator's `return x` whose completion turn awaits x. */ +void scr_async_gen_return_awaits(void); void scr_gen_out_f64(ScrGen *g, double v); /* trampoline completion stores */ void scr_gen_out_bool(ScrGen *g, bool v); void scr_gen_out_ref(ScrGen *g, void *v, void (*release)(void *)); /* moves */ diff --git a/tests/corpus/5904-async-generator-completion.ts b/tests/corpus/5904-async-generator-completion.ts new file mode 100644 index 000000000..478aae6e9 --- /dev/null +++ b/tests/corpus/5904-async-generator-completion.ts @@ -0,0 +1,188 @@ +// Async generator completion against a microtask ticker: falling off the end +// and bare returns settle as the body completes, `return x` takes a turn to +// await x, return() at a yield awaits its value before finally blocks run, +// and for await loops end on the turn Node ends them. Node.js prints the +// same. +const log: string[] = []; +async function ticker(n: number): Promise { + for (let i = 0; i < n; i++) { + log.push("t" + i); + await null; + } +} +async function run(name: string, body: () => Promise): Promise { + log.length = 0; + const tick = ticker(14); + await body(); + await tick; + console.log(name + ": " + log.join(" ")); +} +class Source { + readonly items: number[]; + constructor(items: number[]) { + this.items = items; + } + async *values(): AsyncGenerator { + for (const i of this.items) yield i; + } +} +async function main(): Promise { + await run("fall off", async () => { + async function* g(): AsyncGenerator { yield 1; } + const it = g(); + void it.next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + await it.next().then((r) => log.push(`b:${String(r.value)}/${r.done}`)); + }); + await run("return value", async () => { + async function* g(): AsyncGenerator { yield 1; return 5; } + const it = g(); + void it.next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + await it.next().then((r) => log.push(`b:${String(r.value)}/${r.done}`)); + }); + await run("bare return", async () => { + async function* g(): AsyncGenerator { yield 1; return; } + const it = g(); + void it.next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + await it.next().then((r) => log.push(`b:${String(r.value)}/${r.done}`)); + }); + await run("empty body", async () => { + async function* g(): AsyncGenerator {} + await g().next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + }); + await run("after done", async () => { + async function* g(): AsyncGenerator {} + const it = g(); + await it.next(); + log.push("mark"); + await it.next().then((r) => log.push(`b:${String(r.value)}/${r.done}`)); + }); + await run("return() at yield", async () => { + async function* g(): AsyncGenerator { try { yield 1; } finally { log.push("finally"); } return 0; } + const it = g(); + await it.next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + await it.return(7).then((r) => log.push(`r:${String(r.value)}/${r.done}`)); + }); + await run("return() before start", async () => { + async function* g(): AsyncGenerator { yield 1; return 0; } + await g().return(3).then((r) => log.push(`r:${String(r.value)}/${r.done}`)); + }); + await run("throw at end", async () => { + async function* g(): AsyncGenerator { yield 1; throw new Error("x"); } + const it = g(); + void it.next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + await it.next().then((r) => log.push(`b:${String(r.value)}/${r.done}`), () => log.push("rejected")); + }); + await run("await before end", async () => { + async function* g(): AsyncGenerator { yield 1; await null; } + const it = g(); + void it.next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + await it.next().then((r) => log.push(`b:${String(r.value)}/${r.done}`)); + }); + await run("for await", async () => { + async function* g(): AsyncGenerator { yield 1; yield 2; } + for await (const v of g()) log.push("v" + v); + log.push("loop done"); + }); + await run("for await break", async () => { + async function* g(): AsyncGenerator { try { yield 1; yield 2; } finally { log.push("cleanup"); } } + for await (const v of g()) { log.push("v" + v); break; } + log.push("loop done"); + }); + await run("queued", async () => { + async function* g(): AsyncGenerator { yield 1; } + const it = g(); + void it.next().then((r) => log.push(`a:${String(r.value)}/${r.done}`)); + void it.next().then((r) => log.push(`b:${String(r.value)}/${r.done}`)); + await it.next().then((r) => log.push(`c:${String(r.value)}/${r.done}`)); + }); + + await run("yield in finally", async () => { + async function* g(): AsyncGenerator { try { yield 1; } finally { yield 9; log.push("after"); } return 0; } + const it = g(); + await it.next(); + void it.return(7).then((r) => log.push(`r:${r.value}/${r.done}`)); + await it.next().then((r) => log.push(`n:${r.value}/${r.done}`)); + }); + await run("await in finally", async () => { + async function* g(): AsyncGenerator { try { yield 1; } finally { await null; log.push("cleaned"); } return 0; } + const it = g(); + await it.next(); + await it.return(4).then((r) => log.push(`r:${r.value}/${r.done}`)); + }); + await run("throw at yield", async () => { + async function* g(): AsyncGenerator { try { yield 1; } catch { log.push("caught"); } } + const it = g(); + await it.next(); + await it.throw(new Error("x")).then((r) => log.push(`t:${r.value}/${r.done}`)); + }); + await run("return through finally", async () => { + async function* g(): AsyncGenerator { try { yield 1; return 5; } finally { log.push("fin"); } } + const it = g(); + void it.next().then((r) => log.push(`a:${r.value}/${r.done}`)); + await it.next().then((r) => log.push(`b:${r.value}/${r.done}`)); + }); + await run("return promise", async () => { + async function* g(): AsyncGenerator { yield 1; return Promise.resolve(3); } + const it = g(); + void it.next().then((r) => log.push(`a:${r.value}/${r.done}`)); + await it.next().then((r) => log.push(`b:${r.value}/${r.done}`)); + }); + await run("two returns", async () => { + async function* g(): AsyncGenerator { try { yield 1; } finally { log.push("fin"); } return 0; } + const it = g(); + await it.next(); + void it.return(1).then((r) => log.push(`r1:${r.value}/${r.done}`)); + await it.return(2).then((r) => log.push(`r2:${r.value}/${r.done}`)); + }); + await run("return after done", async () => { + async function* g(): AsyncGenerator { return 1; } + const it = g(); + await it.next(); + log.push("mark"); + await it.return(8).then((r) => log.push(`r:${r.value}/${r.done}`)); + }); + await run("nested loops break", async () => { + async function* g(n: number): AsyncGenerator { try { for (let i = 0; i < n; i++) yield i; } finally { log.push("close" + n); } } + for await (const a of g(2)) { + for await (const b of g(3)) { log.push(`${a}${b}`); if (b === 1) break; } + } + log.push("done"); + }); + await run("strings", async () => { + async function* g(): AsyncGenerator { yield "a"; yield "b"; } + const parts: string[] = []; + for await (const s of g()) parts.push(s); + log.push(parts.join("")); + }); + + await run("finally return override", async () => { + async function* g(): AsyncGenerator { try { yield 1; } finally { log.push("fin"); return 42; } } + const it = g(); + await it.next(); + await it.return(7).then((r) => log.push(`r:${r.value}/${r.done}`)); + }); + await run("class method", async () => { + const parts: number[] = []; + for await (const v of new Source([1, 2, 3]).values()) parts.push(v); + log.push(parts.join(",")); + }); + await run("return while awaiting", async () => { + async function* g(): AsyncGenerator { try { await null; await null; yield 1; } finally { log.push("fin"); } return 0; } + const it = g(); + void it.next().then((r) => log.push(`n:${r.value}/${r.done}`)); + await it.return(5).then((r) => log.push(`r:${r.value}/${r.done}`)); + }); + await run("throw after done", async () => { + async function* g(): AsyncGenerator {} + const it = g(); + await it.next(); + await it.throw(new Error("late")).then(() => log.push("ok"), (e: unknown) => log.push("rejected " + (e as Error).message)); + }); + await run("rejection inside", async () => { + async function* g(): AsyncGenerator { yield 1; await Promise.reject(new Error("inner")); } + const it = g(); + void it.next().then((r) => log.push(`a:${r.value}/${r.done}`)); + await it.next().then(() => log.push("ok"), (e: unknown) => log.push("rejected " + (e as Error).message)); + }); +} +void main(); diff --git a/tests/corpus/5905-array-from-async-generator.ts b/tests/corpus/5905-array-from-async-generator.ts new file mode 100644 index 000000000..f95fd5327 --- /dev/null +++ b/tests/corpus/5905-array-from-async-generator.ts @@ -0,0 +1,61 @@ +// Array.fromAsync over async generators: plain, mapped, async-mapped, a +// throwing or rejecting mapping function (which closes the generator), a +// generator that throws, an empty generator, and two calls at once, +// interleaved with a microtask ticker. Node.js prints the same. +const log: string[] = []; +async function ticker(n: number): Promise { + for (let i = 0; i < n; i++) { + log.push("t" + i); + await null; + } +} +async function* nums(n: number): AsyncGenerator { + try { + for (let i = 0; i < n; i++) { + log.push("yield " + i); + yield i; + } + } finally { + log.push("gen finally"); + } +} +async function* failing(): AsyncGenerator { + yield 1; + throw new Error("gen failure"); +} +async function report(label: string, job: Promise): Promise { + await job.then( + (a) => log.push(label + " [" + a.join(",") + "]"), + (e: unknown) => log.push(label + " rejected " + (e as Error).message), + ); +} +async function run(name: string, body: () => Promise): Promise { + log.length = 0; + const tick = ticker(20); + await body(); + await tick; + console.log(name + ": " + log.join(" ")); +} +async function main(): Promise { + await run("plain", () => report("plain", Array.fromAsync(nums(3)))); + await run("map", () => report("map", Array.fromAsync(nums(3), (x: number, i: number) => x * 10 + i))); + await run("async map", () => report("async map", Array.fromAsync(nums(2), async (x: number) => x + 1))); + await run("map throws", () => + report("map throws", Array.fromAsync(nums(3), (x: number) => { + if (x === 1) throw new Error("map failure"); + return x; + })), + ); + await run("map rejects", () => + report("map rejects", Array.fromAsync(nums(3), async (x: number) => { + if (x === 1) throw new Error("async map failure"); + return x; + })), + ); + await run("generator throws", () => report("generator throws", Array.fromAsync(failing()))); + await run("empty", () => report("empty", Array.fromAsync(nums(0)))); + await run("two at once", async () => { + await Promise.all([report("a", Array.fromAsync(nums(2))), report("b", Array.fromAsync(nums(1)))]); + }); +} +void main(); diff --git a/tests/corpus/5906-array-from-async-generator-js.js b/tests/corpus/5906-array-from-async-generator-js.js new file mode 100644 index 000000000..fa4d22147 --- /dev/null +++ b/tests/corpus/5906-array-from-async-generator-js.js @@ -0,0 +1,60 @@ +// Array.fromAsync over async generators from JavaScript, with and without a +// mapping function, interleaved with a microtask ticker. Node.js prints the +// same. +const log = []; +async function ticker(n ) { + for (let i = 0; i < n; i++) { + log.push("t" + i); + await null; + } +} +async function* nums(n ) { + try { + for (let i = 0; i < n; i++) { + log.push("yield " + i); + yield i; + } + } finally { + log.push("gen finally"); + } +} +async function* failing() { + yield 1; + throw new Error("gen failure"); +} +async function report(label , job ) { + await job.then( + (a) => log.push(label + " [" + a.join(",") + "]"), + (e ) => log.push(label + " rejected " + (e ).message), + ); +} +async function run(name , body ) { + log.length = 0; + const tick = ticker(20); + await body(); + await tick; + console.log(name + ": " + log.join(" ")); +} +async function main() { + await run("plain", () => report("plain", Array.fromAsync(nums(3)))); + await run("map", () => report("map", Array.fromAsync(nums(3), (x , i ) => x * 10 + i))); + await run("async map", () => report("async map", Array.fromAsync(nums(2), async (x ) => x + 1))); + await run("map throws", () => + report("map throws", Array.fromAsync(nums(3), (x ) => { + if (x === 1) throw new Error("map failure"); + return x; + })), + ); + await run("map rejects", () => + report("map rejects", Array.fromAsync(nums(3), async (x ) => { + if (x === 1) throw new Error("async map failure"); + return x; + })), + ); + await run("generator throws", () => report("generator throws", Array.fromAsync(failing()))); + await run("empty", () => report("empty", Array.fromAsync(nums(0)))); + await run("two at once", async () => { + await Promise.all([report("a", Array.fromAsync(nums(2))), report("b", Array.fromAsync(nums(1)))]); + }); +} +void main(); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 6d1199cce..4aaa891ad 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,9 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5904-async-generator-completion.ts": 2950, + "5905-array-from-async-generator.ts": 2750, + "5906-array-from-async-generator-js.js": 2950, "5950-tuple-predicate-methods.ts": 5990, "5951-result-never-widening.ts": 4710, "5955-any-promise-methods.js": 3940, @@ -4472,6 +4475,9 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5904-async-generator-completion.ts": 3800, + "5905-array-from-async-generator.ts": 3500, + "5906-array-from-async-generator-js.js": 3750, "5950-tuple-predicate-methods.ts": 7790, "5951-result-never-widening.ts": 6120, "5955-any-promise-methods.js": 5120, From 23ce40cace02f8168f8159964b3ffe86e6f7bd44 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 23:25:06 -0500 Subject: [PATCH 035/117] Keep JavaScript lets open when a later object literal adds properties An untyped JavaScript `let` initialized with an object literal took the initializer's record shape. A later assignment of an object literal with more properties (`state = { _tag: "PullLeft", right }`, as in Effect's Stream.zip) stored the object, but reading the added property failed with SC1090. Such a binding now uses checked-dynamic storage, as it already does when the program adds a property through the binding, so the added properties read back and missing ones read as undefined, as in Node. Closes #937 Co-authored-by: phall <25888173+phall1@users.noreply.github.com> --- .../src/frontend/lowering/lower-stmts.ts | 17 +++++++++++ ...939-js-let-object-reassigned-wider.js.json | 6 ++++ .../5939-js-let-object-reassigned-wider.js | 29 +++++++++++++++++++ tests/harness/corpus-costs.json | 2 ++ 4 files changed, 54 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5939-js-let-object-reassigned-wider.js.json create mode 100644 tests/corpus/5939-js-let-object-reassigned-wider.js diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 367c147f8..e61bb6c11 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -5037,6 +5037,23 @@ function jsObjectBindingExpands( ) { const name = property(node.left); if (name === null || (name !== undefined && !names.has(name))) expands = true; + // `state = { _tag: "Done", right }` stores an object with properties + // the initializer's shape lacks; later reads of them must see them. + const target = unwrap(node.left); + const value = unwrap(node.right); + const targetSymbol = ts.isIdentifier(target) ? lowerer.resolveValueSymbol(target) : undefined; + if ( + targetSymbol && + aliases.has(targetSymbol) && + ts.isObjectLiteralExpression(value) && + value.properties.some( + (field) => + !(ts.isPropertyAssignment(field) || ts.isShorthandPropertyAssignment(field)) || + !(ts.isIdentifier(field.name) || ts.isStringLiteral(field.name)) || + !names.has(field.name.text), + ) + ) + expands = true; } if (ts.isDeleteExpression(node) && property(node.expression) !== undefined) expands = true; if ( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5939-js-let-object-reassigned-wider.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5939-js-let-object-reassigned-wider.js.json new file mode 100644 index 000000000..b783afe3f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5939-js-let-object-reassigned-wider.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5939-js-let-object-reassigned-wider.js" + ], + "diags": [] +} diff --git a/tests/corpus/5939-js-let-object-reassigned-wider.js b/tests/corpus/5939-js-let-object-reassigned-wider.js new file mode 100644 index 000000000..f23a6a059 --- /dev/null +++ b/tests/corpus/5939-js-let-object-reassigned-wider.js @@ -0,0 +1,29 @@ +// An untyped `let` that starts as one object literal and is later +// assigned object literals with more properties holds each object as +// written: the added properties read back, and properties an object lacks +// read as undefined. +function zip(left, right) { + let state = { _tag: "PullBoth" }; + const out = []; + for (let i = 0; i < left.length; i++) { + if (state._tag === "PullBoth") state = { _tag: "PullLeft", right: right[i] }; + else if (state._tag === "PullLeft") { + out.push([left[i], state.right]); + state = { _tag: "PullBoth" }; + } + } + return { out, last: state._tag, pending: state.right }; +} +console.log(zip([1, 2, 3, 4], ["a", "b", "c", "d"])); + +let point = { x: 1 }; +const update = () => { + point = { x: 2, y: 3 }; +}; +console.log(point.y, Object.keys(point)); +update(); +console.log(point.x, point.y, Object.keys(point), JSON.stringify(point)); + +let config = { name: "base" }; +config = { ...config, debug: true }; +console.log(config.debug, config); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 6d1199cce..8f6ba50bb 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,7 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5939-js-let-object-reassigned-wider.js": 1945, "5950-tuple-predicate-methods.ts": 5990, "5951-result-never-widening.ts": 4710, "5955-any-promise-methods.js": 3940, @@ -4472,6 +4473,7 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5939-js-let-object-reassigned-wider.js": 4436, "5950-tuple-predicate-methods.ts": 7790, "5951-result-never-widening.ts": 6120, "5955-any-promise-methods.js": 5120, From 370bf5962dffa7117847d8a62f4bff6b2772fea5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 23:40:06 -0500 Subject: [PATCH 036/117] Add the cstring class to library profiles Library exports and callbacks passed text only as a pointer and length. profile_format 2 adds the cstring class, a NUL-terminated `const char *` (an i32 pointer in Wasm reactors), for export parameters, export results and callback parameters. Parameters are copied in and decoded as UTF-8, with U+FFFD for malformed bytes; a NULL pointer is the SC4012 host-contract trap. Results live in the result arena like string results. A result or callback argument containing U+0000 traps instead of being truncated. Closes #615 Co-authored-by: ailuoku6 <23209876+ailuoku6@users.noreply.github.com> --- docs/content/docs/wasm.mdx | 4 +- packages/compiler/src/backend/llvm/emitter.ts | 32 ++++++++ .../compiler/src/backend/llvm/expr-calls.ts | 10 +++ .../src/ir/function-references.test.ts | 1 + packages/compiler/src/ir/ir.ts | 21 ++++- packages/compiler/src/ir/validate.ts | 2 +- .../compiler/src/library/library-profile.ts | 46 +++++++++-- packages/compiler/src/library/prepare.ts | 17 +++- packages/runtime/src/scr_core.h | 9 +++ packages/runtime/src/scr_library.c | 24 ++++++ tests/harness/library-mode.test.ts | 45 +++++++++++ tests/harness/library-profile.test.ts | 51 +++++++++++- tests/harness/wasm-library.test.ts | 79 +++++++++++++++++++ tests/library-mode/cstrings/lib.ts | 26 ++++++ tests/library-mode/cstrings/probe.c | 76 ++++++++++++++++++ tests/library-mode/cstrings/profile.json | 22 ++++++ 16 files changed, 450 insertions(+), 15 deletions(-) create mode 100644 tests/library-mode/cstrings/lib.ts create mode 100644 tests/library-mode/cstrings/probe.c create mode 100644 tests/library-mode/cstrings/profile.json diff --git a/docs/content/docs/wasm.mdx b/docs/content/docs/wasm.mdx index a39c31e34..b498eccf7 100644 --- a/docs/content/docs/wasm.mdx +++ b/docs/content/docs/wasm.mdx @@ -96,11 +96,13 @@ After initialization, counter_step(2) returns 2, and a i64, u64JavaScript BigInt. The existing library integer checks and proofs restrict values to the exact JavaScript number range. string, bytes parametersTwo i32 arguments: byte offset and byte length. Strings use UTF-8. Entry parameters are copied into runtime-owned values. string, bytes resultsTwo extra i32 arguments identify writable four-byte output slots. The function writes the result pointer and byte length there, in little-endian order. + cstring parametersOne i32 argument: the byte offset of NUL-terminated UTF-8 text. The text is copied into a runtime-owned string; malformed UTF-8 becomes U+FFFD. A zero pointer traps with SC4012. + cstring resultsAn i32 result: the byte offset of NUL-terminated UTF-8 text in the result arena. A result containing U+0000 traps with SC4015 instead of being truncated. voidNo result. -The native library rules about directions still apply: u8/u32/i32 are export parameters and callback scalars; i64/u64 are export-only. Callback results must be scalars or void. Callback string/byte parameters are borrowed only for the duration of that callback; copy them before retaining them in the host. +The native library rules about directions still apply: u8/u32/i32 are export parameters and callback scalars; i64/u64 are export-only. Callback results must be scalars or void. Callback string/byte parameters are borrowed only for the duration of that callback; copy them before retaining them in the host. A cstring callback parameter is one i32 pointer to NUL-terminated text, borrowed the same way; a value containing U+0000 traps with SC4015. The cstring class requires "profile_format": 2. In native libraries it is a const char * with the same rules. Allocate host input buffers and output slots with scriptc_alloc(size); a zero result indicates allocation failure. Release each allocation exactly once with scriptc_free(pointer). Only free pointers returned by scriptc_alloc. These allocations remain live across application calls, initialization, and collection until freed. diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 2c3a71457..1a2e30464 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -2190,6 +2190,12 @@ export class LlEmitter { if (this.mod.lib.exports.some((e) => e.returns === "bytes")) { this.declare(`declare void @scr_library_bytes_out(ptr, ptr, ptr)`); } + if (this.mod.lib.exports.some((e) => e.params.includes("cstring"))) { + this.declare(`declare ptr @scr_library_cstr_in(ptr, ptr)`); + } + if (this.mod.lib.exports.some((e) => e.returns === "cstring")) { + this.declare(`declare ptr @scr_library_cstr_out(ptr)`); + } } // Helpers assemble BEFORE the declaration table flushes (they add // write/abort declarations). @@ -2966,6 +2972,15 @@ export class LlEmitter { ``, ); } + if (e.inboundCstringTrap !== undefined) { + // The cstring-in helper's host-contract trap message (a NULL + // `const char *`): same assembled structured form and SC4012 code. + const trapBytes = Buffer.byteLength(e.inboundCstringTrap, "utf8"); + out.push( + `@sc_lib_cstr_trap_${e.symbol} = internal constant [${trapBytes + 1} x i8] c"${llStrBytes(e.inboundCstringTrap)}"`, + ``, + ); + } e.params.forEach((cls, i) => { switch (cls) { case "f64": @@ -3023,6 +3038,13 @@ export class LlEmitter { ); args.push(`ptr %c${i}`); break; + case "cstring": + params.push(`ptr %a${i}`); + body.push( + ` %c${i} = call ptr @scr_library_cstr_in(ptr %a${i}, ptr @sc_lib_cstr_trap_${e.symbol})`, + ); + args.push(`ptr %c${i}`); + break; } }); if (e.returns === "string" || e.returns === "bytes") { @@ -3087,6 +3109,16 @@ export class LlEmitter { ` ret void`, ); break; + case "cstring": + // The result's arena copy, returned as `const char *`. + retType = "ptr"; + body.push( + ` %r = call ptr ${target}(${callArgs})`, + ` call void @scr_library_check_exc()`, + ` %z = call ptr @scr_library_cstr_out(ptr %r)`, + ` ret ptr %z`, + ); + break; } out.push( `define ${retType} @${e.symbol}(${params.join(", ")}) ${FN_ATTRS} { ; library export ${e.fnName}`, diff --git a/packages/compiler/src/backend/llvm/expr-calls.ts b/packages/compiler/src/backend/llvm/expr-calls.ts index 1a34f5e81..6e8b8caf4 100644 --- a/packages/compiler/src/backend/llvm/expr-calls.ts +++ b/packages/compiler/src/backend/llvm/expr-calls.ts @@ -333,6 +333,16 @@ export function emitCallExpr( natArgs.push(`ptr ${data}`, `${host.sizeType} ${len}`); break; } + case "cstring": { + // The string's own NUL-terminated data, after the check that + // it holds no U+0000 (a C string cannot carry one). + host.declare(`declare ptr @scr_library_cstr_arg(ptr)`); + const data = B.tmp(); + B.line(`${data} = call ptr @scr_library_cstr_arg(ptr ${arg.name})`); + natTypes.push("ptr"); + natArgs.push(`ptr ${data}`); + break; + } case "bytes": { const lenPtr = B.tmp(); const len = B.tmp(); diff --git a/packages/compiler/src/ir/function-references.test.ts b/packages/compiler/src/ir/function-references.test.ts index 32284c820..0b1f9fb49 100644 --- a/packages/compiler/src/ir/function-references.test.ts +++ b/packages/compiler/src/ir/function-references.test.ts @@ -193,6 +193,7 @@ const MODULE_FIELDS: Record>, Role> = { "lib.exports[].fnName": "reference", "lib.exports[].inboundBytesTrap": "other", "lib.exports[].inboundIntTrap": "other", + "lib.exports[].inboundCstringTrap": "other", "lib.trapOverlays[].code": "other", "lib.trapOverlays[].teaching": "other", "lib.trapOverlays[].remediation": "other", diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index bfaa13c0e..eaee503fa 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1176,8 +1176,19 @@ export interface IrLibExport { /** i64/u64 (ask 4): int64_t/uint64_t at the C edge — inbound values * range-check in the wrapper (`inboundIntTrap`), internal call sites * and returns are compile-time proven before this lands on the IR. */ - params: ("f64" | "bool" | "string" | "bytes" | "u8" | "u32" | "i32" | "i64" | "u64")[]; - returns: "f64" | "bool" | "string" | "bytes" | "void" | "i64" | "u64"; + params: ( + | "f64" + | "bool" + | "string" + | "cstring" + | "bytes" + | "u8" + | "u32" + | "i32" + | "i64" + | "u64" + )[]; + returns: "f64" | "bool" | "string" | "cstring" | "bytes" | "void" | "i64" | "u64"; /** The exact sink-message bytes this wrapper passes to the inbound-bytes * marshalling helper's trap — present exactly when a parameter is * bytes-classed. Already the assembled structured trap-teaching form @@ -1192,6 +1203,10 @@ export interface IrLibExport { * value cannot ride f64 exactly (|v| past 2^53−1). Same assembled * structured form and the same SC4012 code — one host-contract story. */ inboundIntTrap?: string; + /** The sibling message for a NULL cstring parameter: present exactly + * when a parameter is cstring-classed, passed to scr_library_cstr_in. + * Same assembled structured form and the same SC4012 code. */ + inboundCstringTrap?: string; } /** One runtime-trap overlay row: the profile's teaching (replaces the @@ -1218,7 +1233,7 @@ export interface IrLibCallback { name: string; /** The runtime channel slot (profile declaration order). */ slot: number; - params: ("f64" | "bool" | "string" | "bytes" | "u8" | "u32" | "i32")[]; + params: ("f64" | "bool" | "string" | "cstring" | "bytes" | "u8" | "u32" | "i32")[]; returns: "f64" | "bool" | "u8" | "u32" | "i32" | "i64" | "u64" | "pointer" | "void"; /** The unregistered-call trap text (a DETECTED trap: plain bytes the * library funnel classifies SC4025 and assembles with the current diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index d526e7cb8..8278fe356 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -357,7 +357,7 @@ export function validateModule(mod: IrModule): IrValidationError[] { const fits = (cls: string, t: IrType): boolean => cls === "bool" ? t.kind === "bool" - : cls === "string" + : cls === "string" || cls === "cstring" ? t.kind === "string" : cls === "bytes" ? t.kind === "bytes" && t.elem === "u8" diff --git a/packages/compiler/src/library/library-profile.ts b/packages/compiler/src/library/library-profile.ts index f0126c25f..019dbb7e1 100644 --- a/packages/compiler/src/library/library-profile.ts +++ b/packages/compiler/src/library/library-profile.ts @@ -10,7 +10,7 @@ * * Ratified shape (the ratified library-mode design §5.1 + the ABI ratification session): * { - * "profile_format": 1, + * "profile_format": 1 | 2, // 2 adds the cstring class * "name": "", * "entry": "src/lib.ts", // ONE module, profile-relative * "emission": "llvm", // pins the emission; no fallback @@ -268,6 +268,7 @@ export const LIB_PARAM_CLASSES = [ "f64", "bool", "string", + "cstring", "bytes", "u8", "u32", @@ -282,7 +283,16 @@ export const LIB_PARAM_CLASSES = [ * u8/u32/i32 plumbing classes stay param-only: they were ratified as * inbound plumbing, and outbound integers are the proven classes' * business. */ -export const LIB_RETURN_CLASSES = ["f64", "bool", "string", "bytes", "void", "i64", "u64"] as const; +export const LIB_RETURN_CLASSES = [ + "f64", + "bool", + "string", + "cstring", + "bytes", + "void", + "i64", + "u64", +] as const; /** Ask 4's declared integer classes (the prove-or-refuse pair). */ export type LibIntClass = "i64" | "u64"; @@ -297,7 +307,16 @@ export type LibReturnClass = (typeof LIB_RETURN_CLASSES)[number]; * declared integer classes stay export-map surface: an outbound i64/u64 * demands the prove-or-refuse machinery, which is scoped to export * returns today. */ -const LIB_CALLBACK_PARAM_CLASSES = ["f64", "bool", "string", "bytes", "u8", "u32", "i32"] as const; +const LIB_CALLBACK_PARAM_CLASSES = [ + "f64", + "bool", + "string", + "cstring", + "bytes", + "u8", + "u32", + "i32", +] as const; /** Marshalling classes legal in a CALLBACK RETURN position (inbound: host * → compiled code). Scalars only — every conversion to f64 is exact by * construction; a buffer return would need an ownership contract the mode @@ -377,7 +396,7 @@ export interface LibrarySidecarConfig { } export interface LibraryProfile { - profileFormat: 1; + profileFormat: 1 | 2; name: string; /** The profile file that produced this configuration. Semantic * designation errors anchor here, where the offending name is written. */ @@ -516,8 +535,16 @@ export function loadLibraryProfile( } const p = raw as Record; const format = req(p["profile_format"], "profile_format", "number"); - if (format !== 1) - throw new ProfileError(`unsupported profile_format ${format} (this scriptc reads format 1)`); + if (format !== 1 && format !== 2) + throw new ProfileError( + `unsupported profile_format ${format} (this scriptc reads formats 1 and 2)`, + ); + // The cstring class (a NUL-terminated `const char *`) is format 2. + const cstringClass = (cls: string, path: string): void => { + if (cls === "cstring" && format < 2) { + throw new ProfileError(`'${path}' class 'cstring' requires profile_format 2`); + } + }; // Root keys are strict (checked AFTER the format gate, so a future // format's profile refuses as the wrong format, not as a typo). The // ask-5 key names get the pointed message: a `fences` array pasted at @@ -656,6 +683,7 @@ export function loadLibraryProfile( `'${path}.params[${j}]' must be one of ${LIB_PARAM_CLASSES.join("/")}, got ${JSON.stringify(c)}`, ); } + cstringClass(c, `${path}.params[${j}]`); return c as LibParamClass; }); const returns = req(ee["returns"], `${path}.returns`, "string"); @@ -666,6 +694,7 @@ export function loadLibraryProfile( : `'${path}.returns' must be one of ${LIB_RETURN_CLASSES.join("/")}, got '${returns}'`; throw new ProfileError(detail); } + cstringClass(returns, `${path}.returns`); entries.push({ export: exportName, symbol, params, returns: returns as LibReturnClass }); }); @@ -709,12 +738,13 @@ export function loadLibraryProfile( `'${path}.params[${j}]' must be one of ${LIB_CALLBACK_PARAM_CLASSES.join("/")}, got ${JSON.stringify(cls)}`, ); } + cstringClass(cls, `${path}.params[${j}]`); return cls as LibCallbackParamClass; }); const cbReturns = req(cc["returns"], `${path}.returns`, "string"); if (!(LIB_CALLBACK_RETURN_CLASSES as readonly string[]).includes(cbReturns)) { const detail = - cbReturns === "string" || cbReturns === "bytes" + cbReturns === "string" || cbReturns === "cstring" || cbReturns === "bytes" ? `'${path}.returns': a callback return stays scalar — a buffer flowing host → library needs an ownership contract the mode does not define; pass buffers as callback parameters (library → host, borrowed for the call) or entry parameters instead` : `'${path}.returns' must be one of ${LIB_CALLBACK_RETURN_CLASSES.join("/")}, got '${cbReturns}'`; throw new ProfileError(detail); @@ -1010,7 +1040,7 @@ export function loadLibraryProfile( return { ok: true, profile: { - profileFormat: 1, + profileFormat: format as 1 | 2, name, profilePath, entry, diff --git a/packages/compiler/src/library/prepare.ts b/packages/compiler/src/library/prepare.ts index 9c6fe03fc..94f20198a 100644 --- a/packages/compiler/src/library/prepare.ts +++ b/packages/compiler/src/library/prepare.ts @@ -65,6 +65,7 @@ function libClassFits(cls: string, t: IrType): boolean { case "bool": return t.kind === "bool"; case "string": + case "cstring": return t.kind === "string"; case "bytes": return t.kind === "bytes" && t.elem === "u8"; @@ -178,6 +179,18 @@ function resolveLibrarySection( profileRemediation(profile, LIB_INBOUND_BYTES_TRAP_CODE), ); } + if (e.params.includes("cstring")) { + // The host-contract trap for a NULL cstring parameter: a C string + // argument is a pointer to NUL-terminated text, never NULL. Same + // code and assembly-once discipline as the bytes and integer traps. + resolvedExport.inboundCstringTrap = assembleTrapTeaching( + profileTeaching(profile, LIB_INBOUND_BYTES_TRAP_CODE) ?? + "scriptc: library inbound cstring parameter is NULL\n", + LIB_INBOUND_BYTES_TRAP_CODE, + e.symbol, + profileRemediation(profile, LIB_INBOUND_BYTES_TRAP_CODE), + ); + } if (e.params.includes("i64") || e.params.includes("u64")) { // The sibling host-contract trap for inbound declared-integer // parameters (ask 4): a value past ±(2^53−1) cannot ride f64 @@ -524,10 +537,12 @@ export function prepareLibrary( // SC4024 diagnostics, unused channels legal, undeclared references // refused with the callback teaching. The library lane never loads a // native-FFI manifest, so the channel set owns the surface outright. + // A cstring channel parameter is a string on the TypeScript side; the + // channel's own classes (lib.callbacks) drive the marshalling. const cbImports: IrFfiImport[] = profile.callbacks.map((cb) => ({ name: cb.name, symbol: cb.name, - params: [...cb.params], + params: cb.params.map((cls) => (cls === "cstring" ? "string" : cls)), returns: cb.returns, })); const integerSlotRoots: string[] = []; diff --git a/packages/runtime/src/scr_core.h b/packages/runtime/src/scr_core.h index a640169fa..c791d5a12 100644 --- a/packages/runtime/src/scr_core.h +++ b/packages/runtime/src/scr_core.h @@ -294,6 +294,15 @@ double scr_library_i64_in(int64_t v, const char *trap_msg); double scr_library_u64_in(uint64_t v, const char *trap_msg); void scr_library_str_out(ScrStr *s, const uint8_t **out, size_t *out_len); void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len); +/* The cstring class (a NUL-terminated `const char *`). Inbound: a copy + * decoded as UTF-8 with U+FFFD replacement; NULL delivers trap_msg (the + * assembled SC4012 message). Outbound results move into the arena and + * return their data; callback arguments return the string's own data, + * borrowed for the call. A string containing U+0000 cannot be a C string: + * both outbound forms trap instead of truncating. */ +ScrStr *scr_library_cstr_in(const char *p, const char *trap_msg); /* +1 */ +const char *scr_library_cstr_out(ScrStr *s); +const char *scr_library_cstr_arg(const ScrStr *s); #define scr_atexit(fn) scr_library_register_reset(fn) #elif defined(SCR_WORKERS) diff --git a/packages/runtime/src/scr_library.c b/packages/runtime/src/scr_library.c index 60e11ae0c..b2a5d4c75 100644 --- a/packages/runtime/src/scr_library.c +++ b/packages/runtime/src/scr_library.c @@ -371,6 +371,30 @@ void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len) { *out_len = b->len; } +ScrStr *scr_library_cstr_in(const char *p, const char *trap_msg) { + if (p == NULL) scr_trap(trap_msg); + return scr_str_from_utf8_lossy((const uint8_t *)p, strlen(p)); +} + +/* A C string ends at its first NUL: text holding U+0000 cannot cross. */ +static void scr_library_cstr_check(const ScrStr *s) { + if (memchr(s->data, 0, s->len) != NULL) { + scr_trap("scriptc: TypeError: a cstring value contains U+0000, which a C string cannot " + "hold\n"); + } +} + +const char *scr_library_cstr_out(ScrStr *s) { + scr_library_arena_keep(s, true); + scr_library_cstr_check(s); + return s->data; /* NUL-terminated after len (ScrStr layout) */ +} + +const char *scr_library_cstr_arg(const ScrStr *s) { + scr_library_cstr_check(s); + return s->data; +} + /* ── the reset registry + session reset ───────────────────────────────── * Where an executable's always-linked units atexit() their lazy teardowns, * library builds register here (scr_atexit in scr_runtime.h): registered diff --git a/tests/harness/library-mode.test.ts b/tests/harness/library-mode.test.ts index 3825cb3f4..0eb0cf2c3 100644 --- a/tests/harness/library-mode.test.ts +++ b/tests/harness/library-mode.test.ts @@ -299,6 +299,51 @@ wrap empty: len 2 bytes 60 62 expect(run.stdout).toBe(BUFFERS_EXPECTED); }); + /* ── cstring: NUL-terminated text in, out, and through callbacks ─────── */ + + test("cstring parameters, results, and callback arguments", async () => { + const { archive, outDir } = await buildLibrary("cstrings", emission); + const probe = buildProbe("cstrings", archive, outDir); + const run = runProbe(probe, ["ok"]); + expect(run.signal).toBeNull(); + expect(run.status).toBe(0); + expect(run.stdout).toBe(`register: 0 +greet: hello, w\u00f6rld! (strlen 14) +length ascii: 3 +length utf8: 4 +length malformed: 3 +length empty: 0 +log: QUIET (strlen 5, n 5) +echo: 1 +done +`); + }); + + test.each([ + ["nullarg", "scriptc: library inbound cstring parameter is NULL\n", "SC4012", "kc_length"], + [ + "nulresult", + "scriptc: TypeError: a cstring value contains U+0000, which a C string cannot hold\n", + "SC4015", + "kc_with_nul", + ], + [ + "nularg", + "scriptc: TypeError: a cstring value contains U+0000, which a C string cannot hold\n", + "SC4015", + "kc_echo_nul", + ], + ])("cstring %s traps through the sink", async (mode, text, code, symbol) => { + const { archive, outDir } = await buildLibrary("cstrings", emission); + const probe = buildProbe("cstrings", archive, outDir); + const run = runProbe(probe, [mode]); + expect(run.signal).toBeNull(); + expect(run.status).toBe(0); + expect(run.stdout).toBe( + `register: 0\ntext=[${text}]\ncode=[${code}]\nsymbol=[${symbol}]\ntrapped\n`, + ); + }); + /* ── K4: init re-run determinism ─────────────────────────────────────── */ const SESSION = `session start counter=0 diff --git a/tests/harness/library-profile.test.ts b/tests/harness/library-profile.test.ts index fffa88cc3..fc243ccb5 100644 --- a/tests/harness/library-profile.test.ts +++ b/tests/harness/library-profile.test.ts @@ -160,7 +160,56 @@ describe("library profile validation", () => { }); test("parse error", () => expectSc4001("{ not json", "not valid JSON")); - test("wrong format", () => expectSc4001({ ...good, profile_format: 2 }, "profile_format")); + test("wrong format", () => expectSc4001({ ...good, profile_format: 3 }, "profile_format")); + test("the cstring class requires profile_format 2", () => { + const cstringExport = { + export: "greet", + symbol: "kx_greet", + params: ["cstring"], + returns: "cstring", + }; + const v2 = loadLibraryProfile( + writeProfile({ ...good, profile_format: 2, exports: [...good.exports, cstringExport] }), + ); + expect(v2.ok).toBe(true); + if (v2.ok) { + expect(v2.profile.profileFormat).toBe(2); + expect(v2.profile.exports.at(-1)).toMatchObject({ params: ["cstring"], returns: "cstring" }); + } + expectSc4001( + { ...good, exports: [...good.exports, cstringExport] }, + "'exports[2].params[0]' class 'cstring' requires profile_format 2", + ); + expectSc4001( + { ...good, exports: [...good.exports, { ...cstringExport, params: [] }] }, + "'exports[2].returns' class 'cstring' requires profile_format 2", + ); + const callbackAbi = { ...good.abi, callback_register_symbol: "kx_set_callback" }; + const cstringCallback = { name: "log", params: ["cstring"], returns: "void" }; + expect( + loadLibraryProfile( + writeProfile({ + ...good, + profile_format: 2, + abi: callbackAbi, + callbacks: [cstringCallback], + }), + ).ok, + ).toBe(true); + expectSc4001( + { ...good, abi: callbackAbi, callbacks: [cstringCallback] }, + "'callbacks[0].params[0]' class 'cstring' requires profile_format 2", + ); + expectSc4001( + { + ...good, + profile_format: 2, + abi: callbackAbi, + callbacks: [{ name: "log", params: [], returns: "cstring" }], + }, + "a callback return stays scalar", + ); + }); test("missing name", () => { const { name: _drop, ...rest } = good; expectSc4001(rest, "'name'"); diff --git a/tests/harness/wasm-library.test.ts b/tests/harness/wasm-library.test.ts index 8659c03d9..d0bccdc3d 100644 --- a/tests/harness/wasm-library.test.ts +++ b/tests/harness/wasm-library.test.ts @@ -272,6 +272,85 @@ describe.skipIf(!hasZig).each(["node", "native"] as const)( }, ); + test("cstring parameters, results, and callback arguments use NUL-terminated pointers", async () => { + const entry = join(directory, "cstring-lib.ts"); + await writeFile( + entry, + [ + "declare function log(text: string): void;", + "export function greet(name: string): string {", + " log(name.toUpperCase());", + " return `hello, ${name}!`;", + "}", + "export function withNul(): string {", + ' return "a\\u0000b";', + "}", + "", + ].join("\n"), + ); + const profilePath = join(directory, "cstring.json"); + await writeFile( + profilePath, + JSON.stringify({ + profile_format: 2, + name: "wasm-cstring", + entry, + emission: "llvm", + abi: { + prefix: "cs_", + init_symbol: "cs_init", + sink_register_symbol: "cs_sink", + callback_register_symbol: "cs_callback", + collect_symbol: null, + result_reset_symbol: null, + }, + callbacks: [{ name: "log", params: ["cstring"], returns: "void" }], + exports: [ + { export: "greet", symbol: "cs_greet", params: ["cstring"], returns: "cstring" }, + { export: "withNul", symbol: "cs_with_nul", params: [], returns: "cstring" }, + ], + }), + ); + const result = await compileLibrary({ profilePath, outDir: directory }); + if (!result.ok) throw new Error(JSON.stringify(result.diagnostics)); + const wasi = new WASI({ version: "preview1" }); + let api: Api; + const logs: string[] = []; + const panics: string[] = []; + const cString = (ptr: number): string => { + const memory = new Uint8Array(api.memory.buffer); + let end = ptr; + while (memory[end] !== 0) end++; + return new TextDecoder().decode(memory.subarray(ptr, end)); + }; + const instance = new WebAssembly.Instance( + new WebAssembly.Module(await readFile(result.archivePath)), + { + ...wasi.getImportObject(), + scriptc: { + log: (ptr: number) => logs.push(cString(ptr)), + panic: (ptr: number, len: number) => { + const message = new TextDecoder().decode(new Uint8Array(api.memory.buffer, ptr, len)); + panics.push(message); + throw new Error(message); + }, + }, + }, + ); + api = instance.exports as Api; + wasi.initialize(instance); + api.cs_init(); + const input = new TextEncoder().encode("w\u00f6rld\0"); + const ptr = api.scriptc_alloc(input.length); + new Uint8Array(api.memory.buffer, ptr, input.length).set(input); + expect(cString(api.cs_greet(ptr))).toBe("hello, w\u00f6rld!"); + expect(logs).toEqual(["W\u00d6RLD"]); + api.scriptc_free(ptr); + expect(() => api.cs_with_nul()).toThrow(); + expect(panics).toHaveLength(1); + expect(panics[0]).toContain("a cstring value contains U+0000"); + }); + test("refuses collisions with built-in Wasm exports and imports", async () => { for (const change of [ { diff --git a/tests/library-mode/cstrings/lib.ts b/tests/library-mode/cstrings/lib.ts new file mode 100644 index 000000000..1016beb90 --- /dev/null +++ b/tests/library-mode/cstrings/lib.ts @@ -0,0 +1,26 @@ +// cstring conformance fixture: NUL-terminated text in both directions and +// through a callback channel. `withNul` and `echoNul` produce text holding +// U+0000, which a C string cannot carry. +declare function log(text: string, n: number): void; + +export function greet(name: string): string { + return `hello, ${name}!`; +} + +export function length(text: string): number { + return text.length; +} + +export function echo(text: string): number { + log(text.toUpperCase(), text.length); + return 1; +} + +export function withNul(): string { + return "a\u0000b"; +} + +export function echoNul(): number { + log("x\u0000y", 3); + return 1; +} diff --git a/tests/library-mode/cstrings/probe.c b/tests/library-mode/cstrings/probe.c new file mode 100644 index 000000000..ba802f84a --- /dev/null +++ b/tests/library-mode/cstrings/probe.c @@ -0,0 +1,76 @@ +/* cstring probe, mode-selected by argv[1]: + * ok — cstring parameters copy in (UTF-8, U+FFFD for malformed + * bytes), cstring results are NUL-terminated arena copies, + * and a cstring callback argument arrives NUL-terminated + * nullarg — a NULL cstring parameter is the SC4012 host-contract trap + * nulresult — a result holding U+0000 traps instead of truncating + * nularg — a callback argument holding U+0000 traps the same way + */ +#include +#include +#include +#include + +extern void kc_init(void); +extern void kc_set_panic_sink(void (*fn)(void *, const uint8_t *, size_t, uint64_t), void *ctx); +extern void kc_collect(void); +extern int32_t kc_set_callback(const char *name, void (*fn)(void), void *ctx); +extern const char *kc_greet(const char *name); +extern double kc_length(const char *text); +extern double kc_echo(const char *text); +extern const char *kc_with_nul(void); +extern double kc_echo_nul(void); + +static jmp_buf trap_jmp; + +static void sink(void *ctx, const uint8_t *msg, size_t len, uint64_t addr) { + (void)ctx; (void)addr; + /* structured: 0x01 text 0x1F code 0x1F symbol */ + const uint8_t *p = msg + 1, *end = msg + len; + const char *names[3] = {"text", "code", "symbol"}; + for (int field = 0; field < 3 && p <= end; field++) { + const uint8_t *sep = memchr(p, 0x1f, (size_t)(end - p)); + const uint8_t *stop = sep != NULL ? sep : end; + printf("%s=[%.*s]\n", names[field], (int)(stop - p), (const char *)p); + if (sep == NULL) break; + p = sep + 1; + } + longjmp(trap_jmp, 1); +} + +static void on_log(void *ctx, const char *text, double n) { + (void)ctx; + printf("log: %s (strlen %zu, n %.0f)\n", text, strlen(text), n); +} + +int main(int argc, char **argv) { + const char *mode = argc > 1 ? argv[1] : "ok"; + kc_set_panic_sink(sink, NULL); + kc_init(); + printf("register: %d\n", (int)kc_set_callback("log", (void (*)(void))on_log, NULL)); + if (setjmp(trap_jmp) != 0) { + printf("trapped\n"); + return 0; + } + if (strcmp(mode, "ok") == 0) { + const char *g = kc_greet("w\xC3\xB6rld"); + printf("greet: %s (strlen %zu)\n", g, strlen(g)); + printf("length ascii: %.0f\n", kc_length("abc")); + printf("length utf8: %.0f\n", kc_length("caf\xC3\xA9")); + printf("length malformed: %.0f\n", kc_length("a\xFF" "b")); + printf("length empty: %.0f\n", kc_length("")); + printf("echo: %.0f\n", kc_echo("quiet")); + kc_collect(); + printf("done\n"); + } else if (strcmp(mode, "nullarg") == 0) { + kc_length(NULL); + printf("UNREACHABLE\n"); + } else if (strcmp(mode, "nulresult") == 0) { + kc_with_nul(); + printf("UNREACHABLE\n"); + } else if (strcmp(mode, "nularg") == 0) { + kc_echo_nul(); + printf("UNREACHABLE\n"); + } + return 0; +} diff --git a/tests/library-mode/cstrings/profile.json b/tests/library-mode/cstrings/profile.json new file mode 100644 index 000000000..c5a36e424 --- /dev/null +++ b/tests/library-mode/cstrings/profile.json @@ -0,0 +1,22 @@ +{ + "profile_format": 2, + "name": "conformance-cstrings", + "entry": "lib.ts", + "emission": "llvm", + "abi": { + "prefix": "kc_", + "init_symbol": "kc_init", + "sink_register_symbol": "kc_set_panic_sink", + "collect_symbol": "kc_collect", + "result_reset_symbol": null, + "callback_register_symbol": "kc_set_callback" + }, + "callbacks": [{ "name": "log", "params": ["cstring", "f64"], "returns": "void" }], + "exports": [ + { "export": "greet", "symbol": "kc_greet", "params": ["cstring"], "returns": "cstring" }, + { "export": "length", "symbol": "kc_length", "params": ["cstring"], "returns": "f64" }, + { "export": "echo", "symbol": "kc_echo", "params": ["cstring"], "returns": "f64" }, + { "export": "withNul", "symbol": "kc_with_nul", "params": [], "returns": "cstring" }, + { "export": "echoNul", "symbol": "kc_echo_nul", "params": [], "returns": "f64" } + ] +} From 044b7ae42cecc719e3b4968123d34137be126c56 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 17 Oct 2026 23:42:51 -0500 Subject: [PATCH 037/117] Regenerate the surface manifest --- packages/compiler/surface-manifest.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 63efde378..9067e29b2 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -2507,6 +2507,12 @@ "name": "util/types.isDataView", "status": "static" }, + { + "id": "node-builtin.util.types.isFloat16Array", + "kind": "node-builtin", + "name": "util/types.isFloat16Array", + "status": "static" + }, { "id": "node-builtin.util.types.isFloat32Array", "kind": "node-builtin", @@ -4500,6 +4506,13 @@ "status": "static", "note": "compiles statically at arity 1; other declared call shapes are refused with SC2012" }, + { + "id": "stdlib.math.f16round", + "kind": "stdlib", + "name": "Math.f16round", + "status": "static", + "note": "compiles statically at arity 1; other declared call shapes are refused with SC2012" + }, { "id": "stdlib.math.floor", "kind": "stdlib", From 6f9acfd5f8bc0cf0337078b13b4034a43c254171 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 00:08:20 -0500 Subject: [PATCH 038/117] Read fields of a class instance asserted to a wider union A class instance that a type assertion widens to a union, such as (concrete as A | B).value, still lowers as that class's instance. The shared-property lowering now reads the field or calls the getter on the known class instead of refusing the receiver for not being a tagged union. Closes #49 Co-authored-by: Patrick Wozniak <4481570+patlux@users.noreply.github.com> --- .../src/frontend/lowering/lower-exprs.ts | 22 +++++++++ .../5958-asserted-union-receiver.ts.json | 6 +++ tests/corpus/5958-asserted-union-receiver.ts | 47 +++++++++++++++++++ tests/harness/corpus-costs.json | 2 + 4 files changed, 77 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5958-asserted-union-receiver.ts.json create mode 100644 tests/corpus/5958-asserted-union-receiver.ts diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 77676f8f2..1a9169afc 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -14001,6 +14001,28 @@ export function lowerUnionProperty( } return null; } + // A class instance the checker sees through a wider union (`(concrete + // as A | B).value`): the value is that class's instance, so read its + // field directly. + if (value.type.kind === "object") { + const className = value.type.className; + const info = lowerer.classes.get(className) ?? null; + const field = expr.name.text; + const fieldType = info?.fields.get(field); + if (fieldType !== undefined) + return lowerer.fieldGetExpr( + { container: "class", obj: value, className, field, fieldType }, + locOf(expr), + expr, + ); + const getter = lowerer.findMethodOn(info, `get:${field}`); + if (getter) + return lowerer.fieldGetExpr( + { container: "accessor", obj: value, className, field, fieldType: getter.sig.ret }, + locOf(expr), + expr, + ); + } if (value.type.kind !== "union") { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5958-asserted-union-receiver.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5958-asserted-union-receiver.ts.json new file mode 100644 index 000000000..d294caa65 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5958-asserted-union-receiver.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5958-asserted-union-receiver.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5958-asserted-union-receiver.ts b/tests/corpus/5958-asserted-union-receiver.ts new file mode 100644 index 000000000..23a591827 --- /dev/null +++ b/tests/corpus/5958-asserted-union-receiver.ts @@ -0,0 +1,47 @@ +// A class instance asserted to a wider union (`(concrete as A | B).value`) +// keeps its class: field and getter reads go to the known class. +class A { + value: number; + label = "a"; + constructor(value: number) { + this.value = value; + } + describe(): string { + return `A(${this.value})`; + } + get doubled(): number { + return this.value * 2; + } +} +class B { + value: number; + flag = true; + constructor(value: number) { + this.value = value; + } + describe(): string { + return `B(${this.value})`; + } + get doubled(): number { + return this.value * 3; + } +} +class C extends A { + override get doubled(): number { + return this.value * 10; + } +} +type Rec = { value: boolean }; + +const concrete = new A(41); +console.log((concrete as A | B).value + 1, (concrete as A | B).doubled); +console.log((new C(5) as A | B).value, (new C(5) as A | B).doubled, (concrete as A | B).describe()); +console.log((concrete as A | Rec).value, ((concrete as A | B) as A | B).value); +const maybe = (concrete as A | B | undefined)?.value; +console.log(maybe); +function show(x: A): string { + return String((x as A | B).value) + (x satisfies A as A | B).doubled; +} +console.log(show(concrete), show(new C(2))); +const widened = concrete as A | B; +console.log(widened.value, widened instanceof A); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 097ebf723..4df728d5c 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1854,6 +1854,7 @@ "5951-result-never-widening.ts": 4710, "5955-any-promise-methods.js": 3940, "5956-erased-generic-members.ts": 6730, + "5958-asserted-union-receiver.ts": 2430, "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, @@ -4494,6 +4495,7 @@ "5951-result-never-widening.ts": 6120, "5955-any-promise-methods.js": 5120, "5956-erased-generic-members.ts": 8750, + "5958-asserted-union-receiver.ts": 3160, "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, From 3dcb8a1a29122450408f98708cdb33aafb907d3a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 00:12:05 -0500 Subject: [PATCH 039/117] Lower Date.prototype.toJSON with Node's null for invalid dates d.toJSON() now answers the toISOString() string for a valid date and null for an invalid one, as a string | null value although the lib types say string. Unannotated bindings, object and array literal entries initialized by it keep the null, reads of such bindings stay checked, and JSON.stringify serializes the null instead of narrowing it to string. Closes #935 Co-authored-by: phall <25888173+phall1@users.noreply.github.com> --- .../content/limitations/builtin-apis/date.mdx | 2 +- .../src/frontend/lowering/builtins/dates.ts | 89 ++++++++++++++++++- .../src/frontend/lowering/builtins/json.ts | 8 +- .../lowering/expressions/object-literals.ts | 25 ++++++ .../src/frontend/lowering/lower-exprs.ts | 23 +++++ .../compiler/src/frontend/lowering/lowerer.ts | 62 ++++++++++++- .../tests/corpus/5959-date-to-json.ts.json | 6 ++ tests/corpus/5959-date-to-json.ts | 32 +++++++ .../__snapshots__/date-formatters.ts.txt | 4 +- .../harness/__snapshots__/stdlib-fence.ts.txt | 2 +- tests/harness/corpus-costs.json | 2 + 11 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5959-date-to-json.ts.json create mode 100644 tests/corpus/5959-date-to-json.ts diff --git a/docs/content/limitations/builtin-apis/date.mdx b/docs/content/limitations/builtin-apis/date.mdx index 5c465b315..605de4511 100644 --- a/docs/content/limitations/builtin-apis/date.mdx +++ b/docs/content/limitations/builtin-apis/date.mdx @@ -1 +1 @@ -- **Date:** Date unions, year/month constructors, setters, statically typed TypeScript identity comparisons, thrown Date values, and locale/string formatters are unsupported. Zero-argument and single number/string constructors, storage and passing, `getTime`, `valueOf`, `toISOString`, calendar getters, `getTimezoneOffset`, and single-string `Date.parse` compile. JavaScript Dates retain identity through checked storage and support Date-copy construction and JSON serialization. See [Dates and timezones](#dates-and-timezones) for parsing restrictions. +- **Date:** Date unions, year/month constructors, setters, statically typed TypeScript identity comparisons, thrown Date values, and locale/string formatters are unsupported. Zero-argument and single number/string constructors, storage and passing, `getTime`, `valueOf`, `toISOString`, `toJSON` (a `string | null`: null for an invalid date, as in Node), calendar getters, `getTimezoneOffset`, and single-string `Date.parse` compile. JavaScript Dates retain identity through checked storage and support Date-copy construction and JSON serialization. See [Dates and timezones](#dates-and-timezones) for parsing restrictions. diff --git a/packages/compiler/src/frontend/lowering/builtins/dates.ts b/packages/compiler/src/frontend/lowering/builtins/dates.ts index 023d9abf2..fa880bdc9 100644 --- a/packages/compiler/src/frontend/lowering/builtins/dates.ts +++ b/packages/compiler/src/frontend/lowering/builtins/dates.ts @@ -1,7 +1,17 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer, own } from "../lowerer.js"; import { locOf } from "../../program.js"; -import { F64, type IrExpr, type IrLibFn, STRING } from "../../../ir/ir.js"; +import { + BOOL, + F64, + type IrExpr, + type IrLibFn, + type IrStmt, + type IrType, + NULL_T, + STRING, + typeKey, +} from "../../../ir/ir.js"; const DATE_GETTER_FNS: Readonly> = { getFullYear: "date.getFullYear", @@ -24,7 +34,7 @@ const DATE_GETTER_FNS: Readonly> = { }; const DATE_METHOD_HINT = - "getTime(), valueOf(), toISOString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering"; + "getTime(), valueOf(), toISOString(), toJSON(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering"; /** The Date slice: statics plus read-only Date values backed by one * TimeClip'd millisecond scalar. Construction lives in lowerNew; @@ -80,6 +90,7 @@ export function lowerDateCall( if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "date") return null; if (!lowerer.isStdlibMember(access)) return null; const name = access.name.text; + if (name === "toJSON") return lowerDateToJson(lowerer, call, access); if (call.arguments.length !== 0) { lowerer.noLowering(`Date.prototype.${name} with arguments`, call, DATE_METHOD_HINT); } @@ -113,3 +124,77 @@ export function lowerDateCall( lowerer.checker.getSymbolAtLocation(access.name), ); } + +/** `d.toJSON(key?)`: Node answers null for an invalid date and the + * `toISOString()` string otherwise, as `string | null` (the lib types say + * `string`). The argument is evaluated and ignored, as the built-in does. */ +function lowerDateToJson( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.PropertyAccessExpression, +): IrExpr { + const loc = locOf(call); + if (call.arguments.length > 1 || call.arguments.some((a) => ts.isSpreadElement(a))) + lowerer.noLowering(`Date.prototype.toJSON with ${call.arguments.length} arguments`, call); + const raw = lowerer.lowerExpr(access.expression); + const receiver: IrExpr = + raw.type.kind === "dyn" + ? { kind: "libCall", fn: "date.checkedValue", args: [raw], type: { kind: "date" }, loc } + : raw; + if (receiver.type.kind !== "date") + lowerer.badType(access.expression, lowerer.typeOf(access.expression)); + const date = lowerer.declareHiddenLocal("%date", receiver.type); + const stmts: IrStmt[] = [{ kind: "varDecl", localId: date.id, init: receiver, loc }]; + const key = call.arguments[0]; + if (key) stmts.push({ kind: "exprStmt", expr: lowerer.lowerExpr(key), loc }); + const value: IrExpr = { kind: "varRef", localId: date.id, type: receiver.type, loc }; + const time: IrExpr = { kind: "libCall", fn: "date.getTime", args: [value], type: F64, loc }; + const type = dateJsonType(lowerer); + return { + kind: "seqExpr", + stmts, + result: { + kind: "ternary", + // An invalid date's time value is NaN, the one value unequal to itself. + cond: { kind: "bin", op: "!==", left: time, right: time, type: BOOL, loc }, + then: lowerer.coerceToExpected({ kind: "unitLit", unit: "null", type: NULL_T, loc }, type), + else_: lowerer.coerceToExpected( + { kind: "libCall", fn: "date.toISOStringValue", args: [value], type: STRING, loc }, + type, + ), + type, + loc, + }, + type, + loc, + }; +} + +/** `string | null`, the type of a Date's `toJSON()` result. */ +export function dateJsonType(lowerer: Lowerer): IrType { + const arms = [STRING, NULL_T].sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1)); + return { kind: "union", unionId: lowerer.unions.intern(arms) }; +} + +/** A Date `toJSON()` call, or a binding initialized by one + * (Lowerer.dateJsonBindings): its value can be null where the lib types + * say string. */ +export function isDateJsonSource(lowerer: Lowerer, node: ts.Node): boolean { + while (ts.isParenthesizedExpression(node)) node = node.expression; + if (ts.isIdentifier(node)) { + const symbol = + node.parent && ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node + ? lowerer.checker.getShorthandAssignmentValueSymbol(node.parent) + : lowerer.checker.getSymbolAtLocation(node); + return symbol !== undefined && lowerer.dateJsonBindings.has(symbol); + } + if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression)) return false; + const access = node.expression; + return ( + access.name.text === "toJSON" && + !node.questionDotToken && + !access.questionDotToken && + lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind === "date" && + lowerer.isStdlibMember(access) + ); +} diff --git a/packages/compiler/src/frontend/lowering/builtins/json.ts b/packages/compiler/src/frontend/lowering/builtins/json.ts index 475cfd51c..a73c9d5e7 100644 --- a/packages/compiler/src/frontend/lowering/builtins/json.ts +++ b/packages/compiler/src/frontend/lowering/builtins/json.ts @@ -1,3 +1,4 @@ +import { isDateJsonSource } from "./dates.js"; import { dynUndefinedExpr, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; @@ -82,7 +83,12 @@ export function lowerJsonMethodCall( // conversion so a stale capture cannot read an impossible payload. // Optional strings have a serializer that preserves a missing root; // an unchecked array read can still be absent despite its checker type. - if (value.type.kind === "union" && optionalStringTags(lowerer, value.type) === null) { + // A Date's toJSON() result keeps its null: the lib types say string. + if ( + value.type.kind === "union" && + optionalStringTags(lowerer, value.type) === null && + !isDateJsonSource(lowerer, argNode) + ) { const narrowed = lowerer.mapTypeOf(lowerer.typeOf(argNode)); if (narrowed && !isUnitType(narrowed) && narrowed.kind !== "void") { const helper = diff --git a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts index 0ae63de7b..c95731fc7 100644 --- a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts @@ -1,3 +1,4 @@ +import { dateJsonType, isDateJsonSource } from "../builtins/dates.js"; import { dynUndefinedExpr, numLit, strLit, varRef } from "../../../ir/build.js"; import { pathModuleValue } from "../lower-builtin-values.js"; import { InternalCompilerError } from "../../../errors.js"; @@ -1155,6 +1156,30 @@ export function lowerObjectLiteral( type = { kind: "record", shapeId: expected.shapeId }; } } + // A Date's toJSON() result keeps its null in a field with no declared + // destination: the lib types say string. + if (!expected) { + for (const property of expr.properties) { + const value = ts.isPropertyAssignment(property) + ? property.initializer + : ts.isShorthandPropertyAssignment(property) + ? property.name + : null; + if ( + value && + property.name && + (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) && + isDateJsonSource(lowerer, value) + ) { + const widened = lowerer.runtimeOptionalRecordField( + type, + property.name.text, + dateJsonType(lowerer), + ); + if (widened.kind === "record") type = { kind: "record", shapeId: widened.shapeId }; + } + } + } let shape = lowerer.shapes.get(type.shapeId)!; // JavaScript Dates carry native object identity in checked storage. An // inferred scalar Date field would erase that identity before boxing. diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 77676f8f2..4d225c234 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -1,3 +1,4 @@ +import { dateJsonType, isDateJsonSource } from "./builtins/dates.js"; import { guardNullProto, nullProtoRecordShape, recordNullProtoTest } from "./null-prototype.js"; import { lowerProtocolPropertyRead } from "./class-protocol-dispatch.js"; import { generatorDrain } from "./iterator-adapters.js"; @@ -3323,10 +3324,23 @@ export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrEx !(declared.kind === "union" && lowerer.armTag(declared.unionId, UNDEFINED_T) >= 0) ) return expr; + // The same for a field holding a Date's toJSON() result, whose null + // the declared string does not represent. + if ( + expr.kind === "recordGet" && + lowerer.isRuntimeOptionalField(expr.shapeId, expr.field) && + lowerer.armTag(expr.type.unionId, NULL_T) >= 0 && + declared && + !(declared.kind === "union" && lowerer.armTag(declared.unionId, NULL_T) >= 0) + ) + return expr; } if (ts.isIdentifier(node)) { const symbol = lowerer.resolveValueSymbol(node); if (symbol && lowerer.unstableSwitchBindings.has(symbol)) return expr; + // A binding initialized by a Date's toJSON() can hold null where the + // checker says string; consumers check it. + if (symbol && lowerer.dateJsonBindings.has(symbol)) return expr; } if ( ts.isPropertyAccessExpression(node) && @@ -5649,6 +5663,15 @@ export function lowerArrayLiteral( } } } + // A Date's toJSON() element keeps its null in a literal with no declared + // destination: the lib types say string. + if ( + !expected && + mapped?.kind === "array" && + mapped.elem.kind === "string" && + expr.elements.some((element) => isDateJsonSource(lowerer, element)) + ) + mapped = { kind: "array", elem: dateJsonType(lowerer) }; // An array literal inside an npm-static implicit-any instance can // inherit the checker's poisoned any[] context even after the // active binding gives every element one concrete lowering. Recover a diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index d4cf82752..a6238d66d 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -433,7 +433,7 @@ import { } from "./builtins/console.js"; import { lowerConsoleNew } from "./lower-console.js"; import { lowerNumberStaticCall, lowerNumberStaticProperty } from "./builtins/numbers.js"; -import { lowerDateCall } from "./builtins/dates.js"; +import { dateJsonType, isDateJsonSource, lowerDateCall } from "./builtins/dates.js"; import { lowerFsConstantsProperty, lowerBuiltinConstantsProperty, @@ -1876,6 +1876,8 @@ export class Lowerer { /** Record fields promoted to an undefined-armed union by an indexed-read * value. The key is the concrete emitted shape and field name. */ readonly runtimeOptionalFields = new Set(); + /** Bindings initialized by a Date's `toJSON()` (analyzeDateJsonResults). */ + readonly dateJsonBindings = new Set(); /** Record bindings whose flow class reaches storage outside the class: * they keep the declared layout, so an initializer from unchecked reads * converts once instead of the binding adopting the widened variant. */ @@ -3847,6 +3849,62 @@ export class Lowerer { * TypeScript's default indexed-access type is a useful source annotation, * but it is not a runtime proof; promoting only the affected slots keeps * the rest of the dense ABI unchanged. */ + /** A Date's `toJSON()` answers null for an invalid date while the lib + * types say `string`: unannotated bindings initialized by such a call, + * and object-literal fields holding one, keep `string | null`. */ + analyzeDateJsonResults(parts: FileParts[]): void { + const nullable = dateJsonType(this); + for (const { sf } of parts) { + if (!sf.text.includes("toJSON")) continue; + ts.walkPreorder(sf, (node) => { + // `x = d.toJSON()`: the checker narrows x to string after the + // assignment, so its reads must stay checked. + if ( + ts.isBinaryExpression(node) && + node.operatorToken.kind === ts.SyntaxKind.EqualsToken && + ts.isIdentifier(node.left) && + isDateJsonSource(this, node.right) + ) { + const symbol = this.checker.getSymbolAtLocation(node.left); + if (symbol) this.dateJsonBindings.add(symbol); + return undefined; + } + if (!ts.isVariableDeclaration(node) || !node.initializer) return undefined; + if (!ts.isIdentifier(node.name)) return undefined; + const symbol = this.checker.getSymbolAtLocation(node.name); + if (!symbol) return undefined; + let init: ts.Expression = node.initializer; + while (ts.isParenthesizedExpression(init)) init = init.expression; + if (isDateJsonSource(this, init)) { + this.dateJsonBindings.add(symbol); + // An annotation keeps its declared storage. + if (!node.type) this.runtimeOptionalBindingTypes.set(symbol, nullable); + return undefined; + } + if (node.type) return undefined; + if (!ts.isObjectLiteralExpression(init)) return undefined; + const declared = this.mapTypeOf(this.typeOf(node.name)); + if (declared?.kind !== "record") return undefined; + let widened: IrType = declared; + for (const property of init.properties) { + const value = ts.isPropertyAssignment(property) + ? property.initializer + : ts.isShorthandPropertyAssignment(property) + ? property.name + : null; + const name = + property.name && (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) + ? property.name.text + : null; + if (value && name !== null && isDateJsonSource(this, value)) + widened = this.runtimeOptionalRecordField(widened, name, nullable); + } + if (widened !== declared) this.runtimeOptionalBindingTypes.set(symbol, widened); + return undefined; + }); + } + } + analyzeRuntimeOptionalArrayReads(parts: FileParts[]): void { const provenance = RuntimeOptionalProvenance.fromEnvironment(); // The site whose value the current promotion follows (debug only). @@ -5996,6 +6054,7 @@ export class Lowerer { } this.collectProgram(parts); this.analyzeRuntimeOptionalArrayReads(parts); + this.analyzeDateJsonResults(parts); // Decorated classes analyze AFTER the whole collection pass: a // decorator's return type may name a subclass declared below the // class, and reference lowering needs each class's rebindability @@ -6380,6 +6439,7 @@ export class Lowerer { }; this.collectProgram(parts); this.analyzeRuntimeOptionalArrayReads(parts); + this.analyzeDateJsonResults(parts); // Decorated classes analyze post-collection here too: the %init seeds // lower the decoration calls, whose edges (decorator bodies, construct // thunks) reachable emit must see. diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5959-date-to-json.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5959-date-to-json.ts.json new file mode 100644 index 000000000..935958e1d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5959-date-to-json.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5959-date-to-json.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5959-date-to-json.ts b/tests/corpus/5959-date-to-json.ts new file mode 100644 index 000000000..4776a76f9 --- /dev/null +++ b/tests/corpus/5959-date-to-json.ts @@ -0,0 +1,32 @@ +// Date.prototype.toJSON answers the toISOString() string for a valid date +// and null for an invalid one (the lib types say string), through +// bindings, literals, JSON.stringify and console.log. +const good = new Date(Date.UTC(2024, 1, 29, 12, 30, 15, 250)); +const bad = new Date("not a date"); +const epoch = new Date(0); + +console.log(good.toJSON(), bad.toJSON(), epoch.toJSON("ignored key")); +console.log(JSON.stringify(good.toJSON()), JSON.stringify(bad.toJSON())); + +const kept = bad.toJSON(); +const shown = good.toJSON(); +console.log(kept, shown, kept === null, typeof kept, kept ?? "fallback"); +console.log(`${bad.toJSON()} / ${good.toJSON()}`); + +const annotated: string | null = bad.toJSON(); +console.log(annotated, JSON.stringify({ annotated })); + +let changing: string | null = "start"; +changing = bad.toJSON(); +console.log(changing === null, JSON.stringify([changing, epoch.toJSON()])); + +const record = { at: good.toJSON(), never: bad.toJSON(), kept }; +console.log(JSON.stringify(record), record.never === null, record.at); +console.log(JSON.stringify({ direct: bad.toJSON(), also: epoch.toJSON() })); +console.log(JSON.stringify([bad.toJSON(), good.toJSON(), shown])); + +function stamp(date: Date): string { + const text = date.toJSON(); + return text === null ? "invalid" : text.slice(0, 10); +} +console.log(stamp(good), stamp(bad), stamp(epoch)); diff --git a/tests/harness/__snapshots__/date-formatters.ts.txt b/tests/harness/__snapshots__/date-formatters.ts.txt index 881703106..66d98d861 100644 --- a/tests/harness/__snapshots__/date-formatters.ts.txt +++ b/tests/harness/__snapshots__/date-formatters.ts.txt @@ -5,7 +5,7 @@ date-formatters.ts:4:1 - error SC2020: 'Date.prototype.toString' is part of the | ^~~~~~~~~~~~~~~ 5 | date.toLocaleString(); - hint: getTime(), valueOf(), toISOString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering + hint: getTime(), valueOf(), toISOString(), toJSON(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering date-formatters.ts:5:1 - error SC2020: 'Date.prototype.toLocaleString' is part of the standard library types but has no scriptc lowering yet @@ -14,4 +14,4 @@ date-formatters.ts:5:1 - error SC2020: 'Date.prototype.toLocaleString' is part o | ^~~~~~~~~~~~~~~~~~~~~ 6 | - hint: getTime(), valueOf(), toISOString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering \ No newline at end of file + hint: getTime(), valueOf(), toISOString(), toJSON(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering \ No newline at end of file diff --git a/tests/harness/__snapshots__/stdlib-fence.ts.txt b/tests/harness/__snapshots__/stdlib-fence.ts.txt index 77b0e05d8..337354eec 100644 --- a/tests/harness/__snapshots__/stdlib-fence.ts.txt +++ b/tests/harness/__snapshots__/stdlib-fence.ts.txt @@ -66,7 +66,7 @@ stdlib-fence.ts:25:1 - error SC2020: 'Date.prototype.setUTCFullYear with argumen | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 | const sameDate = mutableDate === mutableDate; // scalar storage must not fake object identity - hint: getTime(), valueOf(), toISOString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering + hint: getTime(), valueOf(), toISOString(), toJSON(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering stdlib-fence.ts:26:18 - error SC1043: comparing non-number, non-string values are not supported yet diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 097ebf723..512c84ade 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1854,6 +1854,7 @@ "5951-result-never-widening.ts": 4710, "5955-any-promise-methods.js": 3940, "5956-erased-generic-members.ts": 6730, + "5959-date-to-json.ts": 3330, "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, @@ -4494,6 +4495,7 @@ "5951-result-never-widening.ts": 6120, "5955-any-promise-methods.js": 5120, "5956-erased-generic-members.ts": 8750, + "5959-date-to-json.ts": 4330, "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, From 0f50a7be57ebb0efa1e745a291b268714b1ec3cf Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 00:16:55 -0500 Subject: [PATCH 040/117] Lower mapped types over a generic function's type parameters Inside a monomorphized generic body the checker keeps mapped types over the function's own type parameters symbolic. The instance binds those parameters, so { [K in keyof S]: T } now maps each property of the bound type through the template evaluated at that key, covering indexed templates (S[K], S[K]["_output"]) and conditional ones with infer (S[K] extends Schema ? T : never). Conditional types over bound parameters evaluate the same way elsewhere in the body. Closes #886 Co-authored-by: Malek Mohamed Noureldean Elkssas <87043730+malekelkssas@users.noreply.github.com> --- packages/compiler/src/frontend/type-mapper.ts | 195 ++++++++++++++++++ .../corpus/5960-generic-mapped-types.ts.json | 6 + tests/corpus/5960-generic-mapped-types.ts | 64 ++++++ tests/harness/corpus-costs.json | 2 + 4 files changed, 267 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-generic-mapped-types.ts.json create mode 100644 tests/corpus/5960-generic-mapped-types.ts diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 54fb8f70e..7f3089bb3 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1442,6 +1442,18 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { contextResolutions++; return viaIndexed; } + // A conditional type over a bound parameter (`Infer`, a + // mapped type's member): evaluate it against the bindings. + if (type.isConditionalType()) { + const evaluated = evalMappedTemplate(type, new Map(), new Map(), ctx); + if (evaluated && evaluated !== type) { + const viaConditional = mapType(evaluated, ctx); + if (viaConditional !== null) { + contextResolutions++; + return viaConditional; + } + } + } } const widened = checker.getBaseTypeOfLiteralType(type); const flags = widened.flags; @@ -4086,6 +4098,8 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { if (childShaped && core >= 2) return CHILD_T; } if (flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection) && callSigs.length === 0) { + const viaMapped = mapBoundMappedType(widened, ctx); + if (viaMapped) return viaMapped; const viaAlias = mapGenericUtilityAlias(widened, ctx); if (viaAlias) return viaAlias; const record = mapRecordType(widened, ctx); @@ -4725,6 +4739,187 @@ function mapGenericIndexedAccess(type: ts.Type, ctx: TypeMapperCtx): IrType | nu return covered.every((t) => typeEquals(t, first)) ? first : null; } +/** A mapped type over a type parameter of the instance being lowered (`{ + * [K in keyof S]: S[K] }`, `{ [K in keyof S]: Infer }`): the checker + * keeps it symbolic inside the generic body, but the instance binds `S`, + * so each property of the bound type maps through the template evaluated + * with `K` set to that property's key. Optionality follows the `?` + * modifier, or the bound property's own for a homomorphic mapping. Null + * when the shape is anything else or a template form does not evaluate. */ +function mapBoundMappedType(widened: ts.Type, ctx: TypeMapperCtx): IrType | null { + const { checker, resolveTypeParamTs, shapes, unions } = ctx; + if (!resolveTypeParamTs || !isMappedShape(widened)) return null; + const symbol = widened.getSymbol(); + const node = symbol + ? checker.declarationsOf(symbol).find((d): d is ts.MappedTypeNode => ts.isMappedTypeNode(d)) + : undefined; + const constraint = node?.typeParameter.constraint; + if ( + !node?.type || + !constraint || + !ts.isTypeOperatorNode(constraint) || + constraint.operator !== ts.SyntaxKind.KeyOfKeyword + ) + return null; + const source = checker.getTypeFromTypeNode(constraint.type); + if (!(source.flags & ts.TypeFlags.TypeParameter)) return null; + const bound = resolveTypeParamTs(source); + const key = checker.getSymbolAtLocation(node.typeParameter.name); + if (!bound || !key) return null; + const template = checker.getTypeFromTypeNode(node.type); + const modifier = node.questionToken?.kind; + const fields: { name: string; type: IrType }[] = []; + const order: string[] = []; + for (const property of checker.getPropertiesOfType(bound)) { + const name = property.name; + const evaluated = evalMappedTemplate(template, new Map([[key, name]]), new Map(), ctx); + let type = evaluated ? mapType(evaluated, ctx) : null; + if (!type) return null; + const optional = + modifier === ts.SyntaxKind.MinusToken + ? false + : modifier !== undefined || (property.flags & ts.SymbolFlags.Optional) !== 0; + if (optional) { + const armed = withUndefinedArm(type, unions); + if (!armed) return null; + type = armed; + } + fields.push({ name, type }); + order.push(name); + } + fields.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)); + return { kind: "record", shapeId: shapes.intern(fields, false, undefined, order) }; +} + +/** The checker type a mapped type's template stands for at one key: + * `keys` binds the mapped type parameter to a property name, `aliases` + * binds type-alias and `infer` parameters met on the way. Handles type + * parameters (through the instance's bindings), indexed accesses + * (`S[K]`, `S[K]["_output"]`) and conditional types whose `extends` side + * is a reference to the same generic type as the checked type + * (`S extends Schema ? T : never`); answers the type itself + * when it mentions none of the bound parameters, null otherwise. */ +function evalMappedTemplate( + type: ts.Type, + keys: Map, + aliases: Map, + ctx: TypeMapperCtx, +): ts.Type | null { + const { checker, resolveTypeParamTs } = ctx; + if (type.flags & ts.TypeFlags.TypeParameter) { + const symbol = type.getSymbol(); + if (symbol && keys.has(symbol)) return null; + if (symbol && aliases.has(symbol)) return aliases.get(symbol)!; + return resolveTypeParamTs?.(type) ?? null; + } + if (type.isIndexedAccessType()) { + const object = type.getObjectType(); + const index = type.getIndexType(); + if (!object || !index) return null; + const receiver = evalMappedTemplate(object, keys, aliases, ctx); + const indexSymbol = index.flags & ts.TypeFlags.TypeParameter ? index.getSymbol() : undefined; + const name = + indexSymbol && keys.has(indexSymbol) + ? keys.get(indexSymbol)! + : index.isStringLiteralType() + ? index.value + : index.isNumberLiteralType() + ? String(index.value) + : null; + if (!receiver || name === null) return null; + const property = checker.getPropertyOfType(receiver, name); + return property ? checker.getTypeOfSymbol(property) : null; + } + if (type.isConditionalType()) { + // A conditional reached through an alias (`Infer`) checks the + // alias's own parameters: bind them to the evaluated arguments. + let scope = aliases; + const alias = type.getAliasSymbol(); + const aliasArgs = type.getAliasTypeArguments(); + const aliasDecl = alias + ? checker + .declarationsOf(alias) + .find((d): d is ts.TypeAliasDeclaration => ts.isTypeAliasDeclaration(d)) + : undefined; + if (aliasDecl?.typeParameters && aliasArgs.length === aliasDecl.typeParameters.length) { + scope = new Map(aliases); + for (let i = 0; i < aliasArgs.length; i++) { + const param = checker.getSymbolAtLocation(aliasDecl.typeParameters[i]!.name); + const arg = evalMappedTemplate(aliasArgs[i]!, keys, aliases, ctx); + if (!param || !arg) return null; + scope.set(param, arg); + } + } + const checkType = type.getCheckType(); + const extendsType = type.getExtendsType(); + if (!checkType || !extendsType) return null; + const checked = evalMappedTemplate(checkType, keys, scope, ctx); + if (!checked) return null; + const inferred = matchInferReference(checked, extendsType, ctx); + if (inferred === undefined) return null; + const branch = inferred ? type.getTrueType() : type.getFalseType(); + const branchScope = inferred ? new Map([...scope, ...inferred]) : scope; + return evalMappedTemplate(branch, keys, branchScope, ctx); + } + return mentionsMappedParams(type, keys, aliases) ? null : type; +} + +/** `checked extends G<..., infer T, ...>`: the infer bindings when + * `checked` is a reference to the same generic `G` (its arguments bind the + * infer positions; other positions must be the same types), false when it + * is a reference to another type or a primitive, undefined when the match + * cannot be decided this way. */ +function matchInferReference( + checked: ts.Type, + extendsType: ts.Type, + ctx: TypeMapperCtx, +): Map | false | undefined { + const { checker } = ctx; + const target = (t: ts.Type): ts.Type | undefined => + t.isTypeReference?.() ? (t as ts.TypeReference).getTarget?.() : undefined; + const wantTarget = target(extendsType) ?? extendsType.getAliasSymbol(); + if (!wantTarget) return undefined; + const gotTarget = target(checked) ?? checked.getAliasSymbol(); + if (!gotTarget) return checked.flags & ts.TypeFlags.Object ? undefined : false; + if (gotTarget !== wantTarget) return undefined; + const wantArgs = target(extendsType) + ? checker.getTypeArguments(extendsType as ts.TypeReference) + : extendsType.getAliasTypeArguments(); + const gotArgs = target(checked) + ? checker.getTypeArguments(checked as ts.TypeReference) + : checked.getAliasTypeArguments(); + if (wantArgs.length !== gotArgs.length) return undefined; + const inferred = new Map(); + for (let i = 0; i < wantArgs.length; i++) { + const want = wantArgs[i]!; + const symbol = want.flags & ts.TypeFlags.TypeParameter ? want.getSymbol() : undefined; + const isInfer = symbol + ? checker + .declarationsOf(symbol) + .some((d) => d.parent !== undefined && ts.isInferTypeNode(d.parent)) + : false; + if (isInfer && symbol) inferred.set(symbol, gotArgs[i]!); + else if (want !== gotArgs[i]) return undefined; + } + return inferred; +} + +/** The type mentions a mapped key or bound alias parameter (a template + * shape evalMappedTemplate does not reduce). */ +function mentionsMappedParams( + type: ts.Type, + keys: Map, + aliases: Map, +): boolean { + if (type.flags & ts.TypeFlags.TypeParameter) { + const symbol = type.getSymbol(); + return symbol !== undefined && (keys.has(symbol) || aliases.has(symbol)); + } + if (type.isUnionType() || type.isIntersectionType()) + return ts.constituentTypes(type).some((part) => mentionsMappedParams(part, keys, aliases)); + return false; +} + function mapGenericUtilityAlias(widened: ts.Type, ctx: TypeMapperCtx): IrType | null { const { resolveTypeParam, shapes, unions } = ctx; if (!resolveTypeParam) return null; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-generic-mapped-types.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-generic-mapped-types.ts.json new file mode 100644 index 000000000..a95837f80 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5960-generic-mapped-types.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5960-generic-mapped-types.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5960-generic-mapped-types.ts b/tests/corpus/5960-generic-mapped-types.ts new file mode 100644 index 000000000..229a97d88 --- /dev/null +++ b/tests/corpus/5960-generic-mapped-types.ts @@ -0,0 +1,64 @@ +// Mapped types over a generic function's own type parameters lower in its +// monomorphized instances: homomorphic copies, modifiers, conditional +// templates with infer, and indexed templates, including over an +// index-signature constraint whose keys only the instance knows. +type Schema = { parse(input: unknown): T }; +type Infer = S extends Schema ? T : never; +interface Typed { + readonly _output: Output; +} +type Output> = T["_output"]; + +const str: Schema = { parse: (input) => String(input) }; +const num: Schema = { parse: (input) => Number(input) }; + +function same(value: S): { [K in keyof S]: S[K] } { + return value; +} +function frozen(value: S): { readonly [K in keyof S]: S[K] } { + return { ...value }; +} +function loose(value: S): { [K in keyof S]?: S[K] } { + return value; +} +function pair; right: Schema }>( + shape: S, + input: { left: unknown; right: unknown }, +): { [K in keyof S]: Infer } { + return { + left: shape.left.parse(input.left), + right: shape.right.parse(input.right), + } as { [K in keyof S]: Infer }; +} +function objectWith>>( + shape: S, + build: (shape: S) => { [K in keyof S]: Infer }, +): { [K in keyof S]: Infer } { + const parsed: { [K in keyof S]: Infer } = build(shape); + return parsed; +} +function outputs>>( + values: S, + read: (values: S) => { [K in keyof S]: Output }, +): { [K in keyof S]: Output } { + return read(values); +} + +const s = same({ a: 1, b: "two" }); +console.log(s.a + 1, s.b.length); +const f = frozen({ x: true, y: [1, 2] }); +console.log(f.x, f.y.length); +const l = loose({ n: 3 }); +console.log(l.n ?? 0); +const p = pair({ left: str, right: num }, { left: 12, right: "34" }); +console.log(p.left.length, p.right + 1); +const person = objectWith({ name: str, age: num }, (shape) => ({ + name: shape.name.parse("Ada"), + age: shape.age.parse("36"), +})); +console.log(person.name, person.age + 1); +const out = outputs({ id: { _output: 7 }, tag: { _output: "t" } }, (values) => ({ + id: values.id._output, + tag: values.tag._output, +})); +console.log(out.id * 2, out.tag.toUpperCase()); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 097ebf723..6324e4ada 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1854,6 +1854,7 @@ "5951-result-never-widening.ts": 4710, "5955-any-promise-methods.js": 3940, "5956-erased-generic-members.ts": 6730, + "5960-generic-mapped-types.ts": 2540, "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, @@ -4494,6 +4495,7 @@ "5951-result-never-widening.ts": 6120, "5955-any-promise-methods.js": 5120, "5956-erased-generic-members.ts": 8750, + "5960-generic-mapped-types.ts": 3300, "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, From add07dba3d74f414b3f9f9dc8e3d8948da8c2f36 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 00:46:59 -0500 Subject: [PATCH 041/117] Return a worker's memory when it exits without sharing any of it On Linux, a worker thread that exits without having made any object it allocated reachable from another thread gives back all of its memory: the pages it carved, including ProgramLifetime instances and other objects it never freed, and the system blocks it still holds. A worker carves past each slice's frontier while the arena's free lists and returned regions are set aside, takes from those free lists only once a slice has no bump room left, and records the system blocks it allocates. Messages and intern tables that share published graphs by pointer, and the process-wide key arrays of typed records, mark the thread as sharing; so does a remote free of one of its blocks. When a worker that did not share parks, the trim helper returns its pages, frees its system blocks, and restores the arena to its state at the claim, with the free blocks the worker took free again. A worker that shared keeps its memory as before. SCR_SA_DISCARD=0 keeps every worker's memory; SCR_SA_DISCARD=poison makes the discarded pages inaccessible instead, for tests. --- docs/content/docs/contracts.mdx | 2 +- docs/content/docs/threads.mdx | 2 + .../native-worker-discarded-heaps.ts.json | 6 + packages/runtime/src/scr_alloc.c | 405 +++++++++++++++++- packages/runtime/src/scr_alloc.test.c | 254 +++++++++++ packages/runtime/src/scr_itable.c | 3 + packages/runtime/src/scr_itable.test.c | 10 +- packages/runtime/src/scr_json.c | 1 + packages/runtime/src/scr_message.c | 3 + packages/runtime/src/scr_rc.h | 9 +- tests/corpus/native-worker-discarded-heaps.ts | 102 +++++ tests/harness/corpus-costs.json | 2 + 12 files changed, 780 insertions(+), 19 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json create mode 100644 tests/corpus/native-worker-discarded-heaps.ts diff --git a/docs/content/docs/contracts.mdx b/docs/content/docs/contracts.mdx index 11737da59..8f17f6a98 100644 --- a/docs/content/docs/contracts.mdx +++ b/docs/content/docs/contracts.mdx @@ -331,7 +331,7 @@ $ scriptc build graph.ts ## ProgramLifetime -`ProgramLifetime` marks a class whose instances a program keeps until it exits, such as the nodes of a syntax tree, the symbols of a symbol table or interned types. scriptc then never reference counts, collects or frees instances of the class and of its subclasses: they are never freed, every retain and release on them compiles to nothing, and the cycle collector neither walks them nor needs to trace the objects that point to them. Node.js behavior is unchanged; only memory use differs, because an instance the program drops is never reclaimed. +`ProgramLifetime` marks a class whose instances a program keeps until it exits, such as the nodes of a syntax tree, the symbols of a symbol table or interned types. scriptc then never reference counts, collects or frees instances of the class and of its subclasses: they are never freed, every retain and release on them compiles to nothing, and the cycle collector neither walks them nor needs to trace the objects that point to them. Node.js behavior is unchanged; only memory use differs, because an instance the program drops is never reclaimed. On Linux, the instances a worker thread creates are returned with the rest of its memory when it exits, unless the worker shared objects with other threads (see [cost](/docs/threads#cost)). ```ts:tree.ts import type { ProgramLifetime } from "@scriptc/types"; diff --git a/docs/content/docs/threads.mdx b/docs/content/docs/threads.mdx index 7b394e09f..15a3eb102 100644 --- a/docs/content/docs/threads.mdx +++ b/docs/content/docs/threads.mdx @@ -234,6 +234,8 @@ Without `@scriptc/threads`, a scriptc executable also shares a message of untype Starting a worker thread takes tens of microseconds plus the worker's own module initialization, since every worker initializes the program's modules again, as in Node.js. A worker that exits frees its heap first, which takes time proportional to what it still holds. `SCRIPTC_WORKER_STATS=1` prints, as each worker exits, how long it took to start, to run its script and to exit. +On Linux, a worker that exits without having shared an object it allocated with another thread returns all of its memory, including objects it never freed, such as `ProgramLifetime` instances. A worker shares objects when, for example, it sends a published value or frozen plain data, which other threads read by reference, or stores a value in an `InternTable`. The memory of a worker that shared stays allocated, as on other platforms. Set `SCR_SA_DISCARD=0` in the environment to keep the memory of every worker. + `publish` visits each object of the graph once and marks it immortal, so publication takes time proportional to the graph. Published objects then cost nothing on later sends, and reference counting and the cycle collector skip them. Stores into the types a program publishes carry one extra load and branch. Threads that add to one shared collection of published values while they run can use an [`InternTable`](/docs/experimental#interntable) from `@scriptc/experimental`. diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json new file mode 100644 index 000000000..b7dd8fd17 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/native-worker-discarded-heaps.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_alloc.c b/packages/runtime/src/scr_alloc.c index eaf391a9e..2959e642d 100644 --- a/packages/runtime/src/scr_alloc.c +++ b/packages/runtime/src/scr_alloc.c @@ -630,6 +630,13 @@ static bool scr_sa_reserve_region(void) { * scr_sa_trim). */ static size_t scr_sa_claim_carved[SCR_SA_ARENAS]; static size_t scr_sa_carved(void); +/* A worker thread's memory, discarded when it parks (see "Discarding a + * worker's memory" below). */ +typedef struct ScrSaKeep ScrSaKeep; +static _Thread_local bool scr_sa_worker; /* set by scr_sa_thread_starting */ +static _Thread_local ScrSaKeep *scr_sa_keep; /* while the worker's memory is kept apart */ +static void scr_sa_keep_begin(unsigned i); +static void scr_sa_keep_drained(ScrSaKeep *k, ScrSaBlock *b, unsigned c); #endif /* Moves every block other threads freed into this arena's free lists. */ @@ -638,6 +645,13 @@ static void scr_sa_drain_remote(void) { while (b) { ScrSaBlock *next = b->next; unsigned c = (unsigned)(((uintptr_t)b - scr_sa.base) >> scr_sa.shift); +#ifdef SCR_SA_TRIM + if (scr_sa_keep) { + scr_sa_keep_drained(scr_sa_keep, b, c); + b = next; + continue; + } +#endif b->next = scr_sa.free[c]; scr_sa.free[c] = b; b = next; @@ -672,6 +686,7 @@ static bool scr_sa_reserve(void) { scr_sa_drain_remote(); #ifdef SCR_SA_TRIM scr_sa_claim_carved[i] = scr_sa_carved(); + if (scr_sa_worker) scr_sa_keep_begin(i); #endif return true; } @@ -884,6 +899,303 @@ static void scr_sa_trim(void) { scr_sa_arena, (int)trim, scr_sa_trim_stats[0] >> 20, scr_sa_trim_stats[1] >> 20, scr_sa_trim_stats[2] >> 20); } + +/* Discarding a worker's memory (Linux). Script objects stay on the thread + * that allocated them: other threads reach one only through a message or an + * intern table that shares a published (immortal) graph by pointer, or a + * process-wide immortal cache, and each of those calls + * scr_sa_thread_shares. Runtime state that outlives a thread (messages, + * mailboxes, shared bytes, intern table entries) comes from the system + * allocator directly. So when a worker thread parks without having shared, + * nothing it allocated through scr_mem_* can be reachable from another + * thread, and what it never freed (ProgramLifetime instances, published + * module constants) is garbage. Such a thread's memory goes back whole: + * - when a worker claims an arena, the arena's free lists and returned + * regions are set aside, and the worker carves only past each slice's + * frontier, so its blocks of class c are [start[c], bump[c]), plus the + * blocks it takes from the free lists set aside once a slice has no bump + * room left, which it records; + * - the system blocks it allocates (large blocks, an exhausted slice) are + * recorded until it frees them; + * - a remote free into its blocks means another thread held one: the same + * as sharing; + * - when it parks without having shared, the trim helper returns the pages + * it carved (MADV_DONTNEED; the start of the first page, which it may + * share with older blocks, is cleared), frees the recorded system blocks, + * and parks the arena as the worker found it, with the blocks it took + * free again. A worker that shared parks + * its arena with the blocks set aside added to its free lists, and the + * ordinary trim applies. + * SCR_SA_DISCARD=0 keeps every worker's memory. SCR_SA_DISCARD=poison makes + * the carved pages inaccessible instead, and keeps the system blocks, so + * that a reference to discarded memory faults (a check for tests). */ +#define SCR_SA_SYS_GONE ((void *)1) /* a removed entry of ScrSaKeep.sys */ + +struct ScrSaKeep { + /* The arena as the worker claimed it: free lists (to which remote frees + * of older blocks are added), carve cursors and returned regions. */ + ScrSaBlock *free[SCR_SA_NCLASS]; + char *bump[SCR_SA_NCLASS], *lim[SCR_SA_NCLASS]; + ScrSaHoles holes[SCR_SA_NCLASS]; + /* Each slice's frontier then (bump and limit, NULL limits for a slice not + * opened yet), and the first address the worker carves in it. */ + char *front_bump[SCR_SA_NCLASS], *front_lim[SCR_SA_NCLASS]; + char *start[SCR_SA_NCLASS]; + /* The worker's system blocks: an open-addressing set of `cap` slots (a + * power of two, or 0), NULL for an empty slot and SCR_SA_SYS_GONE for a + * removed entry; `used` counts both kinds of filled slots. */ + void **sys; + size_t cap, used, live; + /* The blocks of the free lists set aside that the worker took once a slice + * had no bump room left, so that older free blocks are used before the + * slice grows; they go back to those lists with the worker's memory. */ + ScrSaBlock **taken; + size_t ntaken, cap_taken; + bool shared; + bool poison; +}; + +static _Thread_local bool scr_sa_discarded; /* this thread's memory went back */ +static ScrSaKeep *scr_sa_parked_keep[SCR_SA_ARENAS]; /* handed to the helper */ + +/* SCR_SA_DISCARD: 0 off, 1 on (the default), 2 poison. */ +static int scr_sa_discard_mode(void) { + const char *mode = getenv("SCR_SA_DISCARD"); + if (!mode) return 1; + if (strcmp(mode, "0") == 0) return 0; + return strcmp(mode, "poison") == 0 ? 2 : 1; +} + +static void scr_sa_keep_begin(unsigned i) { + int mode = scr_sa_discard_mode(); + if (!mode) return; + ScrSaKeep *k = calloc(1, sizeof *k); + if (!k) return; + k->poison = mode == 2; + for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { + ScrSaHoles *h = &scr_sa_holes[i][c]; + k->free[c] = scr_sa.free[c]; + k->bump[c] = scr_sa.bump[c]; + k->lim[c] = scr_sa.lim[c]; + k->holes[c] = *h; + memset(h, 0, sizeof *h); + scr_sa.free[c] = NULL; + /* While the slice carves a returned region, its frontier is kept apart. */ + if (k->holes[c].lim) { + scr_sa.bump[c] = k->holes[c].bump; + scr_sa.lim[c] = k->holes[c].lim; + } + k->front_bump[c] = scr_sa.bump[c]; + k->front_lim[c] = scr_sa.lim[c]; + k->start[c] = scr_sa.lim[c] ? scr_sa.bump[c] : (char *)scr_sa.base + ((size_t)c << scr_sa.shift); + } + scr_sa_keep = k; +} + +/* A remote free of class c, drained while the worker keeps its memory + * apart: one of its own blocks makes it share; an older block goes to the + * free lists set aside. Once the worker has taken blocks from those lists, + * any older block might be one of them, so it shares as well. */ +static void scr_sa_keep_drained(ScrSaKeep *k, ScrSaBlock *b, unsigned c) { + if ((char *)b >= k->start[c] && (char *)b < scr_sa.bump[c]) { + k->shared = true; + b->next = scr_sa.free[c]; + scr_sa.free[c] = b; + } else { + if (k->ntaken) k->shared = true; + b->next = k->free[c]; + k->free[c] = b; + } +} + +/* A block of class c from the free lists set aside, for a worker whose + * slice has no bump room left; NULL when there is none or it cannot be + * recorded. */ +static ScrSaBlock *scr_sa_keep_take(ScrSaKeep *k, unsigned c) { + ScrSaBlock *b = k->free[c]; + if (!b) return NULL; + if (k->ntaken == k->cap_taken) { + size_t cap = k->cap_taken ? 2 * k->cap_taken : 256; + ScrSaBlock **taken = realloc(k->taken, cap * sizeof *taken); + if (!taken) return NULL; + k->taken = taken; + k->cap_taken = cap; + } + k->free[c] = b->next; + k->taken[k->ntaken++] = b; + return b; +} + +static size_t scr_sa_sys_slot(const void *p, size_t cap) { + return (size_t)((((uint64_t)(uintptr_t)p >> 4) * UINT64_C(0x9E3779B97F4A7C15)) >> 32) & (cap - 1); +} + +/* Records system block p. A worker whose set cannot grow keeps its memory. */ +static void scr_sa_keep_add(ScrSaKeep *k, void *p) { + if ((k->used + 1) * 2 > k->cap) { + size_t cap = 64; + while (cap < (k->live + 1) * 4) cap *= 2; + void **sys = calloc(cap, sizeof *sys); + if (!sys) { + k->shared = true; + return; + } + for (size_t s = 0; s < k->cap; s++) { + void *q = k->sys[s]; + if (!q || q == SCR_SA_SYS_GONE) continue; + size_t j = scr_sa_sys_slot(q, cap); + while (sys[j]) j = (j + 1) & (cap - 1); + sys[j] = q; + } + free(k->sys); + k->sys = sys; + k->cap = cap; + k->used = k->live; + } + size_t j = scr_sa_sys_slot(p, k->cap); + while (k->sys[j] && k->sys[j] != SCR_SA_SYS_GONE) j = (j + 1) & (k->cap - 1); + if (!k->sys[j]) k->used++; + k->sys[j] = p; + k->live++; +} + +/* Forgets system block p; whether it was recorded. */ +static bool scr_sa_keep_remove(ScrSaKeep *k, const void *p) { + if (!k->live) return false; + for (size_t j = scr_sa_sys_slot(p, k->cap); k->sys[j]; j = (j + 1) & (k->cap - 1)) { + if (k->sys[j] != p) continue; + k->sys[j] = SCR_SA_SYS_GONE; + k->live--; + return true; + } + return false; +} + +/* The calling thread's arena keeps the worker's memory (it shared): the + * free lists set aside go back, followed by the worker's own free blocks, + * and so do the returned regions, past which the worker carved. */ +static void scr_sa_keep_merge(ScrSaKeep *k) { + for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { + ScrSaBlock *kept = k->free[c]; + if (kept) { + ScrSaBlock *tail = kept; + while (tail->next) tail = tail->next; + tail->next = scr_sa.free[c]; + scr_sa.free[c] = kept; + } + ScrSaHoles *h = &scr_sa_holes[scr_sa_arena][c]; + *h = k->holes[c]; + if (h->lim) { + h->bump = scr_sa.bump[c]; + h->lim = scr_sa.lim[c]; + scr_sa.bump[c] = k->bump[c]; + scr_sa.lim[c] = k->lim[c]; + } + } + free(k->sys); + free(k->taken); + free(k); +} + +/* Returns the memory of the worker whose arena the calling thread (the + * trim helper) holds, and restores the arena to its state at the worker's + * claim; with poison, makes the pages inaccessible and moves the frontier + * past them instead. */ +static void scr_sa_discard(ScrSaKeep *k) { + /* Remote frees since the worker's last drain. */ + scr_sa_keep = k; + scr_sa_drain_remote(); + scr_sa_keep = NULL; + if (k->shared) { + scr_sa_keep_merge(k); + scr_sa_trim(); + return; + } + uintptr_t page = (uintptr_t)sysconf(_SC_PAGESIZE); + if (page == 0 || page == (uintptr_t)-1) page = 4096; + size_t returned = 0, sys_bytes = 0, sys_blocks = 0; + for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { + char *lo = k->start[c], *top = scr_sa.bump[c], *lim = scr_sa.lim[c]; + char *bump = k->front_bump[c], *limit = k->front_lim[c]; + if (lim && top > lo) { + char *first = (char *)(((uintptr_t)lo + page - 1) & ~(page - 1)); + char *used = (char *)(((uintptr_t)top + page - 1) & ~(page - 1)); + /* The part of a page that may also hold older blocks. */ + if (first > lo) memset(lo, 0, (size_t)((first < top ? first : top) - lo)); + if (k->poison) { + if (used > first) (void)mprotect(first, (size_t)(used - first), PROT_NONE); + bump = used > first ? used : top; + limit = lim > bump ? lim : bump; + } else { + char *end = (char *)(((uintptr_t)lim + page - 1) & ~(page - 1)); + if (end > first) { + (void)madvise(first, (size_t)(end - first), MADV_DONTNEED); + returned += (size_t)(end - first); + } + } + } else { + bump = top; + limit = lim; + } + scr_sa.free[c] = k->free[c]; + ScrSaHoles *h = &scr_sa_holes[scr_sa_arena][c]; + *h = k->holes[c]; + if (h->lim) { + h->bump = bump; + h->lim = limit; + scr_sa.bump[c] = k->bump[c]; + scr_sa.lim[c] = k->lim[c]; + } else { + scr_sa.bump[c] = bump; + scr_sa.lim[c] = limit; + } + } + /* The older free blocks the worker took are free again. */ + if (!k->poison) + for (size_t t = 0; t < k->ntaken; t++) { + ScrSaBlock *b = k->taken[t]; + unsigned c = (unsigned)(((uintptr_t)b - scr_sa.base) >> scr_sa.shift); + b->next = scr_sa.free[c]; + scr_sa.free[c] = b; + } + if (!k->poison) + for (size_t s = 0; s < k->cap; s++) { + void *p = k->sys[s]; + if (!p || p == SCR_SA_SYS_GONE) continue; +#if defined(__GLIBC__) + sys_bytes += malloc_usable_size(p); +#endif + sys_blocks++; + free(p); + } +#if defined(__GLIBC__) + if (sys_blocks) (void)malloc_trim(0); +#endif + const char *stats = getenv("SCR_SA_STATS"); + if (stats && stats[0] == '1') + fprintf(stderr, "scr_sa: discard arena %d returned %zu MB, %zu system blocks (%zu MB)\n", scr_sa_arena, + returned >> 20, sys_blocks, sys_bytes >> 20); + free(k->sys); + free(k->taken); + free(k); +} + +/* Hooks of the allocator's system paths and of sharing (scr_rc.h). */ +static void scr_sa_keep_note_system(void *p) { + if (p && scr_sa_keep) scr_sa_keep_add(scr_sa_keep, p); +} + +void scr_sa_thread_shares(void) { + if (scr_sa_keep) scr_sa_keep->shared = true; +} + +/* Library archives run on their embedder's threads and keep their memory. */ +static void scr_sa_worker_starting(void) { +#ifndef SCR_LIB + scr_sa_worker = true; +#endif +} +#define SCR_SA_WORKER_STARTING() scr_sa_worker_starting() #endif #ifdef SCR_SA_TRIM @@ -906,12 +1218,36 @@ static void *scr_sa_trim_main(void *arg) { unsigned i = (unsigned)(uintptr_t)arg; scr_sa_arena = (int)i; scr_sa = scr_sa_parked[i]; - scr_sa_trim(); + ScrSaKeep *k = scr_sa_parked_keep[i]; + scr_sa_parked_keep[i] = NULL; + if (k) scr_sa_discard(k); + else scr_sa_trim(); scr_sa_release(i); atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_release); return NULL; } +/* Hands the calling thread's arena to a trim helper (with `k`, to discard + * the worker's memory); false if no helper could start. */ +static bool scr_sa_start_helper(unsigned i, ScrSaKeep *k) { + scr_sa_parked[i] = scr_sa; + scr_sa_parked_keep[i] = k; + atomic_fetch_add_explicit(&scr_sa_trimming, 1, memory_order_relaxed); + pthread_attr_t attr; + pthread_t helper; + bool started = pthread_attr_init(&attr) == 0; + if (started) { + started = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && + pthread_create(&helper, &attr, scr_sa_trim_main, (void *)(uintptr_t)i) == 0; + pthread_attr_destroy(&attr); + } + if (!started) { + scr_sa_parked_keep[i] = NULL; + atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_relaxed); + } + return started; +} + void scr_sa_wait_trims(void) { while (atomic_load_explicit(&scr_sa_trimming, memory_order_acquire)) { struct timespec pause = {0, 1000000}; @@ -920,6 +1256,7 @@ void scr_sa_wait_trims(void) { } #else void scr_sa_wait_trims(void) {} +void scr_sa_thread_shares(void) {} #endif void scr_sa_thread_park(void) { @@ -929,18 +1266,25 @@ void scr_sa_thread_park(void) { scr_sa_pf_park(); #endif #ifdef SCR_SA_TRIM - if (scr_sa_trim_worth()) { - scr_sa_parked[i] = scr_sa; - atomic_fetch_add_explicit(&scr_sa_trimming, 1, memory_order_relaxed); - pthread_attr_t attr; - pthread_t helper; - bool started = pthread_attr_init(&attr) == 0; - if (started) { - started = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && - pthread_create(&helper, &attr, scr_sa_trim_main, (void *)(uintptr_t)i) == 0; - pthread_attr_destroy(&attr); + ScrSaKeep *k = scr_sa_keep; + scr_sa_keep = NULL; + if (k && !k->shared) { + /* Nothing this thread allocated is reachable from another one: its + * memory goes back, and later frees on this thread are dropped. */ + scr_sa_discarded = true; + if (!scr_sa_start_helper(i, k)) { + scr_sa_discard(k); + scr_sa_release(i); + return; } - if (started) { + memset(&scr_sa, 0, sizeof scr_sa); + scr_sa_arena = -1; + scr_sa_refused = true; + return; + } + if (k) scr_sa_keep_merge(k); + if (scr_sa_trim_worth()) { + if (scr_sa_start_helper(i, NULL)) { /* Later frees on this thread take the foreign path into the arena's * remote list; the helper releases the claim. */ memset(&scr_sa, 0, sizeof scr_sa); @@ -948,7 +1292,6 @@ void scr_sa_thread_park(void) { scr_sa_refused = true; return; } - atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_relaxed); scr_sa_trim(); } #endif @@ -971,6 +1314,9 @@ static size_t scr_sa_foreign_size(const void *p) { } void scr_sa_free_foreign(void *p) { +#ifdef SCR_SA_TRIM + if (scr_sa_discarded) return; /* the block went back with the thread's memory */ +#endif uintptr_t region = atomic_load_explicit(&scr_sa_region, memory_order_acquire); uintptr_t off = (uintptr_t)p - region; if (region && off < scr_sa_arena_span * SCR_SA_ARENAS) { @@ -982,6 +1328,9 @@ void scr_sa_free_foreign(void *p) { memory_order_relaxed)); return; } +#ifdef SCR_SA_TRIM + if (scr_sa_keep) (void)scr_sa_keep_remove(scr_sa_keep, p); +#endif free(p); } #else @@ -1020,6 +1369,15 @@ __attribute__((cold, noinline)) void *scr_sa_slow(size_t n, bool zero) { if (zero) memset(b, 0, n); return b; } +#ifdef SCR_SA_TRIM + /* A worker that keeps its memory apart uses the arena's older free + * blocks before its slice grows. */ + if (scr_sa_keep && (size_t)(scr_sa.lim[c] - scr_sa.bump[c]) < scr_sa_class_size(c) && + (b = scr_sa_keep_take(scr_sa_keep, c)) != NULL) { + if (zero) memset(b, 0, n); + return b; + } +#endif #endif /* Carve from the slice, opening it or raising its limit as needed; * fresh pages are zero. */ @@ -1051,6 +1409,9 @@ __attribute__((cold, noinline)) void *scr_sa_slow(size_t n, bool zero) { SCR_SA_LARGE_NOTE(q, n); SCR_SA_THREAD_LARGE_NOTE(); } +#ifdef SCR_SA_TRIM + scr_sa_keep_note_system(q); +#endif return q; } @@ -1065,8 +1426,14 @@ void *scr_mem_realloc(void *p, size_t n) { } #endif else { +#ifdef SCR_SA_TRIM + bool kept = scr_sa_keep && scr_sa_keep_remove(scr_sa_keep, p); +#endif void *q = realloc(p, n); if (n > SCR_SA_MAX) SCR_SA_LARGE_NOTE(q, n); +#ifdef SCR_SA_TRIM + if (kept) scr_sa_keep_note_system(q ? q : p); /* a failed realloc leaves p */ +#endif return q; } /* Still fits its block, which is aligned for n (see the contract). */ @@ -1082,10 +1449,15 @@ void *scr_mem_realloc(void *p, size_t n) { return realloc(p, n); } #ifdef SCR_WORKERS void scr_sa_thread_park(void) {} void scr_sa_wait_trims(void) {} +void scr_sa_thread_shares(void) {} void scr_sa_free_foreign(void *p) { free(p); } #endif #endif +#ifndef SCR_SA_WORKER_STARTING +#define SCR_SA_WORKER_STARTING() ((void)0) +#endif + #ifdef SCR_WORKERS /* Blocks above SCR_SA_MAX come from glibc, which gives each thread that * allocates its own arena: a heap reserved up front and made usable with @@ -1116,7 +1488,10 @@ void scr_sa_free_foreign(void *p) { free(p); } * that are not workers (they never reserve). */ static _Thread_local unsigned scr_sa_thread_large; -void scr_sa_thread_starting(void) { scr_sa_thread_large = 1; } +void scr_sa_thread_starting(void) { + scr_sa_thread_large = 1; + SCR_SA_WORKER_STARTING(); +} static void scr_sa_thread_reserve(void) { void *blocks[SCR_SA_THREAD_HEAP_RESERVE / SCR_SA_THREAD_HEAP_STEP + 1]; @@ -1136,7 +1511,7 @@ static void scr_sa_thread_large_note(void) { if (count == SCR_SA_THREAD_RESERVE_AFTER) scr_sa_thread_reserve(); } #else -void scr_sa_thread_starting(void) {} +void scr_sa_thread_starting(void) { SCR_SA_WORKER_STARTING(); } #endif #endif diff --git a/packages/runtime/src/scr_alloc.test.c b/packages/runtime/src/scr_alloc.test.c index 26300296e..78251f330 100644 --- a/packages/runtime/src/scr_alloc.test.c +++ b/packages/runtime/src/scr_alloc.test.c @@ -373,6 +373,259 @@ static void check_trim(void) { } #endif +#if defined(SCR_WORKERS) && SCR_SMALL_ALLOC && defined(__linux__) +#include +#include +#include +#include +#include + +/* A worker thread (scr_sa_thread_starting) that exits without sharing + * gives its memory back: the pages it carved, and the system blocks it + * still holds. Older blocks of the arena, and the memory of a worker that + * shared (or got a remote free of its own blocks), stay. */ +/* DISCARD_SIZE and POISON_SIZE are classes the earlier checks leave unused + * in the workers' arena, so their state there is known. */ +enum { DISCARD_BLOCKS = 1 << 20, DISCARD_SIZE = 40, POISON_SIZE = 56, DISCARD_OLD = 64, DISCARD_LARGE = 64 }; +enum { DISCARD_LARGE_SIZE = 64 << 10 }; +static unsigned char *old_blocks[DISCARD_OLD]; +static unsigned char **discard_blocks; +static unsigned char *discard_large[DISCARD_LARGE]; +static uintptr_t discard_base, discard_lo, discard_hi; +static size_t block_size = DISCARD_SIZE; /* of the workers' and reusing threads' blocks */ +static bool discard_shares; +static atomic_int discard_step; + +static void wait_step(int step) { + while (atomic_load(&discard_step) < step) { + struct timespec pause = {0, 100000}; + nanosleep(&pause, NULL); + } +} + +/* A plain script thread whose blocks stay live in its parked arena. */ +static void *discard_old_owner(void *arg) { + (void)arg; + for (unsigned i = 0; i < DISCARD_OLD; i++) { + old_blocks[i] = scr_mem_alloc(DISCARD_SIZE); + assert(owned(old_blocks[i])); + fill(old_blocks[i], DISCARD_SIZE, (unsigned char)i); + } + discard_base = scr_sa.base; + scr_sa_thread_park(); + return NULL; +} + +static void allocate_discardable(void) { + discard_lo = UINTPTR_MAX; + discard_hi = 0; + for (size_t i = 0; i < DISCARD_BLOCKS; i++) { + unsigned char *p = scr_mem_alloc(block_size); + assert(p && owned(p)); + fill(p, block_size, (unsigned char)i); + discard_blocks[i] = p; + if ((uintptr_t)p < discard_lo) discard_lo = (uintptr_t)p; + if ((uintptr_t)p + block_size > discard_hi) discard_hi = (uintptr_t)p + block_size; + } + /* System blocks: some freed, some moved by realloc, the rest kept. */ + for (unsigned i = 0; i < DISCARD_LARGE; i++) { + discard_large[i] = scr_mem_alloc(DISCARD_LARGE_SIZE); + assert(discard_large[i] && !owned(discard_large[i])); + fill(discard_large[i], 64, (unsigned char)i); + } + for (unsigned i = 0; i < DISCARD_LARGE; i += 4) { + scr_mem_free(discard_large[i]); + discard_large[i] = NULL; + } + for (unsigned i = 1; i < DISCARD_LARGE; i += 4) discard_large[i] = scr_mem_realloc(discard_large[i], 2 * DISCARD_LARGE_SIZE); +} + +static void *discard_worker(void *arg) { + (void)arg; + scr_sa_thread_starting(); + allocate_discardable(); + assert(scr_sa.base == discard_base); + /* None of the arena's older blocks or free blocks is reused. */ + for (unsigned i = 0; i < DISCARD_OLD; i++) assert(discard_lo > (uintptr_t)old_blocks[i]); + if (discard_shares) scr_sa_thread_shares(); + scr_sa_thread_park(); + return NULL; +} + +/* A worker one of whose blocks the main thread frees while it runs. */ +static void *remote_freed_worker(void *arg) { + (void)arg; + scr_sa_thread_starting(); + allocate_discardable(); + atomic_store(&discard_step, 1); + wait_step(2); + /* A class this thread has not used: its first block takes the slow path, + * which drains the remote free. */ + void *p = scr_mem_alloc(200); + assert(p); + scr_sa_thread_park(); + return NULL; +} + +/* A plain thread that takes as many blocks again from the arena: carved + * ones must be zero (the fast path does not clear them). */ +static size_t reuse_outside; +static uintptr_t reuse_hi; +static void *discard_reuse(void *arg) { + (void)arg; + reuse_outside = 0; + reuse_hi = 0; + for (size_t i = 0; i < DISCARD_BLOCKS; i++) { + unsigned char *p = scr_mem_calloc(block_size); + assert(p && owned(p)); + assert(scr_sa.base == discard_base); + for (size_t k = 0; k < block_size; k++) assert(p[k] == 0); + for (unsigned j = 0; j < DISCARD_OLD; j++) assert(p != old_blocks[j]); + if ((uintptr_t)p < discard_lo || (uintptr_t)p >= discard_hi) reuse_outside++; + if ((uintptr_t)p + block_size > reuse_hi) reuse_hi = (uintptr_t)p + block_size; + discard_blocks[i] = p; + } + for (size_t i = 0; i < DISCARD_BLOCKS; i++) scr_mem_free(discard_blocks[i]); + scr_sa_thread_park(); + return NULL; +} + +static void run(void *(*fn)(void *)) { + pthread_t t; + assert(pthread_create(&t, NULL, fn, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + scr_sa_wait_trims(); +} + +static void verify_old_blocks(void) { + for (unsigned i = 0; i < DISCARD_OLD; i++) verify(old_blocks[i], DISCARD_SIZE, (unsigned char)i); +} + +/* The worker's blocks stayed as it left them, and the next thread to claim + * the arena carves past them; then they are freed (remote frees). */ +static void verify_kept(void) { + for (size_t i = 0; i < DISCARD_BLOCKS; i++) verify(discard_blocks[i], block_size, (unsigned char)i); + for (unsigned i = 0; i < DISCARD_LARGE; i++) { + if (!discard_large[i]) continue; + verify(discard_large[i], 64, (unsigned char)i); + free(discard_large[i]); + } + for (size_t i = 0; i < DISCARD_BLOCKS; i++) scr_mem_free(discard_blocks[i]); +} + +/* The protection of the mapping that holds address a, from /proc/self/maps. */ +static bool readable(uintptr_t a) { + FILE *maps = fopen("/proc/self/maps", "r"); + assert(maps); + char line[512]; + bool found = false, result = false; + while (!found && fgets(line, sizeof line, maps)) { + unsigned long lo, hi; + char perms[8]; + if (sscanf(line, "%lx-%lx %7s", &lo, &hi, perms) != 3) continue; + if (a >= lo && a < hi) { + found = true; + result = perms[0] == 'r'; + } + } + fclose(maps); + assert(found); + return result; +} + +static void check_discard(void) { + discard_blocks = malloc(DISCARD_BLOCKS * sizeof *discard_blocks); + assert(discard_blocks); + run(discard_old_owner); + size_t page = (size_t)sysconf(_SC_PAGESIZE); + + /* Discarded: its pages are returned, and carved again (zeroed) by the next + * thread, which does not grow the slice. The arena's older blocks stay. */ + discard_shares = false; + run(discard_worker); + verify_old_blocks(); + uintptr_t first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + /* Pre-fault requests still in flight may fault in a few megabytes again. */ + size_t total = (discard_hi - first) / page; + assert(resident_pages(first, discard_hi) < total / 4); + run(discard_reuse); + assert(reuse_outside < 256); + verify_old_blocks(); + + /* SCR_SA_DISCARD=poison makes the pages inaccessible; the next thread + * carves past them. */ + block_size = POISON_SIZE; + setenv("SCR_SA_DISCARD", "poison", 1); + run(discard_worker); + unsetenv("SCR_SA_DISCARD"); + verify_old_blocks(); + first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + assert(!readable(first)); + assert(!readable((discard_hi - 1) & ~(uintptr_t)(page - 1))); + run(discard_reuse); + assert(reuse_outside == DISCARD_BLOCKS); + verify_old_blocks(); + block_size = DISCARD_SIZE; + + /* A worker that shared keeps its memory. */ + discard_shares = true; + run(discard_worker); + verify_old_blocks(); + verify_kept(); + + /* So does one that got a remote free of one of its blocks. */ + atomic_store(&discard_step, 0); + pthread_t t; + assert(pthread_create(&t, NULL, remote_freed_worker, NULL) == 0); + wait_step(1); + scr_mem_free(discard_blocks[0]); + discard_blocks[0] = scr_mem_alloc(DISCARD_SIZE); /* main's own block, for verify_kept */ + fill(discard_blocks[0], DISCARD_SIZE, 0); + atomic_store(&discard_step, 2); + assert(pthread_join(t, NULL) == 0); + scr_sa_wait_trims(); + verify_old_blocks(); + verify_kept(); + + /* SCR_SA_DISCARD=0 keeps every worker's memory. */ + discard_shares = false; + setenv("SCR_SA_DISCARD", "0", 1); + run(discard_worker); + unsetenv("SCR_SA_DISCARD"); + verify_old_blocks(); + verify_kept(); + + /* The kept workers' blocks are free now (remote frees): a worker takes + * them once its slice has no bump room left, and they are free again + * after its memory goes back, so the next thread does not grow the slice + * either. */ + uintptr_t kept_hi = discard_hi; + run(discard_worker); + verify_old_blocks(); + assert(discard_hi <= kept_hi + 64 * page); + run(discard_reuse); + assert(reuse_hi <= kept_hi + 64 * page); + verify_old_blocks(); + + /* Returned regions (holes) of an earlier trim are kept apart while a + * worker runs, and carved again afterwards. */ + run(trim_allocate); + uintptr_t hole_lo = trim_lo, hole_hi = trim_hi; + discard_shares = false; + run(discard_worker); + verify_old_blocks(); + for (size_t k = 0; k < TRIM_BLOCKS / TRIM_KEEP; k++) + verify(trim_kept[k], TRIM_SIZE, (unsigned char)(k * TRIM_KEEP)); + trim_lo = hole_lo; + trim_hi = hole_hi; + run(trim_reuse); + assert(trim_outside < 4 * TRIM_BLOCKS / TRIM_KEEP + 256); + for (size_t k = 0; k < TRIM_BLOCKS / TRIM_KEEP; k++) scr_mem_free(trim_kept[k]); + for (unsigned i = 0; i < DISCARD_OLD; i++) scr_mem_free(old_blocks[i]); + free(discard_blocks); +} +#endif + int main(void) { #if SCR_SMALL_ALLOC check_slice_growth(); /* first: its class must be untouched */ @@ -389,6 +642,7 @@ int main(void) { check_threads(); #ifdef __linux__ check_trim(); + check_discard(); #endif printf("allocator checks passed: size-class workers\n"); #else diff --git a/packages/runtime/src/scr_itable.c b/packages/runtime/src/scr_itable.c index 08db948b5..4842bf79c 100644 --- a/packages/runtime/src/scr_itable.c +++ b/packages/runtime/src/scr_itable.c @@ -428,11 +428,13 @@ static const ScrITableEntry *scr_itable_insert_bytes(ScrITable *t, uint64_t hash const ScrITableEntry *scr_itable_insert_str(ScrITable *t, const ScrStr *key, uint64_t value) { scr_itable_enter(); + scr_sa_thread_shares(); /* the stored value graph is read by every thread */ return scr_itable_insert_bytes(t, scr_itable_str_hash(key), key->data, key->len, value); } const ScrITableEntry *scr_itable_insert_f64(ScrITable *t, double key, uint64_t value) { scr_itable_enter(); + scr_sa_thread_shares(); /* the stored value graph is read by every thread */ uint64_t stored = scr_itable_f64_bits(key) ^ SCR_ITABLE_F64_FLIP; uint64_t hash = scr_itable_f64_hash(stored); ScrITableSegment *seg = scr_itable_segment(t, hash); @@ -588,6 +590,7 @@ const ScrITableEntry *scr_itable_find_arr(ScrITable *t, const ScrArr *key) { const ScrITableEntry *scr_itable_insert_arr(ScrITable *t, const ScrArr *key, uint64_t value) { scr_itable_enter(); + scr_sa_thread_shares(); /* the stored value graph is read by every thread */ char stack[SCR_ITABLE_STACK_KEY]; size_t len; char *bytes = scr_itable_encoded(t, key, stack, sizeof stack, &len); diff --git a/packages/runtime/src/scr_itable.test.c b/packages/runtime/src/scr_itable.test.c index 0f218806b..5e5f22bc9 100644 --- a/packages/runtime/src/scr_itable.test.c +++ b/packages/runtime/src/scr_itable.test.c @@ -8,13 +8,18 @@ #include #include -/* The table unit needs only scr_trap and scr_throw_error_msg from the - * rest of the runtime; refusals are recorded here. */ +/* The table unit needs only scr_trap, scr_throw_error_msg and + * scr_sa_thread_shares from the rest of the runtime; refusals and the + * inserting threads' shares are recorded here. */ _Noreturn void scr_trap(const char *msg) { fputs(msg, stderr); abort(); } +/* Inserts share the stored values with every thread. */ +static atomic_int shares; +void scr_sa_thread_shares(void) { atomic_fetch_add(&shares, 1); } + static char refused[128]; void scr_throw_error_msg(int kind, const char *msg, size_t len) { assert(kind == SCR_ERR_TYPE && len < sizeof refused); @@ -222,6 +227,7 @@ int main(void) { for (unsigned i = 1; i < THREADS; i++) assert(seen_str[i][k] == seen_str[0][k]); assert(scr_itable_size(strings) == KEYS); assert(scr_itable_size(numbers) == KEYS); + assert(atomic_load(&shares) >= 2 * KEYS); printf("intern tables share one entry per key across racing inserts and lookups\n"); return 0; } diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 49aba3acb..d6f6a5693 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -10483,6 +10483,7 @@ static ScrArr *scr_record_shared_keys(const ScrDynTypedRecordOps *record) { #ifdef SCR_RC_AUDIT scr_arr_live_forget(); /* immortal: outside the exit-time RC audit */ #endif + scr_sa_thread_shares(); /* every thread reads the array */ return built; } built->rc = 1; diff --git a/packages/runtime/src/scr_message.c b/packages/runtime/src/scr_message.c index a0b3b8d4e..8ce162a3f 100644 --- a/packages/runtime/src/scr_message.c +++ b/packages/runtime/src/scr_message.c @@ -234,6 +234,7 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) * capsule over the same object, a dyn graph as itself. */ if (input->kind == SCR_DYN_TYPED_REF && input->v.typed_ref.ptr && *(const size_t *)input->v.typed_ref.ptr == SIZE_MAX) { + scr_sa_thread_shares(); encoder->visits[id].view = (ScrDyn *)input; ScrMessageNode *node = &encoder->message->nodes[id]; node->kind = SCR_MESSAGE_TYPED_REF; @@ -251,6 +252,7 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) return id; } if ((input->kind == SCR_DYN_OBJ || input->kind == SCR_DYN_ARR) && input->rc == SIZE_MAX) { + scr_sa_thread_shares(); encoder->visits[id].view = (ScrDyn *)input; ScrMessageNode *node = &encoder->message->nodes[id]; node->kind = SCR_MESSAGE_PUBLISHED; @@ -504,6 +506,7 @@ static ScrMessage *scr_message_try_publish(const ScrDyn *value) { scr_lsan_immortal(d); } } + scr_sa_thread_shares(); message = scr_message_alloc(1, sizeof(*message)); message->nodes = scr_message_alloc(1, sizeof(*message->nodes)); message->count = message->capacity = 1; diff --git a/packages/runtime/src/scr_rc.h b/packages/runtime/src/scr_rc.h index 7069839c7..7b6f05f3a 100644 --- a/packages/runtime/src/scr_rc.h +++ b/packages/runtime/src/scr_rc.h @@ -336,11 +336,18 @@ void scr_sa_thread_park(void); /* Waits until the arenas of exited threads are trimmed (tests). */ void scr_sa_wait_trims(void); /* Called first on a new worker thread: prepares the thread's system- - * allocator heap (scr_alloc.c). */ + * allocator heap, and lets the thread's memory go back when it exits + * (scr_alloc.c). */ void scr_sa_thread_starting(void); +/* The calling thread made objects it allocated reachable from other + * threads: a message or an intern table shares a published graph by + * pointer, or a process-wide cache keeps an immortal object. Its memory + * then stays when it exits (scr_alloc.c). */ +void scr_sa_thread_shares(void); #define SCR_SA_FREE_FOREIGN(p) scr_sa_free_foreign(p) #else #define SCR_SA_FREE_FOREIGN(p) free(p) +#define scr_sa_thread_shares() ((void)0) #endif #if SCR_SMALL_ALLOC diff --git a/tests/corpus/native-worker-discarded-heaps.ts b/tests/corpus/native-worker-discarded-heaps.ts new file mode 100644 index 000000000..bf7a76449 --- /dev/null +++ b/tests/corpus/native-worker-discarded-heaps.ts @@ -0,0 +1,102 @@ +import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads"; +import { publish } from "@scriptc/threads"; +import type { ProgramLifetime } from "@scriptc/types"; + +// Workers whose memory goes back when they exit, and workers whose memory +// stays because other threads hold what they allocated. Builder workers +// create ProgramLifetime instances (which scriptc never frees), ordinary +// objects, strings and large typed arrays, post a checksum and exit. A +// publisher worker posts published graphs (a class graph and a plain +// object) and exits. The main thread reads those graphs again after each +// wave of builders, which in scriptc on Linux reuse the memory of the +// builders before them. + +class Node implements ProgramLifetime { + readonly kind: number; + readonly label: string; + readonly children: Node[] = []; + parent: Node | undefined = undefined; + constructor(kind: number, label: string) { + this.kind = kind; + this.label = label; + } +} + +type Summary = { readonly name: string; readonly values: readonly number[]; readonly nested: { readonly total: number } }; + +type Job = { readonly role: string; readonly seed: number }; + +function build(seed: number, count: number): Node { + const root = new Node(seed, "root" + seed); + let parent = root; + for (let i = 0; i < count; i++) { + const node = new Node((i * 7 + seed) % 31, "n" + (i % 101)); + node.parent = parent; + parent.children.push(node); + if (i % 64 === 63) parent = node; + } + return root; +} + +function checksum(root: Node): number { + let sum = 0; + const stack: Node[] = [root]; + while (stack.length > 0) { + const node = stack.pop()!; + sum = (sum * 31 + node.kind + node.label.length + node.children.length) % 1_000_003; + for (const child of node.children) stack.push(child); + } + return sum; +} + +function startWorker(job: Job, onMessage: (value: unknown) => void): Promise { + return new Promise((resolve, reject) => { + const worker = new Worker(new URL(import.meta.url), { workerData: job }); + worker.on("message", onMessage); + worker.once("messageerror", reject); + worker.once("error", reject); + worker.once("exit", () => resolve()); + }); +} + +if (isMainThread) { + let tree: Node | undefined = undefined; + let summary: Summary | undefined = undefined; + // The publisher posts the tree, then the summary. + await startWorker({ role: "publisher", seed: 3 }, (value) => { + if (tree === undefined) tree = value as Node; + else summary = value as Summary; + }); + const describe = (): string => + `tree ${checksum(tree!)} summary ${summary!.name} ${summary!.values.join(",")} ${summary!.nested.total}`; + console.log("published", describe()); + for (let wave = 0; wave < 3; wave++) { + const sums: number[] = []; + await Promise.all( + [1, 2, 3, 4].map((k) => startWorker({ role: "builder", seed: wave * 10 + k }, (value) => sums.push(value as number))), + ); + sums.sort((a, b) => a - b); + console.log("wave", wave, sums.join(" "), describe()); + } +} else { + const job = workerData as Job; + if (job.role === "publisher") { + parentPort!.postMessage(publish(build(job.seed, 20_000))); + const values: number[] = []; + for (let i = 0; i < 50; i++) values.push(i * job.seed); + parentPort!.postMessage(publish({ name: "summary" + job.seed, values, nested: { total: values.length } })); + } else { + const root = build(job.seed, 150_000); + const samples: Float64Array[] = []; + for (let i = 0; i < 40; i++) { + const sample = new Float64Array(8192); + for (let j = 0; j < sample.length; j += 97) sample[j] = i + j + job.seed; + samples.push(sample); + } + let extra = 0; + for (const sample of samples) extra = (extra + sample[97]! + sample[8148]!) % 1_000_003; + const words: string[] = []; + for (let i = 0; i < 20_000; i++) words.push(`word-${i % 977}-${job.seed}`); + parentPort!.postMessage((checksum(root) + extra + words.join("").length) % 1_000_003); + } +} diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index b83c64674..9a6262a12 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -2371,6 +2371,7 @@ "native-worker-clone-errors.ts": 2347, "native-worker-commonjs.cjs": 2188, "native-worker-delayed-messages.ts": 3114, + "native-worker-discarded-heaps.ts": 4430, "native-worker-environment.ts": 3538, "native-worker-error.ts": 2810, "native-worker-exception-state.ts": 3938, @@ -5013,6 +5014,7 @@ "native-worker-clone-errors.ts": 3629, "native-worker-commonjs.cjs": 3085, "native-worker-delayed-messages.ts": 28752, + "native-worker-discarded-heaps.ts": 39440, "native-worker-environment.ts": 27133, "native-worker-error.ts": 2958, "native-worker-exception-state.ts": 3945, From 0309ff63cbb5f3fac556a97818012c055cde629b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:00:47 -0500 Subject: [PATCH 042/117] Window long source lines in diagnostic code frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit renderDiagnostics printed every frame line whole and rebuilt the file's line index for each diagnostic. On minified sources with thousands of diagnostics the joined report exceeded V8's string length and `scriptc coverage` crashed with RangeError: Invalid string length. Frame lines longer than 400 characters now show a 400-character window around the diagnostic's column, with "…" where text is cut, and the line index is built once per file. Every diagnostic is still rendered. Closes #201 Co-authored-by: Max B <32987678+techfreaque@users.noreply.github.com> --- .../compiler/src/diagnostics/render.test.ts | 56 ++++++++++++++ packages/compiler/src/diagnostics/render.ts | 74 ++++++++++++++++--- .../__snapshots__/deep-binary-nesting.ts.txt | 4 +- .../deep-nesting-preflight.ts.txt | 2 +- 4 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 packages/compiler/src/diagnostics/render.test.ts diff --git a/packages/compiler/src/diagnostics/render.test.ts b/packages/compiler/src/diagnostics/render.test.ts new file mode 100644 index 000000000..c5078dd0e --- /dev/null +++ b/packages/compiler/src/diagnostics/render.test.ts @@ -0,0 +1,56 @@ +import { expect, test } from "vitest"; +import type { ScrDiagnostic } from "./diagnostic.js"; +import { renderDiagnostic, renderDiagnostics } from "./render.js"; + +function diag(file: string, start: number, end: number): ScrDiagnostic { + return { code: "SC2020", message: "not supported", loc: { file, start, end } }; +} + +test("a short line renders whole", () => { + const text = "const a = 1;\nconst b = a.c;\nconst d = 2;"; + const start = text.indexOf("a.c"); + expect(renderDiagnostic(diag("m.ts", start, start + 3), { text })).toBe( + [ + "m.ts:2:11 - error SC2020: not supported", + "", + " 1 | const a = 1;", + " 2 | const b = a.c;", + " | ^~~", + " 3 | const d = 2;", + ].join("\n"), + ); +}); + +test("a long line renders a window around the column", () => { + const line = "x".repeat(1000) + "bad" + "y".repeat(1000); + const text = "first\n" + line + "\nlast"; + const start = text.indexOf("bad"); + const out = renderDiagnostic(diag("min.js", start, start + 3), { text }); + const lines = out.split("\n"); + expect(lines[0]).toBe("min.js:2:1001 - error SC2020: not supported"); + // the window starts 120 characters before the column + expect(lines[3]).toBe(` 2 | …${"x".repeat(120)}bad${"y".repeat(277)}…`); + expect(lines[4]).toBe(` | ${" ".repeat(121)}^~~`); + // context lines share the window: "first" and "last" start before it + expect(lines[2]).toBe(" 1 | …"); + expect(lines[5]).toBe(" 3 | …"); +}); + +test("a window at the line's end keeps the last characters", () => { + const line = "a".repeat(600) + "end"; + const start = line.indexOf("end"); + const out = renderDiagnostic(diag("e.js", start, start + 3), { text: line }); + const lines = out.split("\n"); + expect(lines[2]).toBe(` 1 | …${"a".repeat(397)}end`); + expect(lines[3]).toBe(` | ${" ".repeat(398)}^~~`); +}); + +test("thousands of diagnostics on a minified line render without exhausting string length", () => { + // one 2 MB line with 20,000 diagnostics: rendering every frame line whole + // would need tens of gigabytes + const text = "a;".repeat(1_000_000); + const diags = Array.from({ length: 20_000 }, (_, i) => diag("bundle.js", i * 100, i * 100 + 1)); + const out = renderDiagnostics(diags, new Map([["bundle.js", text]])); + expect(out.split(" - error SC2020: ").length - 1).toBe(20_000); + expect(out.length).toBeLessThan(20_000 * 1_000); +}); diff --git a/packages/compiler/src/diagnostics/render.ts b/packages/compiler/src/diagnostics/render.ts index 7fd68910f..e5a75c6bc 100644 --- a/packages/compiler/src/diagnostics/render.ts +++ b/packages/compiler/src/diagnostics/render.ts @@ -1,6 +1,8 @@ /* Terminal rendering: file:line:col, a hand-rolled code frame with ±1 line * of context and a ^~~~ underline sized to the span, optional hint line, - * and the optional attributed profile-note line after it. + * and the optional attributed profile-note line after it. A source line + * longer than FRAME_MAX_WIDTH (minified sources) shows a window of that + * width around the diagnostic's column, with "…" where text is cut. */ import type { ScrDiagnostic } from "./diagnostic.js"; @@ -11,6 +13,27 @@ export interface RenderOptions { interface SourceLookup { /** Full text of the file the diagnostic points into. */ text: string; + /** The text's lines and their start offsets; computed from `text` when + * absent. renderDiagnostics computes them once per file. */ + index?: LineIndex; +} + +interface LineIndex { + lines: string[]; + lineStarts: number[]; +} + +/** Frame lines longer than this many characters show a window of it. */ +const FRAME_MAX_WIDTH = 400; +/** Characters a windowed frame keeps before the diagnostic's column. */ +const FRAME_LEAD = 120; + +function lineIndex(text: string): LineIndex { + const lineStarts = [0]; + for (let i = 0; i < text.length; i++) { + if (text[i] === "\n") lineStarts.push(i + 1); + } + return { lines: text.split("\n"), lineStarts }; } const RED = "\x1b[31m"; @@ -33,32 +56,52 @@ export function renderDiagnostic( const frame: string[] = []; if (source) { - const lineStarts = [0]; - for (let i = 0; i < source.text.length; i++) { - if (source.text[i] === "\n") lineStarts.push(i + 1); - } + const { lines, lineStarts } = source.index ?? lineIndex(source.text); + // the last line starting at or before the diagnostic let lo = 0; - while (lo + 1 < lineStarts.length && lineStarts[lo + 1]! <= diag.loc.start) lo++; + let hi = lineStarts.length - 1; + while (lo < hi) { + const mid = (lo + hi + 1) >> 1; + if (lineStarts[mid]! <= diag.loc.start) lo = mid; + else hi = mid - 1; + } lineNum = lo + 1; colNum = diag.loc.start - lineStarts[lo]! + 1; - const lines = source.text.split("\n"); + const lineText = lines[lineNum - 1] ?? ""; + // The window every frame line shows: the whole line, or for a long + // line FRAME_MAX_WIDTH characters starting FRAME_LEAD before the column. + const windowStart = + lineText.length > FRAME_MAX_WIDTH + ? Math.max(0, Math.min(colNum - 1 - FRAME_LEAD, lineText.length - FRAME_MAX_WIDTH)) + : 0; + const shown = (text: string): string => { + if (windowStart === 0 && text.length <= FRAME_MAX_WIDTH) return text; + const end = windowStart + FRAME_MAX_WIDTH; + return ( + (windowStart > 0 ? "…" : "") + text.slice(windowStart, end) + (text.length > end ? "…" : "") + ); + }; const gutterWidth = String(Math.min(lineNum + 1, lines.length)).length; const emitLine = (n: number) => { const text = lines[n - 1]; if (text === undefined) return; - frame.push(c(DIM, ` ${String(n).padStart(gutterWidth)} | `) + text); + frame.push(c(DIM, ` ${String(n).padStart(gutterWidth)} | `) + shown(text)); }; emitLine(lineNum - 1); emitLine(lineNum); - const lineText = lines[lineNum - 1] ?? ""; + const caretCol = colNum - 1 - windowStart + (windowStart > 0 ? 1 : 0); + const visibleEnd = + windowStart === 0 && lineText.length <= FRAME_MAX_WIDTH + ? lineText.length + : Math.min(lineText.length, windowStart + FRAME_MAX_WIDTH); const spanOnLine = Math.max( 1, - Math.min(diag.loc.end - diag.loc.start, lineText.length - (colNum - 1)), + Math.min(diag.loc.end - diag.loc.start, visibleEnd - (colNum - 1)), ); frame.push( c(DIM, ` ${" ".repeat(gutterWidth)} | `) + - " ".repeat(colNum - 1) + + " ".repeat(caretCol) + c(/^SC6\d{3}$/.test(diag.code) ? YELLOW : RED, "^" + "~".repeat(spanOnLine - 1)), ); emitLine(lineNum + 1); @@ -94,10 +137,17 @@ export function renderDiagnostics( const sorted = [...diags].sort( (a, b) => a.loc.file.localeCompare(b.loc.file) || a.loc.start - b.loc.start, ); + const indexes = new Map(); return sorted .map((d) => { const text = sourceTextByFile.get(d.loc.file); - return renderDiagnostic(d, text === undefined ? undefined : { text }, opts); + if (text === undefined) return renderDiagnostic(d, undefined, opts); + let index = indexes.get(d.loc.file); + if (index === undefined) { + index = lineIndex(text); + indexes.set(d.loc.file, index); + } + return renderDiagnostic(d, { text, index }, opts); }) .join("\n\n"); } diff --git a/tests/harness/__snapshots__/deep-binary-nesting.ts.txt b/tests/harness/__snapshots__/deep-binary-nesting.ts.txt index 02cce3cdb..9e645656f 100644 --- a/tests/harness/__snapshots__/deep-binary-nesting.ts.txt +++ b/tests/harness/__snapshots__/deep-binary-nesting.ts.txt @@ -1,6 +1,6 @@ deep-binary-nesting.ts:2:9 - error SC1090: expressions nested deeper than 200 levels are not supported yet 1 | // A ~300-term left-nested binary chain crosses the expression-lowering depth floor (LOWER_EXPR_MAX_DEPTH): the named fence fires with ample stack headroom, where ~3000 terms used to overflow two recursive walks as an ICE (invariant signature 11). - 2 | let x = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2 | let x = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + … + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | console.log(x); \ No newline at end of file diff --git a/tests/harness/__snapshots__/deep-nesting-preflight.ts.txt b/tests/harness/__snapshots__/deep-nesting-preflight.ts.txt index 655f881cc..c0eb7534f 100644 --- a/tests/harness/__snapshots__/deep-nesting-preflight.ts.txt +++ b/tests/harness/__snapshots__/deep-nesting-preflight.ts.txt @@ -1,6 +1,6 @@ deep-nesting-preflight.ts:2:1 - error SC1090: expressions nested deeper than 200 levels are not supported yet - 1 | // A ~7000-term left-nested binary chain, the binderBinaryExpressionStress shape: deep enough that the whole-file walks (the checker facade prefetch sweep, the require scans, the nested-var collection) used to overflow the JS stack as a RangeError ICE before the expression-lowering fence could fire — the corpus pair crashed at ~6500 terms, and the bare statement sat within ~50 terms of the nested-var walk's limit. Every such walk is iterative now (walkPreorder), so the program survives to the same named SC1090 fence the ~300-term deep-binary-nesting fixture pins. A BARE expression statement (no initializer position) keeps tsgo's per-node query cost — and this suite — fast; one term per line keeps the snapshot code frame small. 5.9.3's parser (the resolver-parity island sweeps this directory) trampolines binary chains, so the shape parses in both worlds. + 1 | // A ~7000-term left-nested binary chain, the binderBinaryExpressionStress shape: deep enough that the whole-file walks (the checker facade prefetch sweep, the require scans, the nested-var collection) used to overflow the JS stack as a RangeError ICE before the expression-lowering fence could fire — the corpus pair crashed at ~6500 terms, and the bare statement sat within ~50 terms of the nested-… 2 | 1 + | ^~~ 3 | 1 + \ No newline at end of file From aa9c6d2be98ffa6f2f545c479c499a5a211da4a7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:17:39 -0500 Subject: [PATCH 043/117] Answer `in` for class methods and accessors on instances with runtime prototypes `"method" in instance` on a class instance held as `any` answered false for the class's methods, getters and setters when the program also uses instanceof or Object.getPrototypeOf on the class. Those uses attach the class's prototype data to the instance's snapshot, and that object holds only the methods the program reads through the prototype; the literal-key `in` then searched it instead of the class. When a literal key names a method or accessor of a boxed class with prototype data, the class dynamic-dispatch pass now evaluates `in` through the computed-key form, which answers class members from the class itself. --- .../lowering/class-dynamic-dispatch.ts | 51 ++++++++++++++++++ ...914-dyn-in-class-prototype-members.ts.json | 6 +++ .../5914-dyn-in-class-prototype-members.ts | 52 +++++++++++++++++++ tests/harness/corpus-costs.json | 4 ++ 4 files changed, 113 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5914-dyn-in-class-prototype-members.ts.json create mode 100644 tests/corpus/5914-dyn-in-class-prototype-members.ts diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index 4f7344bd1..d14aaf924 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -756,6 +756,7 @@ export class ClassDynamicDispatch { const seenTypes = new Set(); const rewrite = new Set(); const toPrimitiveSites = new Set(); + const hasKeySites = new Set(); const discover = (type: IrType): void => { const key = typeKey(type); if (seenTypes.has(key)) return; @@ -818,6 +819,9 @@ export class ClassDynamicDispatch { ) rewrite.add(fn); break; + case "dynHasKey": + hasKeySites.add(fn); + break; case "dynKeyGet": case "dynInvoke": rewrite.add(fn); @@ -854,6 +858,8 @@ export class ClassDynamicDispatch { const converting = this.convertingHints(lowerer); const calling = this.calledConversions(lowerer); if (converting.size || calling.size) for (const fn of toPrimitiveSites) rewrite.add(fn); + const prototypeMembers = this.prototypeMemberNames(lowerer); + if (prototypeMembers.size) for (const fn of hasKeySites) rewrite.add(fn); for (const fn of functions) { if ( !fn.name.startsWith("%dyn.class.instanceof:") && @@ -1294,6 +1300,38 @@ export class ClassDynamicDispatch { fn.body = transformStmtList(fn.body, { stmt: (stmt) => stmt, expr: (expr) => { + if (expr.kind === "dynHasKey" && prototypeMembers.has(expr.key)) { + // A class instance's snapshot can carry its class's prototype + // data, which holds only the methods the program reads through + // the prototype. The computed-key form answers methods and + // accessors from the class itself. + const loc = expr.loc; + const test: IrExpr = { + kind: "libCall", + fn: "dyn.hasKeyComputed", + args: [ + expr.value, + { + kind: "dynFrom", + value: { kind: "strLit", value: expr.key, type: STRING, loc }, + type: DYN, + loc, + }, + ], + type: BOOL, + loc, + }; + changed = true; + return { + kind: "seqExpr", + stmts: [], + result: expr.negated + ? { kind: "unary", op: "!", operand: test, type: BOOL, loc } + : test, + type: BOOL, + loc, + }; + } const called = calling.size ? this.convertMethodCall(lowerer, fn, expr, calling) : null; if (called) { changed = true; @@ -3435,6 +3473,19 @@ export class ClassDynamicDispatch { }; } + /** The method and accessor names of boxed classes whose instances can + * carry their class's prototype data. */ + private prototypeMemberNames(lowerer: Lowerer): Set { + const names = new Set(); + for (const { info } of this.propertyReceivers(lowerer)) { + if (!hasClassPrototypeData(info)) continue; + for (let c: ClassInfo | null = info; c; c = c.base) + for (const name of c.methods.keys()) + names.add(name.startsWith("get:") || name.startsWith("set:") ? name.slice(4) : name); + } + return names; + } + /** The methods some boxed class declares among valueOf and toString. */ private calledConversions(lowerer: Lowerer): Set<"valueOf" | "toString"> { const methods = new Set<"valueOf" | "toString">(); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5914-dyn-in-class-prototype-members.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5914-dyn-in-class-prototype-members.ts.json new file mode 100644 index 000000000..4df0c23de --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5914-dyn-in-class-prototype-members.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5914-dyn-in-class-prototype-members.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5914-dyn-in-class-prototype-members.ts b/tests/corpus/5914-dyn-in-class-prototype-members.ts new file mode 100644 index 000000000..dd4f85f75 --- /dev/null +++ b/tests/corpus/5914-dyn-in-class-prototype-members.ts @@ -0,0 +1,52 @@ +// The `in` operator with literal keys on class instances held as `any`, in +// a program whose instanceof and Object.getPrototypeOf checks give the +// classes runtime prototypes: methods, getters, setters and inherited +// members answer true, as do own fields and Object.prototype members; +// static methods and missing names answer false. + +class Shape { + name = "shape"; + static create(): Shape { + return new Shape(); + } + area(): number { + return 0; + } + get label(): string { + return this.name; + } + set size(value: number) { + this.name = `size ${value}`; + } +} + +class Square extends Shape { + side = 2; + override area(): number { + return this.side * this.side; + } + perimeter(): number { + return this.side * 4; + } +} + +const shape: any = new Shape(); +const square: any = new Square(); +console.log("instanceof", square instanceof Shape, shape instanceof Square); +console.log("same prototype", Object.getPrototypeOf(shape) === Object.getPrototypeOf(square)); + +console.log("method", "area" in shape, "area" in square); +console.log("subclass method", "perimeter" in shape, "perimeter" in square); +console.log("getter", "label" in shape, "label" in square); +console.log("setter", "size" in shape, "size" in square); +console.log("own field", "name" in shape, "side" in square, "side" in shape); +console.log("object prototype", "toString" in shape, "hasOwnProperty" in square); +console.log("static", "create" in shape, "create" in square); +console.log("missing", "volume" in shape, "volume" in square); +console.log("negated", !("area" in shape), !("volume" in square)); + +const names = ["area", "perimeter", "label", "size", "name", "create", "volume"]; +for (const name of names) { + const key: any = JSON.parse(JSON.stringify(name)); + console.log("computed", name, key in shape, key in square); +} diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 96154eb11..0b360f5c1 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1854,7 +1854,9 @@ "5906-array-from-async-generator-js.js": 2950, "5910-set-prototype-of-primitive-object-kinds.ts": 2719, "5911-dyn-class-to-primitive.ts": 2850, + "5912-dyn-class-conversion-methods.ts": 3251, "5913-prototype-type-error-messages.ts": 2484, + "5914-dyn-in-class-prototype-members.ts": 3169, "5939-js-let-object-reassigned-wider.js": 1945, "5942-local-class-observed-methods.ts": 5063, "5950-tuple-predicate-methods.ts": 5990, @@ -4502,7 +4504,9 @@ "5906-array-from-async-generator-js.js": 3750, "5910-set-prototype-of-primitive-object-kinds.ts": 5033, "5911-dyn-class-to-primitive.ts": 4732, + "5912-dyn-class-conversion-methods.ts": 4424, "5913-prototype-type-error-messages.ts": 4068, + "5914-dyn-in-class-prototype-members.ts": 4327, "5939-js-let-object-reassigned-wider.js": 4436, "5942-local-class-observed-methods.ts": 6212, "5950-tuple-predicate-methods.ts": 7790, From 5d56b57a80c7abf5e6a4b980cb706b9ef9e4e0df Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:22:45 -0500 Subject: [PATCH 044/117] Read .groups on matchAll rows in JavaScript callbacks An inline JavaScript callback receives a matchAll row as a dynamic array. The groups projection now reads its captures through dynamic index reads, and throws Node's TypeError for null and undefined rows. Rows kept by filter, slice, toReversed and toSorted, or picked by find, findLast and at, trace to the drain's regex; a reassigned callback parameter does not. { groups } patterns serve dynamic rows and pattern parameters. The groups record has a null prototype. maybeNarrow takes the receiver's declared shape from its non-nullable type, so a JavaScript read of a nonparticipating group keeps its undefined arm instead of narrowing to string. --- .../src/frontend/lowering/lower-exprs.ts | 128 +++++++++++++----- .../src/frontend/lowering/lower-stmts.ts | 95 +++++++------ .../compiler/src/frontend/lowering/lowerer.ts | 18 +++ .../corpus/5923-matchall-groups-js.js.json | 6 + .../corpus/5922-matchall-groups-callbacks.ts | 12 +- tests/corpus/5923-matchall-groups-js.js | 42 ++++++ tests/harness/corpus-costs.json | 4 + 7 files changed, 232 insertions(+), 73 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5923-matchall-groups-js.js.json create mode 100644 tests/corpus/5923-matchall-groups-js.js diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 1cdf653bc..f8424e1b8 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -3312,7 +3312,11 @@ export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrEx (expr.kind === "recordGet" || expr.kind === "recordKeyGet") && (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) ) { - const receiver = lowerer.mapTypeOf(lowerer.typeOf(node.expression)); + // The read itself rules out a null or undefined receiver, which a + // JavaScript receiver such as `m.groups` still declares. + const receiver = lowerer.mapTypeOf( + lowerer.checker.getNonNullableType(lowerer.typeOf(node.expression)), + ); const shape = receiver?.kind === "record" ? lowerer.shapes.get(receiver.shapeId) : undefined; const declared = expr.kind === "recordGet" @@ -13458,6 +13462,15 @@ function matchProducerRegexOf(lowerer: Lowerer, e: ts.Expression): ts.Expression if (ts.isElementAccessExpression(expr)) { return matchAllRegexOf(lowerer, expr.expression); } + // A row picked by `rows.find(cb)`, `rows.findLast(cb)` or `rows.at(i)`. + if ( + ts.isCallExpression(expr) && + ts.isPropertyAccessExpression(expr.expression) && + MATCH_ROW_PICK_METHODS.has(expr.expression.name.text) && + lowerer.isStdlibMember(expr.expression) + ) { + return matchAllRegexOf(lowerer, expr.expression.expression); + } if (ts.isIdentifier(expr)) { // The for-of binding over a matchAll drain: `for (const m of // s.matchAll(re))` (or over a stored const rows). @@ -13482,6 +13495,12 @@ function matchProducerRegexOf(lowerer: Lowerer, e: ts.Expression): ts.Expression return null; } +/** Array methods that return one row of the receiver. */ +const MATCH_ROW_PICK_METHODS = new Set(["find", "findLast", "at"]); + +/** Array methods whose result holds rows of the receiver. */ +const MATCH_ROW_SUBSET_METHODS = new Set(["filter", "slice", "toReversed", "toSorted"]); + const MATCH_ROW_CALLBACK_METHODS = new Set([ "map", "forEach", @@ -13502,6 +13521,11 @@ function matchAllCallbackRegexOf( const fn = param.parent; if (!(ts.isArrowFunction(fn) || ts.isFunctionExpression(fn)) || fn.parameters[0] !== param) return null; + // A reassigned parameter can hold a row of another regex. + if (ts.isIdentifier(param.name)) { + const sym = lowerer.checker.getSymbolAtLocation(param.name); + if (sym === undefined || !bindingNeverReassigned(lowerer, sym, param)) return null; + } let site: ts.Node = fn; while (ts.isParenthesizedExpression(site.parent)) site = site.parent; const call = site.parent; @@ -13523,6 +13547,17 @@ function matchAllCallbackRegexOf( return null; } +/** The named groups of the rows `param` receives when it is the first + * parameter of an inline matchAll callback (matchAllCallbackRegexOf). */ +export function matchCallbackParamGroupsOf( + lowerer: Lowerer, + param: ts.ParameterDeclaration, +): { name: string; index: number }[] | null { + const reExpr = matchAllCallbackRegexOf(lowerer, param); + const pattern = reExpr === null ? null : staticRegexPatternOf(lowerer, reExpr); + return pattern === null ? null : namedCaptureGroupsOfPattern(pattern); +} + /** The regex argument of a (possibly const-stored) `s.matchAll(re)`. */ function matchAllRegexOf(lowerer: Lowerer, e: ts.Expression): ts.Expression | null { let expr = e; @@ -13548,6 +13583,14 @@ function matchAllRegexOf(lowerer: Lowerer, e: ts.Expression): ts.Expression | nu const only = expr.elements[0]!; if (ts.isSpreadElement(only)) return matchAllRegexOf(lowerer, only.expression); } + if ( + ts.isCallExpression(expr) && + ts.isPropertyAccessExpression(expr.expression) && + MATCH_ROW_SUBSET_METHODS.has(expr.expression.name.text) && + lowerer.isStdlibMember(expr.expression) + ) { + return matchAllRegexOf(lowerer, expr.expression.expression); + } if (ts.isIdentifier(expr)) { const init = constInitializerOf(lowerer, expr); if (init !== null) return matchAllRegexOf(lowerer, init); @@ -13571,11 +13614,11 @@ function matchAllRegexOf(lowerer: Lowerer, e: ts.Expression): ts.Expression | nu * - ES2025 duplicate names (distinct alternatives) project the first * participating occurrence, including a participating empty string; * - key order is group declaration order (declaredOrder), Node's own. - * The record has no prototype — Node's groups object is null-prototype, - * observable only through util.inspect's "[Object: null prototype]" - * prefix (the Object.groupBy stance, ledgered). Null when the receiver - * isn't a match slice or the regex isn't traceable — the caller's - * member fence (with the groups hint) names the gap. */ + * The record has a null prototype, like Node's groups object. A + * JavaScript callback parameter holds the row as a dynamic array; the + * projection reads its elements through dynamic reads. Null when the + * receiver isn't a match slice or the regex isn't traceable — the + * caller's member fence (with the groups hint) names the gap. */ function lowerMatchGroupsRead(lowerer: Lowerer, expr: ts.PropertyAccessExpression): IrExpr | null { if (expr.name.text !== "groups" || expr.questionDotToken !== undefined) return null; const loc = locOf(expr); @@ -13601,11 +13644,9 @@ function lowerMatchGroupsRead(lowerer: Lowerer, expr: ts.PropertyAccessExpressio return null; } const recv = lowerer.lowerExpr(expr.expression); - // A JavaScript callback parameter holds the row as a checked-dynamic - // value without its groups: refuse rather than read undefined. - if (recv.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) - lowerer.stdlibMemberFence(expr); - if (!isMatchSliceType(lowerer, recv.type)) return null; + // A JavaScript callback parameter holds the row as a dynamic array. + const dynRow = recv.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile()); + if (!dynRow && !isMatchSliceType(lowerer, recv.type)) return null; return lowerGroupsProjection(lowerer, recv, groups, loc); } @@ -13651,6 +13692,21 @@ function matchSliceUnionArms( return { arrTag, units }; } +/** Node's TypeError for `.groups` read off null or undefined. */ +function groupsReadTypeError(unit: "null" | "undefined", loc: SrcLoc): IrStmt { + return { + kind: "throw", + value: { + kind: "libCall", + fn: "error.new", + args: [strLit(`Cannot read properties of ${unit} (reading 'groups')`, loc)], + type: { kind: "object", className: "%TypeError" }, + loc, + }, + loc, + }; +} + /** The groups-record projection holds string | undefined values, including * an own overflow entry for every nonparticipating capture. One lifted helper per * (index list, receiver representation) builds it; see @@ -13677,7 +13733,8 @@ export function lowerGroupsProjection( const valueType = arrayValueType(lowerer, STRING); const shapeId = lowerer.shapes.intern([], false, valueType); const recordT: IrType = { kind: "record", shapeId }; - const recvKey = recv.type.kind === "union" ? recv.type.unionId : "arr"; + const recvKey = + recv.type.kind === "union" ? recv.type.unionId : recv.type.kind === "dyn" ? "dyn" : "arr"; const key = `regexgroups:${shapeId}:${groups.map((g) => `${g.name}=${g.index}`).join(",")}:${recvKey}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { @@ -13701,26 +13758,7 @@ export function lowerGroupsProjection( type: BOOL, loc, }, - then: [ - { - kind: "throw", - value: { - kind: "libCall", - fn: "error.new", - args: [ - { - kind: "strLit", - value: `Cannot read properties of ${u.unit} (reading 'groups')`, - type: STRING, - loc, - }, - ], - type: { kind: "object", className: "%TypeError" }, - loc, - }, - loc, - }, - ], + then: [groupsReadTypeError(u.unit, loc)], else_: null, loc, }); @@ -13736,10 +13774,33 @@ export function lowerGroupsProjection( locals.push({ id: "arr.0", name: "arr", type: arrayOf(STRING), mutable: false }); body.push({ kind: "varDecl", localId: "arr.0", init: narrowed, loc }); mRef = { kind: "varRef", localId: "arr.0", type: arrayOf(STRING), loc }; + } else if (recv.type.kind === "dyn") { + // A JavaScript callback parameter holds the row as a dynamic array: + // Node's TypeError for null and undefined, then dynamic element reads. + for (const unit of ["null", "undefined"] as const) { + body.push({ + kind: "if", + cond: { kind: "dynTest", test: unit, value: mRef, type: BOOL, loc }, + then: [groupsReadTypeError(unit, loc)], + else_: null, + loc, + }); + } } const elem = (index: number): IrExpr => - arrayValueRead(lowerer, mRef, numLit(index, loc), STRING, loc); + mRef.type.kind === "dyn" + ? lowerer.coerceToExpected( + { + kind: "dynKeyGet", + value: mRef, + key: strLit(String(index), loc), + type: DYN, + loc, + }, + valueType, + ) + : arrayValueRead(lowerer, mRef, numLit(index, loc), STRING, loc); const values = new Map(); order.forEach((name, i) => { const idxs = indicesByName.get(name)!; @@ -13777,6 +13838,7 @@ export function lowerGroupsProjection( value: { kind: "recordLit", fields: order.map((name) => ({ name, value: values.get(name)!, overflow: true as const })), + nullProto: true, type: recordT, loc, }, diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index e61bb6c11..a437a05c2 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -1914,44 +1914,14 @@ export function lowerDestructuringDecl( init = { kind: "unionNarrow", unionId: init.type.unionId, tag, value: uref, type: arm, loc }; } } - // `const { groups } = re.exec(s)!` / `const { groups: { year } } = m` - // — every pattern element binds `groups` off a MATCH SLICE whose - // regex is statically known: the slice has no record shape of its - // own, so the groups projection (lowerGroupsProjection — the same - // record `m.groups` reads produce) wraps one level in a synthesized - // `{ groups: ... }` record and the ordinary record destructure below - // serves the pattern — aliases and nested patterns included. Only - // named-group regexes take the wrap: a group-less regex destructures - // `groups: undefined` in Node (a nested pattern then throws), which - // the fence reports honestly instead. - if ( - ts.isObjectBindingPattern(decl.name) && - decl.name.elements.length > 0 && - isMatchSliceType(lowerer, init.type) && - decl.name.elements.every((el) => { - if (el.dotDotDotToken !== undefined || el.name === undefined) return false; - const prop = el.propertyName; - if (prop === undefined) return ts.isIdentifier(el.name) && el.name.text === "groups"; - return (ts.isIdentifier(prop) || ts.isStringLiteral(prop)) && prop.text === "groups"; - }) - ) { - const groups = matchResultNamedGroupsOf(lowerer, decl.initializer!); - if (groups !== null && groups.length > 0) { - const proj = lowerGroupsProjection(lowerer, init, groups, loc); - const outerShape = lowerer.shapes.intern( - [{ name: "groups", type: proj.type }], - false, - undefined, - ["groups"], - ); - init = { - kind: "recordLit", - fields: [{ name: "groups", value: proj }], - type: { kind: "record", shapeId: outerShape }, - loc, - }; - } - } + const groupsSource = matchGroupsPatternSource( + lowerer, + decl.name, + init, + () => matchResultNamedGroupsOf(lowerer, decl.initializer!), + loc, + ); + if (groupsSource !== null) init = groupsSource; const tmp = lowerer.declareHiddenLocal("%destr", init.type); out.push({ kind: "varDecl", localId: tmp.id, init, loc }); // V8's destructuring TypeError spells STATIC sources: an identifier @@ -1978,6 +1948,55 @@ export function lowerDestructuringDecl( return out; } +/** `const { groups } = re.exec(s)!` / `const { groups: { year } } = m` + * — every pattern element binds `groups` off a match row whose regex is + * statically known. The slice (or a JavaScript callback's dynamic row) + * has no record shape of its own, so the groups projection + * (lowerGroupsProjection — the same record `m.groups` reads produce) + * wraps one level in a synthesized `{ groups: ... }` record and the + * ordinary record destructure serves the pattern — aliases and nested + * patterns included. Only named-group regexes take the wrap: a + * group-less regex destructures `groups: undefined` in Node (a nested + * pattern then throws), which the fence reports honestly instead. Null + * when the pattern or the row does not qualify. */ +export function matchGroupsPatternSource( + lowerer: Lowerer, + pattern: ts.BindingName, + row: IrExpr, + groupsOf: () => { name: string; index: number }[] | null, + loc: SrcLoc, +): IrExpr | null { + if ( + !ts.isObjectBindingPattern(pattern) || + pattern.elements.length === 0 || + !(row.type.kind === "dyn" + ? isJsSourceFile(pattern.getSourceFile()) + : isMatchSliceType(lowerer, row.type)) || + !pattern.elements.every((el) => { + if (el.dotDotDotToken !== undefined || el.name === undefined) return false; + const prop = el.propertyName; + if (prop === undefined) return ts.isIdentifier(el.name) && el.name.text === "groups"; + return (ts.isIdentifier(prop) || ts.isStringLiteral(prop)) && prop.text === "groups"; + }) + ) + return null; + const groups = groupsOf(); + if (groups === null || groups.length === 0) return null; + const proj = lowerGroupsProjection(lowerer, row, groups, loc); + const outerShape = lowerer.shapes.intern( + [{ name: "groups", type: proj.type }], + false, + undefined, + ["groups"], + ); + return { + kind: "recordLit", + fields: [{ name: "groups", value: proj }], + type: { kind: "record", shapeId: outerShape }, + loc, + }; +} + /** One pattern level: emits a declaration (or global assignment) per * bound name, recursing through hidden temps for nested patterns. */ export function lowerBindingPattern( diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index e17e4ccdc..2ab95089d 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -524,6 +524,7 @@ import { lowerExprStatement, lowerForOf, lowerForStatement, + matchGroupsPatternSource, } from "./lower-stmts.js"; import { type FieldTarget, @@ -558,6 +559,7 @@ import { fieldSetStmt, lowerFieldCompound, uniqueSymbolKeyOf, + matchCallbackParamGroupsOf, } from "./lower-exprs.js"; import { finishOptionalChain, @@ -9984,6 +9986,22 @@ export class Lowerer { const pickedT = shape.bodyType; srcType = pickedT; srcRef = () => ({ kind: "varRef", localId: src.id, type: pickedT, loc }); + } else { + // `({ groups }) => ...` over matchAll rows. + const groupsSource = matchGroupsPatternSource( + this, + decl.name, + srcRef(), + () => matchCallbackParamGroupsOf(this, decl), + loc, + ); + if (groupsSource !== null) { + const src = this.declareHiddenLocal("%psrc", groupsSource.type); + prologue.push({ kind: "varDecl", localId: src.id, init: groupsSource, loc }); + const groupsT = groupsSource.type; + srcType = groupsT; + srcRef = () => ({ kind: "varRef", localId: src.id, type: groupsT, loc }); + } } this.lowerBindingPattern(decl.name, srcRef, srcType, true, prologue); return; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5923-matchall-groups-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5923-matchall-groups-js.js.json new file mode 100644 index 000000000..591c14d12 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5923-matchall-groups-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5923-matchall-groups-js.js" + ], + "diags": [] +} diff --git a/tests/corpus/5922-matchall-groups-callbacks.ts b/tests/corpus/5922-matchall-groups-callbacks.ts index e7dbfa476..9c0c62639 100644 --- a/tests/corpus/5922-matchall-groups-callbacks.ts +++ b/tests/corpus/5922-matchall-groups-callbacks.ts @@ -1,6 +1,7 @@ // .groups on matchAll rows reached through array callbacks (map, forEach, -// filter, some, find) and Array.from's mapping function, with plain and -// duplicate named groups. +// filter, some, find), Array.from's mapping function and parameter +// destructuring, on rows kept by filter, slice and toReversed or picked by +// find and at, with plain, duplicate and nonparticipating named groups. const text = "a1b2c3"; console.log([...text.matchAll(/(?[a-z])/g)].map((m) => m.groups!.k).join("")); console.log([...text.matchAll(/(?[a-z])|(?\d)/g)].map((m) => m.groups!.k).join("")); @@ -9,3 +10,10 @@ const rows = [...text.matchAll(/(?[a-z])(?\d)/g)]; rows.forEach((m) => console.log(m.groups!.letter, m.groups!.digit, JSON.stringify(m.groups))); console.log(rows.filter((m) => m.groups!.digit !== "2").length); console.log(rows.some((m) => m.groups!.letter === "c"), rows.find((m) => m.groups!.digit === "3") !== undefined); +console.log(rows.map(({ groups }) => groups!.letter + groups!.digit).join(",")); +console.log(rows[0]!.groups); +const mixed = [..."2024 and x9".matchAll(/(?[a-z]+)|(?\d+)/g)]; +console.log(mixed.filter((m) => m.groups!.num !== undefined).map((m) => m.groups!.num).join(",")); +console.log(mixed.slice(1).map((m) => m.groups!.word ?? m.groups!.num).join(" ")); +console.log(mixed.find((m) => m.groups!.word === "and")!.groups); +console.log(mixed.at(-1)!.groups!.num, mixed.toReversed().map((m) => m.groups!.word ?? "-").join("")); diff --git a/tests/corpus/5923-matchall-groups-js.js b/tests/corpus/5923-matchall-groups-js.js new file mode 100644 index 000000000..883d184b6 --- /dev/null +++ b/tests/corpus/5923-matchall-groups-js.js @@ -0,0 +1,42 @@ +// .groups on matchAll rows in JavaScript: array callbacks, Array.from's +// mapping function, destructuring, rows picked with find/at or kept by +// filter/slice, nonparticipating and duplicate named groups. +const text = "a1b2c3"; +console.log([...text.matchAll(/(?[a-z])/g)].map((m) => m.groups.k).join("")); +console.log([...text.matchAll(/(?[a-z])|(?\d)/g)].map((m) => m.groups.k).join("")); +console.log(Array.from(text.matchAll(/(?\d)/g), (m) => m.groups.d).join("+")); +const rows = [...text.matchAll(/(?[a-z])(?\d)/g)]; +rows.forEach((m) => console.log(m.groups.letter, m.groups.digit, JSON.stringify(m.groups))); +console.log(rows.filter((m) => m.groups.digit !== "2").length); +console.log(rows.some((m) => m.groups.letter === "c"), rows.find((m) => m.groups.digit === "3") !== undefined); +rows.forEach(function (m) { + const { groups } = m; + const { + groups: { digit }, + } = m; + console.log(groups.letter, digit); +}); +console.log(rows.map(({ groups }) => groups.letter + groups.digit).join(",")); + +const mixed = [..."2024 and x9".matchAll(/(?[a-z]+)|(?\d+)/g)]; +mixed.forEach((m) => { + console.log(m.groups.word === undefined, m.groups.num ?? "-", typeof m.groups.word, m.groups); +}); +console.log(mixed.filter((m) => m.groups.num !== undefined).map((m) => m.groups.num).join(",")); +console.log(mixed.slice(1).map((m) => m.groups.word ?? m.groups.num).join(" ")); +console.log(mixed.find((m) => m.groups.word === "and").groups); +console.log(mixed.findLast((m) => m.groups.word !== undefined).groups.word); +console.log(mixed.at(-1).groups.num, Object.keys(mixed.at(0).groups)); +try { + console.log(mixed.find((m) => m.groups.word === "zzz").groups); +} catch (e) { + console.log(e instanceof TypeError, e.message); +} + +const dup = [..."a1-b".matchAll(/(?[a-z])|(?\d)|-/g)]; +console.log(dup.map((m) => String(m.groups.v)).join("|")); +const plain = [..."ab".matchAll(/[a-z]/g)]; +console.log(plain.map((m) => m.groups === undefined).join()); + +const one = /(?a)|(?b)/.exec("a"); +console.log(one.groups.n, one.groups.n === undefined, one.groups); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index a0be8c095..4a406f13e 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1864,6 +1864,8 @@ "5910-set-prototype-of-primitive-object-kinds.ts": 2719, "5911-dyn-class-to-primitive.ts": 2850, "5913-prototype-type-error-messages.ts": 2484, + "5922-matchall-groups-callbacks.ts": 3650, + "5923-matchall-groups-js.js": 3970, "5939-js-let-object-reassigned-wider.js": 1945, "5942-local-class-observed-methods.ts": 5063, "5950-tuple-predicate-methods.ts": 5990, @@ -4521,6 +4523,8 @@ "5910-set-prototype-of-primitive-object-kinds.ts": 5033, "5911-dyn-class-to-primitive.ts": 4732, "5913-prototype-type-error-messages.ts": 4068, + "5922-matchall-groups-callbacks.ts": 5960, + "5923-matchall-groups-js.js": 6650, "5939-js-let-object-reassigned-wider.js": 4436, "5942-local-class-observed-methods.ts": 6212, "5950-tuple-predicate-methods.ts": 7790, From 8a2fbeec3545713555f1e6e0e8ce225ce01b0982 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:26:35 -0500 Subject: [PATCH 045/117] Give querystring.parse results a null prototype querystring.parse and querystring.decode build their result with a null prototype, as Node does: util.inspect prints the [Object: null prototype] base, Object.getPrototypeOf answers null, ToPrimitive throws a TypeError, and Object.prototype methods are not reachable through the result. --- .../src/backend/llvm/lib-filesystem.ts | 2 ++ .../5842-qs-parse-null-prototype.ts.json | 6 ++++ .../5843-qs-parse-null-prototype-js.mjs.json | 6 ++++ tests/corpus/5842-qs-parse-null-prototype.ts | 34 +++++++++++++++++++ .../5843-qs-parse-null-prototype-js.mjs | 12 +++++++ tests/harness/corpus-costs.json | 4 +++ 6 files changed, 64 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5842-qs-parse-null-prototype.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5843-qs-parse-null-prototype-js.mjs.json create mode 100644 tests/corpus/5842-qs-parse-null-prototype.ts create mode 100644 tests/corpus/5843-qs-parse-null-prototype-js.mjs diff --git a/packages/compiler/src/backend/llvm/lib-filesystem.ts b/packages/compiler/src/backend/llvm/lib-filesystem.ts index 1083c69d5..b1d8869fd 100644 --- a/packages/compiler/src/backend/llvm/lib-filesystem.ts +++ b/packages/compiler/src/backend/llvm/lib-filesystem.ts @@ -746,6 +746,8 @@ export function emitPathUrlLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll const dict = B.tmp(); B.line(`${dict} = call ptr @${mangleRecordNew(e.type.shapeId)}()`); const out = host.own({ name: dict, type: e.type }); + // Node builds the result with a null prototype. + B.line(`store i8 1, ptr ${host.recordMapFlagsPtr(dict, e.type.shapeId)}`); const ovf = host.recordOvfPtr(dict, e.type.shapeId); B.line( `call void @scr_qs_parse_into(ptr ${ovf}, ptr ${args[0]!.name}, ptr ${args[1]!.name}, ptr ${args[2]!.name}, double ${args[3]!.name}, i32 ${strTag}, i32 ${arrTag})`, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5842-qs-parse-null-prototype.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5842-qs-parse-null-prototype.ts.json new file mode 100644 index 000000000..a5b4a3e21 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5842-qs-parse-null-prototype.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5842-qs-parse-null-prototype.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5843-qs-parse-null-prototype-js.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5843-qs-parse-null-prototype-js.mjs.json new file mode 100644 index 000000000..228f0a4c0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5843-qs-parse-null-prototype-js.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5843-qs-parse-null-prototype-js.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/5842-qs-parse-null-prototype.ts b/tests/corpus/5842-qs-parse-null-prototype.ts new file mode 100644 index 000000000..02d5cc134 --- /dev/null +++ b/tests/corpus/5842-qs-parse-null-prototype.ts @@ -0,0 +1,34 @@ +// querystring.parse and querystring.decode return a null-prototype +// object: inspection prints the "[Object: null prototype]" base, +// getPrototypeOf answers null, and ToPrimitive and Object.prototype +// methods throw TypeErrors. Spread copies keep Object.prototype. +import * as qs from "node:querystring"; +import { inspect } from "node:util"; + +const parsed = qs.parse("a=1&b=2&b=3&c"); +console.log(parsed); +console.log(inspect(parsed), inspect({ nested: parsed }), inspect([qs.parse("")])); +console.log(qs.decode("x=1;y=2", ";")); +console.log(Object.getPrototypeOf(parsed) === null, Object.keys(parsed), JSON.stringify(parsed)); + +const attempt = (label: string, f: () => unknown): void => { + try { + console.log(label, f()); + } catch (e) { + console.log(label, (e as Error).name, (e as Error).message); + } +}; +attempt("String", () => String(parsed)); +attempt("template", () => `${parsed}`); +attempt("concat", () => "q=" + parsed); +attempt("hasOwnProperty", () => parsed.hasOwnProperty("a")); +attempt("toString", () => parsed.toString()); +console.log(Object.prototype.toString.call(parsed), Object.hasOwn(parsed, "b")); +console.log(Object.prototype.hasOwnProperty.call(parsed, "c")); + +const copy = { ...parsed }; +console.log(copy, Object.getPrototypeOf(copy) === Object.prototype, String(copy)); + +parsed.added = "yes"; +delete parsed.a; +console.log(parsed, parsed.b, parsed.added); diff --git a/tests/corpus/5843-qs-parse-null-prototype-js.mjs b/tests/corpus/5843-qs-parse-null-prototype-js.mjs new file mode 100644 index 000000000..676d188c4 --- /dev/null +++ b/tests/corpus/5843-qs-parse-null-prototype-js.mjs @@ -0,0 +1,12 @@ +// querystring.parse results keep their null prototype when they cross into +// checked-dynamic values in a JavaScript module: inspection, getPrototypeOf, +// ToPrimitive and the `in` operator. +import qs from "node:querystring"; +const parsed = qs.parse("a=1&b=2&b=3"); +const holder = { parsed, list: [parsed] }; +console.log(holder); +const dyn = JSON.parse("{}"); +dyn.p = parsed; +console.log(dyn, Object.getPrototypeOf(dyn.p) === null); +try { console.log(String(dyn.p)); } catch (e) { console.log(e.name, e.message); } +console.log("toString" in parsed, "a" in parsed); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index a0be8c095..221659356 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1849,6 +1849,8 @@ "5836-url-search-params-tuple-pairs.ts": 2118, "5837-util-format-json-circular.ts": 3117, "5838-qs-stringify-bigint.ts": 2207, + "5842-qs-parse-null-prototype.ts": 1774, + "5843-qs-parse-null-prototype-js.mjs": 1559, "5858-disposable-stack.ts": 3050, "5859-disposable-stack-js.js": 3100, "5881-inspect-weak-collections.ts": 2615, @@ -4506,6 +4508,8 @@ "5836-url-search-params-tuple-pairs.ts": 3193, "5837-util-format-json-circular.ts": 3408, "5838-qs-stringify-bigint.ts": 3519, + "5842-qs-parse-null-prototype.ts": 7077, + "5843-qs-parse-null-prototype-js.mjs": 5395, "5858-disposable-stack.ts": 3750, "5859-disposable-stack-js.js": 3600, "5881-inspect-weak-collections.ts": 2915, From 399931131935640d3c067fe2b13b8f8c005f62df Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:30:10 -0500 Subject: [PATCH 046/117] Give the discard test's trim run an array of its own check_discard ran trim_allocate again for its returned-regions case, which writes the blocks into trim_blocks, the array check_trim had freed. Where glibc maps an 8 MB block by itself (its adaptive mmap threshold, which the allocator's heap policy leaves alone unless transparent huge pages are in madvise mode), the free unmaps it and the worker thread's first write faults. The case now allocates the array again and frees it. The check that a worker takes the free blocks set aside compared the highest block it carved with that of the worker before it, which took its blocks from free lists below the slice's frontier, and it passed when a worker never took them. Each run now counts the blocks it allocates past the highest block of the class so far: at most the bump room the slice had left, against all of them when a worker does not take the free blocks. The residency bound after a discard allows for pre-fault requests still in flight. --- packages/runtime/src/scr_alloc.test.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/runtime/src/scr_alloc.test.c b/packages/runtime/src/scr_alloc.test.c index 78251f330..c367c9a61 100644 --- a/packages/runtime/src/scr_alloc.test.c +++ b/packages/runtime/src/scr_alloc.test.c @@ -393,6 +393,10 @@ static unsigned char **discard_blocks; static unsigned char *discard_large[DISCARD_LARGE]; static uintptr_t discard_base, discard_lo, discard_hi; static size_t block_size = DISCARD_SIZE; /* of the workers' and reusing threads' blocks */ +/* The end of the highest block of class DISCARD_SIZE so far, and how many blocks of a run lay past the mark + * at its start: those the slice grew for. */ +static uintptr_t class_hi; +static size_t discard_beyond, reuse_beyond; static bool discard_shares; static atomic_int discard_step; @@ -419,14 +423,17 @@ static void *discard_old_owner(void *arg) { static void allocate_discardable(void) { discard_lo = UINTPTR_MAX; discard_hi = 0; + discard_beyond = 0; for (size_t i = 0; i < DISCARD_BLOCKS; i++) { unsigned char *p = scr_mem_alloc(block_size); assert(p && owned(p)); fill(p, block_size, (unsigned char)i); discard_blocks[i] = p; + if ((uintptr_t)p >= class_hi) discard_beyond++; if ((uintptr_t)p < discard_lo) discard_lo = (uintptr_t)p; if ((uintptr_t)p + block_size > discard_hi) discard_hi = (uintptr_t)p + block_size; } + if (block_size == DISCARD_SIZE && discard_hi > class_hi) class_hi = discard_hi; /* System blocks: some freed, some moved by realloc, the rest kept. */ for (unsigned i = 0; i < DISCARD_LARGE; i++) { discard_large[i] = scr_mem_alloc(DISCARD_LARGE_SIZE); @@ -475,6 +482,7 @@ static void *discard_reuse(void *arg) { (void)arg; reuse_outside = 0; reuse_hi = 0; + reuse_beyond = 0; for (size_t i = 0; i < DISCARD_BLOCKS; i++) { unsigned char *p = scr_mem_calloc(block_size); assert(p && owned(p)); @@ -483,8 +491,10 @@ static void *discard_reuse(void *arg) { for (unsigned j = 0; j < DISCARD_OLD; j++) assert(p != old_blocks[j]); if ((uintptr_t)p < discard_lo || (uintptr_t)p >= discard_hi) reuse_outside++; if ((uintptr_t)p + block_size > reuse_hi) reuse_hi = (uintptr_t)p + block_size; + if ((uintptr_t)p >= class_hi) reuse_beyond++; discard_blocks[i] = p; } + if (block_size == DISCARD_SIZE && reuse_hi > class_hi) class_hi = reuse_hi; for (size_t i = 0; i < DISCARD_BLOCKS; i++) scr_mem_free(discard_blocks[i]); scr_sa_thread_park(); return NULL; @@ -547,7 +557,7 @@ static void check_discard(void) { uintptr_t first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); /* Pre-fault requests still in flight may fault in a few megabytes again. */ size_t total = (discard_hi - first) / page; - assert(resident_pages(first, discard_hi) < total / 4); + assert(resident_pages(first, discard_hi) < total / 2); run(discard_reuse); assert(reuse_outside < 256); verify_old_blocks(); @@ -598,17 +608,20 @@ static void check_discard(void) { /* The kept workers' blocks are free now (remote frees): a worker takes * them once its slice has no bump room left, and they are free again * after its memory goes back, so the next thread does not grow the slice - * either. */ - uintptr_t kept_hi = discard_hi; + * either. Past the highest block so far, each carves at most the bump room + * the slice had left (a few megabytes). */ + size_t room = ((size_t)4 << 20) / DISCARD_SIZE; run(discard_worker); verify_old_blocks(); - assert(discard_hi <= kept_hi + 64 * page); + assert(discard_beyond < room); run(discard_reuse); - assert(reuse_hi <= kept_hi + 64 * page); + assert(reuse_beyond < room); verify_old_blocks(); /* Returned regions (holes) of an earlier trim are kept apart while a * worker runs, and carved again afterwards. */ + trim_blocks = malloc(TRIM_BLOCKS * sizeof *trim_blocks); /* check_trim freed its own */ + assert(trim_blocks); run(trim_allocate); uintptr_t hole_lo = trim_lo, hole_hi = trim_hi; discard_shares = false; @@ -621,6 +634,7 @@ static void check_discard(void) { run(trim_reuse); assert(trim_outside < 4 * TRIM_BLOCKS / TRIM_KEEP + 256); for (size_t k = 0; k < TRIM_BLOCKS / TRIM_KEEP; k++) scr_mem_free(trim_kept[k]); + free(trim_blocks); for (unsigned i = 0; i < DISCARD_OLD; i++) scr_mem_free(old_blocks[i]); free(discard_blocks); } From 588e16d8c777a654b6c8b6dd15c19a2de7530b2d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:30:29 -0500 Subject: [PATCH 047/117] Skip WebAssembly irreducible control flow analysis on reducible functions LLVM's WebAssembly pass that gives multiple-entry loops a single entry first records, for every block, every block it can reach. Its time and memory grow with the square of a function's block count even when the function has no such loop. In the three.js nodes fixture a module initializer of 40,000 blocks spent four minutes and 22 GB in it, which set the helper's peak and most of its wall time. The helper now runs the pass only on functions whose control flow graph is irreducible, and WebAssembly object emission leaves out the module pass that collects external symbols for assembly declarations, so each function's machine code is freed once it is printed. Optimized partitions are compiled through the thin backend's pre-codegen hook to use the same pipeline. Objects are unchanged. --- native/llvm-codegen/README.md | 2 + native/llvm-codegen/src/emit.cpp | 183 +++++++++++++++++- .../test/native-codegen-integration.test.ts | 66 +++++++ 3 files changed, 249 insertions(+), 2 deletions(-) diff --git a/native/llvm-codegen/README.md b/native/llvm-codegen/README.md index 5b8f38f2a..8debaeeaf 100644 --- a/native/llvm-codegen/README.md +++ b/native/llvm-codegen/README.md @@ -35,6 +35,8 @@ requested output. Repeating `--output` divides the program into that many partitions, which are compiled concurrently and linked together. The helper splits the emitter's LLVM assembly text directly, so partitions also parse concurrently; input outside the emitter's narrow grammar is parsed whole and split with LLVM instead. Internal definitions become hidden so partitions can reference each other. At opt-level 0 each partition is compiled independently. Optimized partitions follow the ThinLTO model: each is simplified and summarized on its own thread, a thin link decides which small functions every partition imports for inlining and which hidden definitions become internal again, and each partition is then optimized and compiled on its own thread. Partition placement depends only on the module and the partition count, so output never depends on the host. +WebAssembly code generation differs from LLVM's default pipeline in two ways that do not change its output. The pass that gives multiple-entry loops a single entry runs only on functions whose control flow is irreducible; its reachability analysis grows with the square of a function's block count even when it has nothing to change. Object emission also leaves out the module pass that collects external symbols for assembly declarations, so each function's machine code is freed once it is printed instead of when the whole module is compiled. + `--cache-dir ` names a private directory the caller owns for one helper build. Simplified partitions are stored under the hash of their exact source and objects under the hash of the exact module after importing, each with a trailing digest and published by rename, so a rebuild recompiles only the partitions an edit can affect. Unsanitized `speed` program builds, and unsanitized `release` builds of programs small enough for one partition, pass `--import-bitcode ` once per runtime-pack unit the program links that ships bitcode. Small runtime functions reachable from the program's runtime calls are imported as `available_externally` so LLVM can inline them; the runtime objects remain the only definitions. The helper never runs a sanitizer pass, so with import it also drops the emitter's inert `sanitize_address` attributes, which would otherwise block that inlining. Without `--import-bitcode` the module is optimized exactly as emitted. diff --git a/native/llvm-codegen/src/emit.cpp b/native/llvm-codegen/src/emit.cpp index b39d2c1bf..a5f87e4b6 100644 --- a/native/llvm-codegen/src/emit.cpp +++ b/native/llvm-codegen/src/emit.cpp @@ -10,9 +10,15 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Analysis/RuntimeLibcallInfo.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LegacyPassManager.h" @@ -20,6 +26,9 @@ #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/LTO/LTO.h" +#include "llvm/Pass.h" +#include "llvm/PassInfo.h" +#include "llvm/PassRegistry.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/Caching.h" #include "llvm/Support/FileSystem.h" @@ -140,6 +149,138 @@ std::optional verify(Module &M, StringRef Code) { return std::nullopt; } +// Runs WebAssembly's pass that gives multiple-entry loops a single entry only +// on functions that have such a loop. The pass first records, for every +// block, every block it can reach, so its time and memory grow with the +// square of the block count even when it changes nothing: a module +// initializer of 40,000 blocks took four minutes and 22 GB in it. It changes +// a function only when two loop entries can reach each other, which a +// reducible control flow graph never has, so skipping reducible functions +// leaves the output unchanged. +class IrreducibleControlFlowOnly final : public MachineFunctionPass { +public: + static char ID; + + explicit IrreducibleControlFlowOnly(FunctionPass *Fix) + : MachineFunctionPass(ID), Fix(Fix) {} + + StringRef getPassName() const override { return Fix->getPassName(); } + + bool doInitialization(Module &M) override { + MachineFunctionPass::doInitialization(M); + return Fix->doInitialization(M); + } + + bool doFinalization(Module &M) override { return Fix->doFinalization(M); } + + void getAnalysisUsage(AnalysisUsage &Usage) const override { + Fix->getAnalysisUsage(Usage); + } + + bool runOnMachineFunction(MachineFunction &MF) override { + if (isReducible(MF)) + return false; + // The wrapped pass reads the machine function through the module's + // machine code analysis, which this pass requires on its behalf. + if (Fix->getResolver() == nullptr) { + auto *Resolver = new AnalysisResolver(getResolver()->getPMDataManager()); + Resolver->addAnalysisImplsPair( + &MachineModuleInfoWrapperPass::ID, + &getAnalysis()); + Fix->setResolver(Resolver); + } + return Fix->runOnFunction(MF.getFunction()); + } + +private: + // A graph is reducible when every edge that a depth-first search finds + // going back to a block on its stack targets a block that dominates the + // edge's source. Blocks the entry cannot reach count as irreducible, since + // the wrapped pass also examines them. + static bool isReducible(MachineFunction &MF) { + MachineDominatorTree Dominators(MF); + enum class State : unsigned char { New, Active, Done }; + std::vector States(MF.getNumBlockIDs(), State::New); + SmallVector, + 32> + Stack; + size_t Visited = 1; + MachineBasicBlock *Entry = &MF.front(); + States[Entry->getNumber()] = State::Active; + Stack.push_back({Entry, Entry->succ_begin()}); + while (!Stack.empty()) { + auto &[Block, Next] = Stack.back(); + if (Next == Block->succ_end()) { + States[Block->getNumber()] = State::Done; + Stack.pop_back(); + continue; + } + MachineBasicBlock *Successor = *Next++; + State &Seen = States[Successor->getNumber()]; + if (Seen == State::Active) { + if (!Dominators.dominates(Successor, Block)) + return false; + } else if (Seen == State::New) { + Seen = State::Active; + ++Visited; + Stack.push_back({Successor, Successor->succ_begin()}); + } + } + return Visited == MF.size(); + } + + std::unique_ptr Fix; +}; + +char IrreducibleControlFlowOnly::ID = 0; + +// The code generation pipeline for one module, with two changes for +// WebAssembly. The irreducible control flow pass runs only where it can +// change the function (see IrreducibleControlFlowOnly). Object emission also +// leaves out the last machine pass, a module pass that records the external +// symbols every function uses so that assembly output can declare them +// before the first function. A module pass in the middle of the pipeline +// keeps the machine code of every function alive until all of them are +// compiled. Object files do not contain those declarations, and the printer +// creates each symbol when it lowers the first use, so without the pass each +// function's machine code is freed once it is printed. +class CodeGenPasses final : public legacy::PassManagerBase { +public: + CodeGenPasses(const TargetMachine &Machine, CodeGenFileType Type) + : Wasm(Machine.getTargetTriple().isWasm()), + Object(Type == CodeGenFileType::ObjectFile) {} + + void add(Pass *P) override { + if (Wasm) { + StringRef Argument = passArgument(*P); + if (Argument == "wasm-fix-irreducible-control-flow") { + Passes.add( + new IrreducibleControlFlowOnly(static_cast(P))); + return; + } + if (Object && Argument == "wasm-mclower-prepass") { + delete P; + return; + } + } + Passes.add(P); + } + + void run(Module &M) { Passes.run(M); } + +private: + static StringRef passArgument(const Pass &P) { + const PassInfo *Info = + PassRegistry::getPassRegistry()->getPassInfo(P.getPassID()); + return Info == nullptr ? StringRef() : Info->getPassArgument(); + } + + bool Wasm; + bool Object; + legacy::PassManager Passes; +}; + // Writes code for an optimized module to a unique sibling of OutputPath, // which is appended to Temporaries once it exists. std::optional @@ -153,7 +294,7 @@ generateCode(Module &M, TargetMachine &Machine, CodeGenFileType Type, return EmitFailure{"output_open_failed", EC.message()}; Temporaries.push_back(TemporaryPath); raw_fd_ostream Output(TemporaryFd, true); - legacy::PassManager CodeGeneration; + CodeGenPasses CodeGeneration(Machine, Type); if (Machine.addPassesToEmitFile(CodeGeneration, Output, nullptr, Type)) return EmitFailure{"emission_not_supported", "target does not support the requested file type"}; @@ -325,7 +466,7 @@ compileUnoptimizedPartitions(const EmitOptions &Options, P.PB.buildPerModuleDefaultPipeline(OptimizationLevel::O0) .run(**Mod, P.MAM); raw_svector_ostream Output(Objects[I]); - legacy::PassManager CodeGeneration; + CodeGenPasses CodeGeneration(*Machine, CodeGenFileType::ObjectFile); if (Machine->addPassesToEmitFile(CodeGeneration, Output, nullptr, CodeGenFileType::ObjectFile)) return Failures.set({"emission_not_supported", @@ -437,6 +578,44 @@ compileOptimizedPartitions(const EmitOptions &Options, return true; }; + // The backend's own code generation cannot use CodeGenPasses, so + // WebAssembly partitions are compiled here with the passes it would add, + // and returning false skips it. + if (TargetTriple.isWasm()) + Config.PreCodeGenModuleHook = [&](unsigned Task, const Module &Optimized) { + size_t I = Task - 1; + if (I >= Count) + return true; + std::string LookupError; + std::unique_ptr Machine = + createTargetMachine(Options.Target, Options.OptLevel, LookupError); + if (!Machine) { + Failures.set({"target_machine_failed", LookupError}); + return false; + } + // The backend passes the module it owns; only the hook's signature is + // const. + Module &Mod = const_cast(Optimized); + Objects[I].clear(); + raw_svector_ostream Output(Objects[I]); + CodeGenPasses CodeGeneration(*Machine, CodeGenFileType::ObjectFile); + TargetLibraryInfoImpl LibraryInfo(Mod.getTargetTriple(), + Machine->Options.VecLib); + CodeGeneration.add(new TargetLibraryInfoWrapperPass(LibraryInfo)); + CodeGeneration.add(new RuntimeLibraryInfoWrapper( + Mod.getTargetTriple(), Machine->Options.ExceptionModel, + Machine->Options.FloatABIType, Machine->Options.EABIVersion, + Machine->Options.MCOptions.ABIName, Machine->Options.VecLib)); + if (Machine->addPassesToEmitFile(CodeGeneration, Output, nullptr, + CodeGenFileType::ObjectFile)) { + Failures.set({"emission_not_supported", + "target does not support object emission"}); + return false; + } + CodeGeneration.run(Mod); + return false; + }; + // The link refers to module identifiers for its whole lifetime. std::vector Names(Count); for (size_t I = 0; I < Count; ++I) diff --git a/packages/compiler/test/native-codegen-integration.test.ts b/packages/compiler/test/native-codegen-integration.test.ts index fb00116cc..1c5f9e3e7 100644 --- a/packages/compiler/test/native-codegen-integration.test.ts +++ b/packages/compiler/test/native-codegen-integration.test.ts @@ -205,6 +205,72 @@ ${[0, 1, 2, 3, 4, 5].map((index) => ` call void @add${index}(i64 ${index + 2})` }); }); + test("WebAssembly emission gives irreducible loops a single entry", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-helper-irreducible-")); + dirs.push(dir); + const input = join(dir, "loops.ll"); + // @irreducible enters its loop at %a or %b; @reducible has one loop entry. + await writeFile( + input, + `declare void @step(i32) + +define i32 @irreducible(i32 %n, i1 %c) { +entry: + br i1 %c, label %a, label %b +a: + %ia = phi i32 [ 0, %entry ], [ %ib1, %b ] + call void @step(i32 %ia) + %ia1 = add i32 %ia, 1 + %da = icmp slt i32 %ia1, %n + br i1 %da, label %b, label %done +b: + %ib = phi i32 [ 0, %entry ], [ %ia1, %a ] + call void @step(i32 %ib) + %ib1 = add i32 %ib, 2 + %db = icmp slt i32 %ib1, %n + br i1 %db, label %a, label %done +done: + %r = phi i32 [ %ia1, %a ], [ %ib1, %b ] + ret i32 %r +} + +define i32 @reducible(i32 %n) { +entry: + br label %loop +loop: + %i = phi i32 [ 0, %entry ], [ %i1, %loop ] + call void @step(i32 %i) + %i1 = add i32 %i, 1 + %d = icmp slt i32 %i1, %n + br i1 %d, label %loop, label %done +done: + ret i32 %i1 +} +`, + ); + const wasm = "wasm32-unknown-wasi"; + const assemblyPath = join(dir, "loops.s"); + const assemblyArgs = helperArgs(input, assemblyPath, wasm); + assemblyArgs[assemblyArgs.indexOf("--filetype") + 1] = "asm"; + expect((await run(helper, assemblyArgs)).exitCode).toBe(0); + const assembly = await readFile(assemblyPath, "utf8"); + const body = (name: string) => + assembly.slice(assembly.indexOf(`\n${name}:\n`)).split("end_function")[0]!; + // The dispatch block that replaces the second loop entry. + expect(body("irreducible")).toMatch(/\bbr_table\b/); + expect(body("reducible")).not.toMatch(/\bbr_table\b/); + + const unoptimized = helperArgs(input, join(dir, "dev.o"), wasm); + unoptimized[unoptimized.indexOf("--opt-level") + 1] = "0"; + expect((await run(helper, unoptimized)).exitCode).toBe(0); + const partitioned = [ + ...helperArgs(input, join(dir, "a.o"), wasm), + "--output", + join(dir, "b.o"), + ]; + expect((await run(helper, partitioned)).exitCode).toBe(0); + }); + test("LLVM fatal diagnostics remain process-isolated JSON", async () => { const result = await execFileAsync(helper, ["version", "--format=json"], { encoding: "utf8", From d8f707a35eeb1926fc751cc252cdfd699f15d363 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:35:31 -0500 Subject: [PATCH 048/117] Drop the util.types.isFloat16Array entry main already adds --- packages/compiler/src/frontend/lowering/surfaces.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index c07d61906..5f8baa6fb 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -1750,7 +1750,6 @@ export const BUILTIN_MODULE_FNS: Record< isInt8Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, isInt16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, isInt32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isFloat16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, isFloat32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, isFloat64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, isMap: { fn: "util.typeIs", params: [DYN], result: BOOL }, From 24096c6e679d3a19947e3d83079c88b2285d55d7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 01:41:19 -0500 Subject: [PATCH 049/117] Remove the leftover always-false isFloat16Array probe The util.types brands answered isFloat16Array with false for every value. Float16Array now answers it from the value's storage kind, ahead of that probe, so this drops the unreachable entry and the declaration that returns boolean. --- packages/compiler/ambient/scriptc-node-fallback.d.ts | 1 - packages/runtime/src/scr_json.c | 8 +++----- tests/corpus/5831-util-types-brands.ts | 6 +++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 27dcf99c4..8d2eaab10 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3280,7 +3280,6 @@ declare module "util/types" { export function isBoxedPrimitive(value: unknown): boolean; export function isBigInt64Array(value: unknown): value is BigInt64Array; export function isBigUint64Array(value: unknown): value is BigUint64Array; - export function isFloat16Array(value: unknown): boolean; export function isCryptoKey(value: unknown): boolean; export function isExternal(value: unknown): boolean; } diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index ce9a43d62..e5d6f8d6a 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -3163,13 +3163,11 @@ bool scr_dyn_util_type_is(const ScrDyn *value, const ScrStr *probe) { if (PROBE("isMapIterator")) return scr_native_iterator_over(value, 2); if (PROBE("isSetIterator")) return scr_native_iterator_over(value, 3); if (PROBE("isKeyObject")) return value->kind == SCR_DYN_HANDLE && value->v.handle.tag == SCR_DYNH_KEY_OBJECT; - /* Boxed primitives, BigInt64Array, BigUint64Array, Float16Array, CryptoKey - * and external values cannot be created here, so no value has these - * brands. */ + /* Boxed primitives, BigInt64Array, BigUint64Array, CryptoKey and external + * values cannot be created here, so no value has these brands. */ if (PROBE("isNumberObject") || PROBE("isStringObject") || PROBE("isBooleanObject") || PROBE("isBigIntObject") || PROBE("isSymbolObject") || PROBE("isBoxedPrimitive") || - PROBE("isBigInt64Array") || PROBE("isBigUint64Array") || PROBE("isFloat16Array") || - PROBE("isCryptoKey") || PROBE("isExternal")) + PROBE("isBigInt64Array") || PROBE("isBigUint64Array") || PROBE("isCryptoKey") || PROBE("isExternal")) return false; if (PROBE("isNativeError")) { ScrError *error = scr_errdyn_err_of(value); diff --git a/tests/corpus/5831-util-types-brands.ts b/tests/corpus/5831-util-types-brands.ts index 7deec967d..d38200914 100644 --- a/tests/corpus/5831-util-types-brands.ts +++ b/tests/corpus/5831-util-types-brands.ts @@ -1,9 +1,9 @@ // util.types brand checks over typed values: isDate, isSharedArrayBuffer, // isMapIterator, isSetIterator and isKeyObject answer from the value's // internal brand, and isBoxedPrimitive (with the per-kind boxed checks), -// isBigInt64Array, isBigUint64Array, isFloat16Array, isCryptoKey and -// isExternal answer false for every value a program here can create. A -// Date-typed argument answers from its static type. +// isBigInt64Array, isBigUint64Array, isCryptoKey and isExternal answer +// false for every value a program here can create. A Date-typed argument +// answers from its static type. import { types } from "node:util"; import * as direct from "node:util/types"; import { createSecretKey } from "node:crypto"; From f7a9fa988d9e750fed8f4599ce7e6c7f1a7645c5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 02:24:53 -0500 Subject: [PATCH 050/117] Free large dead cycle sets in address order A cycle pass tears down its dead set in the order the walk found it, so the LIFO free lists handed the blocks of a large dead structure to the next allocations scattered over every page it used, and the structures built from them missed the cache on most objects. Sets of at least 16384 objects are now torn down in descending address order (scr_mem_order_for_free, a bitmap of block indices per size class), so the free lists hand the blocks back in ascending order, the order the bump pointers carve fresh memory in. A full pass takes every candidate buffer, so markGray now clears each reached object's buffered mark in the header write it makes anyway, instead of a separate loop over the candidates. --- packages/runtime/src/scr_alloc.c | 86 +++++++++++++++++++++++++++ packages/runtime/src/scr_alloc.test.c | 57 ++++++++++++++++++ packages/runtime/src/scr_cycle.c | 40 ++++++++++--- packages/runtime/src/scr_rc.h | 5 ++ 4 files changed, 179 insertions(+), 9 deletions(-) diff --git a/packages/runtime/src/scr_alloc.c b/packages/runtime/src/scr_alloc.c index 2959e642d..ffe98bcf8 100644 --- a/packages/runtime/src/scr_alloc.c +++ b/packages/runtime/src/scr_alloc.c @@ -1527,6 +1527,92 @@ void scr_mem_prefault(void *lo, void *hi) { #endif } +/* Free order. Free lists are LIFO, so blocks freed in descending address + * order come back in ascending order, the order the bump pointers carve + * fresh memory in, and the order the program then touches them in. The + * order within a page matters as much as across pages: blocks of a page + * handed out in no particular order defeat the hardware prefetcher. + * + * The pointers are marked in a bitmap of block indices per class, over the + * range of blocks they span, and read back from the highest block down. + * That takes one bit per block in that range, at most one per block in + * use, and reading the bitmaps back costs a step per word; a set spread so + * thinly that they would take more than SCR_SA_ORDER_SPARSE words per + * pointer is left as it is. Pointers outside the reservation, not at + * `offset` in a block, or repeated, come first, in the order they had. */ +#define SCR_SA_ORDER_SPARSE 8 + +#if SCR_SMALL_ALLOC +/* The class and block index of a pointer `off` bytes past the reservation + * base plus the block offset, if it is at that offset in a block. Slices + * span at most 1 << 30 bytes, so an offset within one fits in 32 bits. */ +static inline bool scr_sa_order_block(uintptr_t off, uintptr_t span, unsigned shift, + const uint32_t *size, unsigned *c, uint32_t *idx) { + if (off >= span) return false; + *c = (unsigned)(off >> shift); + uint32_t in = (uint32_t)(off & (((uintptr_t)1 << shift) - 1)); + *idx = in / size[*c]; + return in == *idx * size[*c]; +} +#endif + +void scr_mem_order_for_free(void **ptrs, size_t n, size_t offset) { +#if SCR_SMALL_ALLOC + if (n < 2 || !scr_sa.span) return; + uintptr_t base = scr_sa.base + offset, span = scr_sa.span; + unsigned shift = scr_sa.shift, c; + uint32_t idx; + uint32_t size[SCR_SA_NCLASS], lo[SCR_SA_NCLASS], hi[SCR_SA_NCLASS]; + size_t at[SCR_SA_NCLASS], words = 0; + for (c = 0; c < SCR_SA_NCLASS; c++) { + size[c] = (uint32_t)scr_sa_class_size(c); + lo[c] = UINT32_MAX; + hi[c] = 0; + } + for (size_t i = 0; i < n; i++) { + if (!scr_sa_order_block((uintptr_t)ptrs[i] - base, span, shift, size, &c, &idx)) continue; + if (idx < lo[c]) lo[c] = idx; + if (idx > hi[c]) hi[c] = idx; + } + for (c = 0; c < SCR_SA_NCLASS; c++) { + at[c] = words; + if (lo[c] <= hi[c]) words += hi[c] / 64 - lo[c] / 64 + 1; + } + if (words == 0 || words / SCR_SA_ORDER_SPARSE > n) return; + uint64_t *bits = calloc(words, sizeof *bits); + if (!bits) return; /* the order only affects performance */ + size_t k = 0; + for (size_t i = 0; i < n; i++) { + void *p = ptrs[i]; + if (scr_sa_order_block((uintptr_t)p - base, span, shift, size, &c, &idx)) { + uint64_t *word = &bits[at[c] + idx / 64 - lo[c] / 64], bit = (uint64_t)1 << (idx % 64); + if (!(*word & bit)) { + *word |= bit; + continue; + } + } + ptrs[k++] = p; + } + for (c = 0; c < SCR_SA_NCLASS; c++) { + if (lo[c] > hi[c]) continue; + char *first = (char *)base + ((uintptr_t)c << shift) + (size_t)(lo[c] / 64) * 64 * size[c]; + for (size_t w = hi[c] / 64 - lo[c] / 64 + 1; w-- > 0;) { + uint64_t word = bits[at[c] + w]; + while (word) { + unsigned b = 63 - (unsigned)__builtin_clzll(word); + word &= ~((uint64_t)1 << b); + ptrs[k++] = first + (w * 64 + b) * size[c]; + } + } + } + free(bits); +#else + (void)ptrs; + (void)n; + (void)offset; +#endif +} + #if defined(__SANITIZE_ADDRESS__) #define SCR_HEAP_SANITIZER 1 #elif defined(__has_feature) diff --git a/packages/runtime/src/scr_alloc.test.c b/packages/runtime/src/scr_alloc.test.c index c367c9a61..032c41f7f 100644 --- a/packages/runtime/src/scr_alloc.test.c +++ b/packages/runtime/src/scr_alloc.test.c @@ -119,6 +119,62 @@ static void check_churn(void) { } } +/* scr_mem_order_for_free keeps every pointer, puts system blocks first and + * each class's blocks in descending address order, and freeing in that + * order hands each class's blocks back in ascending address order. Builds + * without the size-class allocator leave the array as it is. */ +static int compare_pointers(const void *a, const void *b) { + uintptr_t x = (uintptr_t)*(void *const *)a, y = (uintptr_t)*(void *const *)b; + return x < y ? -1 : x > y; +} + +static void check_free_order(void) { + enum { BLOCKS = 12000, SYSTEM = 64, N = BLOCKS + SYSTEM }; + static void *ptrs[N], *before[N], *a[N], *b[N]; + const size_t sizes[2] = {32, 96}; + for (size_t i = 0; i < BLOCKS; i++) ptrs[i] = scr_mem_alloc(sizes[i % 2]); + for (size_t i = BLOCKS; i < N; i++) ptrs[i] = malloc(1024); + uint32_t x = 0x2545f491u; + for (size_t i = N - 1; i > 0; i--) { + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + size_t j = x % (i + 1); + void *t = ptrs[i]; + ptrs[i] = ptrs[j]; + ptrs[j] = t; + } + memcpy(before, ptrs, sizeof ptrs); + scr_mem_order_for_free(ptrs, N, 0); + memcpy(a, ptrs, sizeof ptrs); + memcpy(b, before, sizeof before); + qsort(a, N, sizeof *a, compare_pointers); + qsort(b, N, sizeof *b, compare_pointers); + assert(memcmp(a, b, sizeof a) == 0); +#if SCR_SMALL_ALLOC + size_t i = 0; + uintptr_t last[SCR_SA_NCLASS] = {0}; + for (; i < SYSTEM; i++) assert(!owned(ptrs[i])); + for (; i < N; i++) { + assert(owned(ptrs[i])); + unsigned c = (unsigned)(((uintptr_t)ptrs[i] - scr_sa.base) >> scr_sa.shift); + assert(!last[c] || (uintptr_t)ptrs[i] < last[c]); + last[c] = (uintptr_t)ptrs[i]; + } + for (i = 0; i < N; i++) scr_mem_free(ptrs[i]); + for (size_t c = 0; c < 2; c++) { + for (size_t k = 0; k < BLOCKS / 2; k++) { + a[k] = scr_mem_alloc(sizes[c]); + if (k) assert(a[k] > a[k - 1]); + } + for (size_t k = 0; k < BLOCKS / 2; k++) scr_mem_free(a[k]); + } +#else + assert(memcmp(ptrs, before, sizeof ptrs) == 0); + for (size_t i = 0; i < N; i++) scr_mem_free(ptrs[i]); +#endif +} + #if SCR_SMALL_ALLOC #include #ifdef __linux__ @@ -649,6 +705,7 @@ int main(void) { check_realloc(); check_system_pointers(); check_churn(); + check_free_order(); #if SCR_SMALL_ALLOC && defined(__linux__) && defined(__GLIBC__) check_heap_huge_pages(); #endif diff --git a/packages/runtime/src/scr_cycle.c b/packages/runtime/src/scr_cycle.c index 229122e71..6cadfcda6 100644 --- a/packages/runtime/src/scr_cycle.c +++ b/packages/runtime/src/scr_cycle.c @@ -926,6 +926,9 @@ static void scr_mark_gray(void *obj, uintptr_t depth) { ScrCycHdr *h = scr_cyc_hdr(obj); if (scr_cyc_color(h) == SCR_CYC_GRAY) return; scr_cyc_set_color(h, SCR_CYC_GRAY); + /* A full pass takes every buffer, so each buffered object it reaches + * leaves its buffer here, in the header write the walk makes anyway. */ + if (scr_gen_limit == SCR_CYC_OLD && !scr_cyc_take) scr_cyc_clear_buffered(h); if (scr_white.n < SCR_CYC_GRAY_LIST_MAX) scr_cyc_push_work(&scr_white, obj); if (SCR_RC(obj) > 0) scr_gray_referenced++; if (depth == SCR_CYC_WALK_DEPTH) { @@ -1047,6 +1050,10 @@ static SCR_CYC_COMPACT void scr_xg_release(void *obj) { scr_rc_destroy(obj, scr_xg_destroy); } +/* Dead sets at least this large are torn down in address order. Smaller + * ones mostly stay in cache, where ordering them costs more than it saves. */ +#define SCR_CYC_ORDER_MIN 16384 + /* One pass over every candidate at or below `gen_limit`; returns how many * objects it freed. */ /* The second half of a pass: settle the white set, promote, re-buffer, @@ -1125,8 +1132,18 @@ static SCR_CYC_COMPACT size_t scr_cyc_settle(unsigned gen_limit) { /* Teardowns run after the full walk. They may release untraced children * (plain RC) — which can re-buffer survivors for the NEXT pass — but - * never touch traced (white, already-accounted) edges. */ + * never touch traced (white, already-accounted) edges. + * + * A large dead set is torn down in address order, highest address first + * (scr_mem_order_for_free). The walk leaves it in graph order, in which + * the free lists would hand its blocks to the next allocations scattered + * over every page the dead structure used, and the structures built from + * them, and every later walk over those, would miss the cache on most + * objects. In address order the blocks come back in the order the bump + * pointers hand out fresh memory. Teardown order is not observable. */ size_t freed = scr_white.n; + if (scr_white.n >= SCR_CYC_ORDER_MIN) + scr_mem_order_for_free(scr_white.v, scr_white.n, sizeof(ScrCycHdr)); for (size_t i = 0; i < scr_white.n; i++) { void *obj = scr_white.v[i]; scr_cyc_type(scr_cyc_hdr(obj))->free_fn(obj); @@ -1242,18 +1259,23 @@ static size_t scr_cyc_pass(unsigned gen_limit) { scr_cands = scr_roots[largest]; scr_roots[largest] = previous; scr_roots[largest].n = 0; - for (size_t i = 0; i < scr_cands.n; i++) { - ScrCycHdr *h = scr_cyc_hdr(scr_cands.v[i]); - scr_cyc_clear_buffered(h); - if (gen_limit < SCR_CYC_OLD) scr_cyc_walked(scr_cyc_type(h), gen_limit); - } + /* A full pass clears the buffered marks as markGray reaches the + * candidates, so only a limited level's candidates are touched here. */ + if (gen_limit < SCR_CYC_OLD) + for (size_t i = 0; i < scr_cands.n; i++) { + ScrCycHdr *h = scr_cyc_hdr(scr_cands.v[i]); + scr_cyc_clear_buffered(h); + scr_cyc_walked(scr_cyc_type(h), gen_limit); + } } for (unsigned g = 0; g <= gen_limit && !scr_cyc_take; g++) { for (size_t i = 0; i < scr_roots[g].n; i++) { void *obj = scr_roots[g].v[i]; - ScrCycHdr *h = scr_cyc_hdr(obj); - scr_cyc_clear_buffered(h); - if (gen_limit < SCR_CYC_OLD) scr_cyc_walked(scr_cyc_type(h), gen_limit); + if (gen_limit < SCR_CYC_OLD) { + ScrCycHdr *h = scr_cyc_hdr(obj); + scr_cyc_clear_buffered(h); + scr_cyc_walked(scr_cyc_type(h), gen_limit); + } scr_cyc_push(&scr_cands, obj); } scr_roots[g].n = 0; diff --git a/packages/runtime/src/scr_rc.h b/packages/runtime/src/scr_rc.h index 7b6f05f3a..cdc03c966 100644 --- a/packages/runtime/src/scr_rc.h +++ b/packages/runtime/src/scr_rc.h @@ -235,6 +235,11 @@ void scr_rt_free(void *p); * of [lo, hi), aligned to 256 KiB, in ahead of use; builds without the * helper ignore it. */ void scr_mem_prefault(void *lo, void *hi); +/* Reorders ptrs, distinct pointers `offset` bytes into blocks that are + * about to be freed in array order, so that the free lists hand the blocks + * back in ascending address order (scr_alloc.c). Builds without the + * small-object allocator leave the array as it is. */ +void scr_mem_order_for_free(void **ptrs, size_t n, size_t offset); /* Size classes: requests up to 128 bytes take a class per 8-byte step * (small objects often sit just under a 16-byte boundary), larger ones a From 1899b5f6ae34f7fa5ffeb0cad92d43c191b31460 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 03:28:59 -0500 Subject: [PATCH 051/117] Key the differential oracle cache on the inherited environment The Node oracle runs with the harness's environment, but its cached verdict was keyed only on SCRIPTC_TEST_ENV among the variables. A program whose output reads NODE_ENV or another variable reused a verdict recorded under a different value. The key now covers every inherited variable except the test runner's worker numbers, which differ between workers of one run. Closes #51 Co-authored-by: Patrick Wozniak <4481570+patlux@users.noreply.github.com> --- tests/harness/differential.test.ts | 7 ++++--- tests/harness/oracle-env.test.ts | 25 +++++++++++++++++++++++++ tests/harness/oracle-env.ts | 15 +++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/harness/oracle-env.test.ts create mode 100644 tests/harness/oracle-env.ts diff --git a/tests/harness/differential.test.ts b/tests/harness/differential.test.ts index fbf9cb1ec..a2206fd97 100644 --- a/tests/harness/differential.test.ts +++ b/tests/harness/differential.test.ts @@ -22,6 +22,7 @@ import { describe, expect, test } from "vitest"; import ts5 from "typescript"; import { compile } from "@scriptc/compiler"; import { corpusSelect, shardSuffix } from "./shard.js"; +import { oracleEnvKey } from "./oracle-env.js"; const execFileAsync = promisify(execFile); const repoRoot = join(import.meta.dirname, "../.."); @@ -238,8 +239,8 @@ function programInputs(file: string): string[] { // Node's verdict for a corpus program is a pure function of the program bytes, // the shims, and the Node build (corpus stdout is deterministic by // construction — it must be identical to a non-Node native binary's output). So -// cache it, keyed by all of those plus the invocation shape (SCRIPTC_TEST_ENV -// and the cwd). Only the SPAWN is skipped: the native side always runs live +// cache it, keyed by all of those plus the invocation shape (the inherited +// environment, see oracle-env.ts, and the cwd). Only the SPAWN is skipped: the native side always runs live // and the comparison itself never changes. SCRIPTC_NO_CACHE=1 (or an unset // SCRIPTC_CACHE_DIR) disables the cache in both directions — no reads, no writes. // Storage shares the compile cache's root and its LRU sweep (see native-toolchain.ts). @@ -265,7 +266,7 @@ function oracleKeyBase(): Promise { .update(readFileSync(fileURLToPath(comptimeShim))) .update("\0") .update("\0") - .update(process.env["SCRIPTC_TEST_ENV"] ?? "") + .update(oracleEnvKey(process.env)) .update("\0") .update(process.cwd()) .update("\0") diff --git a/tests/harness/oracle-env.test.ts b/tests/harness/oracle-env.test.ts new file mode 100644 index 000000000..da09dde25 --- /dev/null +++ b/tests/harness/oracle-env.test.ts @@ -0,0 +1,25 @@ +import { expect, test } from "vitest"; +import { oracleEnvKey } from "./oracle-env.js"; + +test("the oracle key changes with any inherited variable", () => { + const base = { PATH: "/bin", SCRIPTC_TEST_ENV: "from-harness" }; + expect(oracleEnvKey({ ...base, NODE_ENV: "production" })).not.toBe( + oracleEnvKey({ ...base, NODE_ENV: "test" }), + ); + expect(oracleEnvKey({ ...base, NODE_ENV: "test" })).not.toBe(oracleEnvKey(base)); + expect(oracleEnvKey({ ...base, FOO: "a=b" })).not.toBe( + oracleEnvKey({ ...base, FOO: "a", B: "" }), + ); +}); + +test("the oracle key ignores the runner's worker numbers and variable order", () => { + expect(oracleEnvKey({ A: "1", B: "2", VITEST_WORKER_ID: "1", VITEST_POOL_ID: "1" })).toBe( + oracleEnvKey({ + VITEST_POOL_ID: "7", + B: "2", + TINYPOOL_WORKER_ID: "3", + A: "1", + VITEST_WORKER_ID: "9", + }), + ); +}); diff --git a/tests/harness/oracle-env.ts b/tests/harness/oracle-env.ts new file mode 100644 index 000000000..5f66f26bb --- /dev/null +++ b/tests/harness/oracle-env.ts @@ -0,0 +1,15 @@ +/* The environment part of the differential oracle cache key. The Node + * oracle runs with the harness's inherited environment, so a program whose + * output reads a variable (NODE_ENV, SCRIPTC_TEST_ENV, ...) must not reuse a + * verdict recorded under a different value. The variables that number the + * test runner's own workers differ between workers of one run and are left + * out, so every worker shares the cache. */ +const WORKER_VARIABLES = new Set(["VITEST_POOL_ID", "VITEST_WORKER_ID", "TINYPOOL_WORKER_ID"]); + +export function oracleEnvKey(env: NodeJS.ProcessEnv): string { + return Object.keys(env) + .filter((name) => !WORKER_VARIABLES.has(name) && env[name] !== undefined) + .sort() + .map((name) => `${name}=${env[name]}\0`) + .join(""); +} From 3fd1d2bde6ff3fd9c67d957f141398d6f111ac77 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 03:37:07 -0500 Subject: [PATCH 052/117] Revert "Return a worker's memory when it exits without sharing any of it (#1258)" This reverts commit 2385fc4fff997aea91fc050b755555b7db2faed6. --- docs/content/docs/contracts.mdx | 2 +- docs/content/docs/threads.mdx | 2 - .../native-worker-discarded-heaps.ts.json | 6 - packages/runtime/src/scr_alloc.c | 405 +----------------- packages/runtime/src/scr_alloc.test.c | 268 ------------ packages/runtime/src/scr_itable.c | 3 - packages/runtime/src/scr_itable.test.c | 10 +- packages/runtime/src/scr_json.c | 1 - packages/runtime/src/scr_message.c | 3 - packages/runtime/src/scr_rc.h | 9 +- tests/corpus/native-worker-discarded-heaps.ts | 102 ----- tests/harness/corpus-costs.json | 2 - 12 files changed, 19 insertions(+), 794 deletions(-) delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json delete mode 100644 tests/corpus/native-worker-discarded-heaps.ts diff --git a/docs/content/docs/contracts.mdx b/docs/content/docs/contracts.mdx index 8f17f6a98..11737da59 100644 --- a/docs/content/docs/contracts.mdx +++ b/docs/content/docs/contracts.mdx @@ -331,7 +331,7 @@ $ scriptc build graph.ts ## ProgramLifetime -`ProgramLifetime` marks a class whose instances a program keeps until it exits, such as the nodes of a syntax tree, the symbols of a symbol table or interned types. scriptc then never reference counts, collects or frees instances of the class and of its subclasses: they are never freed, every retain and release on them compiles to nothing, and the cycle collector neither walks them nor needs to trace the objects that point to them. Node.js behavior is unchanged; only memory use differs, because an instance the program drops is never reclaimed. On Linux, the instances a worker thread creates are returned with the rest of its memory when it exits, unless the worker shared objects with other threads (see [cost](/docs/threads#cost)). +`ProgramLifetime` marks a class whose instances a program keeps until it exits, such as the nodes of a syntax tree, the symbols of a symbol table or interned types. scriptc then never reference counts, collects or frees instances of the class and of its subclasses: they are never freed, every retain and release on them compiles to nothing, and the cycle collector neither walks them nor needs to trace the objects that point to them. Node.js behavior is unchanged; only memory use differs, because an instance the program drops is never reclaimed. ```ts:tree.ts import type { ProgramLifetime } from "@scriptc/types"; diff --git a/docs/content/docs/threads.mdx b/docs/content/docs/threads.mdx index 15a3eb102..7b394e09f 100644 --- a/docs/content/docs/threads.mdx +++ b/docs/content/docs/threads.mdx @@ -234,8 +234,6 @@ Without `@scriptc/threads`, a scriptc executable also shares a message of untype Starting a worker thread takes tens of microseconds plus the worker's own module initialization, since every worker initializes the program's modules again, as in Node.js. A worker that exits frees its heap first, which takes time proportional to what it still holds. `SCRIPTC_WORKER_STATS=1` prints, as each worker exits, how long it took to start, to run its script and to exit. -On Linux, a worker that exits without having shared an object it allocated with another thread returns all of its memory, including objects it never freed, such as `ProgramLifetime` instances. A worker shares objects when, for example, it sends a published value or frozen plain data, which other threads read by reference, or stores a value in an `InternTable`. The memory of a worker that shared stays allocated, as on other platforms. Set `SCR_SA_DISCARD=0` in the environment to keep the memory of every worker. - `publish` visits each object of the graph once and marks it immortal, so publication takes time proportional to the graph. Published objects then cost nothing on later sends, and reference counting and the cycle collector skip them. Stores into the types a program publishes carry one extra load and branch. Threads that add to one shared collection of published values while they run can use an [`InternTable`](/docs/experimental#interntable) from `@scriptc/experimental`. diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json deleted file mode 100644 index b7dd8fd17..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/corpus/native-worker-discarded-heaps.ts" - ], - "diags": [] -} diff --git a/packages/runtime/src/scr_alloc.c b/packages/runtime/src/scr_alloc.c index ffe98bcf8..76d056d7c 100644 --- a/packages/runtime/src/scr_alloc.c +++ b/packages/runtime/src/scr_alloc.c @@ -630,13 +630,6 @@ static bool scr_sa_reserve_region(void) { * scr_sa_trim). */ static size_t scr_sa_claim_carved[SCR_SA_ARENAS]; static size_t scr_sa_carved(void); -/* A worker thread's memory, discarded when it parks (see "Discarding a - * worker's memory" below). */ -typedef struct ScrSaKeep ScrSaKeep; -static _Thread_local bool scr_sa_worker; /* set by scr_sa_thread_starting */ -static _Thread_local ScrSaKeep *scr_sa_keep; /* while the worker's memory is kept apart */ -static void scr_sa_keep_begin(unsigned i); -static void scr_sa_keep_drained(ScrSaKeep *k, ScrSaBlock *b, unsigned c); #endif /* Moves every block other threads freed into this arena's free lists. */ @@ -645,13 +638,6 @@ static void scr_sa_drain_remote(void) { while (b) { ScrSaBlock *next = b->next; unsigned c = (unsigned)(((uintptr_t)b - scr_sa.base) >> scr_sa.shift); -#ifdef SCR_SA_TRIM - if (scr_sa_keep) { - scr_sa_keep_drained(scr_sa_keep, b, c); - b = next; - continue; - } -#endif b->next = scr_sa.free[c]; scr_sa.free[c] = b; b = next; @@ -686,7 +672,6 @@ static bool scr_sa_reserve(void) { scr_sa_drain_remote(); #ifdef SCR_SA_TRIM scr_sa_claim_carved[i] = scr_sa_carved(); - if (scr_sa_worker) scr_sa_keep_begin(i); #endif return true; } @@ -899,303 +884,6 @@ static void scr_sa_trim(void) { scr_sa_arena, (int)trim, scr_sa_trim_stats[0] >> 20, scr_sa_trim_stats[1] >> 20, scr_sa_trim_stats[2] >> 20); } - -/* Discarding a worker's memory (Linux). Script objects stay on the thread - * that allocated them: other threads reach one only through a message or an - * intern table that shares a published (immortal) graph by pointer, or a - * process-wide immortal cache, and each of those calls - * scr_sa_thread_shares. Runtime state that outlives a thread (messages, - * mailboxes, shared bytes, intern table entries) comes from the system - * allocator directly. So when a worker thread parks without having shared, - * nothing it allocated through scr_mem_* can be reachable from another - * thread, and what it never freed (ProgramLifetime instances, published - * module constants) is garbage. Such a thread's memory goes back whole: - * - when a worker claims an arena, the arena's free lists and returned - * regions are set aside, and the worker carves only past each slice's - * frontier, so its blocks of class c are [start[c], bump[c]), plus the - * blocks it takes from the free lists set aside once a slice has no bump - * room left, which it records; - * - the system blocks it allocates (large blocks, an exhausted slice) are - * recorded until it frees them; - * - a remote free into its blocks means another thread held one: the same - * as sharing; - * - when it parks without having shared, the trim helper returns the pages - * it carved (MADV_DONTNEED; the start of the first page, which it may - * share with older blocks, is cleared), frees the recorded system blocks, - * and parks the arena as the worker found it, with the blocks it took - * free again. A worker that shared parks - * its arena with the blocks set aside added to its free lists, and the - * ordinary trim applies. - * SCR_SA_DISCARD=0 keeps every worker's memory. SCR_SA_DISCARD=poison makes - * the carved pages inaccessible instead, and keeps the system blocks, so - * that a reference to discarded memory faults (a check for tests). */ -#define SCR_SA_SYS_GONE ((void *)1) /* a removed entry of ScrSaKeep.sys */ - -struct ScrSaKeep { - /* The arena as the worker claimed it: free lists (to which remote frees - * of older blocks are added), carve cursors and returned regions. */ - ScrSaBlock *free[SCR_SA_NCLASS]; - char *bump[SCR_SA_NCLASS], *lim[SCR_SA_NCLASS]; - ScrSaHoles holes[SCR_SA_NCLASS]; - /* Each slice's frontier then (bump and limit, NULL limits for a slice not - * opened yet), and the first address the worker carves in it. */ - char *front_bump[SCR_SA_NCLASS], *front_lim[SCR_SA_NCLASS]; - char *start[SCR_SA_NCLASS]; - /* The worker's system blocks: an open-addressing set of `cap` slots (a - * power of two, or 0), NULL for an empty slot and SCR_SA_SYS_GONE for a - * removed entry; `used` counts both kinds of filled slots. */ - void **sys; - size_t cap, used, live; - /* The blocks of the free lists set aside that the worker took once a slice - * had no bump room left, so that older free blocks are used before the - * slice grows; they go back to those lists with the worker's memory. */ - ScrSaBlock **taken; - size_t ntaken, cap_taken; - bool shared; - bool poison; -}; - -static _Thread_local bool scr_sa_discarded; /* this thread's memory went back */ -static ScrSaKeep *scr_sa_parked_keep[SCR_SA_ARENAS]; /* handed to the helper */ - -/* SCR_SA_DISCARD: 0 off, 1 on (the default), 2 poison. */ -static int scr_sa_discard_mode(void) { - const char *mode = getenv("SCR_SA_DISCARD"); - if (!mode) return 1; - if (strcmp(mode, "0") == 0) return 0; - return strcmp(mode, "poison") == 0 ? 2 : 1; -} - -static void scr_sa_keep_begin(unsigned i) { - int mode = scr_sa_discard_mode(); - if (!mode) return; - ScrSaKeep *k = calloc(1, sizeof *k); - if (!k) return; - k->poison = mode == 2; - for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { - ScrSaHoles *h = &scr_sa_holes[i][c]; - k->free[c] = scr_sa.free[c]; - k->bump[c] = scr_sa.bump[c]; - k->lim[c] = scr_sa.lim[c]; - k->holes[c] = *h; - memset(h, 0, sizeof *h); - scr_sa.free[c] = NULL; - /* While the slice carves a returned region, its frontier is kept apart. */ - if (k->holes[c].lim) { - scr_sa.bump[c] = k->holes[c].bump; - scr_sa.lim[c] = k->holes[c].lim; - } - k->front_bump[c] = scr_sa.bump[c]; - k->front_lim[c] = scr_sa.lim[c]; - k->start[c] = scr_sa.lim[c] ? scr_sa.bump[c] : (char *)scr_sa.base + ((size_t)c << scr_sa.shift); - } - scr_sa_keep = k; -} - -/* A remote free of class c, drained while the worker keeps its memory - * apart: one of its own blocks makes it share; an older block goes to the - * free lists set aside. Once the worker has taken blocks from those lists, - * any older block might be one of them, so it shares as well. */ -static void scr_sa_keep_drained(ScrSaKeep *k, ScrSaBlock *b, unsigned c) { - if ((char *)b >= k->start[c] && (char *)b < scr_sa.bump[c]) { - k->shared = true; - b->next = scr_sa.free[c]; - scr_sa.free[c] = b; - } else { - if (k->ntaken) k->shared = true; - b->next = k->free[c]; - k->free[c] = b; - } -} - -/* A block of class c from the free lists set aside, for a worker whose - * slice has no bump room left; NULL when there is none or it cannot be - * recorded. */ -static ScrSaBlock *scr_sa_keep_take(ScrSaKeep *k, unsigned c) { - ScrSaBlock *b = k->free[c]; - if (!b) return NULL; - if (k->ntaken == k->cap_taken) { - size_t cap = k->cap_taken ? 2 * k->cap_taken : 256; - ScrSaBlock **taken = realloc(k->taken, cap * sizeof *taken); - if (!taken) return NULL; - k->taken = taken; - k->cap_taken = cap; - } - k->free[c] = b->next; - k->taken[k->ntaken++] = b; - return b; -} - -static size_t scr_sa_sys_slot(const void *p, size_t cap) { - return (size_t)((((uint64_t)(uintptr_t)p >> 4) * UINT64_C(0x9E3779B97F4A7C15)) >> 32) & (cap - 1); -} - -/* Records system block p. A worker whose set cannot grow keeps its memory. */ -static void scr_sa_keep_add(ScrSaKeep *k, void *p) { - if ((k->used + 1) * 2 > k->cap) { - size_t cap = 64; - while (cap < (k->live + 1) * 4) cap *= 2; - void **sys = calloc(cap, sizeof *sys); - if (!sys) { - k->shared = true; - return; - } - for (size_t s = 0; s < k->cap; s++) { - void *q = k->sys[s]; - if (!q || q == SCR_SA_SYS_GONE) continue; - size_t j = scr_sa_sys_slot(q, cap); - while (sys[j]) j = (j + 1) & (cap - 1); - sys[j] = q; - } - free(k->sys); - k->sys = sys; - k->cap = cap; - k->used = k->live; - } - size_t j = scr_sa_sys_slot(p, k->cap); - while (k->sys[j] && k->sys[j] != SCR_SA_SYS_GONE) j = (j + 1) & (k->cap - 1); - if (!k->sys[j]) k->used++; - k->sys[j] = p; - k->live++; -} - -/* Forgets system block p; whether it was recorded. */ -static bool scr_sa_keep_remove(ScrSaKeep *k, const void *p) { - if (!k->live) return false; - for (size_t j = scr_sa_sys_slot(p, k->cap); k->sys[j]; j = (j + 1) & (k->cap - 1)) { - if (k->sys[j] != p) continue; - k->sys[j] = SCR_SA_SYS_GONE; - k->live--; - return true; - } - return false; -} - -/* The calling thread's arena keeps the worker's memory (it shared): the - * free lists set aside go back, followed by the worker's own free blocks, - * and so do the returned regions, past which the worker carved. */ -static void scr_sa_keep_merge(ScrSaKeep *k) { - for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { - ScrSaBlock *kept = k->free[c]; - if (kept) { - ScrSaBlock *tail = kept; - while (tail->next) tail = tail->next; - tail->next = scr_sa.free[c]; - scr_sa.free[c] = kept; - } - ScrSaHoles *h = &scr_sa_holes[scr_sa_arena][c]; - *h = k->holes[c]; - if (h->lim) { - h->bump = scr_sa.bump[c]; - h->lim = scr_sa.lim[c]; - scr_sa.bump[c] = k->bump[c]; - scr_sa.lim[c] = k->lim[c]; - } - } - free(k->sys); - free(k->taken); - free(k); -} - -/* Returns the memory of the worker whose arena the calling thread (the - * trim helper) holds, and restores the arena to its state at the worker's - * claim; with poison, makes the pages inaccessible and moves the frontier - * past them instead. */ -static void scr_sa_discard(ScrSaKeep *k) { - /* Remote frees since the worker's last drain. */ - scr_sa_keep = k; - scr_sa_drain_remote(); - scr_sa_keep = NULL; - if (k->shared) { - scr_sa_keep_merge(k); - scr_sa_trim(); - return; - } - uintptr_t page = (uintptr_t)sysconf(_SC_PAGESIZE); - if (page == 0 || page == (uintptr_t)-1) page = 4096; - size_t returned = 0, sys_bytes = 0, sys_blocks = 0; - for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { - char *lo = k->start[c], *top = scr_sa.bump[c], *lim = scr_sa.lim[c]; - char *bump = k->front_bump[c], *limit = k->front_lim[c]; - if (lim && top > lo) { - char *first = (char *)(((uintptr_t)lo + page - 1) & ~(page - 1)); - char *used = (char *)(((uintptr_t)top + page - 1) & ~(page - 1)); - /* The part of a page that may also hold older blocks. */ - if (first > lo) memset(lo, 0, (size_t)((first < top ? first : top) - lo)); - if (k->poison) { - if (used > first) (void)mprotect(first, (size_t)(used - first), PROT_NONE); - bump = used > first ? used : top; - limit = lim > bump ? lim : bump; - } else { - char *end = (char *)(((uintptr_t)lim + page - 1) & ~(page - 1)); - if (end > first) { - (void)madvise(first, (size_t)(end - first), MADV_DONTNEED); - returned += (size_t)(end - first); - } - } - } else { - bump = top; - limit = lim; - } - scr_sa.free[c] = k->free[c]; - ScrSaHoles *h = &scr_sa_holes[scr_sa_arena][c]; - *h = k->holes[c]; - if (h->lim) { - h->bump = bump; - h->lim = limit; - scr_sa.bump[c] = k->bump[c]; - scr_sa.lim[c] = k->lim[c]; - } else { - scr_sa.bump[c] = bump; - scr_sa.lim[c] = limit; - } - } - /* The older free blocks the worker took are free again. */ - if (!k->poison) - for (size_t t = 0; t < k->ntaken; t++) { - ScrSaBlock *b = k->taken[t]; - unsigned c = (unsigned)(((uintptr_t)b - scr_sa.base) >> scr_sa.shift); - b->next = scr_sa.free[c]; - scr_sa.free[c] = b; - } - if (!k->poison) - for (size_t s = 0; s < k->cap; s++) { - void *p = k->sys[s]; - if (!p || p == SCR_SA_SYS_GONE) continue; -#if defined(__GLIBC__) - sys_bytes += malloc_usable_size(p); -#endif - sys_blocks++; - free(p); - } -#if defined(__GLIBC__) - if (sys_blocks) (void)malloc_trim(0); -#endif - const char *stats = getenv("SCR_SA_STATS"); - if (stats && stats[0] == '1') - fprintf(stderr, "scr_sa: discard arena %d returned %zu MB, %zu system blocks (%zu MB)\n", scr_sa_arena, - returned >> 20, sys_blocks, sys_bytes >> 20); - free(k->sys); - free(k->taken); - free(k); -} - -/* Hooks of the allocator's system paths and of sharing (scr_rc.h). */ -static void scr_sa_keep_note_system(void *p) { - if (p && scr_sa_keep) scr_sa_keep_add(scr_sa_keep, p); -} - -void scr_sa_thread_shares(void) { - if (scr_sa_keep) scr_sa_keep->shared = true; -} - -/* Library archives run on their embedder's threads and keep their memory. */ -static void scr_sa_worker_starting(void) { -#ifndef SCR_LIB - scr_sa_worker = true; -#endif -} -#define SCR_SA_WORKER_STARTING() scr_sa_worker_starting() #endif #ifdef SCR_SA_TRIM @@ -1218,36 +906,12 @@ static void *scr_sa_trim_main(void *arg) { unsigned i = (unsigned)(uintptr_t)arg; scr_sa_arena = (int)i; scr_sa = scr_sa_parked[i]; - ScrSaKeep *k = scr_sa_parked_keep[i]; - scr_sa_parked_keep[i] = NULL; - if (k) scr_sa_discard(k); - else scr_sa_trim(); + scr_sa_trim(); scr_sa_release(i); atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_release); return NULL; } -/* Hands the calling thread's arena to a trim helper (with `k`, to discard - * the worker's memory); false if no helper could start. */ -static bool scr_sa_start_helper(unsigned i, ScrSaKeep *k) { - scr_sa_parked[i] = scr_sa; - scr_sa_parked_keep[i] = k; - atomic_fetch_add_explicit(&scr_sa_trimming, 1, memory_order_relaxed); - pthread_attr_t attr; - pthread_t helper; - bool started = pthread_attr_init(&attr) == 0; - if (started) { - started = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && - pthread_create(&helper, &attr, scr_sa_trim_main, (void *)(uintptr_t)i) == 0; - pthread_attr_destroy(&attr); - } - if (!started) { - scr_sa_parked_keep[i] = NULL; - atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_relaxed); - } - return started; -} - void scr_sa_wait_trims(void) { while (atomic_load_explicit(&scr_sa_trimming, memory_order_acquire)) { struct timespec pause = {0, 1000000}; @@ -1256,7 +920,6 @@ void scr_sa_wait_trims(void) { } #else void scr_sa_wait_trims(void) {} -void scr_sa_thread_shares(void) {} #endif void scr_sa_thread_park(void) { @@ -1266,25 +929,18 @@ void scr_sa_thread_park(void) { scr_sa_pf_park(); #endif #ifdef SCR_SA_TRIM - ScrSaKeep *k = scr_sa_keep; - scr_sa_keep = NULL; - if (k && !k->shared) { - /* Nothing this thread allocated is reachable from another one: its - * memory goes back, and later frees on this thread are dropped. */ - scr_sa_discarded = true; - if (!scr_sa_start_helper(i, k)) { - scr_sa_discard(k); - scr_sa_release(i); - return; - } - memset(&scr_sa, 0, sizeof scr_sa); - scr_sa_arena = -1; - scr_sa_refused = true; - return; - } - if (k) scr_sa_keep_merge(k); if (scr_sa_trim_worth()) { - if (scr_sa_start_helper(i, NULL)) { + scr_sa_parked[i] = scr_sa; + atomic_fetch_add_explicit(&scr_sa_trimming, 1, memory_order_relaxed); + pthread_attr_t attr; + pthread_t helper; + bool started = pthread_attr_init(&attr) == 0; + if (started) { + started = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && + pthread_create(&helper, &attr, scr_sa_trim_main, (void *)(uintptr_t)i) == 0; + pthread_attr_destroy(&attr); + } + if (started) { /* Later frees on this thread take the foreign path into the arena's * remote list; the helper releases the claim. */ memset(&scr_sa, 0, sizeof scr_sa); @@ -1292,6 +948,7 @@ void scr_sa_thread_park(void) { scr_sa_refused = true; return; } + atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_relaxed); scr_sa_trim(); } #endif @@ -1314,9 +971,6 @@ static size_t scr_sa_foreign_size(const void *p) { } void scr_sa_free_foreign(void *p) { -#ifdef SCR_SA_TRIM - if (scr_sa_discarded) return; /* the block went back with the thread's memory */ -#endif uintptr_t region = atomic_load_explicit(&scr_sa_region, memory_order_acquire); uintptr_t off = (uintptr_t)p - region; if (region && off < scr_sa_arena_span * SCR_SA_ARENAS) { @@ -1328,9 +982,6 @@ void scr_sa_free_foreign(void *p) { memory_order_relaxed)); return; } -#ifdef SCR_SA_TRIM - if (scr_sa_keep) (void)scr_sa_keep_remove(scr_sa_keep, p); -#endif free(p); } #else @@ -1369,15 +1020,6 @@ __attribute__((cold, noinline)) void *scr_sa_slow(size_t n, bool zero) { if (zero) memset(b, 0, n); return b; } -#ifdef SCR_SA_TRIM - /* A worker that keeps its memory apart uses the arena's older free - * blocks before its slice grows. */ - if (scr_sa_keep && (size_t)(scr_sa.lim[c] - scr_sa.bump[c]) < scr_sa_class_size(c) && - (b = scr_sa_keep_take(scr_sa_keep, c)) != NULL) { - if (zero) memset(b, 0, n); - return b; - } -#endif #endif /* Carve from the slice, opening it or raising its limit as needed; * fresh pages are zero. */ @@ -1409,9 +1051,6 @@ __attribute__((cold, noinline)) void *scr_sa_slow(size_t n, bool zero) { SCR_SA_LARGE_NOTE(q, n); SCR_SA_THREAD_LARGE_NOTE(); } -#ifdef SCR_SA_TRIM - scr_sa_keep_note_system(q); -#endif return q; } @@ -1426,14 +1065,8 @@ void *scr_mem_realloc(void *p, size_t n) { } #endif else { -#ifdef SCR_SA_TRIM - bool kept = scr_sa_keep && scr_sa_keep_remove(scr_sa_keep, p); -#endif void *q = realloc(p, n); if (n > SCR_SA_MAX) SCR_SA_LARGE_NOTE(q, n); -#ifdef SCR_SA_TRIM - if (kept) scr_sa_keep_note_system(q ? q : p); /* a failed realloc leaves p */ -#endif return q; } /* Still fits its block, which is aligned for n (see the contract). */ @@ -1449,15 +1082,10 @@ void *scr_mem_realloc(void *p, size_t n) { return realloc(p, n); } #ifdef SCR_WORKERS void scr_sa_thread_park(void) {} void scr_sa_wait_trims(void) {} -void scr_sa_thread_shares(void) {} void scr_sa_free_foreign(void *p) { free(p); } #endif #endif -#ifndef SCR_SA_WORKER_STARTING -#define SCR_SA_WORKER_STARTING() ((void)0) -#endif - #ifdef SCR_WORKERS /* Blocks above SCR_SA_MAX come from glibc, which gives each thread that * allocates its own arena: a heap reserved up front and made usable with @@ -1488,10 +1116,7 @@ void scr_sa_free_foreign(void *p) { free(p); } * that are not workers (they never reserve). */ static _Thread_local unsigned scr_sa_thread_large; -void scr_sa_thread_starting(void) { - scr_sa_thread_large = 1; - SCR_SA_WORKER_STARTING(); -} +void scr_sa_thread_starting(void) { scr_sa_thread_large = 1; } static void scr_sa_thread_reserve(void) { void *blocks[SCR_SA_THREAD_HEAP_RESERVE / SCR_SA_THREAD_HEAP_STEP + 1]; @@ -1511,7 +1136,7 @@ static void scr_sa_thread_large_note(void) { if (count == SCR_SA_THREAD_RESERVE_AFTER) scr_sa_thread_reserve(); } #else -void scr_sa_thread_starting(void) { SCR_SA_WORKER_STARTING(); } +void scr_sa_thread_starting(void) {} #endif #endif diff --git a/packages/runtime/src/scr_alloc.test.c b/packages/runtime/src/scr_alloc.test.c index 032c41f7f..b3228ce89 100644 --- a/packages/runtime/src/scr_alloc.test.c +++ b/packages/runtime/src/scr_alloc.test.c @@ -429,273 +429,6 @@ static void check_trim(void) { } #endif -#if defined(SCR_WORKERS) && SCR_SMALL_ALLOC && defined(__linux__) -#include -#include -#include -#include -#include - -/* A worker thread (scr_sa_thread_starting) that exits without sharing - * gives its memory back: the pages it carved, and the system blocks it - * still holds. Older blocks of the arena, and the memory of a worker that - * shared (or got a remote free of its own blocks), stay. */ -/* DISCARD_SIZE and POISON_SIZE are classes the earlier checks leave unused - * in the workers' arena, so their state there is known. */ -enum { DISCARD_BLOCKS = 1 << 20, DISCARD_SIZE = 40, POISON_SIZE = 56, DISCARD_OLD = 64, DISCARD_LARGE = 64 }; -enum { DISCARD_LARGE_SIZE = 64 << 10 }; -static unsigned char *old_blocks[DISCARD_OLD]; -static unsigned char **discard_blocks; -static unsigned char *discard_large[DISCARD_LARGE]; -static uintptr_t discard_base, discard_lo, discard_hi; -static size_t block_size = DISCARD_SIZE; /* of the workers' and reusing threads' blocks */ -/* The end of the highest block of class DISCARD_SIZE so far, and how many blocks of a run lay past the mark - * at its start: those the slice grew for. */ -static uintptr_t class_hi; -static size_t discard_beyond, reuse_beyond; -static bool discard_shares; -static atomic_int discard_step; - -static void wait_step(int step) { - while (atomic_load(&discard_step) < step) { - struct timespec pause = {0, 100000}; - nanosleep(&pause, NULL); - } -} - -/* A plain script thread whose blocks stay live in its parked arena. */ -static void *discard_old_owner(void *arg) { - (void)arg; - for (unsigned i = 0; i < DISCARD_OLD; i++) { - old_blocks[i] = scr_mem_alloc(DISCARD_SIZE); - assert(owned(old_blocks[i])); - fill(old_blocks[i], DISCARD_SIZE, (unsigned char)i); - } - discard_base = scr_sa.base; - scr_sa_thread_park(); - return NULL; -} - -static void allocate_discardable(void) { - discard_lo = UINTPTR_MAX; - discard_hi = 0; - discard_beyond = 0; - for (size_t i = 0; i < DISCARD_BLOCKS; i++) { - unsigned char *p = scr_mem_alloc(block_size); - assert(p && owned(p)); - fill(p, block_size, (unsigned char)i); - discard_blocks[i] = p; - if ((uintptr_t)p >= class_hi) discard_beyond++; - if ((uintptr_t)p < discard_lo) discard_lo = (uintptr_t)p; - if ((uintptr_t)p + block_size > discard_hi) discard_hi = (uintptr_t)p + block_size; - } - if (block_size == DISCARD_SIZE && discard_hi > class_hi) class_hi = discard_hi; - /* System blocks: some freed, some moved by realloc, the rest kept. */ - for (unsigned i = 0; i < DISCARD_LARGE; i++) { - discard_large[i] = scr_mem_alloc(DISCARD_LARGE_SIZE); - assert(discard_large[i] && !owned(discard_large[i])); - fill(discard_large[i], 64, (unsigned char)i); - } - for (unsigned i = 0; i < DISCARD_LARGE; i += 4) { - scr_mem_free(discard_large[i]); - discard_large[i] = NULL; - } - for (unsigned i = 1; i < DISCARD_LARGE; i += 4) discard_large[i] = scr_mem_realloc(discard_large[i], 2 * DISCARD_LARGE_SIZE); -} - -static void *discard_worker(void *arg) { - (void)arg; - scr_sa_thread_starting(); - allocate_discardable(); - assert(scr_sa.base == discard_base); - /* None of the arena's older blocks or free blocks is reused. */ - for (unsigned i = 0; i < DISCARD_OLD; i++) assert(discard_lo > (uintptr_t)old_blocks[i]); - if (discard_shares) scr_sa_thread_shares(); - scr_sa_thread_park(); - return NULL; -} - -/* A worker one of whose blocks the main thread frees while it runs. */ -static void *remote_freed_worker(void *arg) { - (void)arg; - scr_sa_thread_starting(); - allocate_discardable(); - atomic_store(&discard_step, 1); - wait_step(2); - /* A class this thread has not used: its first block takes the slow path, - * which drains the remote free. */ - void *p = scr_mem_alloc(200); - assert(p); - scr_sa_thread_park(); - return NULL; -} - -/* A plain thread that takes as many blocks again from the arena: carved - * ones must be zero (the fast path does not clear them). */ -static size_t reuse_outside; -static uintptr_t reuse_hi; -static void *discard_reuse(void *arg) { - (void)arg; - reuse_outside = 0; - reuse_hi = 0; - reuse_beyond = 0; - for (size_t i = 0; i < DISCARD_BLOCKS; i++) { - unsigned char *p = scr_mem_calloc(block_size); - assert(p && owned(p)); - assert(scr_sa.base == discard_base); - for (size_t k = 0; k < block_size; k++) assert(p[k] == 0); - for (unsigned j = 0; j < DISCARD_OLD; j++) assert(p != old_blocks[j]); - if ((uintptr_t)p < discard_lo || (uintptr_t)p >= discard_hi) reuse_outside++; - if ((uintptr_t)p + block_size > reuse_hi) reuse_hi = (uintptr_t)p + block_size; - if ((uintptr_t)p >= class_hi) reuse_beyond++; - discard_blocks[i] = p; - } - if (block_size == DISCARD_SIZE && reuse_hi > class_hi) class_hi = reuse_hi; - for (size_t i = 0; i < DISCARD_BLOCKS; i++) scr_mem_free(discard_blocks[i]); - scr_sa_thread_park(); - return NULL; -} - -static void run(void *(*fn)(void *)) { - pthread_t t; - assert(pthread_create(&t, NULL, fn, NULL) == 0); - assert(pthread_join(t, NULL) == 0); - scr_sa_wait_trims(); -} - -static void verify_old_blocks(void) { - for (unsigned i = 0; i < DISCARD_OLD; i++) verify(old_blocks[i], DISCARD_SIZE, (unsigned char)i); -} - -/* The worker's blocks stayed as it left them, and the next thread to claim - * the arena carves past them; then they are freed (remote frees). */ -static void verify_kept(void) { - for (size_t i = 0; i < DISCARD_BLOCKS; i++) verify(discard_blocks[i], block_size, (unsigned char)i); - for (unsigned i = 0; i < DISCARD_LARGE; i++) { - if (!discard_large[i]) continue; - verify(discard_large[i], 64, (unsigned char)i); - free(discard_large[i]); - } - for (size_t i = 0; i < DISCARD_BLOCKS; i++) scr_mem_free(discard_blocks[i]); -} - -/* The protection of the mapping that holds address a, from /proc/self/maps. */ -static bool readable(uintptr_t a) { - FILE *maps = fopen("/proc/self/maps", "r"); - assert(maps); - char line[512]; - bool found = false, result = false; - while (!found && fgets(line, sizeof line, maps)) { - unsigned long lo, hi; - char perms[8]; - if (sscanf(line, "%lx-%lx %7s", &lo, &hi, perms) != 3) continue; - if (a >= lo && a < hi) { - found = true; - result = perms[0] == 'r'; - } - } - fclose(maps); - assert(found); - return result; -} - -static void check_discard(void) { - discard_blocks = malloc(DISCARD_BLOCKS * sizeof *discard_blocks); - assert(discard_blocks); - run(discard_old_owner); - size_t page = (size_t)sysconf(_SC_PAGESIZE); - - /* Discarded: its pages are returned, and carved again (zeroed) by the next - * thread, which does not grow the slice. The arena's older blocks stay. */ - discard_shares = false; - run(discard_worker); - verify_old_blocks(); - uintptr_t first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); - /* Pre-fault requests still in flight may fault in a few megabytes again. */ - size_t total = (discard_hi - first) / page; - assert(resident_pages(first, discard_hi) < total / 2); - run(discard_reuse); - assert(reuse_outside < 256); - verify_old_blocks(); - - /* SCR_SA_DISCARD=poison makes the pages inaccessible; the next thread - * carves past them. */ - block_size = POISON_SIZE; - setenv("SCR_SA_DISCARD", "poison", 1); - run(discard_worker); - unsetenv("SCR_SA_DISCARD"); - verify_old_blocks(); - first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); - assert(!readable(first)); - assert(!readable((discard_hi - 1) & ~(uintptr_t)(page - 1))); - run(discard_reuse); - assert(reuse_outside == DISCARD_BLOCKS); - verify_old_blocks(); - block_size = DISCARD_SIZE; - - /* A worker that shared keeps its memory. */ - discard_shares = true; - run(discard_worker); - verify_old_blocks(); - verify_kept(); - - /* So does one that got a remote free of one of its blocks. */ - atomic_store(&discard_step, 0); - pthread_t t; - assert(pthread_create(&t, NULL, remote_freed_worker, NULL) == 0); - wait_step(1); - scr_mem_free(discard_blocks[0]); - discard_blocks[0] = scr_mem_alloc(DISCARD_SIZE); /* main's own block, for verify_kept */ - fill(discard_blocks[0], DISCARD_SIZE, 0); - atomic_store(&discard_step, 2); - assert(pthread_join(t, NULL) == 0); - scr_sa_wait_trims(); - verify_old_blocks(); - verify_kept(); - - /* SCR_SA_DISCARD=0 keeps every worker's memory. */ - discard_shares = false; - setenv("SCR_SA_DISCARD", "0", 1); - run(discard_worker); - unsetenv("SCR_SA_DISCARD"); - verify_old_blocks(); - verify_kept(); - - /* The kept workers' blocks are free now (remote frees): a worker takes - * them once its slice has no bump room left, and they are free again - * after its memory goes back, so the next thread does not grow the slice - * either. Past the highest block so far, each carves at most the bump room - * the slice had left (a few megabytes). */ - size_t room = ((size_t)4 << 20) / DISCARD_SIZE; - run(discard_worker); - verify_old_blocks(); - assert(discard_beyond < room); - run(discard_reuse); - assert(reuse_beyond < room); - verify_old_blocks(); - - /* Returned regions (holes) of an earlier trim are kept apart while a - * worker runs, and carved again afterwards. */ - trim_blocks = malloc(TRIM_BLOCKS * sizeof *trim_blocks); /* check_trim freed its own */ - assert(trim_blocks); - run(trim_allocate); - uintptr_t hole_lo = trim_lo, hole_hi = trim_hi; - discard_shares = false; - run(discard_worker); - verify_old_blocks(); - for (size_t k = 0; k < TRIM_BLOCKS / TRIM_KEEP; k++) - verify(trim_kept[k], TRIM_SIZE, (unsigned char)(k * TRIM_KEEP)); - trim_lo = hole_lo; - trim_hi = hole_hi; - run(trim_reuse); - assert(trim_outside < 4 * TRIM_BLOCKS / TRIM_KEEP + 256); - for (size_t k = 0; k < TRIM_BLOCKS / TRIM_KEEP; k++) scr_mem_free(trim_kept[k]); - free(trim_blocks); - for (unsigned i = 0; i < DISCARD_OLD; i++) scr_mem_free(old_blocks[i]); - free(discard_blocks); -} -#endif - int main(void) { #if SCR_SMALL_ALLOC check_slice_growth(); /* first: its class must be untouched */ @@ -713,7 +446,6 @@ int main(void) { check_threads(); #ifdef __linux__ check_trim(); - check_discard(); #endif printf("allocator checks passed: size-class workers\n"); #else diff --git a/packages/runtime/src/scr_itable.c b/packages/runtime/src/scr_itable.c index 4842bf79c..08db948b5 100644 --- a/packages/runtime/src/scr_itable.c +++ b/packages/runtime/src/scr_itable.c @@ -428,13 +428,11 @@ static const ScrITableEntry *scr_itable_insert_bytes(ScrITable *t, uint64_t hash const ScrITableEntry *scr_itable_insert_str(ScrITable *t, const ScrStr *key, uint64_t value) { scr_itable_enter(); - scr_sa_thread_shares(); /* the stored value graph is read by every thread */ return scr_itable_insert_bytes(t, scr_itable_str_hash(key), key->data, key->len, value); } const ScrITableEntry *scr_itable_insert_f64(ScrITable *t, double key, uint64_t value) { scr_itable_enter(); - scr_sa_thread_shares(); /* the stored value graph is read by every thread */ uint64_t stored = scr_itable_f64_bits(key) ^ SCR_ITABLE_F64_FLIP; uint64_t hash = scr_itable_f64_hash(stored); ScrITableSegment *seg = scr_itable_segment(t, hash); @@ -590,7 +588,6 @@ const ScrITableEntry *scr_itable_find_arr(ScrITable *t, const ScrArr *key) { const ScrITableEntry *scr_itable_insert_arr(ScrITable *t, const ScrArr *key, uint64_t value) { scr_itable_enter(); - scr_sa_thread_shares(); /* the stored value graph is read by every thread */ char stack[SCR_ITABLE_STACK_KEY]; size_t len; char *bytes = scr_itable_encoded(t, key, stack, sizeof stack, &len); diff --git a/packages/runtime/src/scr_itable.test.c b/packages/runtime/src/scr_itable.test.c index 5e5f22bc9..0f218806b 100644 --- a/packages/runtime/src/scr_itable.test.c +++ b/packages/runtime/src/scr_itable.test.c @@ -8,18 +8,13 @@ #include #include -/* The table unit needs only scr_trap, scr_throw_error_msg and - * scr_sa_thread_shares from the rest of the runtime; refusals and the - * inserting threads' shares are recorded here. */ +/* The table unit needs only scr_trap and scr_throw_error_msg from the + * rest of the runtime; refusals are recorded here. */ _Noreturn void scr_trap(const char *msg) { fputs(msg, stderr); abort(); } -/* Inserts share the stored values with every thread. */ -static atomic_int shares; -void scr_sa_thread_shares(void) { atomic_fetch_add(&shares, 1); } - static char refused[128]; void scr_throw_error_msg(int kind, const char *msg, size_t len) { assert(kind == SCR_ERR_TYPE && len < sizeof refused); @@ -227,7 +222,6 @@ int main(void) { for (unsigned i = 1; i < THREADS; i++) assert(seen_str[i][k] == seen_str[0][k]); assert(scr_itable_size(strings) == KEYS); assert(scr_itable_size(numbers) == KEYS); - assert(atomic_load(&shares) >= 2 * KEYS); printf("intern tables share one entry per key across racing inserts and lookups\n"); return 0; } diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index f43315634..e5d6f8d6a 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -10555,7 +10555,6 @@ static ScrArr *scr_record_shared_keys(const ScrDynTypedRecordOps *record) { #ifdef SCR_RC_AUDIT scr_arr_live_forget(); /* immortal: outside the exit-time RC audit */ #endif - scr_sa_thread_shares(); /* every thread reads the array */ return built; } built->rc = 1; diff --git a/packages/runtime/src/scr_message.c b/packages/runtime/src/scr_message.c index 8ce162a3f..a0b3b8d4e 100644 --- a/packages/runtime/src/scr_message.c +++ b/packages/runtime/src/scr_message.c @@ -234,7 +234,6 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) * capsule over the same object, a dyn graph as itself. */ if (input->kind == SCR_DYN_TYPED_REF && input->v.typed_ref.ptr && *(const size_t *)input->v.typed_ref.ptr == SIZE_MAX) { - scr_sa_thread_shares(); encoder->visits[id].view = (ScrDyn *)input; ScrMessageNode *node = &encoder->message->nodes[id]; node->kind = SCR_MESSAGE_TYPED_REF; @@ -252,7 +251,6 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) return id; } if ((input->kind == SCR_DYN_OBJ || input->kind == SCR_DYN_ARR) && input->rc == SIZE_MAX) { - scr_sa_thread_shares(); encoder->visits[id].view = (ScrDyn *)input; ScrMessageNode *node = &encoder->message->nodes[id]; node->kind = SCR_MESSAGE_PUBLISHED; @@ -506,7 +504,6 @@ static ScrMessage *scr_message_try_publish(const ScrDyn *value) { scr_lsan_immortal(d); } } - scr_sa_thread_shares(); message = scr_message_alloc(1, sizeof(*message)); message->nodes = scr_message_alloc(1, sizeof(*message->nodes)); message->count = message->capacity = 1; diff --git a/packages/runtime/src/scr_rc.h b/packages/runtime/src/scr_rc.h index cdc03c966..7e24ff569 100644 --- a/packages/runtime/src/scr_rc.h +++ b/packages/runtime/src/scr_rc.h @@ -341,18 +341,11 @@ void scr_sa_thread_park(void); /* Waits until the arenas of exited threads are trimmed (tests). */ void scr_sa_wait_trims(void); /* Called first on a new worker thread: prepares the thread's system- - * allocator heap, and lets the thread's memory go back when it exits - * (scr_alloc.c). */ + * allocator heap (scr_alloc.c). */ void scr_sa_thread_starting(void); -/* The calling thread made objects it allocated reachable from other - * threads: a message or an intern table shares a published graph by - * pointer, or a process-wide cache keeps an immortal object. Its memory - * then stays when it exits (scr_alloc.c). */ -void scr_sa_thread_shares(void); #define SCR_SA_FREE_FOREIGN(p) scr_sa_free_foreign(p) #else #define SCR_SA_FREE_FOREIGN(p) free(p) -#define scr_sa_thread_shares() ((void)0) #endif #if SCR_SMALL_ALLOC diff --git a/tests/corpus/native-worker-discarded-heaps.ts b/tests/corpus/native-worker-discarded-heaps.ts deleted file mode 100644 index bf7a76449..000000000 --- a/tests/corpus/native-worker-discarded-heaps.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads"; -import { publish } from "@scriptc/threads"; -import type { ProgramLifetime } from "@scriptc/types"; - -// Workers whose memory goes back when they exit, and workers whose memory -// stays because other threads hold what they allocated. Builder workers -// create ProgramLifetime instances (which scriptc never frees), ordinary -// objects, strings and large typed arrays, post a checksum and exit. A -// publisher worker posts published graphs (a class graph and a plain -// object) and exits. The main thread reads those graphs again after each -// wave of builders, which in scriptc on Linux reuse the memory of the -// builders before them. - -class Node implements ProgramLifetime { - readonly kind: number; - readonly label: string; - readonly children: Node[] = []; - parent: Node | undefined = undefined; - constructor(kind: number, label: string) { - this.kind = kind; - this.label = label; - } -} - -type Summary = { readonly name: string; readonly values: readonly number[]; readonly nested: { readonly total: number } }; - -type Job = { readonly role: string; readonly seed: number }; - -function build(seed: number, count: number): Node { - const root = new Node(seed, "root" + seed); - let parent = root; - for (let i = 0; i < count; i++) { - const node = new Node((i * 7 + seed) % 31, "n" + (i % 101)); - node.parent = parent; - parent.children.push(node); - if (i % 64 === 63) parent = node; - } - return root; -} - -function checksum(root: Node): number { - let sum = 0; - const stack: Node[] = [root]; - while (stack.length > 0) { - const node = stack.pop()!; - sum = (sum * 31 + node.kind + node.label.length + node.children.length) % 1_000_003; - for (const child of node.children) stack.push(child); - } - return sum; -} - -function startWorker(job: Job, onMessage: (value: unknown) => void): Promise { - return new Promise((resolve, reject) => { - const worker = new Worker(new URL(import.meta.url), { workerData: job }); - worker.on("message", onMessage); - worker.once("messageerror", reject); - worker.once("error", reject); - worker.once("exit", () => resolve()); - }); -} - -if (isMainThread) { - let tree: Node | undefined = undefined; - let summary: Summary | undefined = undefined; - // The publisher posts the tree, then the summary. - await startWorker({ role: "publisher", seed: 3 }, (value) => { - if (tree === undefined) tree = value as Node; - else summary = value as Summary; - }); - const describe = (): string => - `tree ${checksum(tree!)} summary ${summary!.name} ${summary!.values.join(",")} ${summary!.nested.total}`; - console.log("published", describe()); - for (let wave = 0; wave < 3; wave++) { - const sums: number[] = []; - await Promise.all( - [1, 2, 3, 4].map((k) => startWorker({ role: "builder", seed: wave * 10 + k }, (value) => sums.push(value as number))), - ); - sums.sort((a, b) => a - b); - console.log("wave", wave, sums.join(" "), describe()); - } -} else { - const job = workerData as Job; - if (job.role === "publisher") { - parentPort!.postMessage(publish(build(job.seed, 20_000))); - const values: number[] = []; - for (let i = 0; i < 50; i++) values.push(i * job.seed); - parentPort!.postMessage(publish({ name: "summary" + job.seed, values, nested: { total: values.length } })); - } else { - const root = build(job.seed, 150_000); - const samples: Float64Array[] = []; - for (let i = 0; i < 40; i++) { - const sample = new Float64Array(8192); - for (let j = 0; j < sample.length; j += 97) sample[j] = i + j + job.seed; - samples.push(sample); - } - let extra = 0; - for (const sample of samples) extra = (extra + sample[97]! + sample[8148]!) % 1_000_003; - const words: string[] = []; - for (let i = 0; i < 20_000; i++) words.push(`word-${i % 977}-${job.seed}`); - parentPort!.postMessage((checksum(root) + extra + words.join("").length) % 1_000_003); - } -} diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index d1a8838a9..cc21a9c85 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -2396,7 +2396,6 @@ "native-worker-clone-errors.ts": 2347, "native-worker-commonjs.cjs": 2188, "native-worker-delayed-messages.ts": 3114, - "native-worker-discarded-heaps.ts": 4430, "native-worker-environment.ts": 3538, "native-worker-error.ts": 2810, "native-worker-exception-state.ts": 3938, @@ -5064,7 +5063,6 @@ "native-worker-clone-errors.ts": 3629, "native-worker-commonjs.cjs": 3085, "native-worker-delayed-messages.ts": 28752, - "native-worker-discarded-heaps.ts": 39440, "native-worker-environment.ts": 27133, "native-worker-error.ts": 2958, "native-worker-exception-state.ts": 3945, From 84916f25e44568dbf7d36c480c42c8c705e2fb03 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 03:37:40 -0500 Subject: [PATCH 053/117] Support the regex v flag Regex literals and new RegExp calls accept the v (unicode sets) flag, which the vendored engine implements: class subtraction and intersection, nested classes, \q{...} string literals and properties of strings. The flag uses unicode mode for pattern decoding and string iteration, and flags read in getter order (dgimsuvy). Regex literals now also report their flags in getter order, as Node does for /x/yg, and the flag getters (global, unicodeSets and the rest) compile on statically typed regexes. In v mode the engine rejected `-` and doubled punctuation outside a character class, and the `\-` escape inside \q{...}. It now applies the class-only checks inside classes and \q{...} only, and parses \q{...} contents with the class escapes, matching Node. The d flag is still refused. --- .../builtin-apis/regular-expressions.mdx | 2 +- .../compiler/src/diagnostics/diagnostic.ts | 2 +- .../src/frontend/lowering/lower-classes.ts | 18 ++----- .../src/frontend/lowering/lower-exprs.ts | 52 +++++++++++++++---- packages/compiler/src/ir/ir.ts | 2 +- packages/compiler/src/ir/validate.ts | 4 +- packages/compiler/surface-manifest.json | 2 +- .../corpus/5857-regexp-unicode-sets.ts.json | 6 +++ packages/runtime/src/scr_regex.c | 19 ++++--- .../runtime/vendor/quickjs-ng/libregexp.c | 6 +-- tests/corpus/5857-regexp-unicode-sets.ts | 48 +++++++++++++++++ tests/diagnostics/regex-constructor-flags.ts | 5 +- tests/diagnostics/regex.ts | 3 +- .../regex-constructor-flags.ts.txt | 19 ++----- tests/harness/__snapshots__/regex.ts.txt | 27 ++++------ tests/harness/corpus-costs.json | 2 + 16 files changed, 137 insertions(+), 80 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5857-regexp-unicode-sets.ts.json create mode 100644 tests/corpus/5857-regexp-unicode-sets.ts diff --git a/docs/content/limitations/builtin-apis/regular-expressions.mdx b/docs/content/limitations/builtin-apis/regular-expressions.mdx index 4578cfc93..a765bbe3c 100644 --- a/docs/content/limitations/builtin-apis/regular-expressions.mdx +++ b/docs/content/limitations/builtin-apis/regular-expressions.mdx @@ -1 +1 @@ -- **Regular expressions:** Native checked storage preserves identity, `source`, `flags`, flag properties, and stateful `test`. Static `exec`, global `match`, and numeric `lastIndex` access use the native matcher. Runtime constructors accept checked strings and native regex copies; `replace` and `replaceAll` accept native regex values with string templates or callbacks, including captures, named groups, and UTF-16 offsets. Non-numeric `lastIndex`, detached methods, and `exec` through an untyped receiver are unsupported. The `d` (match indices) and `v` (unicode sets) flags are unsupported: regex literals and `new RegExp` calls with a literal flag string containing them fail to compile with SC1120, and `new RegExp` with a computed flag string containing them throws an error naming the flag. +- **Regular expressions:** Native checked storage preserves identity, `source`, `flags`, flag properties, and stateful `test`, and the flag getters (`global`, `unicodeSets`, and the rest) compile on statically typed regexes. Static `exec`, global `match`, and numeric `lastIndex` access use the native matcher. Runtime constructors accept checked strings and native regex copies; `replace` and `replaceAll` accept native regex values with string templates or callbacks, including captures, named groups, and UTF-16 offsets. Non-numeric `lastIndex`, detached methods, and `exec` through an untyped receiver are unsupported. The `v` (unicode sets) flag supports class set operations (`--`, `&&`), nested classes, `\q{...}` string literals, and properties of strings such as `\p{RGI_Emoji}`. `new RegExp` with an invalid pattern throws a `SyntaxError` whose message comes from the native engine and can differ from Node's. The `d` (match indices) flag is unsupported: regex literals and `new RegExp` calls with a literal flag string containing it fail to compile with SC1120, and `new RegExp` with a computed flag string containing it throws an error naming the flag. diff --git a/packages/compiler/src/diagnostics/diagnostic.ts b/packages/compiler/src/diagnostics/diagnostic.ts index 9a7b4a37a..eaae1b531 100644 --- a/packages/compiler/src/diagnostics/diagnostic.ts +++ b/packages/compiler/src/diagnostics/diagnostic.ts @@ -411,7 +411,7 @@ export const UNSUPPORTED: Record = { SC1120: { feature: "this regex feature", milestone: "later", - hint: "supported: literal regexes with the g/i/m/s/u/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \\k), .source/.flags, and string replace/replaceAll/split with string replacement templates", + hint: "supported: literal regexes with the g/i/m/s/u/v/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \\k), .source/.flags, and string replace/replaceAll/split with string replacement templates", }, // SC1121 (stateful g/y regex tests) shipped — code retired, do not reuse. }; diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index b0203af0d..ca202c87d 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -8890,20 +8890,10 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { }; const pattern = strArg(args[0], "pattern"); const flags = strArg(args[1], "flags argument"); - // Node accepts the 'd' and 'v' flags the engine does not have; a - // literal flags string refuses here like the literal regex form. - if (flags.kind === "strLit" && args[1] !== undefined) { - for (const f of ["d", "v"]) { - if (flags.value.includes(f)) { - lowerer.unsupported( - "SC1120", - args[1], - f === "d" - ? "the regex 'd' flag (match indices)" - : "the regex 'v' flag (unicode sets)", - ); - } - } + // Node accepts the 'd' flag the engine does not have; a literal + // flags string refuses here like the literal regex form. + if (flags.kind === "strLit" && args[1] !== undefined && flags.value.includes("d")) { + lowerer.unsupported("SC1120", args[1], "the regex 'd' flag (match indices)"); } return { kind: "libCall", diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 61dfcef3b..391dd7c88 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -5332,6 +5332,27 @@ export function lowerIntrinsicProperty( loc: locOf(expr), }; } + // The flag getters answer whether `flags` holds the flag's letter. + const flag = REGEX_FLAG_GETTERS.get(name); + if (flag !== undefined) { + const loc = locOf(expr); + const flags: IrExpr = { + kind: "regexIntrinsic", + method: "flags", + receiver: strictReceiver({ kind: "regex" }), + args: [], + type: STRING, + loc, + }; + return { + kind: "strIntrinsic", + method: "includes", + receiver: flags, + args: [{ kind: "strLit", value: flag, type: STRING, loc }], + type: BOOL, + loc, + }; + } if (name === "test") { lowerer.unsupported("SC1090", expr, "regex methods as values (call 'test' directly)"); } @@ -13251,10 +13272,22 @@ function lowerRuntimeKeyIn( return { kind: "call", callee: helper, args: [keyIr, recv], type: BOOL, loc }; } +/** RegExp.prototype's flag getters and the flag each one reads. */ +const REGEX_FLAG_GETTERS: ReadonlyMap = new Map([ + ["hasIndices", "d"], + ["global", "g"], + ["ignoreCase", "i"], + ["multiline", "m"], + ["dotAll", "s"], + ["unicode", "u"], + ["unicodeSets", "v"], + ["sticky", "y"], +]); + /** A regex literal `/ab+c/gi` → regexLit (fresh state per evaluation, * shared bytecode per (pattern, flags) pair). The TS parser has already syntax-checked the literal; - * what remains here is the flag-alphabet fence (d and v are - * declared-valid TS flags outside this slice). Named capture groups + * what remains here is the flag-alphabet fence (d is a + * declared-valid TS flag outside this slice). Named capture groups * `(?...)` and `\k` backreferences compile — libregexp * executes them natively, replace templates resolve `$` at * runtime, and `.groups` reads desugar at their access sites @@ -13265,20 +13298,19 @@ export function lowerRegexLiteral(lowerer: Lowerer, expr: ts.RegularExpressionLi const text = expr.text; const lastSlash = text.lastIndexOf("/"); const pattern = text.slice(1, lastSlash); - const flags = text.slice(lastSlash + 1); - for (const f of flags) { - if (!"gimsuy".includes(f)) { + const written = text.slice(lastSlash + 1); + for (const f of written) { + if (!"gimsuvy".includes(f)) { lowerer.unsupported( "SC1120", expr, - f === "d" - ? "the regex 'd' flag (match indices)" - : f === "v" - ? "the regex 'v' flag (unicode sets)" - : `the regex '${f}' flag`, + f === "d" ? "the regex 'd' flag (match indices)" : `the regex '${f}' flag`, ); } } + // `flags`, `toString()` and inspection list the flags in getter order, + // whatever order the literal spells them in. + const flags = [..."gimsuvy"].filter((f) => written.includes(f)).join(""); return { kind: "regexLit", pattern, flags, type: REGEX, loc: locOf(expr) }; } diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 41284118b..4041cd265 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -2564,7 +2564,7 @@ export type IrExpr = } /** A regex literal `/ab+c/gi`. `pattern` is the text between the slashes * exactly as written (escapes UNprocessed — the regex engine parses them), - * `flags` the trailing flags in source order (alphabet fenced to gimsuy by + * `flags` the trailing flags in getter order (alphabet fenced to gimsuvy by * the frontend). Backends intern ONE immortal static per (pattern, flags) * pair — like string literals, so repeated evaluation is free and * `re === re` would hold — and compile the pattern lazily at first use diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 8278fe356..dec6ab201 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -1932,8 +1932,8 @@ function validateFunction( } case "regexLit": { if (e.type.kind !== "regex") err("regexLit must be regex-typed", e.loc); - if (!/^[gimsuy]*$/.test(e.flags)) { - err(`regexLit flags "${e.flags}" outside the supported alphabet (gimsuy)`, e.loc); + if (!/^[gimsuvy]*$/.test(e.flags)) { + err(`regexLit flags "${e.flags}" outside the supported alphabet (gimsuvy)`, e.loc); } if (new Set(e.flags).size !== e.flags.length) { err(`regexLit flags "${e.flags}" contain a duplicate`, e.loc); diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 9a0188cf3..683df3777 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -192,7 +192,7 @@ "name": "this regex feature", "status": "unsupported", "code": "SC1120", - "note": "supported: literal regexes with the g/i/m/s/u/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \\k), .source/.flags, and string replace/replaceAll/split with string replacement templates" + "note": "supported: literal regexes with the g/i/m/s/u/v/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \\k), .source/.flags, and string replace/replaceAll/split with string replacement templates" }, { "id": "diagnostic.sc2001", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5857-regexp-unicode-sets.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5857-regexp-unicode-sets.ts.json new file mode 100644 index 000000000..20742aa5a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5857-regexp-unicode-sets.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5857-regexp-unicode-sets.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_regex.c b/packages/runtime/src/scr_regex.c index 2526ca595..b24261a4d 100644 --- a/packages/runtime/src/scr_regex.c +++ b/packages/runtime/src/scr_regex.c @@ -85,6 +85,7 @@ static int scr_lre_flags(const ScrStr *flags) { case 's': mask |= LRE_FLAG_DOTALL; break; case 'u': mask |= LRE_FLAG_UNICODE; break; case 'y': mask |= LRE_FLAG_STICKY; break; + case 'v': mask |= LRE_FLAG_UNICODE_SETS; break; default: scr_trap_fmt("scriptc: internal error: unexpected regex flag '%c'\n", flags->data[i]); @@ -201,7 +202,7 @@ static uint8_t *scr_regex_bc(ScrRegex *re) { const char *pat = re->source->data; size_t pat_len = re->source->len; char *cesu = NULL; - if (!(flags & LRE_FLAG_UNICODE)) { + if (!(flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS))) { cesu = scr_pattern_cesu8(re->source, &pat_len); if (cesu) pat = cesu; } @@ -2042,11 +2043,9 @@ ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) { } /* Valid in Node, absent from the engine: name the gap rather than * report a flag Node accepts as invalid. */ - if (seen_flags & ((1u << 6) | (1u << 7))) { + if (seen_flags & (1u << 6)) { static const char d_msg[] = "the regex 'd' flag (match indices) is not supported yet [SC1120]"; - static const char v_msg[] = "the regex 'v' flag (unicode sets) is not supported yet [SC1120]"; - if (seen_flags & (1u << 6)) scr_throw_error_msg(SCR_ERR_ERROR, d_msg, sizeof d_msg - 1); - else scr_throw_error_msg(SCR_ERR_ERROR, v_msg, sizeof v_msg - 1); + scr_throw_error_msg(SCR_ERR_ERROR, d_msg, sizeof d_msg - 1); return NULL; } ScrRegex *re = calloc(1, sizeof *re); @@ -2057,11 +2056,11 @@ ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) { re->source = pattern->len > 0 ? scr_str_retain(pattern) : scr_str_new("(?:)", 4); /* Public flags use getter order, independently of constructor spelling. * Validate first so duplicates and invalid flags retain their errors. */ - char canonical[6]; + char canonical[8]; size_t flag_count = 0; - const char *order = "gimsuy"; - for (unsigned i = 0; i < 6; i++) { - if (seen_flags & (1u << i)) canonical[flag_count++] = order[i]; + static const unsigned order_bits[] = {0, 1, 2, 3, 4, 7, 5}; + for (unsigned i = 0; i < sizeof order_bits / sizeof order_bits[0]; i++) { + if (seen_flags & (1u << order_bits[i])) canonical[flag_count++] = "gimsuvy"[i]; } re->flags = flag_count == flags->len && memcmp(canonical, flags->data, flag_count) == 0 ? scr_str_retain(flags) : scr_str_new(canonical, flag_count); @@ -2078,7 +2077,7 @@ ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) { const char *pat = re->source->data; size_t pat_len = re->source->len; char *cesu = NULL; - if (!(lre_flags & LRE_FLAG_UNICODE)) { + if (!(lre_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS))) { cesu = scr_pattern_cesu8(re->source, &pat_len); if (cesu) pat = cesu; } diff --git a/packages/runtime/vendor/quickjs-ng/libregexp.c b/packages/runtime/vendor/quickjs-ng/libregexp.c index 2191c6879..09720139d 100644 --- a/packages/runtime/vendor/quickjs-ng/libregexp.c +++ b/packages/runtime/vendor/quickjs-ng/libregexp.c @@ -1020,7 +1020,7 @@ static int parse_class_string_disjunction(REParseState *s, REStringList *cr, for(;;) { str.size = 0; while (*p != '}' && *p != '|') { - c = get_class_atom(s, NULL, &p, false); + c = get_class_atom(s, NULL, &p, true); if (c < 0) goto fail; if (dbuf_put_u32(&str, c)) { @@ -1193,7 +1193,7 @@ static int get_class_atom(REParseState *s, REStringList *cr, case '^': case '`': case '~': - if (s->unicode_sets && p[1] == c) { + if (s->unicode_sets && inclass && p[1] == c) { /* forbidden double characters */ return re_parse_error(s, "invalid class set operation in regular expression"); } @@ -1208,7 +1208,7 @@ static int get_class_atom(REParseState *s, REStringList *cr, case '/': case '-': case '|': - if (s->unicode_sets) { + if (s->unicode_sets && inclass) { /* invalid characters in unicode sets */ return re_parse_error(s, "invalid character in class in regular expression"); } diff --git a/tests/corpus/5857-regexp-unicode-sets.ts b/tests/corpus/5857-regexp-unicode-sets.ts new file mode 100644 index 000000000..3bfdaf692 --- /dev/null +++ b/tests/corpus/5857-regexp-unicode-sets.ts @@ -0,0 +1,48 @@ +// The regex v flag (unicode sets): class subtraction and intersection, nested +// classes, \q{...} string literals, properties of strings, case folding, +// code-point iteration, and the constructor with literal and computed flags. +// Regex literals report their flags in getter order. Node.js prints the same. +const letters = /[\p{L}--[a-z]]/gv; +console.log(letters.flags, letters.source, String(letters), letters); +console.log("aBcD-É".match(letters)); +console.log(/[[a-z]&&[aeiou]]/v.test("e"), /[[a-z]&&[aeiou]]/v.test("b")); +console.log("vowels: education".replace(/[[a-z]&&[^aeiou]]/gv, "_")); +console.log("x😀y".match(/[\q{😀|xy}]/gv), "xy😀".match(/[\q{😀|xy}]/gv)); +console.log("abcab".match(/[\q{abc}a]/gv)); +console.log(/^\p{RGI_Emoji}$/v.test("👍🏽"), /^\p{RGI_Emoji}$/v.test("a")); +console.log("hi 🇫🇷 1️⃣".match(/\p{RGI_Emoji_Flag_Sequence}|\p{Emoji_Keycap_Sequence}/gv)); +console.log("family \u{1F468}\u200D\u{1F469}\u200D\u{1F467} ok".replace(/\p{RGI_Emoji_ZWJ_Sequence}/v, "[zwj]")); +console.log(/[^\d--[5]]/v.test("5"), /[^\d--[5]]/v.test("7"), /[^\d--[5]]/v.test("x")); +console.log(/[[0-9]--[5-9]]+/v.exec("98123")?.[0]); +console.log(/[\p{Lu}--[A-C]]/vi.test("a"), /[\p{Lu}--[A-C]]/vi.test("d"), /[^\p{Lu}]/vi.test("A")); +console.log("😀😀".replace(/(?:)/gv, "-"), "😀😀".split(/(?:)/v)); +console.log("a😀b".replace(/./gv, (c) => `<${c}>`)); +console.log("A1b2C3".replace(/[\w--\d]/gv, (c) => c.toLowerCase())); +console.log("one, two;three".split(/[[\p{P}\s]--[\-]]+/v)); +const m = /(?[\p{L}--\p{Lu}]+)-(?[\d--[0]]+)/v.exec("ABcd-102"); +if (m) console.log(m[0], m.index, m.groups?.word, m.groups?.num); +console.log("2024-07".replace(/(?[\d]{4})-(?\d\d)/v, "$/$")); + +const spelled = /x/vgimsy; +console.log(spelled.flags, String(spelled), /x/yg.flags, /x/mi.flags); +console.log(letters.global, letters.unicodeSets, letters.unicode, letters.ignoreCase, letters.hasIndices); +console.log(spelled.multiline, spelled.dotAll, spelled.sticky, /x/u.unicode, /x/u.unicodeSets); + +console.log(new RegExp("[\\w--\\d]", "v").test("5"), new RegExp("[\\w--\\d]", "vg").flags); +const computed = ["v", "gv", "iv"]; +for (const flags of computed) { + const re = new RegExp("[[0-9a-f]--[5]]", flags); + console.log(flags, re.flags, re.test("5"), re.test("F")); +} +for (const flags of ["uv", "vv"]) { + try { + new RegExp("a", flags); + } catch (e) { + console.log((e as Error).name, (e as Error).message); + } +} +const u: unknown = /[\q{abc}]/v; +console.log(u instanceof RegExp, String(u)); +// Punctuation that only class contents reserve stays literal outside them. +console.log(/x-y/v.test("x-y"), /a,,b/v.test("a,,b"), /a&&b|!!/v.exec("!!")?.[0], /a--b/v.test("a--b")); +console.log("a-b".match(/[\q{\-}]/gv), "key-value".split(/-/v)); diff --git a/tests/diagnostics/regex-constructor-flags.ts b/tests/diagnostics/regex-constructor-flags.ts index 3d388601c..cbf7de7ee 100644 --- a/tests/diagnostics/regex-constructor-flags.ts +++ b/tests/diagnostics/regex-constructor-flags.ts @@ -1,4 +1,3 @@ -// new RegExp with literal d or v flags refuses like the regex literal -// forms; computed flags reach the runtime, which names the same gap. -const sets = new RegExp("[\\w--\\d]", "v"); +// new RegExp with a literal d flag refuses like the regex literal form; +// computed flags reach the runtime, which names the same gap. const indices = new RegExp("cat", "dg"); diff --git a/tests/diagnostics/regex.ts b/tests/diagnostics/regex.ts index ec29bc70e..e2b3fc4ae 100644 --- a/tests/diagnostics/regex.ts +++ b/tests/diagnostics/regex.ts @@ -1,8 +1,7 @@ -// The d/v flags are outside the native slice; .groups needs a +// The d flag is outside the native slice; .groups needs a // statically-known regex. Named capture groups compile (corpus 2604). // Method values and regex union arms remain unsupported; arrays compile. const indices = /cat/d; -const sets = /[\p{L}]/v; const asValue = /x/.test; const maybe: RegExp | undefined = /a/; function readGroups(re: RegExp): void { diff --git a/tests/harness/__snapshots__/regex-constructor-flags.ts.txt b/tests/harness/__snapshots__/regex-constructor-flags.ts.txt index 74aa9ab94..e3aaeb1d9 100644 --- a/tests/harness/__snapshots__/regex-constructor-flags.ts.txt +++ b/tests/harness/__snapshots__/regex-constructor-flags.ts.txt @@ -1,17 +1,8 @@ -regex-constructor-flags.ts:3:39 - error SC1120: the regex 'v' flag (unicode sets) is not supported yet +regex-constructor-flags.ts:3:35 - error SC1120: the regex 'd' flag (match indices) is not supported yet - 2 | // forms; computed flags reach the runtime, which names the same gap. - 3 | const sets = new RegExp("[\\w--\\d]", "v"); - | ^~~ - 4 | const indices = new RegExp("cat", "dg"); - - hint: supported: literal regexes with the g/i/m/s/u/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \k), .source/.flags, and string replace/replaceAll/split with string replacement templates - -regex-constructor-flags.ts:4:35 - error SC1120: the regex 'd' flag (match indices) is not supported yet - - 3 | const sets = new RegExp("[\\w--\\d]", "v"); - 4 | const indices = new RegExp("cat", "dg"); + 2 | // computed flags reach the runtime, which names the same gap. + 3 | const indices = new RegExp("cat", "dg"); | ^~~~ - 5 | + 4 | - hint: supported: literal regexes with the g/i/m/s/u/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \k), .source/.flags, and string replace/replaceAll/split with string replacement templates \ No newline at end of file + hint: supported: literal regexes with the g/i/m/s/u/v/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \k), .source/.flags, and string replace/replaceAll/split with string replacement templates \ No newline at end of file diff --git a/tests/harness/__snapshots__/regex.ts.txt b/tests/harness/__snapshots__/regex.ts.txt index 2db17d9c8..22bdbef90 100644 --- a/tests/harness/__snapshots__/regex.ts.txt +++ b/tests/harness/__snapshots__/regex.ts.txt @@ -3,31 +3,22 @@ regex.ts:4:17 - error SC1120: the regex 'd' flag (match indices) is not supporte 3 | // Method values and regex union arms remain unsupported; arrays compile. 4 | const indices = /cat/d; | ^~~~~~ - 5 | const sets = /[\p{L}]/v; + 5 | const asValue = /x/.test; - hint: supported: literal regexes with the g/i/m/s/u/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \k), .source/.flags, and string replace/replaceAll/split with string replacement templates + hint: supported: literal regexes with the g/i/m/s/u/v/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \k), .source/.flags, and string replace/replaceAll/split with string replacement templates -regex.ts:5:14 - error SC1120: the regex 'v' flag (unicode sets) is not supported yet +regex.ts:5:17 - error SC1090: regex methods as values (call 'test' directly) are not supported yet 4 | const indices = /cat/d; - 5 | const sets = /[\p{L}]/v; - | ^~~~~~~~~~ - 6 | const asValue = /x/.test; - - hint: supported: literal regexes with the g/i/m/s/u/y flags — .test(), .exec()/.match()/.matchAll(), named capture groups (.groups, $ templates, \k), .source/.flags, and string replace/replaceAll/split with string replacement templates - -regex.ts:6:17 - error SC1090: regex methods as values (call 'test' directly) are not supported yet - - 5 | const sets = /[\p{L}]/v; - 6 | const asValue = /x/.test; + 5 | const asValue = /x/.test; | ^~~~~~~~ - 7 | const maybe: RegExp | undefined = /a/; + 6 | const maybe: RegExp | undefined = /a/; -regex.ts:10:22 - error SC2020: 'RegExpExecArray.groups' is part of the standard library types but has no scriptc lowering yet +regex.ts:9:22 - error SC2020: 'RegExpExecArray.groups' is part of the standard library types but has no scriptc lowering yet - 9 | const m = re.exec("2024-07"); - 10 | if (m) console.log(m.groups); + 8 | const m = re.exec("2024-07"); + 9 | if (m) console.log(m.groups); | ^~~~~~~~ - 11 | } + 10 | } hint: '.groups' lowers when the match's regex is STATICALLY known — a regex literal, or a const initialized with one (the group-name table is built at compile time) — and the read is not an optional-chain step: narrow the match instead (if (m) { m.groups } or m!.groups) \ No newline at end of file diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index d1a8838a9..7c01dc937 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1851,6 +1851,7 @@ "5838-qs-stringify-bigint.ts": 2207, "5842-qs-parse-null-prototype.ts": 1774, "5843-qs-parse-null-prototype-js.mjs": 1559, + "5857-regexp-unicode-sets.ts": 3350, "5858-disposable-stack.ts": 3050, "5859-disposable-stack-js.js": 3100, "5881-inspect-weak-collections.ts": 2615, @@ -4519,6 +4520,7 @@ "5838-qs-stringify-bigint.ts": 3519, "5842-qs-parse-null-prototype.ts": 7077, "5843-qs-parse-null-prototype-js.mjs": 5395, + "5857-regexp-unicode-sets.ts": 3900, "5858-disposable-stack.ts": 3750, "5859-disposable-stack-js.js": 3600, "5881-inspect-weak-collections.ts": 2915, From 51777dee63f42fa18d8d9e92578f28a2d4ffc57e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 03:43:06 -0500 Subject: [PATCH 054/117] Add markAsUncloneable and worker[Symbol.asyncDispose] markAsUncloneable(value) marks a plain object, a record, an error or a class instance (scr_json.c); structuredClone and postMessage then throw DataCloneError "Cannot clone object of unsupported type." for it, also where it is nested. As in Node, the mark has no effect on primitives, arrays, typed arrays and ArrayBuffers. Marked values are retained until the thread exits; with nothing marked, the clone paths add one branch. worker[Symbol.asyncDispose]() terminates the worker and resolves with undefined after its 'exit' event, so `await using` disposes a Worker at the end of its block. The Worker handle's symbol_get op answers the well-known symbol: the symbol unit registers Symbol.asyncDispose with the dyn core when the program names it, and scr_dyn_is_async_dispose_symbol tells the worker unit, so worker programs that never name the symbol do not link the symbol unit. static-support.json adds rows for markAsUncloneable, isInternalThread (already lowered as false and declared) and worker[Symbol.asyncDispose](). Corpus 5990-5991 match Node v24.22.0; corpus-costs.json records their costs. --- .../limitations/native-worker-threads.mdx | 2 +- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 22 +++--- .../generated/node-v24-backlog.json | 46 ++++++----- .../generated/node-v24-internal.json | 27 +++++-- internal/compatibility/static-support.json | 2 + .../ambient/scriptc-node-fallback.d.ts | 5 ++ .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../src/frontend/lowering/builtin-calls.ts | 4 + .../src/frontend/lowering/builtins/workers.ts | 19 +++++ .../compiler/src/ir/builtin-signatures.ts | 2 + .../corpus/5990-worker-uncloneable.mjs.json | 6 ++ .../corpus/5991-worker-async-dispose.mjs.json | 6 ++ packages/runtime/src/scr_dyn.h | 11 +++ packages/runtime/src/scr_json.c | 79 +++++++++++++++++++ packages/runtime/src/scr_message.c | 4 + packages/runtime/src/scr_symbol.c | 5 ++ packages/runtime/src/scr_worker_events.c | 39 +++++++++ tests/corpus/5990-worker-uncloneable.mjs | 59 ++++++++++++++ tests/corpus/5991-worker-async-dispose.mjs | 25 ++++++ tests/harness/corpus-costs.json | 4 + 21 files changed, 329 insertions(+), 41 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5990-worker-uncloneable.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5991-worker-async-dispose.mjs.json create mode 100644 tests/corpus/5990-worker-uncloneable.mjs create mode 100644 tests/corpus/5991-worker-async-dispose.mjs diff --git a/docs/content/limitations/native-worker-threads.mdx b/docs/content/limitations/native-worker-threads.mdx index 972eadeca..0510936d6 100644 --- a/docs/content/limitations/native-worker-threads.mdx +++ b/docs/content/limitations/native-worker-threads.mdx @@ -1,6 +1,6 @@ `node:worker_threads` runs workers as native threads. Worker entry points must resolve at build time: use a source-relative `new URL("./worker.ts", import.meta.url)`, the current module URL, an absolute path, or CommonJS `__filename`. Each worker initializes its own module state, event loop, environment snapshot, and reference-counted heap. Nested workers inherit their parent's environment snapshot. Supported constructor options are `workerData`, `argv`, a `transferList` of MessagePorts, `name` (reported by `threadName` and `worker.threadName`), `stdout`, `stderr` and `stdin`, and `resourceLimits.stackSizeMb`, which sets the worker thread's stack size (at least 192 KiB; without it a worker's stack is 8 MiB, where Node's is 4 MiB). The `resourceLimits` heap limits (`maxOldGenerationSizeMb`, `maxYoungGenerationSizeMb`, and `codeRangeSizeMb`), `worker.resourceLimits` while the worker runs, and `resourceLimits` read inside a worker are refused; in the main thread `resourceLimits` is `{}`, and after a worker exits `worker.resourceLimits` is `{}`, as in Node. With the `stdout` or `stderr` option, the worker's writes to that stream reach `worker.stdout` or `worker.stderr`, a Readable that ends after the worker's `'exit'` event; its chunks arrive in order with the worker's other events. Without the option a worker writes to the process's own output, and reading `worker.stdout` or `worker.stderr` is refused. With the `stdin` option, `worker.stdin` is a Writable whose chunks the worker reads from `process.stdin`, in order with the worker's other events, and `process.stdin` ends when `worker.stdin` ends; without it `worker.stdin` is `null` and the worker's `process.stdin` ends without data, as in Node. Runtime paths, `eval`, loaders, and shared environments are unsupported. `setEnvironmentData` and `getEnvironmentData` keep a map per thread with SameValueZero keys; each new Worker starts from a clone of its parent's entries taken by the constructor, which throws `DataCloneError` when an entry cannot be cloned. Worker argument strings containing null bytes are also unsupported. -Workers support `online`, `message`, `error`, and `exit` events, `postMessage`, `terminate`, `ref`, and `unref`. A worker's uncaught exception reaches its `error` listeners as Node's error serializer sends it: an Error keeps the nearest of `Error` and its six native subclasses (an `AggregateError` arrives as an `Error` named `AggregateError`) along with its name, message, cause, and other data properties and their enumerability, and other thrown values clone as messages do. An unhandled rejection whose reason is not error-like arrives as an `UnhandledPromiseRejection` Error with code `ERR_UNHANDLED_REJECTION` quoting the reason. A thrown value that does not clone, such as a function, arrives as an `ERR_WORKER_UNSERIALIZABLE_ERROR` Error, where Node sends its `util.inspect` string. `new MessageChannel()` from `node:worker_threads` makes two entangled MessagePorts, in one thread or across threads once a port is transferred, with `receiveMessageOnPort`. Port messages arrive in Node's order: each port's queued messages as one batch before `setImmediate` callbacks, a port's own `'close'` after the poll phase, and the other port's `'close'` after its queued messages while the loop keeps running. `receiveMessageOnPort(parentPort)` in a worker takes the parent's next message. A port's `onmessage` property and `addEventListener` are unsupported. `BroadcastChannel` delivers each message to every other open channel with the same name, in any thread, as a `'message'` `MessageEvent` through `onmessage` and `addEventListener`; an open channel keeps the process alive until `close()` or `unref()`. A `messageerror` event is never dispatched. The parent port supports message listeners, `postMessage`, `close`, `start`, `ref`, `unref`, and `hasRef`. Messages clone primitives, plain object graphs, arrays, errors, ArrayBuffers, typed arrays, and DataViews, preserving cycles and aliases. Program class instances arrive as plain objects with their own data properties, without their prototype, methods, accessors, or private fields, as in Node. `markAsUntransferable` marks objects for the current thread, and a marked ArrayBuffer or MessagePort in a transfer list throws `DataCloneError`, as does the ArrayBuffer of a pooled Buffer; marked objects other than ArrayBuffers stay alive until their thread exits. A MessagePort travels with a message when the message's transfer list (an array or `{ transfer }`) names it, and the sending port is unusable afterwards; a port in a message without that listing throws `DataCloneError`. Other transferable values, functions, proxies, and other native handles are refused. SharedArrayBuffers share their backing storage while retaining separate wrappers in each thread. Graphs made immutable with `@scriptc/threads` are passed by reference instead of cloned; see [Sharing Data Between Workers](/docs/threads). +Workers support `online`, `message`, `error`, and `exit` events, `postMessage`, `terminate`, `ref`, and `unref`. `worker[Symbol.asyncDispose]()` terminates the worker and resolves with `undefined` after its `exit` event, so `await using` disposes a Worker at the end of its block. A worker's uncaught exception reaches its `error` listeners as Node's error serializer sends it: an Error keeps the nearest of `Error` and its six native subclasses (an `AggregateError` arrives as an `Error` named `AggregateError`) along with its name, message, cause, and other data properties and their enumerability, and other thrown values clone as messages do. An unhandled rejection whose reason is not error-like arrives as an `UnhandledPromiseRejection` Error with code `ERR_UNHANDLED_REJECTION` quoting the reason. A thrown value that does not clone, such as a function, arrives as an `ERR_WORKER_UNSERIALIZABLE_ERROR` Error, where Node sends its `util.inspect` string. `new MessageChannel()` from `node:worker_threads` makes two entangled MessagePorts, in one thread or across threads once a port is transferred, with `receiveMessageOnPort`. Port messages arrive in Node's order: each port's queued messages as one batch before `setImmediate` callbacks, a port's own `'close'` after the poll phase, and the other port's `'close'` after its queued messages while the loop keeps running. `receiveMessageOnPort(parentPort)` in a worker takes the parent's next message. A port's `onmessage` property and `addEventListener` are unsupported. `BroadcastChannel` delivers each message to every other open channel with the same name, in any thread, as a `'message'` `MessageEvent` through `onmessage` and `addEventListener`; an open channel keeps the process alive until `close()` or `unref()`. A `messageerror` event is never dispatched. The parent port supports message listeners, `postMessage`, `close`, `start`, `ref`, `unref`, and `hasRef`. Messages clone primitives, plain object graphs, arrays, errors, ArrayBuffers, typed arrays, and DataViews, preserving cycles and aliases. Program class instances arrive as plain objects with their own data properties, without their prototype, methods, accessors, or private fields, as in Node. `markAsUntransferable` marks objects for the current thread, and a marked ArrayBuffer or MessagePort in a transfer list throws `DataCloneError`, as does the ArrayBuffer of a pooled Buffer; marked objects other than ArrayBuffers stay alive until their thread exits. `markAsUncloneable` marks a plain object, an error, or a class instance, and `structuredClone` and `postMessage` then throw `DataCloneError` for it, also where it is nested; as in Node, the mark has no effect on primitives, arrays, typed arrays, and ArrayBuffers. A plain object that the compiler copies into a container with a fixed element type, such as an array literal whose elements all have one shape, is a separate object in the copy, which is not marked. Marked objects stay alive until their thread exits. A MessagePort travels with a message when the message's transfer list (an array or `{ transfer }`) names it, and the sending port is unusable afterwards; a port in a message without that listing throws `DataCloneError`. Other transferable values, functions, proxies, and other native handles are refused. SharedArrayBuffers share their backing storage while retaining separate wrappers in each thread. Graphs made immutable with `@scriptc/threads` are passed by reference instead of cloned; see [Sharing Data Between Workers](/docs/threads). SharedArrayBuffer storage is fixed-length. Atomics supports integer `load`, `store`, `exchange`, `compareExchange`, `add`, `sub`, `and`, `or`, and `xor` over 8-, 16-, and 32-bit integer arrays. `wait` and `notify` use Int32Array views; BigInt atomics, `waitAsync`, and growable buffers are unsupported. Atomics operations run as sequentially consistent atomic instructions and take no lock. Other reads and writes of shared storage access each element atomically; a copy, fill, or conversion that runs while another thread writes the same storage can observe some of those writes, as in Node. `terminate` unwinds at runtime checkpoints, including loops and parked atomic waits, without running JavaScript catch or finally blocks. Blocking native calls finish before the next checkpoint. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 55fdcc23a..ca824b4cc 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "f2365d9fcaf87f1ccf46", + "artifactVersion": "b67c1214a0f3f7f3c49f", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index e3da0a715..986725b5d 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -884,9 +884,9 @@ "apiEntries": 66, "static": { "supported": 0, - "partial": 43, + "partial": 46, "refused": 0, - "not-implemented": 23, + "not-implemented": 20, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -83564,9 +83564,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -83955,9 +83955,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -84070,9 +84070,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 7c7453777..eebcf8083 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1131, - "verify-gap": 2198, + "audit-partial": 1134, + "verify-gap": 2195, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -84573,12 +84573,14 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.worker", + "tests": [ + "tests/corpus/5991-worker-async-dispose.mjs" + ] } } }, @@ -85052,12 +85054,14 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.worker_threads.markAsUncloneable", + "tests": [ + "tests/corpus/5990-worker-uncloneable.mjs" + ] } } }, @@ -85185,12 +85189,14 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:worker_threads", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:worker_threads.isInternalThread", + "tests": [ + "tests/corpus/5990-worker-uncloneable.mjs" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index c444c9934..2dfa8f8bd 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -941,9 +941,9 @@ "apiEntries": 66, "static": { "supported": 0, - "partial": 43, + "partial": 46, "refused": 0, - "not-implemented": 23, + "not-implemented": 20, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -113045,6 +113045,8 @@ "tests/corpus/5874-worker-stdio-streams.ts", "tests/corpus/5875-worker-stdout-pipe.cjs", "tests/corpus/5879-worker-stdin.ts", + "tests/corpus/5990-worker-uncloneable.mjs", + "tests/corpus/5991-worker-async-dispose.mjs", "tests/corpus/native-worker-clone-errors.ts", "tests/corpus/native-worker-commonjs.cjs", "tests/corpus/native-worker-delayed-messages.ts", @@ -113936,8 +113938,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.worker", + "tests": [ + "tests/corpus/5991-worker-async-dispose.mjs" + ] }, "anchorSource": "exact" }, @@ -114394,8 +114399,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.worker_threads.markAsUncloneable", + "tests": [ + "tests/corpus/5990-worker-uncloneable.mjs" + ] }, "anchorSource": "exact" }, @@ -114519,8 +114527,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:worker_threads" + "status": "partial", + "evidence": "compiler-feature:worker_threads.isInternalThread", + "tests": [ + "tests/corpus/5990-worker-uncloneable.mjs" + ] }, "anchorSource": "chapter" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 04a98792b..67a9b95e0 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -211,6 +211,8 @@ {"chapter": "worker_threads", "symbols": ["worker_threads.getEnvironmentData", "worker_threads.setEnvironmentData"], "status": "partial", "evidence": ["tests/corpus/5803-worker-environment-data.ts", "tests/corpus/5804-worker-environment-data.cjs"]}, {"chapter": "worker_threads", "symbols": ["stdout", "stderr", "stdin"], "status": "partial", "evidence": ["tests/corpus/5874-worker-stdio-streams.ts", "tests/corpus/5875-worker-stdout-pipe.cjs", "tests/corpus/5879-worker-stdin.ts"]}, {"chapter": "worker_threads", "symbols": ["threadName", "worker_threads.markAsUntransferable", "worker_threads.isMarkedAsUntransferable"], "status": "partial", "evidence": ["tests/corpus/5870-worker-thread-names.ts", "tests/corpus/5871-worker-untransferable.cjs"]}, + {"chapter": "worker_threads", "symbols": ["worker_threads.markAsUncloneable", "isInternalThread"], "status": "partial", "evidence": ["tests/corpus/5990-worker-uncloneable.mjs"]}, + {"chapter": "worker_threads", "signatures": ["`worker[Symbol.asyncDispose]()`"], "status": "partial", "evidence": ["tests/corpus/5991-worker-async-dispose.mjs"]}, {"chapter": "worker_threads", "symbols": ["resourceLimits"], "status": "partial", "evidence": ["tests/corpus/5806-worker-resource-limits.ts"]}, {"chapter": "worker_threads", "symbols": ["BroadcastChannel extends EventTarget", "broadcastChannel.close", "broadcastChannel.postMessage", "broadcastChannel.ref", "broadcastChannel.unref", "onmessage"], "status": "partial", "evidence": ["tests/corpus/5800-broadcast-channel.ts", "tests/corpus/5801-broadcast-channel.cjs", "tests/corpus/5802-broadcast-channel-workers.ts"]}, {"chapter": "util", "symbols": ["util.types.isAnyArrayBuffer", "util.types.isArrayBuffer", "util.types.isArrayBufferView", "util.types.isDataView", "util.types.isTypedArray", "util.types.isUint8Array", "util.types.isUint8ClampedArray", "util.types.isUint16Array", "util.types.isUint32Array", "util.types.isInt8Array", "util.types.isInt16Array", "util.types.isInt32Array", "util.types.isFloat32Array", "util.types.isFloat64Array", "util.types.isMap", "util.types.isSet", "util.types.isWeakMap", "util.types.isWeakSet", "util.types.isRegExp", "util.types.isNativeError", "util.types.isPromise", "util.types.isProxy", "util.types.isAsyncFunction", "util.types.isGeneratorFunction", "util.types.isGeneratorObject"], "status": "partial", "evidence": ["tests/corpus/node24-util-types.ts", "tests/corpus/node24-util-types.js", "tests/corpus/node24-util-types.cjs", "tests/fixtures/node-types/util-types.ts"]}, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 9b67e50fc..d866c81f7 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -5857,6 +5857,8 @@ declare module "worker_threads" { readonly stderr: import("stream").Readable; /* with the stdin option: what the worker reads from process.stdin */ readonly stdin: import("stream").Writable | null; + /* terminate(), resolving with undefined once the worker exited */ + [Symbol.asyncDispose](): Promise; on(event: "online", listener: () => void): this; on(event: "message", listener: (value: any) => void): this; on(event: "error", listener: (error: any) => void): this; @@ -5906,6 +5908,9 @@ declare module "worker_threads" { export function getEnvironmentData(key: any): any; /* A marked object cannot be listed in a transfer list. */ export function markAsUntransferable(object: any): void; + /* structuredClone and postMessage throw DataCloneError for a marked + * object, error or class instance */ + export function markAsUncloneable(object: any): void; export function isMarkedAsUntransferable(object: any): boolean; /* Delivers each message to every other open channel with the name, in * any thread, as a 'message' MessageEvent. */ diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9b7b758e3..6516756e9 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -945,6 +945,7 @@ export const LIB_FN_SYMS: Record = { "worker.getEnvironmentData": "scr_worker_get_environment_data", "worker.markUntransferable": "scr_worker_mark_untransferable", "worker.isMarkedUntransferable": "scr_worker_is_marked_untransferable", + "dyn.markUncloneable": "scr_mark_uncloneable", "stream.workerStdio": "scr_stream_worker_stdio", "worker.broadcastChannel": "scr_worker_broadcast_channel", "event.broadcastInstall": "scr_et_broadcast_install", diff --git a/packages/compiler/src/frontend/lowering/builtin-calls.ts b/packages/compiler/src/frontend/lowering/builtin-calls.ts index b535b8a5d..037b3e5a7 100644 --- a/packages/compiler/src/frontend/lowering/builtin-calls.ts +++ b/packages/compiler/src/frontend/lowering/builtin-calls.ts @@ -2,6 +2,7 @@ import { lowerReadlineCursorCall } from "./builtins/readline.js"; import { lowerEnvironmentData, lowerReceiveMessageOnPort, + lowerUncloneable, lowerUntransferable, } from "./builtins/workers.js"; import * as ts from "../ts7/adapter.js"; @@ -117,6 +118,9 @@ export function lowerBuiltinCall( ) { return lowerUntransferable(lowerer, expr, bi.member); } + if (bi.module === "worker_threads" && bi.member === "markAsUncloneable") { + return lowerUncloneable(lowerer, expr); + } const builtinFn = builtinModuleFnOf(lowerer, bi.module, bi.member); if (!builtinFn) { lowerer.noLowering( diff --git a/packages/compiler/src/frontend/lowering/builtins/workers.ts b/packages/compiler/src/frontend/lowering/builtins/workers.ts index 1061f1389..2311e0f96 100644 --- a/packages/compiler/src/frontend/lowering/builtins/workers.ts +++ b/packages/compiler/src/frontend/lowering/builtins/workers.ts @@ -328,6 +328,25 @@ export function lowerEnvironmentData( }; } +/** markAsUncloneable(value): structuredClone and postMessage then throw + * DataCloneError for the value (scr_json.c). It needs no worker runtime. */ +export function lowerUncloneable(lowerer: Lowerer, call: ts.CallExpression): IrExpr { + const args = call.arguments; + if (args.length > 1 || args.some(ts.isSpreadElement)) { + lowerer.noLowering(`markAsUncloneable with ${args.length} arguments`, call); + } + const loc = locOf(call); + const value: IrExpr = args[0] + ? lowerer.lowerExprExpecting(args[0], DYN) + : { + kind: "dynFrom", + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type: DYN, + loc, + }; + return { kind: "libCall", fn: "dyn.markUncloneable", args: [value], type: VOID, loc }; +} + /** markAsUntransferable(value) and isMarkedAsUntransferable(value): marks * kept by this thread (an ArrayBuffer's on its storage). */ export function lowerUntransferable( diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 40fb951c3..6c09eeb01 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1132,6 +1132,8 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * (scr_worker_events.c; the value borrowed). */ "worker.markUntransferable": { argTypes: [DYN], result: VOID }, "worker.isMarkedUntransferable": { argTypes: [DYN], result: BOOL }, + /** markAsUncloneable(value) (scr_json.c; the value borrowed). */ + "dyn.markUncloneable": { argTypes: [DYN], result: VOID }, /** before new Worker() with the stdout or stderr option: links the stream * unit that worker.stdout and worker.stderr read through (scr_stream.c). */ "stream.workerStdio": { argTypes: [], result: VOID }, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5990-worker-uncloneable.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5990-worker-uncloneable.mjs.json new file mode 100644 index 000000000..93337e4a0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5990-worker-uncloneable.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5990-worker-uncloneable.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5991-worker-async-dispose.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5991-worker-async-dispose.mjs.json new file mode 100644 index 000000000..bed1b18a9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5991-worker-async-dispose.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5991-worker-async-dispose.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 08a4d79b1..84482201a 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -669,6 +669,10 @@ ScrDyn *scr_dyn_from_iterator(const ScrDyn *value, int *kind); ScrDyn *scr_dyn_iterator_result_get(const ScrDyn *result, const char *key, size_t len); void scr_dyn_install_iterator_symbol(ScrDyn *key); void scr_dyn_install_async_iterator_symbol(ScrDyn *key); +void scr_dyn_install_async_dispose_symbol(ScrDyn *key); +/* True when key is Symbol.asyncDispose (registered by the symbol unit when + * the program names it); handle symbol_get ops outside that unit use it. */ +bool scr_dyn_is_async_dispose_symbol(const ScrDyn *key); ScrDyn *scr_dyn_array_values_function(void); ScrDyn *scr_dyn_array_from_iterator(const ScrDyn *value); ScrDyn *scr_dyn_iterator_result(ScrDyn *value); @@ -956,6 +960,13 @@ ScrDyn *scr_structured_clone_transfer_fail_with(const ScrDyn *first); /* Validates a structuredClone options dyn value (throws on failure — * callers must check scr_exc_pending). Borrowed, NULL-tolerant. */ void scr_sc_validate_options(const ScrDyn *options); +/* markAsUncloneable(value) and the check structuredClone and postMessage + * make (scr_json.c); both borrow the value. scr_uncloneable_count is the + * number of marked values, so the clone paths test it inline and call + * scr_uncloneable_marked only once something is marked. */ +void scr_mark_uncloneable(ScrDyn *value); +bool scr_uncloneable_marked(const ScrDyn *value); +extern SCR_TL size_t scr_uncloneable_count; /* An %Error as the boundary's dyn shape ({name, message[, code]}). * Borrows; +1. */ ScrDyn *scr_dyn_from_error(const ScrError *e); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 6633f4840..9e443c61f 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -108,6 +108,26 @@ static void scr_async_iterator_symbol_cleanup(void) { scr_async_iterator_symbol = NULL; } +static SCR_TL ScrDyn *scr_async_dispose_symbol; + +static void scr_async_dispose_symbol_cleanup(void) { + scr_dyn_release(scr_async_dispose_symbol); + scr_async_dispose_symbol = NULL; +} + +/* Symbol.asyncDispose, registered by the symbol unit when the program + * first names it, for handle classes outside that unit (a Worker). */ +void scr_dyn_install_async_dispose_symbol(ScrDyn *key) { + if (scr_async_dispose_symbol) return; + scr_async_dispose_symbol = scr_dyn_retain(key); + scr_atexit(scr_async_dispose_symbol_cleanup); +} + +bool scr_dyn_is_async_dispose_symbol(const ScrDyn *key) { + return scr_async_dispose_symbol && key->kind == SCR_DYN_SYMBOL && + key->v.symbol.value == scr_async_dispose_symbol->v.symbol.value; +} + static void scr_to_primitive_symbol_cleanup(void) { scr_dyn_release(scr_to_primitive_symbol); scr_to_primitive_symbol = NULL; @@ -9489,6 +9509,61 @@ void scr_sc_validate_options(const ScrDyn *options) { scr_dyn_release(transferView); } +/* ── markAsUncloneable ─────────────────────────────────────────────── */ + +/* The plain objects, errors and class instances marked with + * markAsUncloneable (node:worker_threads): structuredClone and + * postMessage throw DataCloneError for them. Node's mark has no effect on + * primitives, arrays, Maps, Sets, Dates, typed arrays and ArrayBuffers. + * The marked values are retained until the thread exits, so an identity + * is never reused while marked. */ +static SCR_TL ScrDyn **scr_uncloneable; +SCR_TL size_t scr_uncloneable_count; +static SCR_TL size_t scr_uncloneable_capacity; + +static void scr_uncloneable_cleanup(void) { + for (size_t i = 0; i < scr_uncloneable_count; i++) scr_dyn_release(scr_uncloneable[i]); + free(scr_uncloneable); + scr_uncloneable = NULL; + scr_uncloneable_count = scr_uncloneable_capacity = 0; +} + +/* The identity a mark is kept under: a class instance's or a record's + * object, or a plain object's source (its own box otherwise); NULL for + * values Node does not mark. */ +static const void *scr_uncloneable_identity(const ScrDyn *value) { + if (value->kind == SCR_DYN_TYPED_REF && + ((value->v.typed_ref.type_key_len > 7 && !memcmp(value->v.typed_ref.type_key, "object:", 7)) || + (value->v.typed_ref.type_key_len > 7 && !memcmp(value->v.typed_ref.type_key, "record:", 7)))) + return value->v.typed_ref.ptr; + if (value->kind == SCR_DYN_OBJ) + return value->v.obj.source_identity ? value->v.obj.source_identity : (const void *)value; + return NULL; +} + +void scr_mark_uncloneable(ScrDyn *value) { + const void *identity = scr_uncloneable_identity(value); + if (!identity || scr_uncloneable_marked(value)) return; + if (scr_uncloneable_count == scr_uncloneable_capacity) { + if (!scr_uncloneable_capacity) scr_atexit(scr_uncloneable_cleanup); + size_t capacity = scr_uncloneable_capacity ? scr_uncloneable_capacity * 2 : 8; + ScrDyn **values = realloc(scr_uncloneable, capacity * sizeof *values); + if (!values) scr_trap("scriptc: out of memory\n"); + scr_uncloneable = values; + scr_uncloneable_capacity = capacity; + } + scr_uncloneable[scr_uncloneable_count++] = scr_dyn_retain(value); +} + +bool scr_uncloneable_marked(const ScrDyn *value) { + if (scr_uncloneable_count == 0) return false; + const void *identity = scr_uncloneable_identity(value); + if (!identity) return false; + for (size_t i = 0; i < scr_uncloneable_count; i++) + if (scr_uncloneable_identity(scr_uncloneable[i]) == identity) return true; + return false; +} + /* The parent chain rides the C stack: a revisit is a cycle. */ typedef struct ScrScParent { const ScrDyn *node; @@ -9499,6 +9574,10 @@ typedef struct ScrScParent { * throw), so it is tagged like a parse result (ScrDynRegion); a leaf the * region may not hold clears it. */ static ScrDyn *scr_sc_clone(const ScrDyn *v, const ScrScParent *up, ScrDynRegion *region) { + if (scr_uncloneable_count && scr_uncloneable_marked(v)) { + scr_throw_domex("DataCloneError", "Cannot clone object of unsupported type."); + return NULL; + } if (v->kind == SCR_DYN_PROXY) { scr_throw_domex("DataCloneError", "# could not be cloned."); return NULL; diff --git a/packages/runtime/src/scr_message.c b/packages/runtime/src/scr_message.c index 31cbc7f8e..82428a6fe 100644 --- a/packages/runtime/src/scr_message.c +++ b/packages/runtime/src/scr_message.c @@ -265,6 +265,10 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) case SCR_DYN_HANDLE: identity = input->v.handle.ptr; domain = 4; break; default: break; } + if (scr_uncloneable_count && scr_uncloneable_marked(input)) { + scr_throw_domex("DataCloneError", "Cannot clone object of unsupported type."); + return SIZE_MAX; + } size_t found = scr_message_find(encoder, identity, domain); if (found != SIZE_MAX) return found; size_t id = scr_message_node(encoder); diff --git a/packages/runtime/src/scr_symbol.c b/packages/runtime/src/scr_symbol.c index ebfb56291..383b95986 100644 --- a/packages/runtime/src/scr_symbol.c +++ b/packages/runtime/src/scr_symbol.c @@ -90,6 +90,11 @@ ScrSym *scr_sym_well_known(ScrStr *name) { scr_dyn_install_async_iterator_symbol(key); scr_dyn_release(key); } + if (name->len == 12 && !memcmp(name->data, "asyncDispose", 12)) { + ScrDyn *key = scr_dyn_new_symbol(symbol); + scr_dyn_install_async_dispose_symbol(key); + scr_dyn_release(key); + } if (name->len == 11 && !memcmp(name->data, "toPrimitive", 11)) { ScrDyn *key = scr_dyn_new_symbol(symbol); scr_dyn_install_to_primitive_symbol(key); diff --git a/packages/runtime/src/scr_worker_events.c b/packages/runtime/src/scr_worker_events.c index a4a10b3b8..53041f3d5 100644 --- a/packages/runtime/src/scr_worker_events.c +++ b/packages/runtime/src/scr_worker_events.c @@ -10,6 +10,7 @@ typedef struct ScrWorkerView { ScrEmitter *events; ScrWorkerThread *thread; ScrPromise *termination; + ScrPromise *disposal; /* worker[Symbol.asyncDispose]()'s promise */ bool port; bool closed; bool referenced; @@ -130,6 +131,7 @@ static void scr_worker_view_trace(void *ptr, ScrTraceVisit visit, void *ctx) { ScrWorkerView *view = ptr; visit(view->events, ctx); visit(view->termination, ctx); + visit(view->disposal, ctx); for (int i = 0; i < 2; i++) { visit(view->stdio[i], ctx); visit(view->stdio_box[i], ctx); @@ -158,6 +160,7 @@ static void scr_worker_view_destroy(void *ptr) { ScrWorkerView *view = ptr; scr_emitter_release(view->events); scr_promise_release(view->termination); + scr_promise_release(view->disposal); for (int i = 0; i < 2; i++) { if (view->stdio[i]) scr_worker_stdio_ops->release(view->stdio[i]); scr_dyn_release(view->stdio_box[i]); @@ -457,6 +460,39 @@ static ScrDyn *scr_worker_method_call(ScrClosure *closure, ScrDyn *const *args, return result; } +/* worker[Symbol.asyncDispose](): Node's `await this.terminate()`, a + * promise of undefined once the worker exited. */ +static ScrDyn *scr_worker_async_dispose_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + (void)args; + (void)argc; + ScrDyn *self = scr_dyn_this_get(); + ScrDyn *result = NULL; + if (self->kind != SCR_DYN_HANDLE || self->v.handle.tag != SCR_DYNH_WORKER) { + static const char message[] = "Illegal invocation"; + scr_throw_error_msg_code(SCR_ERR_TYPE, message, sizeof message - 1, "ERR_INVALID_THIS"); + } else { + ScrWorkerView *view = self->v.handle.ptr; + if (!view->disposal) { + view->disposal = scr_promise_new(); + if (view->closed) scr_promise_fulfill_ref(view->disposal, + scr_dyn_retain(scr_dyn_undefined()), scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v); + else if (!view->termination) scr_worker_thread_terminate(view->thread); + } + result = scr_dyn_new_promise(view->disposal); + } + scr_dyn_release(self); + return result; +} + +/* worker[Symbol.asyncDispose] */ +static ScrDyn *scr_worker_symbol_get(void *ptr, const ScrDyn *key) { + (void)ptr; + if (!scr_dyn_is_async_dispose_symbol(key)) return NULL; + ScrClosure *closure = scr_closure_new((void *)&scr_worker_async_dispose_call, 0); + return scr_dyn_new_func(closure, &scr_worker_async_dispose_call, 0, "()", "[Symbol.asyncDispose]"); +} + static ScrDyn *scr_worker_view_get(void *ptr, const char *key, size_t length) { ScrWorkerView *view = ptr; if (!view->port && length == 8 && !memcmp(key, "threadId", 8)) @@ -735,6 +771,8 @@ static void scr_worker_dispatch(void) { view->closed = true; if (view->termination) scr_promise_fulfill_ref(view->termination, scr_dyn_new_num(event->code), scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v); + if (view->disposal) scr_promise_fulfill_ref(view->disposal, + scr_dyn_retain(scr_dyn_undefined()), scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v); ScrWorkerView **slot = &scr_worker_views; while (*slot != view) slot = &(*slot)->next; *slot = view->next; @@ -819,6 +857,7 @@ static bool scr_worker_events_install(void) { static const ScrDynHandleOps worker_ops = { .cls = "Worker", .retain = scr_worker_view_retain, .release = scr_worker_view_release, .invoke = scr_worker_view_invoke, .get = scr_worker_view_get, + .symbol_get = scr_worker_symbol_get, }; static const ScrDynHandleOps port_ops = { .cls = "MessagePort", .retain = scr_worker_view_retain, .release = scr_worker_view_release, diff --git a/tests/corpus/5990-worker-uncloneable.mjs b/tests/corpus/5990-worker-uncloneable.mjs new file mode 100644 index 000000000..5960a18bb --- /dev/null +++ b/tests/corpus/5990-worker-uncloneable.mjs @@ -0,0 +1,59 @@ +// markAsUncloneable: structuredClone and postMessage throw DataCloneError +// for a marked object, error or class instance, also nested in an object; +// the mark has no effect on primitives, arrays and typed arrays. +import { markAsUncloneable, MessageChannel, isInternalThread } from "node:worker_threads"; + +console.log("isInternalThread", isInternalThread); +const { port1, port2 } = new MessageChannel(); +port2.on("message", (m) => console.log("received", JSON.stringify(m))); + +class Point { + constructor(x) { + this.x = x; + } +} +const cases = { + object: { a: 1 }, + error: new Error("e"), + instance: new Point(1), + array: [1, 2], + bytes: new Uint8Array(2), +}; +for (const [name, value] of Object.entries(cases)) { + markAsUncloneable(value); + let cloned; + let posted; + try { + structuredClone(value); + cloned = "cloned"; + } catch (e) { + cloned = `${e.name} ${e.message} ${e.code}`; + } + try { + port1.postMessage(value); + posted = "posted"; + } catch (e) { + posted = `${e.name} ${e.message}`; + } + console.log(name, "|", cloned, "|", posted); +} +markAsUncloneable(5); +markAsUncloneable("text"); +markAsUncloneable(undefined); +console.log("primitives", structuredClone(5), structuredClone("text")); +const marked = { inner: true }; +markAsUncloneable(marked); +markAsUncloneable(marked); +try { + structuredClone({ nested: marked }); +} catch (e) { + console.log("nested", e.name, e.message); +} +try { + port1.postMessage({ nested: marked }); +} catch (e) { + console.log("nested post", e.name, e.message); +} +const copy = { ...marked }; +console.log("spread copy", JSON.stringify(structuredClone(copy))); +setTimeout(() => port1.close(), 50); diff --git a/tests/corpus/5991-worker-async-dispose.mjs b/tests/corpus/5991-worker-async-dispose.mjs new file mode 100644 index 000000000..94ee22036 --- /dev/null +++ b/tests/corpus/5991-worker-async-dispose.mjs @@ -0,0 +1,25 @@ +// worker[Symbol.asyncDispose]() terminates the worker and resolves with +// undefined after its 'exit' event; `await using` disposes a Worker at the +// end of its block. +import { Worker, isMainThread, parentPort } from "node:worker_threads"; + +if (isMainThread) { + const worker = new Worker(new URL(import.meta.url)); + const dispose = worker[Symbol.asyncDispose]; + console.log(typeof dispose, dispose.name, dispose.length); + worker.on("exit", (code) => console.log("exit", code)); + await new Promise((resolve) => worker.once("message", resolve)); + const result = await worker[Symbol.asyncDispose](); + console.log("disposed", result); + console.log("again", await worker[Symbol.asyncDispose]()); + { + await using scoped = new Worker(new URL(import.meta.url)); + scoped.on("exit", (code) => console.log("scoped exit", code)); + await new Promise((resolve) => scoped.once("message", resolve)); + console.log("leaving block"); + } + console.log("after block"); +} else { + parentPort.postMessage("ready"); + setInterval(() => {}, 1000); +} diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index c74808ab3..addb2062c 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1899,6 +1899,8 @@ "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, + "5990-worker-uncloneable.mjs": 3283, + "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, @@ -4583,6 +4585,8 @@ "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, + "5990-worker-uncloneable.mjs": 22432, + "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, From 6d80207e4c0225518a28735ee41a5e6de427ed92 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 04:07:51 -0500 Subject: [PATCH 055/117] Convert errors held as any with Error.prototype.toString Errors that reach checked-dynamic code are objects carrying the reserved "%error" marker, with name and message either own or on their prototype. Several string conversions handled them differently from Node: - `"" + error`, `error + ""` and `error == "TypeError: ..."` converted through the plain-object path and answered "[object Object]". - Template literals and Array join read name and message as own members only, so a builtin error whose name is inherited printed its message alone. - String(error) used the native error, which did not see name and message assigned through the dynamic view. scr_dyn_error_string implements Error.prototype.toString over the encoding, reading both members through the prototype, and the template renderer, Array join, ToPrimitive, ToString and the numeric conversion use it. Assigning a string name or message through the dynamic view now also updates the native error, as assigning stack and cause already did. --- packages/compiler/src/backend/llvm/dyn.ts | 89 +++---------------- .../5915-dyn-error-string-conversions.ts.json | 6 ++ packages/runtime/src/scr_dyn.h | 1 + packages/runtime/src/scr_dyn_invoke.c | 11 +-- packages/runtime/src/scr_json.c | 74 ++++++++++++++- .../5915-dyn-error-string-conversions.ts | 48 ++++++++++ tests/harness/corpus-costs.json | 2 + 7 files changed, 147 insertions(+), 84 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5915-dyn-error-string-conversions.ts.json create mode 100644 tests/corpus/5915-dyn-error-string-conversions.ts diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 86a8a945e..d16d8244c 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -3209,82 +3209,19 @@ export class LlDyn { this.puts(B, "%b", "[object Object]"); B.br(done); B.startBlock(lErr); - const en = this.objGetLit(B, "%d", "name"); - const em = this.objGetLit(B, "%d", "message"); - // ens/ems: the member's ScrStr when it is a string, else null. - const strOf = (m: string, hint: string): string => { - const slot = B.slot(); - B.entryAllocas.push(`${slot} = alloca ptr`); - B.line(`store ptr null, ptr ${slot}`); - const nn = B.tmp(); - B.line(`${nn} = icmp ne ptr ${m}, null`); - const lt = B.newLabel(`${hint}.t`); - const lj = B.newLabel(`${hint}.j`); - B.condBr(nn, lt, lj); - B.startBlock(lt); - const k = this.kindOf(B, m); - const isStr = B.tmp(); - B.line(`${isStr} = icmp eq i32 ${k}, ${DYN_KIND.STR}`); - const ls = B.newLabel(`${hint}.s`); - B.condBr(isStr, ls, lj); - B.startBlock(ls); - const sv = this.payloadOf(B, m, "ptr"); - B.line(`store ptr ${sv}, ptr ${slot}`); - B.br(lj); - B.startBlock(lj); - const out = B.tmp(); - B.line(`${out} = load ptr, ptr ${slot}`); - return out; - }; - const ens = strOf(en, "ds.en"); - const ems = strOf(em, "ds.em"); - const putIf = (s: string, hint: string): void => { - const nn = B.tmp(); - B.line(`${nn} = icmp ne ptr ${s}, null`); - const lt = B.newLabel(`${hint}.t`); - const lj = B.newLabel(`${hint}.j`); - B.condBr(nn, lt, lj); - B.startBlock(lt); - this.putScrStr(B, "%b", s); - B.br(lj); - B.startBlock(lj); - }; - putIf(ens, "ds.pn"); - { - // if (ens && ens->len && ems && ems->len) ": " - const lenNz = (s: string, hint: string): string => { - const slot = B.slot(); - B.entryAllocas.push(`${slot} = alloca i1`); - B.line(`store i1 false, ptr ${slot}`); - const nn = B.tmp(); - B.line(`${nn} = icmp ne ptr ${s}, null`); - const lt = B.newLabel(`${hint}.t`); - const lj = B.newLabel(`${hint}.j`); - B.condBr(nn, lt, lj); - B.startBlock(lt); - const { len } = this.strParts(B, s); - const nz = B.tmp(); - B.line(`${nz} = icmp ne ${this.S} ${len}, 0`); - B.line(`store i1 ${nz}, ptr ${slot}`); - B.br(lj); - B.startBlock(lj); - const out = B.tmp(); - B.line(`${out} = load i1, ptr ${slot}`); - return out; - }; - const a = lenNz(ens, "ds.ln"); - const b2 = lenNz(ems, "ds.lm"); - const both = B.tmp(); - B.line(`${both} = and i1 ${a}, ${b2}`); - const lt = B.newLabel("ds.cl"); - const lj = B.newLabel("ds.cj"); - B.condBr(both, lt, lj); - B.startBlock(lt); - this.puts(B, "%b", ": "); - B.br(lj); - B.startBlock(lj); - } - putIf(ems, "ds.pm"); + // Error.prototype.toString, reading name and message through the + // prototype. Null leaves the exception its conversion threw pending. + host.declare(`declare ptr @scr_dyn_error_string(ptr)`); + host.declare(`declare void @scr_str_release(ptr)`); + const text = B.tmp(); + B.line(`${text} = call ptr @scr_dyn_error_string(ptr %d)`); + const written = B.tmp(); + B.line(`${written} = icmp ne ptr ${text}, null`); + const lPut = B.newLabel("ds.ep"); + B.condBr(written, lPut, done); + B.startBlock(lPut); + this.putScrStr(B, "%b", text); + B.line(`call void @scr_str_release(ptr ${text})`); B.br(done); } B.startBlock(labels.get(DYN_KIND.BYTES)!); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5915-dyn-error-string-conversions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5915-dyn-error-string-conversions.ts.json new file mode 100644 index 000000000..032b5c5ba --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5915-dyn-error-string-conversions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5915-dyn-error-string-conversions.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 08a4d79b1..d47ed66a3 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -890,6 +890,7 @@ bool scr_dyn_same_value(const ScrDyn *left, const ScrDyn *right); ScrDyn *scr_dyn_builtin_method(const ScrStr *prototype, const ScrStr *method); ScrStr *scr_dyn_to_string_argument(const ScrDyn *d, const ScrDyn *argument, const ScrStr *what); ScrDyn *scr_dyn_value_of(const ScrDyn *d, const ScrStr *what); +ScrStr *scr_dyn_error_string(const ScrDyn *d); ScrStr *scr_num_to_string_radix(double value, const ScrDyn *radix); /* JS String() over the dyn kind (units render "null"/"undefined" where * scr_dyn_to_string throws) — the web globals' WebIDL ToString. +1. */ diff --git a/packages/runtime/src/scr_dyn_invoke.c b/packages/runtime/src/scr_dyn_invoke.c index 59cf34a10..a3085399f 100644 --- a/packages/runtime/src/scr_dyn_invoke.c +++ b/packages/runtime/src/scr_dyn_invoke.c @@ -82,13 +82,10 @@ static void scr_dyn_display_buf(ScrJsonBuf *b, const ScrDyn *d) { case SCR_DYN_OBJ: { const ScrDyn *marker = scr_dyn_obj_get(d, "%error", 6); if (marker) { - const ScrDyn *en = scr_dyn_obj_get(d, "name", 4); - const ScrDyn *em = scr_dyn_obj_get(d, "message", 7); - const ScrStr *ens = (en && en->kind == SCR_DYN_STR) ? en->v.str : NULL; - const ScrStr *ems = (em && em->kind == SCR_DYN_STR) ? em->v.str : NULL; - if (ens) scr_jb_write(b, ens->data, ens->len); - if (ens && ens->len && ems && ems->len) scr_jb_puts(b, ": "); - if (ems) scr_jb_write(b, ems->data, ems->len); + ScrStr *text = scr_dyn_error_string(d); + if (!text) return; + scr_jb_write(b, text->data, text->len); + scr_str_release(text); return; } scr_jb_puts(b, "[object Object]"); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 87a2776a3..e82485124 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -5947,11 +5947,28 @@ void scr_errdyn_put(ScrError *e, ScrDyn *d) { scr_errdyn_append(e, d); } static void scr_error_sync_cause(ScrDyn *view, const ScrStr *key) { bool cause = key->len == 5 && memcmp(key->data, "cause", 5) == 0; bool stack = key->len == 5 && memcmp(key->data, "stack", 5) == 0; - if (!cause && !stack) return; + bool name = key->len == 4 && memcmp(key->data, "name", 4) == 0; + bool message = key->len == 7 && memcmp(key->data, "message", 7) == 0; + if (!cause && !stack && !name && !message) return; size_t hit = scr_errdyn_find(view, false); if (hit == SIZE_MAX) return; ScrDynEntry *entry = scr_dyn_entry(view, key); ScrError *e = scr_errdyn_cache[hit].err; + if (name || message) { + /* The native error's toString and inspect read these fields. */ + if (!entry || entry->accessor || entry->value->kind != SCR_DYN_STR) return; + ScrStr **field = name ? &e->name : &e->message; + scr_str_release(*field); + *field = scr_str_retain(entry->value->v.str); + if (name) { + e->name_present = true; + e->name_enumerable = entry->enumerable; + } else { + e->message_present = true; + e->message_enumerable = entry->enumerable; + } + return; + } if (stack) { if (entry && entry->value->kind == SCR_DYN_STR) { scr_str_release(e->stack); @@ -5967,6 +5984,46 @@ static void scr_error_sync_cause(ScrDyn *view, const ScrStr *key) { e->cause_enumerable = entry && entry->enumerable; } +/* Error.prototype.toString over the checked-dynamic error encoding (an + * object carrying the reserved "%error" marker): `name` defaults to "Error" + * and `message` to "", both read through the prototype; either empty leaves + * the other alone, otherwise "name: message". NULL with a pending exception + * when a member's string conversion throws. */ +ScrStr *scr_dyn_error_string(const ScrDyn *d) { + ScrStr *parts[2] = { NULL, NULL }; + static const char *const keys[2] = { "name", "message" }; + for (int i = 0; i < 2; i++) { + ScrDyn *member = scr_dyn_obj_read(d, keys[i], strlen(keys[i])); + if (!member || member->kind == SCR_DYN_UNDEF) { + parts[i] = i == 0 ? scr_str_new("Error", 5) : scr_str_new("", 0); + } else { + parts[i] = scr_dyn_string_coerce_js(member); + } + scr_dyn_release(member); + if (!parts[i]) { + scr_str_release(parts[0]); + return NULL; + } + } + if (parts[0]->len == 0 || parts[1]->len == 0) { + ScrStr *out = parts[0]->len == 0 ? parts[1] : parts[0]; + scr_str_release(out == parts[0] ? parts[1] : parts[0]); + return out; + } + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_put_str(&b, parts[0]); + scr_jb_puts(&b, ": "); + scr_jb_put_str(&b, parts[1]); + scr_str_release(parts[0]); + scr_str_release(parts[1]); + return scr_jb_finish(&b); +} + +static bool scr_dyn_error_encoding(const ScrDyn *d) { + return d->kind == SCR_DYN_OBJ && scr_dyn_obj_get(d, "%error", 6) != NULL; +} + /* Receiver-kind-dispatched toString() on a checked-dynamic value (the * dyn method surface — a stream's 'data'/for-await chunk is the common * receiver): bytes decode per the encoding (Node's Buffer.toString, @@ -6002,6 +6059,7 @@ ScrStr *scr_dyn_to_string(const ScrDyn *d, const ScrStr *enc) { case SCR_DYN_BOOL: return d->v.b ? scr_str_new("true", 4) : scr_str_new("false", 5); case SCR_DYN_OBJ: + if (scr_dyn_error_encoding(d) && !scr_dyn_property_owner(d, "toString", 8)) return scr_dyn_error_string(d); return scr_str_new("[object Object]", 15); case SCR_DYN_HANDLE: if (d->v.handle.tag == SCR_DYNH_REGEXP || d->v.handle.tag == SCR_DYNH_URL) { @@ -6396,6 +6454,13 @@ bool scr_dyn_number_coerce_js(const ScrDyn *d, double *out) { * number-hint protocol advances to toString. */ continue; } + if (i == 1 && scr_dyn_error_encoding(d)) { + ScrStr *text = scr_dyn_error_string(d); + if (!text) return false; + *out = scr_string_to_number(text); + scr_str_release(text); + return true; + } if (scr_dyn_has_object_prototype(d) && i == 1) { *out = NAN; /* Number("[object Object]") */ return true; @@ -6511,6 +6576,13 @@ static ScrDyn *scr_dyn_add_primitive(const ScrDyn *d) { const ScrDyn *owner = scr_dyn_property_owner(d, methods[i], strlen(methods[i])); ScrDyn *method = owner ? scr_dyn_obj_read(d, methods[i], strlen(methods[i])) : NULL; if (!method) { + if (i == 1 && scr_dyn_error_encoding(d)) { + ScrStr *str = scr_dyn_error_string(d); + if (!str) return NULL; + ScrDyn *out = scr_dyn_new_str(str); + scr_str_release(str); + return out; + } if (i == 1 && scr_dyn_has_object_prototype(d)) { ScrStr *str = scr_str_new("[object Object]", 15); ScrDyn *out = scr_dyn_new_str(str); diff --git a/tests/corpus/5915-dyn-error-string-conversions.ts b/tests/corpus/5915-dyn-error-string-conversions.ts new file mode 100644 index 000000000..4e56b5c01 --- /dev/null +++ b/tests/corpus/5915-dyn-error-string-conversions.ts @@ -0,0 +1,48 @@ +// Errors held as `any` convert to strings through Error.prototype.toString +// in every dynamic conversion: template literals, `+` with a string on +// either side, String(), Array join, loose equality, Number() and property +// keys. The name is read through the prototype ("Error", "TypeError", a +// subclass's own name), an empty name or message leaves the other alone, +// and a subclass without its own name inherits "Error". + +class NamedError extends Error { + constructor(message: string) { + super(message); + this.name = "NamedError"; + } +} + +class PlainSubclass extends Error {} + +function show(label: string, error: any): void { + console.log(label, "|", `${error}`, "|", "" + error, "|", error + "!", "|", String(error), "|", [error, 1].join(" ")); +} + +show("error", new Error("plain")); +show("type", new TypeError("bad thing")); +show("range", new RangeError("too far")); +show("syntax", new SyntaxError("unexpected")); +show("named", new NamedError("mine")); +show("subclass", new PlainSubclass("inherited name")); +show("empty message", new TypeError("")); +show("no message", new Error()); + +const renamed: any = new Error("message only"); +renamed.name = ""; +show("empty name", renamed); + +const changed: any = new RangeError("before"); +changed.message = "after"; +show("changed message", changed); + +const numeric: any = new Error("42"); +numeric.name = ""; +const unnumbered: any = new TypeError("x"); +console.log("Number", Number(numeric), Number(unnumbered), +numeric); + +const type: any = new TypeError("bad thing"); +console.log("loose equality", type == "TypeError: bad thing", type == "bad thing"); + +const keyed: any = {}; +keyed[type] = 1; +console.log("key", Object.keys(keyed).join(",")); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 7f89295df..ddd89cbe8 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1886,6 +1886,7 @@ "5912-dyn-class-conversion-methods.ts": 3251, "5913-prototype-type-error-messages.ts": 2484, "5914-dyn-in-class-prototype-members.ts": 3169, + "5915-dyn-error-string-conversions.ts": 3200, "5922-matchall-groups-callbacks.ts": 3650, "5923-matchall-groups-js.js": 3970, "5939-js-let-object-reassigned-wider.js": 1945, @@ -4570,6 +4571,7 @@ "5912-dyn-class-conversion-methods.ts": 4424, "5913-prototype-type-error-messages.ts": 4068, "5914-dyn-in-class-prototype-members.ts": 4327, + "5915-dyn-error-string-conversions.ts": 4247, "5922-matchall-groups-callbacks.ts": 5960, "5923-matchall-groups-js.js": 6650, "5939-js-let-object-reassigned-wider.js": 4436, From 58096a768c9be27a95f671b4b223ad4ac5911b73 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 04:19:12 -0500 Subject: [PATCH 056/117] Define scr_uncloneable_count with an initializer packages/runtime/test/common-symbols.test.ts requires runtime globals to be definitions, not tentative definitions that some toolchains emit as common symbols; scr_uncloneable_count now starts at 0 explicitly. --- packages/runtime/src/scr_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 9e443c61f..c3aab4dfb 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -9518,7 +9518,7 @@ void scr_sc_validate_options(const ScrDyn *options) { * The marked values are retained until the thread exits, so an identity * is never reused while marked. */ static SCR_TL ScrDyn **scr_uncloneable; -SCR_TL size_t scr_uncloneable_count; +SCR_TL size_t scr_uncloneable_count = 0; static SCR_TL size_t scr_uncloneable_capacity; static void scr_uncloneable_cleanup(void) { From c88981a46689e59a28f885ef8089a081a033cfa6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 04:32:24 -0500 Subject: [PATCH 057/117] Describe why mock.timers' tick leaves a fired timer queued scr_mt_tick removes a fired entry only while it is still the queue's first entry, as Node's MockTimers.tick does. A callback that queues an entry sorting before it, such as an immediate due at now - 1, leaves the fired timer queued, so it runs again, as it does in Node. The comment now says so and names the fixture that checks the order against Node. --- packages/runtime/src/scr_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/scr_test.c b/packages/runtime/src/scr_test.c index 6388857a6..f8bca0cfa 100644 --- a/packages/runtime/src/scr_test.c +++ b/packages/runtime/src/scr_test.c @@ -1305,7 +1305,11 @@ static void scr_mt_tick(ScrMockTimers *m, double time) { scr_mt_unref(timer); return; } - /* A callback that cleared its own timer already removed it. */ + /* Node's tick() removes the fired entry only while it is still first + * in the queue: a callback that cleared its own timer already removed + * it, and one that queued an entry sorting before it (an immediate, + * due at now - 1) leaves it queued, so it runs again, as in Node. The + * mock-timers-date fixture checks that order against Node. */ ScrMockTimer *after = scr_mt_peek(m); if (after && after->id == timer->id) { timer->pos = 0; From 4fe392cd2507fa898098c4137581939312b644d6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 05:15:17 -0500 Subject: [PATCH 058/117] Return a worker's memory once it and the other workers are done On Linux, a worker thread that exits without having made any object it allocated reachable from another thread gives back all of its memory: the pages it carved, including ProgramLifetime instances and other objects it never freed, and the system blocks it still holds. The memory goes back once no other worker thread is running, so that returning it does not slow the workers that are still running. A worker carves past each slice's frontier while the arena's free lists and returned regions are set aside, takes from those free lists only once a slice has no bump room left, and records the system blocks it allocates. Messages and intern tables that share published graphs by pointer, and the process-wide key arrays of typed records, mark the thread as sharing; so does a remote free of one of its blocks. A worker that did not share parks with its arena claimed and its discard queued: returning pages makes the kernel interrupt every running thread of the process to flush its TLB, and glibc's trim locks the arenas other threads allocate from. The last worker to park starts one helper that returns each queued worker's pages, frees its system blocks, and restores its arena to its state at the claim, with the free blocks the worker took free again. A thread that finds every arena claimed runs the queued discards itself. A worker that shared keeps its memory as before. SCR_SA_DISCARD=0 keeps every worker's memory; SCR_SA_DISCARD=poison makes the discarded pages inaccessible instead, for tests. --- docs/content/docs/contracts.mdx | 2 +- docs/content/docs/threads.mdx | 2 + .../native-worker-discarded-heaps.ts.json | 6 + packages/runtime/src/scr_alloc.c | 487 +++++++++++++++++- packages/runtime/src/scr_alloc.test.c | 327 ++++++++++++ packages/runtime/src/scr_itable.c | 3 + packages/runtime/src/scr_itable.test.c | 10 +- packages/runtime/src/scr_json.c | 1 + packages/runtime/src/scr_message.c | 3 + packages/runtime/src/scr_rc.h | 9 +- tests/corpus/native-worker-discarded-heaps.ts | 102 ++++ tests/harness/corpus-costs.json | 2 + 12 files changed, 936 insertions(+), 18 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json create mode 100644 tests/corpus/native-worker-discarded-heaps.ts diff --git a/docs/content/docs/contracts.mdx b/docs/content/docs/contracts.mdx index 11737da59..d1bfb8cad 100644 --- a/docs/content/docs/contracts.mdx +++ b/docs/content/docs/contracts.mdx @@ -331,7 +331,7 @@ $ scriptc build graph.ts ## ProgramLifetime -`ProgramLifetime` marks a class whose instances a program keeps until it exits, such as the nodes of a syntax tree, the symbols of a symbol table or interned types. scriptc then never reference counts, collects or frees instances of the class and of its subclasses: they are never freed, every retain and release on them compiles to nothing, and the cycle collector neither walks them nor needs to trace the objects that point to them. Node.js behavior is unchanged; only memory use differs, because an instance the program drops is never reclaimed. +`ProgramLifetime` marks a class whose instances a program keeps until it exits, such as the nodes of a syntax tree, the symbols of a symbol table or interned types. scriptc then never reference counts, collects or frees instances of the class and of its subclasses: they are never freed, every retain and release on them compiles to nothing, and the cycle collector neither walks them nor needs to trace the objects that point to them. Node.js behavior is unchanged; only memory use differs, because an instance the program drops is never reclaimed. On Linux, the instances a worker thread creates are returned with the rest of its memory after it exits, unless the worker shared objects with other threads (see [cost](/docs/threads#cost)). ```ts:tree.ts import type { ProgramLifetime } from "@scriptc/types"; diff --git a/docs/content/docs/threads.mdx b/docs/content/docs/threads.mdx index 7b394e09f..6f9b5f062 100644 --- a/docs/content/docs/threads.mdx +++ b/docs/content/docs/threads.mdx @@ -234,6 +234,8 @@ Without `@scriptc/threads`, a scriptc executable also shares a message of untype Starting a worker thread takes tens of microseconds plus the worker's own module initialization, since every worker initializes the program's modules again, as in Node.js. A worker that exits frees its heap first, which takes time proportional to what it still holds. `SCRIPTC_WORKER_STATS=1` prints, as each worker exits, how long it took to start, to run its script and to exit. +On Linux, a worker that exits without having shared an object it allocated with another thread returns all of its memory, including objects it never freed, such as `ProgramLifetime` instances, once no other worker thread is running. A worker shares objects when, for example, it sends a published value or frozen plain data, which other threads read by reference, or stores a value in an `InternTable`. The memory of a worker that shared stays allocated, as on other platforms. Set `SCR_SA_DISCARD=0` in the environment to keep the memory of every worker. + `publish` visits each object of the graph once and marks it immortal, so publication takes time proportional to the graph. Published objects then cost nothing on later sends, and reference counting and the cycle collector skip them. Stores into the types a program publishes carry one extra load and branch. Threads that add to one shared collection of published values while they run can use an [`InternTable`](/docs/experimental#interntable) from `@scriptc/experimental`. diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json new file mode 100644 index 000000000..b7dd8fd17 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-discarded-heaps.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/native-worker-discarded-heaps.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_alloc.c b/packages/runtime/src/scr_alloc.c index 76d056d7c..2212a1a36 100644 --- a/packages/runtime/src/scr_alloc.c +++ b/packages/runtime/src/scr_alloc.c @@ -630,6 +630,14 @@ static bool scr_sa_reserve_region(void) { * scr_sa_trim). */ static size_t scr_sa_claim_carved[SCR_SA_ARENAS]; static size_t scr_sa_carved(void); +/* A worker thread's memory, discarded when it parks (see "Discarding a + * worker's memory" below). */ +typedef struct ScrSaKeep ScrSaKeep; +static _Thread_local bool scr_sa_worker; /* set by scr_sa_thread_starting */ +static _Thread_local ScrSaKeep *scr_sa_keep; /* while the worker's memory is kept apart */ +static void scr_sa_keep_begin(unsigned i); +static void scr_sa_keep_drained(ScrSaKeep *k, ScrSaBlock *b, unsigned c); +static bool scr_sa_drain(void); #endif /* Moves every block other threads freed into this arena's free lists. */ @@ -638,6 +646,13 @@ static void scr_sa_drain_remote(void) { while (b) { ScrSaBlock *next = b->next; unsigned c = (unsigned)(((uintptr_t)b - scr_sa.base) >> scr_sa.shift); +#ifdef SCR_SA_TRIM + if (scr_sa_keep) { + scr_sa_keep_drained(scr_sa_keep, b, c); + b = next; + continue; + } +#endif b->next = scr_sa.free[c]; scr_sa.free[c] = b; b = next; @@ -655,6 +670,15 @@ static bool scr_sa_reserve(void) { uint32_t claimed = atomic_load_explicit(&scr_sa_claimed, memory_order_relaxed); for (;;) { if (claimed == UINT32_MAX) { +#ifdef SCR_SA_TRIM + /* Arenas held by discards that wait (see scr_sa_thread_park): this + * thread discards them and claims one. */ + if (scr_sa_drain()) { + scr_sa_refused = false; + claimed = atomic_load_explicit(&scr_sa_claimed, memory_order_relaxed); + continue; + } +#endif scr_sa_refused = true; return false; } @@ -672,6 +696,7 @@ static bool scr_sa_reserve(void) { scr_sa_drain_remote(); #ifdef SCR_SA_TRIM scr_sa_claim_carved[i] = scr_sa_carved(); + if (scr_sa_worker) scr_sa_keep_begin(i); #endif return true; } @@ -884,6 +909,312 @@ static void scr_sa_trim(void) { scr_sa_arena, (int)trim, scr_sa_trim_stats[0] >> 20, scr_sa_trim_stats[1] >> 20, scr_sa_trim_stats[2] >> 20); } + +/* Discarding a worker's memory (Linux). Script objects stay on the thread + * that allocated them: other threads reach one only through a message or an + * intern table that shares a published (immortal) graph by pointer, or a + * process-wide immortal cache, and each of those calls + * scr_sa_thread_shares. Runtime state that outlives a thread (messages, + * mailboxes, shared bytes, intern table entries) comes from the system + * allocator directly. So when a worker thread parks without having shared, + * nothing it allocated through scr_mem_* can be reachable from another + * thread, and what it never freed (ProgramLifetime instances, published + * module constants) is garbage. Such a thread's memory goes back whole: + * - when a worker claims an arena, the arena's free lists and returned + * regions are set aside, and the worker carves only past each slice's + * frontier, so its blocks of class c are [start[c], bump[c]), plus the + * blocks it takes from the free lists set aside once a slice has no bump + * room left, which it records; + * - the system blocks it allocates (large blocks, an exhausted slice) are + * recorded until it frees them; + * - a remote free into its blocks means another thread held one: the same + * as sharing; + * - when it parks without having shared, its arena stays claimed until no + * other worker thread is running (scr_sa_thread_park): returning pages + * interrupts every running thread of the process to flush its TLB, and + * glibc's trim locks the arenas other threads allocate from, so discards + * wait for the last worker of a group, which hands them to one helper; + * - the helper then returns the pages + * it carved (MADV_DONTNEED; the start of the first page, which it may + * share with older blocks, is cleared), frees the recorded system blocks, + * and parks the arena as the worker found it, with the blocks it took + * free again. A worker that shared parks + * its arena with the blocks set aside added to its free lists, and the + * ordinary trim applies. + * SCR_SA_DISCARD=0 keeps every worker's memory. SCR_SA_DISCARD=poison makes + * the carved pages inaccessible instead, and keeps the system blocks, so + * that a reference to discarded memory faults (a check for tests). */ +#define SCR_SA_SYS_GONE ((void *)1) /* a removed entry of ScrSaKeep.sys */ + +struct ScrSaKeep { + /* The arena as the worker claimed it: free lists (to which remote frees + * of older blocks are added), carve cursors and returned regions. */ + ScrSaBlock *free[SCR_SA_NCLASS]; + char *bump[SCR_SA_NCLASS], *lim[SCR_SA_NCLASS]; + ScrSaHoles holes[SCR_SA_NCLASS]; + /* Each slice's frontier then (bump and limit, NULL limits for a slice not + * opened yet), and the first address the worker carves in it. */ + char *front_bump[SCR_SA_NCLASS], *front_lim[SCR_SA_NCLASS]; + char *start[SCR_SA_NCLASS]; + /* The worker's system blocks: an open-addressing set of `cap` slots (a + * power of two, or 0), NULL for an empty slot and SCR_SA_SYS_GONE for a + * removed entry; `used` counts both kinds of filled slots. */ + void **sys; + size_t cap, used, live; + /* The blocks of the free lists set aside that the worker took once a slice + * had no bump room left, so that older free blocks are used before the + * slice grows; they go back to those lists with the worker's memory. */ + ScrSaBlock **taken; + size_t ntaken, cap_taken; + bool shared; + bool poison; +}; + +static _Thread_local bool scr_sa_discarded; /* this thread's memory went back */ +static ScrSaKeep *scr_sa_parked_keep[SCR_SA_ARENAS]; /* of discards that wait */ + +/* SCR_SA_DISCARD: 0 off, 1 on (the default), 2 poison. */ +static int scr_sa_discard_mode(void) { + const char *mode = getenv("SCR_SA_DISCARD"); + if (!mode) return 1; + if (strcmp(mode, "0") == 0) return 0; + return strcmp(mode, "poison") == 0 ? 2 : 1; +} + +static void scr_sa_keep_begin(unsigned i) { + int mode = scr_sa_discard_mode(); + if (!mode) return; + ScrSaKeep *k = calloc(1, sizeof *k); + if (!k) return; + k->poison = mode == 2; + for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { + ScrSaHoles *h = &scr_sa_holes[i][c]; + k->free[c] = scr_sa.free[c]; + k->bump[c] = scr_sa.bump[c]; + k->lim[c] = scr_sa.lim[c]; + k->holes[c] = *h; + memset(h, 0, sizeof *h); + scr_sa.free[c] = NULL; + /* While the slice carves a returned region, its frontier is kept apart. */ + if (k->holes[c].lim) { + scr_sa.bump[c] = k->holes[c].bump; + scr_sa.lim[c] = k->holes[c].lim; + } + k->front_bump[c] = scr_sa.bump[c]; + k->front_lim[c] = scr_sa.lim[c]; + k->start[c] = scr_sa.lim[c] ? scr_sa.bump[c] : (char *)scr_sa.base + ((size_t)c << scr_sa.shift); + } + scr_sa_keep = k; +} + +/* A remote free of class c, drained while the worker keeps its memory + * apart: one of its own blocks makes it share; an older block goes to the + * free lists set aside. Once the worker has taken blocks from those lists, + * any older block might be one of them, so it shares as well. */ +static void scr_sa_keep_drained(ScrSaKeep *k, ScrSaBlock *b, unsigned c) { + if ((char *)b >= k->start[c] && (char *)b < scr_sa.bump[c]) { + k->shared = true; + b->next = scr_sa.free[c]; + scr_sa.free[c] = b; + } else { + if (k->ntaken) k->shared = true; + b->next = k->free[c]; + k->free[c] = b; + } +} + +/* A block of class c from the free lists set aside, for a worker whose + * slice has no bump room left; NULL when there is none or it cannot be + * recorded. */ +static ScrSaBlock *scr_sa_keep_take(ScrSaKeep *k, unsigned c) { + ScrSaBlock *b = k->free[c]; + if (!b) return NULL; + if (k->ntaken == k->cap_taken) { + size_t cap = k->cap_taken ? 2 * k->cap_taken : 256; + ScrSaBlock **taken = realloc(k->taken, cap * sizeof *taken); + if (!taken) return NULL; + k->taken = taken; + k->cap_taken = cap; + } + k->free[c] = b->next; + k->taken[k->ntaken++] = b; + return b; +} + +static size_t scr_sa_sys_slot(const void *p, size_t cap) { + return (size_t)((((uint64_t)(uintptr_t)p >> 4) * UINT64_C(0x9E3779B97F4A7C15)) >> 32) & (cap - 1); +} + +/* Records system block p. A worker whose set cannot grow keeps its memory. */ +static void scr_sa_keep_add(ScrSaKeep *k, void *p) { + if ((k->used + 1) * 2 > k->cap) { + size_t cap = 64; + while (cap < (k->live + 1) * 4) cap *= 2; + void **sys = calloc(cap, sizeof *sys); + if (!sys) { + k->shared = true; + return; + } + for (size_t s = 0; s < k->cap; s++) { + void *q = k->sys[s]; + if (!q || q == SCR_SA_SYS_GONE) continue; + size_t j = scr_sa_sys_slot(q, cap); + while (sys[j]) j = (j + 1) & (cap - 1); + sys[j] = q; + } + free(k->sys); + k->sys = sys; + k->cap = cap; + k->used = k->live; + } + size_t j = scr_sa_sys_slot(p, k->cap); + while (k->sys[j] && k->sys[j] != SCR_SA_SYS_GONE) j = (j + 1) & (k->cap - 1); + if (!k->sys[j]) k->used++; + k->sys[j] = p; + k->live++; +} + +/* Forgets system block p; whether it was recorded. */ +static bool scr_sa_keep_remove(ScrSaKeep *k, const void *p) { + if (!k->live) return false; + for (size_t j = scr_sa_sys_slot(p, k->cap); k->sys[j]; j = (j + 1) & (k->cap - 1)) { + if (k->sys[j] != p) continue; + k->sys[j] = SCR_SA_SYS_GONE; + k->live--; + return true; + } + return false; +} + +/* The calling thread's arena keeps the worker's memory (it shared): the + * free lists set aside go back, followed by the worker's own free blocks, + * and so do the returned regions, past which the worker carved. */ +static void scr_sa_keep_merge(ScrSaKeep *k) { + for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { + ScrSaBlock *kept = k->free[c]; + if (kept) { + ScrSaBlock *tail = kept; + while (tail->next) tail = tail->next; + tail->next = scr_sa.free[c]; + scr_sa.free[c] = kept; + } + ScrSaHoles *h = &scr_sa_holes[scr_sa_arena][c]; + *h = k->holes[c]; + if (h->lim) { + h->bump = scr_sa.bump[c]; + h->lim = scr_sa.lim[c]; + scr_sa.bump[c] = k->bump[c]; + scr_sa.lim[c] = k->lim[c]; + } + } + free(k->sys); + free(k->taken); + free(k); +} + +/* Returns the memory of the worker whose arena the calling thread (the + * trim helper) holds, and restores the arena to its state at the worker's + * claim; with poison, makes the pages inaccessible and moves the frontier + * past them instead. */ +static void scr_sa_discard(ScrSaKeep *k) { + /* Remote frees since the worker's last drain. */ + scr_sa_keep = k; + scr_sa_drain_remote(); + scr_sa_keep = NULL; + if (k->shared) { + scr_sa_keep_merge(k); + scr_sa_trim(); + return; + } + uintptr_t page = (uintptr_t)sysconf(_SC_PAGESIZE); + if (page == 0 || page == (uintptr_t)-1) page = 4096; + size_t returned = 0, sys_bytes = 0, sys_blocks = 0; + for (unsigned c = 0; c < SCR_SA_NCLASS; c++) { + char *lo = k->start[c], *top = scr_sa.bump[c], *lim = scr_sa.lim[c]; + char *bump = k->front_bump[c], *limit = k->front_lim[c]; + if (lim && top > lo) { + char *first = (char *)(((uintptr_t)lo + page - 1) & ~(page - 1)); + char *used = (char *)(((uintptr_t)top + page - 1) & ~(page - 1)); + /* The part of a page that may also hold older blocks. */ + if (first > lo) memset(lo, 0, (size_t)((first < top ? first : top) - lo)); + if (k->poison) { + if (used > first) (void)mprotect(first, (size_t)(used - first), PROT_NONE); + bump = used > first ? used : top; + limit = lim > bump ? lim : bump; + } else { + char *end = (char *)(((uintptr_t)lim + page - 1) & ~(page - 1)); + if (end > first) { + (void)madvise(first, (size_t)(end - first), MADV_DONTNEED); + returned += (size_t)(end - first); + } + } + } else { + bump = top; + limit = lim; + } + scr_sa.free[c] = k->free[c]; + ScrSaHoles *h = &scr_sa_holes[scr_sa_arena][c]; + *h = k->holes[c]; + if (h->lim) { + h->bump = bump; + h->lim = limit; + scr_sa.bump[c] = k->bump[c]; + scr_sa.lim[c] = k->lim[c]; + } else { + scr_sa.bump[c] = bump; + scr_sa.lim[c] = limit; + } + } + /* The older free blocks the worker took are free again. */ + if (!k->poison) + for (size_t t = 0; t < k->ntaken; t++) { + ScrSaBlock *b = k->taken[t]; + unsigned c = (unsigned)(((uintptr_t)b - scr_sa.base) >> scr_sa.shift); + b->next = scr_sa.free[c]; + scr_sa.free[c] = b; + } + if (!k->poison) + for (size_t s = 0; s < k->cap; s++) { + void *p = k->sys[s]; + if (!p || p == SCR_SA_SYS_GONE) continue; +#if defined(__GLIBC__) + sys_bytes += malloc_usable_size(p); +#endif + sys_blocks++; + free(p); + } +#if defined(__GLIBC__) + if (sys_blocks) (void)malloc_trim(0); +#endif + const char *stats = getenv("SCR_SA_STATS"); + if (stats && stats[0] == '1') + fprintf(stderr, "scr_sa: discard arena %d returned %zu MB, %zu system blocks (%zu MB)\n", scr_sa_arena, + returned >> 20, sys_blocks, sys_bytes >> 20); + free(k->sys); + free(k->taken); + free(k); +} + +/* Hooks of the allocator's system paths and of sharing (scr_rc.h). */ +static void scr_sa_keep_note_system(void *p) { + if (p && scr_sa_keep) scr_sa_keep_add(scr_sa_keep, p); +} + +void scr_sa_thread_shares(void) { + if (scr_sa_keep) scr_sa_keep->shared = true; +} + +/* Worker threads that started and have not parked. */ +static _Atomic(unsigned) scr_sa_workers_live; + +/* Library archives run on their embedder's threads and keep their memory. */ +static void scr_sa_worker_starting(void) { +#ifndef SCR_LIB + scr_sa_worker = true; + atomic_fetch_add_explicit(&scr_sa_workers_live, 1, memory_order_relaxed); +#endif +} +#define SCR_SA_WORKER_STARTING() scr_sa_worker_starting() #endif #ifdef SCR_SA_TRIM @@ -912,6 +1243,85 @@ static void *scr_sa_trim_main(void *arg) { return NULL; } +/* Hands the calling thread's arena to a trim helper; false if no helper + * could start. */ +static bool scr_sa_start_helper(unsigned i) { + scr_sa_parked[i] = scr_sa; + atomic_fetch_add_explicit(&scr_sa_trimming, 1, memory_order_relaxed); + pthread_attr_t attr; + pthread_t helper; + bool started = pthread_attr_init(&attr) == 0; + if (started) { + started = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && + pthread_create(&helper, &attr, scr_sa_trim_main, (void *)(uintptr_t)i) == 0; + pthread_attr_destroy(&attr); + } + if (!started) atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_relaxed); + return started; +} + +/* Discards that wait for the last running worker: one bit per arena, whose + * state and ScrSaKeep are in scr_sa_parked and scr_sa_parked_keep. */ +static pthread_mutex_t scr_sa_pending_lock = PTHREAD_MUTEX_INITIALIZER; +static uint32_t scr_sa_pending; + +/* Queues the discard of the calling worker's arena i; the arena stays + * claimed until it is done. */ +static void scr_sa_defer_discard(unsigned i, ScrSaKeep *k) { + atomic_fetch_add_explicit(&scr_sa_trimming, 1, memory_order_relaxed); + pthread_mutex_lock(&scr_sa_pending_lock); + scr_sa_parked[i] = scr_sa; + scr_sa_parked_keep[i] = k; + scr_sa_pending |= 1u << i; + pthread_mutex_unlock(&scr_sa_pending_lock); +} + +/* Runs the waiting discards on the calling thread, which ends with no arena; + * returns whether there were any. */ +static bool scr_sa_drain(void) { + bool any = false; + for (;;) { + pthread_mutex_lock(&scr_sa_pending_lock); + uint32_t pending = scr_sa_pending; + unsigned i = pending ? (unsigned)__builtin_ctz(pending) : 0; + scr_sa_pending &= ~(1u << i); + pthread_mutex_unlock(&scr_sa_pending_lock); + if (!pending) return any; + any = true; + scr_sa_arena = (int)i; + scr_sa = scr_sa_parked[i]; + ScrSaKeep *k = scr_sa_parked_keep[i]; + scr_sa_parked_keep[i] = NULL; + scr_sa_discard(k); + scr_sa_release(i); + atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_release); + } +} + +static void *scr_sa_drain_main(void *arg) { + (void)arg; + scr_sa_drain(); + return NULL; +} + +/* A worker parked: the last one running starts the waiting discards. */ +static void scr_sa_worker_parked(void) { + if (atomic_fetch_sub_explicit(&scr_sa_workers_live, 1, memory_order_acq_rel) != 1) return; + pthread_mutex_lock(&scr_sa_pending_lock); + bool pending = scr_sa_pending != 0; + pthread_mutex_unlock(&scr_sa_pending_lock); + if (!pending) return; + pthread_attr_t attr; + pthread_t helper; + bool started = pthread_attr_init(&attr) == 0; + if (started) { + started = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && + pthread_create(&helper, &attr, scr_sa_drain_main, NULL) == 0; + pthread_attr_destroy(&attr); + } + if (!started) scr_sa_drain(); +} + void scr_sa_wait_trims(void) { while (atomic_load_explicit(&scr_sa_trimming, memory_order_acquire)) { struct timespec pause = {0, 1000000}; @@ -920,27 +1330,45 @@ void scr_sa_wait_trims(void) { } #else void scr_sa_wait_trims(void) {} +void scr_sa_thread_shares(void) {} #endif +static void scr_sa_park_arena(void); + void scr_sa_thread_park(void) { +#ifdef SCR_SA_TRIM + bool worker = scr_sa_worker; + scr_sa_worker = false; + scr_sa_park_arena(); + if (worker) scr_sa_worker_parked(); +#else + scr_sa_park_arena(); +#endif +} + +static void scr_sa_park_arena(void) { if (scr_sa_arena < 0) return; unsigned i = (unsigned)scr_sa_arena; #if defined(SCR_SA_PREFAULT) && defined(SCR_WORKERS) scr_sa_pf_park(); #endif #ifdef SCR_SA_TRIM + ScrSaKeep *k = scr_sa_keep; + scr_sa_keep = NULL; + if (k && !k->shared) { + /* Nothing this thread allocated is reachable from another one: its + * memory goes back once no other worker runs (scr_sa_worker_parked), + * and later frees on this thread are dropped. */ + scr_sa_discarded = true; + scr_sa_defer_discard(i, k); + memset(&scr_sa, 0, sizeof scr_sa); + scr_sa_arena = -1; + scr_sa_refused = true; + return; + } + if (k) scr_sa_keep_merge(k); if (scr_sa_trim_worth()) { - scr_sa_parked[i] = scr_sa; - atomic_fetch_add_explicit(&scr_sa_trimming, 1, memory_order_relaxed); - pthread_attr_t attr; - pthread_t helper; - bool started = pthread_attr_init(&attr) == 0; - if (started) { - started = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && - pthread_create(&helper, &attr, scr_sa_trim_main, (void *)(uintptr_t)i) == 0; - pthread_attr_destroy(&attr); - } - if (started) { + if (scr_sa_start_helper(i)) { /* Later frees on this thread take the foreign path into the arena's * remote list; the helper releases the claim. */ memset(&scr_sa, 0, sizeof scr_sa); @@ -948,7 +1376,6 @@ void scr_sa_thread_park(void) { scr_sa_refused = true; return; } - atomic_fetch_sub_explicit(&scr_sa_trimming, 1, memory_order_relaxed); scr_sa_trim(); } #endif @@ -971,6 +1398,9 @@ static size_t scr_sa_foreign_size(const void *p) { } void scr_sa_free_foreign(void *p) { +#ifdef SCR_SA_TRIM + if (scr_sa_discarded) return; /* the block went back with the thread's memory */ +#endif uintptr_t region = atomic_load_explicit(&scr_sa_region, memory_order_acquire); uintptr_t off = (uintptr_t)p - region; if (region && off < scr_sa_arena_span * SCR_SA_ARENAS) { @@ -982,6 +1412,9 @@ void scr_sa_free_foreign(void *p) { memory_order_relaxed)); return; } +#ifdef SCR_SA_TRIM + if (scr_sa_keep) (void)scr_sa_keep_remove(scr_sa_keep, p); +#endif free(p); } #else @@ -1020,6 +1453,15 @@ __attribute__((cold, noinline)) void *scr_sa_slow(size_t n, bool zero) { if (zero) memset(b, 0, n); return b; } +#ifdef SCR_SA_TRIM + /* A worker that keeps its memory apart uses the arena's older free + * blocks before its slice grows. */ + if (scr_sa_keep && (size_t)(scr_sa.lim[c] - scr_sa.bump[c]) < scr_sa_class_size(c) && + (b = scr_sa_keep_take(scr_sa_keep, c)) != NULL) { + if (zero) memset(b, 0, n); + return b; + } +#endif #endif /* Carve from the slice, opening it or raising its limit as needed; * fresh pages are zero. */ @@ -1051,6 +1493,9 @@ __attribute__((cold, noinline)) void *scr_sa_slow(size_t n, bool zero) { SCR_SA_LARGE_NOTE(q, n); SCR_SA_THREAD_LARGE_NOTE(); } +#ifdef SCR_SA_TRIM + scr_sa_keep_note_system(q); +#endif return q; } @@ -1065,8 +1510,14 @@ void *scr_mem_realloc(void *p, size_t n) { } #endif else { +#ifdef SCR_SA_TRIM + bool kept = scr_sa_keep && scr_sa_keep_remove(scr_sa_keep, p); +#endif void *q = realloc(p, n); if (n > SCR_SA_MAX) SCR_SA_LARGE_NOTE(q, n); +#ifdef SCR_SA_TRIM + if (kept) scr_sa_keep_note_system(q ? q : p); /* a failed realloc leaves p */ +#endif return q; } /* Still fits its block, which is aligned for n (see the contract). */ @@ -1082,10 +1533,15 @@ void *scr_mem_realloc(void *p, size_t n) { return realloc(p, n); } #ifdef SCR_WORKERS void scr_sa_thread_park(void) {} void scr_sa_wait_trims(void) {} +void scr_sa_thread_shares(void) {} void scr_sa_free_foreign(void *p) { free(p); } #endif #endif +#ifndef SCR_SA_WORKER_STARTING +#define SCR_SA_WORKER_STARTING() ((void)0) +#endif + #ifdef SCR_WORKERS /* Blocks above SCR_SA_MAX come from glibc, which gives each thread that * allocates its own arena: a heap reserved up front and made usable with @@ -1116,7 +1572,10 @@ void scr_sa_free_foreign(void *p) { free(p); } * that are not workers (they never reserve). */ static _Thread_local unsigned scr_sa_thread_large; -void scr_sa_thread_starting(void) { scr_sa_thread_large = 1; } +void scr_sa_thread_starting(void) { + scr_sa_thread_large = 1; + SCR_SA_WORKER_STARTING(); +} static void scr_sa_thread_reserve(void) { void *blocks[SCR_SA_THREAD_HEAP_RESERVE / SCR_SA_THREAD_HEAP_STEP + 1]; @@ -1136,7 +1595,7 @@ static void scr_sa_thread_large_note(void) { if (count == SCR_SA_THREAD_RESERVE_AFTER) scr_sa_thread_reserve(); } #else -void scr_sa_thread_starting(void) {} +void scr_sa_thread_starting(void) { SCR_SA_WORKER_STARTING(); } #endif #endif diff --git a/packages/runtime/src/scr_alloc.test.c b/packages/runtime/src/scr_alloc.test.c index b3228ce89..f0efdc935 100644 --- a/packages/runtime/src/scr_alloc.test.c +++ b/packages/runtime/src/scr_alloc.test.c @@ -429,6 +429,332 @@ static void check_trim(void) { } #endif +#if defined(SCR_WORKERS) && SCR_SMALL_ALLOC && defined(__linux__) +#include +#include +#include +#include +#include + +/* A worker thread (scr_sa_thread_starting) that exits without sharing + * gives its memory back: the pages it carved, and the system blocks it + * still holds. Older blocks of the arena, and the memory of a worker that + * shared (or got a remote free of its own blocks), stay. */ +/* DISCARD_SIZE and POISON_SIZE are classes the earlier checks leave unused + * in the workers' arena, so their state there is known. */ +enum { DISCARD_BLOCKS = 1 << 20, DISCARD_SIZE = 40, POISON_SIZE = 56, DISCARD_OLD = 64, DISCARD_LARGE = 64 }; +enum { DISCARD_LARGE_SIZE = 64 << 10 }; +static unsigned char *old_blocks[DISCARD_OLD]; +static unsigned char **discard_blocks; +static unsigned char *discard_large[DISCARD_LARGE]; +static uintptr_t discard_base, discard_lo, discard_hi; +static size_t block_size = DISCARD_SIZE; /* of the workers' and reusing threads' blocks */ +/* Whether discard workers claim the arena of discard_old_owner (no other worker holds it). */ +static bool discard_in_old_arena = true; +/* The end of the highest block of class DISCARD_SIZE so far, and how many blocks of a run lay past the mark + * at its start: those the slice grew for. */ +static uintptr_t class_hi; +static size_t discard_beyond, reuse_beyond; +static bool discard_shares; +static atomic_int discard_step; + +static void wait_step(int step) { + while (atomic_load(&discard_step) < step) { + struct timespec pause = {0, 100000}; + nanosleep(&pause, NULL); + } +} + +/* A plain script thread whose blocks stay live in its parked arena. */ +static void *discard_old_owner(void *arg) { + (void)arg; + for (unsigned i = 0; i < DISCARD_OLD; i++) { + old_blocks[i] = scr_mem_alloc(DISCARD_SIZE); + assert(owned(old_blocks[i])); + fill(old_blocks[i], DISCARD_SIZE, (unsigned char)i); + } + discard_base = scr_sa.base; + scr_sa_thread_park(); + return NULL; +} + +static void allocate_discardable(void) { + discard_lo = UINTPTR_MAX; + discard_hi = 0; + discard_beyond = 0; + for (size_t i = 0; i < DISCARD_BLOCKS; i++) { + unsigned char *p = scr_mem_alloc(block_size); + assert(p && owned(p)); + fill(p, block_size, (unsigned char)i); + discard_blocks[i] = p; + if ((uintptr_t)p >= class_hi) discard_beyond++; + if ((uintptr_t)p < discard_lo) discard_lo = (uintptr_t)p; + if ((uintptr_t)p + block_size > discard_hi) discard_hi = (uintptr_t)p + block_size; + } + if (block_size == DISCARD_SIZE && discard_hi > class_hi) class_hi = discard_hi; + /* System blocks: some freed, some moved by realloc, the rest kept. */ + for (unsigned i = 0; i < DISCARD_LARGE; i++) { + discard_large[i] = scr_mem_alloc(DISCARD_LARGE_SIZE); + assert(discard_large[i] && !owned(discard_large[i])); + fill(discard_large[i], 64, (unsigned char)i); + } + for (unsigned i = 0; i < DISCARD_LARGE; i += 4) { + scr_mem_free(discard_large[i]); + discard_large[i] = NULL; + } + for (unsigned i = 1; i < DISCARD_LARGE; i += 4) discard_large[i] = scr_mem_realloc(discard_large[i], 2 * DISCARD_LARGE_SIZE); +} + +static void *discard_worker(void *arg) { + (void)arg; + scr_sa_thread_starting(); + allocate_discardable(); + /* None of the arena's older blocks or free blocks is reused. */ + if (scr_sa.base == discard_base) + for (unsigned i = 0; i < DISCARD_OLD; i++) assert(discard_lo > (uintptr_t)old_blocks[i]); + else assert(!discard_in_old_arena); + if (discard_shares) scr_sa_thread_shares(); + scr_sa_thread_park(); + return NULL; +} + +/* A worker one of whose blocks the main thread frees while it runs. */ +static void *remote_freed_worker(void *arg) { + (void)arg; + scr_sa_thread_starting(); + allocate_discardable(); + atomic_store(&discard_step, 1); + wait_step(2); + /* A class this thread has not used: its first block takes the slow path, + * which drains the remote free. */ + void *p = scr_mem_alloc(200); + assert(p); + scr_sa_thread_park(); + return NULL; +} + +/* A plain thread that takes as many blocks again from the arena: carved + * ones must be zero (the fast path does not clear them). */ +static size_t reuse_outside; +static uintptr_t reuse_hi; +static void *discard_reuse(void *arg) { + (void)arg; + reuse_outside = 0; + reuse_hi = 0; + reuse_beyond = 0; + for (size_t i = 0; i < DISCARD_BLOCKS; i++) { + unsigned char *p = scr_mem_calloc(block_size); + assert(p && owned(p)); + assert(scr_sa.base == discard_base); + for (size_t k = 0; k < block_size; k++) assert(p[k] == 0); + for (unsigned j = 0; j < DISCARD_OLD; j++) assert(p != old_blocks[j]); + if ((uintptr_t)p < discard_lo || (uintptr_t)p >= discard_hi) reuse_outside++; + if ((uintptr_t)p + block_size > reuse_hi) reuse_hi = (uintptr_t)p + block_size; + if ((uintptr_t)p >= class_hi) reuse_beyond++; + discard_blocks[i] = p; + } + if (block_size == DISCARD_SIZE && reuse_hi > class_hi) class_hi = reuse_hi; + for (size_t i = 0; i < DISCARD_BLOCKS; i++) scr_mem_free(discard_blocks[i]); + scr_sa_thread_park(); + return NULL; +} + +static void run(void *(*fn)(void *)) { + pthread_t t; + assert(pthread_create(&t, NULL, fn, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + scr_sa_wait_trims(); +} + +static void verify_old_blocks(void) { + for (unsigned i = 0; i < DISCARD_OLD; i++) verify(old_blocks[i], DISCARD_SIZE, (unsigned char)i); +} + +/* The worker's blocks stayed as it left them, and the next thread to claim + * the arena carves past them; then they are freed (remote frees). */ +static void verify_kept(void) { + for (size_t i = 0; i < DISCARD_BLOCKS; i++) verify(discard_blocks[i], block_size, (unsigned char)i); + for (unsigned i = 0; i < DISCARD_LARGE; i++) { + if (!discard_large[i]) continue; + verify(discard_large[i], 64, (unsigned char)i); + free(discard_large[i]); + } + for (size_t i = 0; i < DISCARD_BLOCKS; i++) scr_mem_free(discard_blocks[i]); +} + +/* The protection of the mapping that holds address a, from /proc/self/maps. */ +static bool readable(uintptr_t a) { + FILE *maps = fopen("/proc/self/maps", "r"); + assert(maps); + char line[512]; + bool found = false, result = false; + while (!found && fgets(line, sizeof line, maps)) { + unsigned long lo, hi; + char perms[8]; + if (sscanf(line, "%lx-%lx %7s", &lo, &hi, perms) != 3) continue; + if (a >= lo && a < hi) { + found = true; + result = perms[0] == 'r'; + } + } + fclose(maps); + assert(found); + return result; +} + +/* A worker that runs until discard_step reaches 3. */ +static void *holding_worker(void *arg) { + (void)arg; + scr_sa_thread_starting(); + void *p = scr_mem_alloc(DISCARD_SIZE); + assert(p && owned(p)); + atomic_store(&discard_step, 1); + wait_step(3); + scr_sa_thread_park(); + return NULL; +} + +/* A worker that allocates one block of a class the other checks leave + * alone and parks without sharing. */ +static void *small_worker(void *arg) { + (void)arg; + scr_sa_thread_starting(); + void *p = scr_mem_alloc(200); + assert(p && owned(p)); + scr_sa_thread_park(); + return NULL; +} + +/* Discards wait while another worker runs, and the last worker to park + * starts them. When every arena is held by a discard that waits, a worker + * that needs one runs them itself. */ +static void check_deferred_discard(void) { + size_t page = (size_t)sysconf(_SC_PAGESIZE); + atomic_store(&discard_step, 0); + pthread_t holder; + assert(pthread_create(&holder, NULL, holding_worker, NULL) == 0); + wait_step(1); + discard_shares = false; + discard_in_old_arena = false; + pthread_t t; + assert(pthread_create(&t, NULL, discard_worker, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + uintptr_t first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + size_t total = (discard_hi - first) / page; + /* Still resident (the arena is not reused meanwhile, so the blocks are intact). */ + assert(resident_pages(first, discard_hi) > total / 2); + for (size_t i = 0; i < DISCARD_BLOCKS; i += 4099) verify(discard_blocks[i], block_size, (unsigned char)i); + /* More arenas held by waiting discards than there are free ones. */ + for (unsigned n = 0; n < 40; n++) { + assert(pthread_create(&t, NULL, small_worker, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + } + atomic_store(&discard_step, 3); + assert(pthread_join(holder, NULL) == 0); + scr_sa_wait_trims(); + assert(resident_pages(first, discard_hi) < total / 2); + discard_in_old_arena = true; +} + +static void check_discard(void) { + discard_blocks = malloc(DISCARD_BLOCKS * sizeof *discard_blocks); + assert(discard_blocks); + run(discard_old_owner); + size_t page = (size_t)sysconf(_SC_PAGESIZE); + + /* Discarded: its pages are returned, and carved again (zeroed) by the next + * thread, which does not grow the slice. The arena's older blocks stay. */ + discard_shares = false; + run(discard_worker); + verify_old_blocks(); + uintptr_t first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + /* Pre-fault requests still in flight may fault in a few megabytes again. */ + size_t total = (discard_hi - first) / page; + assert(resident_pages(first, discard_hi) < total / 2); + run(discard_reuse); + assert(reuse_outside < 256); + verify_old_blocks(); + + /* SCR_SA_DISCARD=poison makes the pages inaccessible; the next thread + * carves past them. */ + block_size = POISON_SIZE; + setenv("SCR_SA_DISCARD", "poison", 1); + run(discard_worker); + unsetenv("SCR_SA_DISCARD"); + verify_old_blocks(); + first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + assert(!readable(first)); + assert(!readable((discard_hi - 1) & ~(uintptr_t)(page - 1))); + run(discard_reuse); + assert(reuse_outside == DISCARD_BLOCKS); + verify_old_blocks(); + block_size = DISCARD_SIZE; + + /* A worker that shared keeps its memory. */ + discard_shares = true; + run(discard_worker); + verify_old_blocks(); + verify_kept(); + + /* So does one that got a remote free of one of its blocks. */ + atomic_store(&discard_step, 0); + pthread_t t; + assert(pthread_create(&t, NULL, remote_freed_worker, NULL) == 0); + wait_step(1); + scr_mem_free(discard_blocks[0]); + discard_blocks[0] = scr_mem_alloc(DISCARD_SIZE); /* main's own block, for verify_kept */ + fill(discard_blocks[0], DISCARD_SIZE, 0); + atomic_store(&discard_step, 2); + assert(pthread_join(t, NULL) == 0); + scr_sa_wait_trims(); + verify_old_blocks(); + verify_kept(); + + /* SCR_SA_DISCARD=0 keeps every worker's memory. */ + discard_shares = false; + setenv("SCR_SA_DISCARD", "0", 1); + run(discard_worker); + unsetenv("SCR_SA_DISCARD"); + verify_old_blocks(); + verify_kept(); + + /* The kept workers' blocks are free now (remote frees): a worker takes + * them once its slice has no bump room left, and they are free again + * after its memory goes back, so the next thread does not grow the slice + * either. Past the highest block so far, each carves at most the bump room + * the slice had left (a few megabytes). */ + size_t room = ((size_t)4 << 20) / DISCARD_SIZE; + run(discard_worker); + verify_old_blocks(); + assert(discard_beyond < room); + run(discard_reuse); + assert(reuse_beyond < room); + verify_old_blocks(); + + /* Returned regions (holes) of an earlier trim are kept apart while a + * worker runs, and carved again afterwards. */ + trim_blocks = malloc(TRIM_BLOCKS * sizeof *trim_blocks); /* check_trim freed its own */ + assert(trim_blocks); + run(trim_allocate); + uintptr_t hole_lo = trim_lo, hole_hi = trim_hi; + discard_shares = false; + run(discard_worker); + verify_old_blocks(); + for (size_t k = 0; k < TRIM_BLOCKS / TRIM_KEEP; k++) + verify(trim_kept[k], TRIM_SIZE, (unsigned char)(k * TRIM_KEEP)); + trim_lo = hole_lo; + trim_hi = hole_hi; + run(trim_reuse); + assert(trim_outside < 4 * TRIM_BLOCKS / TRIM_KEEP + 256); + for (size_t k = 0; k < TRIM_BLOCKS / TRIM_KEEP; k++) scr_mem_free(trim_kept[k]); + free(trim_blocks); + + check_deferred_discard(); + for (unsigned i = 0; i < DISCARD_OLD; i++) scr_mem_free(old_blocks[i]); + free(discard_blocks); +} +#endif + int main(void) { #if SCR_SMALL_ALLOC check_slice_growth(); /* first: its class must be untouched */ @@ -446,6 +772,7 @@ int main(void) { check_threads(); #ifdef __linux__ check_trim(); + check_discard(); #endif printf("allocator checks passed: size-class workers\n"); #else diff --git a/packages/runtime/src/scr_itable.c b/packages/runtime/src/scr_itable.c index 08db948b5..4842bf79c 100644 --- a/packages/runtime/src/scr_itable.c +++ b/packages/runtime/src/scr_itable.c @@ -428,11 +428,13 @@ static const ScrITableEntry *scr_itable_insert_bytes(ScrITable *t, uint64_t hash const ScrITableEntry *scr_itable_insert_str(ScrITable *t, const ScrStr *key, uint64_t value) { scr_itable_enter(); + scr_sa_thread_shares(); /* the stored value graph is read by every thread */ return scr_itable_insert_bytes(t, scr_itable_str_hash(key), key->data, key->len, value); } const ScrITableEntry *scr_itable_insert_f64(ScrITable *t, double key, uint64_t value) { scr_itable_enter(); + scr_sa_thread_shares(); /* the stored value graph is read by every thread */ uint64_t stored = scr_itable_f64_bits(key) ^ SCR_ITABLE_F64_FLIP; uint64_t hash = scr_itable_f64_hash(stored); ScrITableSegment *seg = scr_itable_segment(t, hash); @@ -588,6 +590,7 @@ const ScrITableEntry *scr_itable_find_arr(ScrITable *t, const ScrArr *key) { const ScrITableEntry *scr_itable_insert_arr(ScrITable *t, const ScrArr *key, uint64_t value) { scr_itable_enter(); + scr_sa_thread_shares(); /* the stored value graph is read by every thread */ char stack[SCR_ITABLE_STACK_KEY]; size_t len; char *bytes = scr_itable_encoded(t, key, stack, sizeof stack, &len); diff --git a/packages/runtime/src/scr_itable.test.c b/packages/runtime/src/scr_itable.test.c index 0f218806b..5e5f22bc9 100644 --- a/packages/runtime/src/scr_itable.test.c +++ b/packages/runtime/src/scr_itable.test.c @@ -8,13 +8,18 @@ #include #include -/* The table unit needs only scr_trap and scr_throw_error_msg from the - * rest of the runtime; refusals are recorded here. */ +/* The table unit needs only scr_trap, scr_throw_error_msg and + * scr_sa_thread_shares from the rest of the runtime; refusals and the + * inserting threads' shares are recorded here. */ _Noreturn void scr_trap(const char *msg) { fputs(msg, stderr); abort(); } +/* Inserts share the stored values with every thread. */ +static atomic_int shares; +void scr_sa_thread_shares(void) { atomic_fetch_add(&shares, 1); } + static char refused[128]; void scr_throw_error_msg(int kind, const char *msg, size_t len) { assert(kind == SCR_ERR_TYPE && len < sizeof refused); @@ -222,6 +227,7 @@ int main(void) { for (unsigned i = 1; i < THREADS; i++) assert(seen_str[i][k] == seen_str[0][k]); assert(scr_itable_size(strings) == KEYS); assert(scr_itable_size(numbers) == KEYS); + assert(atomic_load(&shares) >= 2 * KEYS); printf("intern tables share one entry per key across racing inserts and lookups\n"); return 0; } diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 90b8f822e..57e0a1fbd 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -10709,6 +10709,7 @@ static ScrArr *scr_record_shared_keys(const ScrDynTypedRecordOps *record) { #ifdef SCR_RC_AUDIT scr_arr_live_forget(); /* immortal: outside the exit-time RC audit */ #endif + scr_sa_thread_shares(); /* every thread reads the array */ return built; } built->rc = 1; diff --git a/packages/runtime/src/scr_message.c b/packages/runtime/src/scr_message.c index 684f6c0ca..82428a6fe 100644 --- a/packages/runtime/src/scr_message.c +++ b/packages/runtime/src/scr_message.c @@ -278,6 +278,7 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) * capsule over the same object, a dyn graph as itself. */ if (input->kind == SCR_DYN_TYPED_REF && input->v.typed_ref.ptr && *(const size_t *)input->v.typed_ref.ptr == SIZE_MAX) { + scr_sa_thread_shares(); encoder->visits[id].view = (ScrDyn *)input; ScrMessageNode *node = &encoder->message->nodes[id]; node->kind = SCR_MESSAGE_TYPED_REF; @@ -295,6 +296,7 @@ static size_t scr_message_value(ScrMessageEncoder *encoder, const ScrDyn *input) return id; } if ((input->kind == SCR_DYN_OBJ || input->kind == SCR_DYN_ARR) && input->rc == SIZE_MAX) { + scr_sa_thread_shares(); encoder->visits[id].view = (ScrDyn *)input; ScrMessageNode *node = &encoder->message->nodes[id]; node->kind = SCR_MESSAGE_PUBLISHED; @@ -558,6 +560,7 @@ static ScrMessage *scr_message_try_publish(const ScrDyn *value) { scr_lsan_immortal(d); } } + scr_sa_thread_shares(); message = scr_message_alloc(1, sizeof(*message)); message->nodes = scr_message_alloc(1, sizeof(*message->nodes)); message->count = message->capacity = 1; diff --git a/packages/runtime/src/scr_rc.h b/packages/runtime/src/scr_rc.h index 7e24ff569..cdc03c966 100644 --- a/packages/runtime/src/scr_rc.h +++ b/packages/runtime/src/scr_rc.h @@ -341,11 +341,18 @@ void scr_sa_thread_park(void); /* Waits until the arenas of exited threads are trimmed (tests). */ void scr_sa_wait_trims(void); /* Called first on a new worker thread: prepares the thread's system- - * allocator heap (scr_alloc.c). */ + * allocator heap, and lets the thread's memory go back when it exits + * (scr_alloc.c). */ void scr_sa_thread_starting(void); +/* The calling thread made objects it allocated reachable from other + * threads: a message or an intern table shares a published graph by + * pointer, or a process-wide cache keeps an immortal object. Its memory + * then stays when it exits (scr_alloc.c). */ +void scr_sa_thread_shares(void); #define SCR_SA_FREE_FOREIGN(p) scr_sa_free_foreign(p) #else #define SCR_SA_FREE_FOREIGN(p) free(p) +#define scr_sa_thread_shares() ((void)0) #endif #if SCR_SMALL_ALLOC diff --git a/tests/corpus/native-worker-discarded-heaps.ts b/tests/corpus/native-worker-discarded-heaps.ts new file mode 100644 index 000000000..bf7a76449 --- /dev/null +++ b/tests/corpus/native-worker-discarded-heaps.ts @@ -0,0 +1,102 @@ +import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads"; +import { publish } from "@scriptc/threads"; +import type { ProgramLifetime } from "@scriptc/types"; + +// Workers whose memory goes back when they exit, and workers whose memory +// stays because other threads hold what they allocated. Builder workers +// create ProgramLifetime instances (which scriptc never frees), ordinary +// objects, strings and large typed arrays, post a checksum and exit. A +// publisher worker posts published graphs (a class graph and a plain +// object) and exits. The main thread reads those graphs again after each +// wave of builders, which in scriptc on Linux reuse the memory of the +// builders before them. + +class Node implements ProgramLifetime { + readonly kind: number; + readonly label: string; + readonly children: Node[] = []; + parent: Node | undefined = undefined; + constructor(kind: number, label: string) { + this.kind = kind; + this.label = label; + } +} + +type Summary = { readonly name: string; readonly values: readonly number[]; readonly nested: { readonly total: number } }; + +type Job = { readonly role: string; readonly seed: number }; + +function build(seed: number, count: number): Node { + const root = new Node(seed, "root" + seed); + let parent = root; + for (let i = 0; i < count; i++) { + const node = new Node((i * 7 + seed) % 31, "n" + (i % 101)); + node.parent = parent; + parent.children.push(node); + if (i % 64 === 63) parent = node; + } + return root; +} + +function checksum(root: Node): number { + let sum = 0; + const stack: Node[] = [root]; + while (stack.length > 0) { + const node = stack.pop()!; + sum = (sum * 31 + node.kind + node.label.length + node.children.length) % 1_000_003; + for (const child of node.children) stack.push(child); + } + return sum; +} + +function startWorker(job: Job, onMessage: (value: unknown) => void): Promise { + return new Promise((resolve, reject) => { + const worker = new Worker(new URL(import.meta.url), { workerData: job }); + worker.on("message", onMessage); + worker.once("messageerror", reject); + worker.once("error", reject); + worker.once("exit", () => resolve()); + }); +} + +if (isMainThread) { + let tree: Node | undefined = undefined; + let summary: Summary | undefined = undefined; + // The publisher posts the tree, then the summary. + await startWorker({ role: "publisher", seed: 3 }, (value) => { + if (tree === undefined) tree = value as Node; + else summary = value as Summary; + }); + const describe = (): string => + `tree ${checksum(tree!)} summary ${summary!.name} ${summary!.values.join(",")} ${summary!.nested.total}`; + console.log("published", describe()); + for (let wave = 0; wave < 3; wave++) { + const sums: number[] = []; + await Promise.all( + [1, 2, 3, 4].map((k) => startWorker({ role: "builder", seed: wave * 10 + k }, (value) => sums.push(value as number))), + ); + sums.sort((a, b) => a - b); + console.log("wave", wave, sums.join(" "), describe()); + } +} else { + const job = workerData as Job; + if (job.role === "publisher") { + parentPort!.postMessage(publish(build(job.seed, 20_000))); + const values: number[] = []; + for (let i = 0; i < 50; i++) values.push(i * job.seed); + parentPort!.postMessage(publish({ name: "summary" + job.seed, values, nested: { total: values.length } })); + } else { + const root = build(job.seed, 150_000); + const samples: Float64Array[] = []; + for (let i = 0; i < 40; i++) { + const sample = new Float64Array(8192); + for (let j = 0; j < sample.length; j += 97) sample[j] = i + j + job.seed; + samples.push(sample); + } + let extra = 0; + for (const sample of samples) extra = (extra + sample[97]! + sample[8148]!) % 1_000_003; + const words: string[] = []; + for (let i = 0; i < 20_000; i++) words.push(`word-${i % 977}-${job.seed}`); + parentPort!.postMessage((checksum(root) + extra + words.join("").length) % 1_000_003); + } +} diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 24eca7d43..4263cb627 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -2416,6 +2416,7 @@ "native-worker-clone-errors.ts": 2347, "native-worker-commonjs.cjs": 2188, "native-worker-delayed-messages.ts": 3114, + "native-worker-discarded-heaps.ts": 4430, "native-worker-environment.ts": 3538, "native-worker-error.ts": 2810, "native-worker-exception-state.ts": 3938, @@ -5103,6 +5104,7 @@ "native-worker-clone-errors.ts": 3629, "native-worker-commonjs.cjs": 3085, "native-worker-delayed-messages.ts": 28752, + "native-worker-discarded-heaps.ts": 39440, "native-worker-environment.ts": 27133, "native-worker-error.ts": 2958, "native-worker-exception-state.ts": 3945, From 89b5baedd7bf9be293c949e34f7743bc534f375c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 05:31:40 -0500 Subject: [PATCH 059/117] Add t.assert.snapshot and t.assert.fileSnapshot node:test changes, matching Node 24.22: - t.assert.snapshot(value[, options]) serializes the value with Node's default serializer, JSON.stringify(value, null, 2), or with an options.serializers array literal applied in order, and compares it with assert.strictEqual against the snapshot stored under " " in ".snapshot". - t.assert.fileSnapshot(value, path[, options]) compares the serialized value with the contents of path. - Snapshot files are read in the form Node writes them, exports[`key`] = `value`; statements, with template escapes and CRLF line endings cooked as in a template literal. - Missing snapshots, unreadable snapshot files and throwing serializers throw Node's ERR_INVALID_STATE errors, with Node's messages. - Running the binary with Node's --test-update-snapshots flag as its first argument records the values and writes the snapshot files after the last test, keys sorted as Node sorts them. The flag is kept out of process.argv and appears in process.execArgv, which is otherwise []. - Snapshot assertions count toward the test's plan. The snapshot fixture compares the reporter output with Node, plain and with SCRIPTC_SAN=1, against a snapshot file Node wrote. The update-mode harness test runs Node and the binary with --test-update-snapshots and compares the files they write. The node:test normalization also drops the "... N lines matching cause stack trace ..." line Node prints for an error cause, with the stack frames it summarizes. --- .../limitations/builtin-apis/test-runner.mdx | 1 + .../process-arguments-and-errors.mdx | 2 +- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 16 +- .../generated/node-v24-backlog.json | 34 +- .../generated/node-v24-internal.json | 21 +- internal/compatibility/static-support.json | 1 + .../ambient/scriptc-node-fallback.d.ts | 5 + packages/compiler/src/backend/llvm/emitter.ts | 7 +- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../compiler/src/backend/llvm/lib-test.ts | 8 + .../src/backend/llvm/reference-writes.ts | 1 + .../src/frontend/lowering/builtins/process.ts | 6 +- .../src/frontend/lowering/lower-test.ts | 145 ++++- packages/compiler/src/ir/builtin-effects.ts | 3 + .../compiler/src/ir/builtin-signatures.ts | 15 + packages/compiler/src/library/ir-policy.ts | 1 + .../tests/diagnostics/snapshot-fences.ts.json | 6 + packages/runtime/src/scr_lib.c | 33 + packages/runtime/src/scr_lib.h | 7 + packages/runtime/src/scr_test.c | 572 ++++++++++++++++++ packages/runtime/src/scr_test.h | 14 + tests/diagnostics/snapshot-fences.ts | 19 + .../node-test/cases/snapshot-files/value.json | 6 + tests/fixtures/node-test/cases/snapshot.ts | 72 +++ .../node-test/cases/snapshot.ts.snapshot | 82 +++ .../node-test/update/snapshot-update.ts | 27 + .../__snapshots__/snapshot-fences.ts.txt | 26 + tests/harness/node-test-normalize.ts | 10 +- tests/harness/node-test.test.ts | 67 +- 30 files changed, 1160 insertions(+), 50 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/snapshot-fences.ts.json create mode 100644 tests/diagnostics/snapshot-fences.ts create mode 100644 tests/fixtures/node-test/cases/snapshot-files/value.json create mode 100644 tests/fixtures/node-test/cases/snapshot.ts create mode 100644 tests/fixtures/node-test/cases/snapshot.ts.snapshot create mode 100644 tests/fixtures/node-test/update/snapshot-update.ts create mode 100644 tests/harness/__snapshots__/snapshot-fences.ts.txt diff --git a/docs/content/limitations/builtin-apis/test-runner.mdx b/docs/content/limitations/builtin-apis/test-runner.mdx index be138b3ca..7a50901db 100644 --- a/docs/content/limitations/builtin-apis/test-runner.mdx +++ b/docs/content/limitations/builtin-apis/test-runner.mdx @@ -1 +1,2 @@ - **Concurrent tests:** with `{ concurrency }` above 1, subtests run on their own fibers, and results are reported in declaration order, as in Node. Concurrent bodies resume in Node's order around `beforeEach` hooks and nested suites. Other runner steps, such as `afterEach` and `after` hooks, take no microtask turns between bodies, so code that observes the interleaving of concurrent bodies across those steps can see a different order than Node. +- **Snapshots:** `t.assert.snapshot` and `t.assert.fileSnapshot` compile, with Node's default serializer, `JSON.stringify(value, null, 2)`, or an `options.serializers` array literal. A compiled test reads the snapshot file Node writes beside the entry file, `.snapshot`, at the entry file's path when the program was compiled. Running the binary with Node's flag `--test-update-snapshots` as its first argument writes the snapshot files instead; as in Node, the flag is kept out of `process.argv` and appears in `process.execArgv`. Snapshot files are read in the form Node writes them, `` exports[`key`] = `value`; `` statements. The `snapshot.setDefaultSnapshotSerializers` and `snapshot.setResolveSnapshotPath` module functions throw `SC2020`. diff --git a/docs/content/limitations/process-arguments-and-errors.mdx b/docs/content/limitations/process-arguments-and-errors.mdx index 4cca7a808..d048b4154 100644 --- a/docs/content/limitations/process-arguments-and-errors.mdx +++ b/docs/content/limitations/process-arguments-and-errors.mdx @@ -1,4 +1,4 @@ -`process.argv[0]` is `"scriptc"`, `process.argv[1]` is the binary's path, and program arguments begin at index 2. `process.version` and `process.versions.node` report the Node.js release the runtime is verified against. +`process.argv[0]` is `"scriptc"`, `process.argv[1]` is the binary's path, and program arguments begin at index 2. In programs that use `node:test`, a leading `--test-update-snapshots` argument is Node's snapshot update flag: it is kept out of `process.argv` and appears in `process.execArgv`, which is otherwise `[]`. `process.version` and `process.versions.node` report the Node.js release the runtime is verified against. Uncaught exceptions print `Uncaught ` to stderr instead of Node.js's source excerpt and stack-trace block; thrown strings and numbers print their value. Exit codes and output written before the exception are preserved. Runtime errors expose `message` and Node's `code`, but not `errno`, `syscall`, or `path`. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 1c1969968..500876593 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "823524db8f12948bdc73", + "artifactVersion": "56f660f5e2eb7391a048", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 3a986ebf7..568cdb4c9 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -689,9 +689,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 51, + "partial": 53, "refused": 0, - "not-implemented": 66, + "not-implemented": 64, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -66401,9 +66401,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66424,9 +66424,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 565aadbb3..683d477a5 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1140, - "verify-gap": 2189, + "audit-partial": 1142, + "verify-gap": 2187, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -67667,12 +67667,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.context.assert.fileSnapshot", + "tests": [ + "tests/fixtures/node-test/cases/snapshot.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -67692,12 +67695,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.context.assert.snapshot", + "tests": [ + "tests/fixtures/node-test/cases/snapshot.ts", + "tests/harness/node-test.test.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index d3d1addfe..393955bc0 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -746,9 +746,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 51, + "partial": 53, "refused": 0, - "not-implemented": 66, + "not-implemented": 64, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -90951,6 +90951,7 @@ "tests/fixtures/node-test/cases/mock-timers-date.ts", "tests/fixtures/node-test/cases/mock-timers.ts", "tests/fixtures/node-test/cases/only-nested.ts", + "tests/fixtures/node-test/cases/snapshot.ts", "tests/fixtures/node-test/cases/suite-variants.ts", "tests/fixtures/node-test/cases/todo-suites.ts", "tests/harness/node-test.test.ts" @@ -93602,8 +93603,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.context.assert.fileSnapshot", + "tests": [ + "tests/fixtures/node-test/cases/snapshot.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -93625,8 +93630,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.context.assert.snapshot", + "tests": [ + "tests/fixtures/node-test/cases/snapshot.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index b86e033f9..cdd025b72 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -354,6 +354,7 @@ { "chapter": "url", "parent": "Class: `URL`", "signatures": ["`href` Type: {string}", "`pathname` Type: {string}", "`search` Type: {string}", "`hash` Type: {string}"], "status": "partial", "evidence": ["tests/corpus/node24-url-mutation.ts", "tests/corpus/node24-url-mutation-coercion.js", "tests/fixtures/node-types/url-mutation.ts"] }, { "chapter": "url", "signatures": ["`port` Type: {string}"], "status": "partial", "evidence": ["tests/corpus/2946-url-port-hash.ts"] }, { "chapter": "url", "signatures": ["Legacy `urlObject`", "`urlObject.auth`", "`urlObject.hash`", "`urlObject.host`", "`urlObject.hostname`", "`urlObject.href`", "`urlObject.path`", "`urlObject.pathname`", "`urlObject.port`", "`urlObject.protocol`", "`urlObject.query`", "`urlObject.search`", "`urlObject.slashes`"], "status": "partial", "evidence": ["tests/corpus/5221-url-parse-shapes.ts", "tests/corpus/5222-url-parse-hosts.ts", "tests/corpus/5223-url-parse-query.ts", "tests/corpus/5224-url-format-objects.ts", "tests/fixtures/node-types/url-legacy.ts"] }, + { "chapter": "test", "parent": "`context.assert`", "symbols": ["context.assert.snapshot", "context.assert.fileSnapshot"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/snapshot.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.diagnostic", "context.name"], "status": "partial", "evidence": ["tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.fn"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.method", "mock.reset", "mock.restoreAll"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-method.ts", "tests/corpus/5810-mock-method-records.ts", "tests/corpus/5811-mock-tracker-restore.ts", "tests/harness/node-test.test.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index b9475d51f..8cb8c972f 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3338,7 +3338,12 @@ declare module "node:test" { beforeEach(fn: HookFn): void; afterEach(fn: HookFn): void; } + interface AssertSnapshotOptions { + readonly serializers?: ReadonlyArray<(value: any) => any> | undefined; + } interface TestContextAssert { + snapshot(value: any, options?: AssertSnapshotOptions): void; + fileSnapshot(value: any, path: string, options?: AssertSnapshotOptions): void; ok(value: unknown, message?: string): void; strictEqual(actual: unknown, expected: unknown, message?: string): void; notStrictEqual(actual: unknown, expected: unknown, message?: string): void; diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 5b2561962..8bae1abaf 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -2066,7 +2066,10 @@ export class LlEmitter { if (usesHttp) this.declare(`declare void @scr_http_dyn_install()`); if (usesFetch) this.declare(`declare void @scr_fetch_install()`); - if (usesNodeTest) this.declare(`declare i32 @scr_test_exit_code()`); + if (usesNodeTest) { + this.declare(`declare i32 @scr_test_exit_code()`); + this.declare(`declare void @scr_test_init()`); + } if (snapshotsTlsCa) { this.declare(`declare void @scr_tls_ca_install()`); } @@ -2666,6 +2669,8 @@ export class LlEmitter { ...(usesHttp2 ? [` call void @scr_http2_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, + // node:test takes Node's --test-update-snapshots out of argv first. + ...(usesNodeTest ? [` call void @scr_test_init()`] : []), ...(asyncEntry ? [` %top = call ptr @${mangleAsyncSpawn(this.mod.entry)}()`] : [` call void @${mangleFunction(this.mod.entry)}()`]), diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index c0b3725b7..6a85a8eb3 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -200,6 +200,7 @@ export const LIB_FN_SYMS: Record = { "os.userHomedir": "scr_os_user_homedir", "os.tmpdir": "scr_os_tmpdir", "process.argv": "scr_process_argv", + "process.execArgv": "scr_process_exec_argv", "process.platform": "scr_process_platform", "process.cwd": "scr_process_cwd", "process.pid": "scr_process_pid", diff --git a/packages/compiler/src/backend/llvm/lib-test.ts b/packages/compiler/src/backend/llvm/lib-test.ts index 8ceadae2f..d0d9a9bfc 100644 --- a/packages/compiler/src/backend/llvm/lib-test.ts +++ b/packages/compiler/src/backend/llvm/lib-test.ts @@ -66,6 +66,14 @@ export function emitTestLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlVal return finishRuntimeCall(host, e, "scr_test_ctx_mock_restore_all", a); case "test.ctxMockReset": return finishRuntimeCall(host, e, "scr_test_ctx_mock_reset", a); + case "test.snapshotValue": + return finishRuntimeCall(host, e, "scr_test_snapshot_value", a); + case "test.ctxSnapshot": + return finishRuntimeCall(host, e, "scr_test_ctx_snapshot", a); + case "test.fileSnapshot": + return finishRuntimeCall(host, e, "scr_test_file_snapshot", a); + case "test.snapshotSerialize": + return finishRuntimeCall(host, e, "scr_test_snapshot_serialize", a); case "test.mockTimersEnable": return finishRuntimeCall(host, e, "scr_test_mock_timers_enable", a); case "test.mockTimersTick": diff --git a/packages/compiler/src/backend/llvm/reference-writes.ts b/packages/compiler/src/backend/llvm/reference-writes.ts index 33110eaa4..2371147a9 100644 --- a/packages/compiler/src/backend/llvm/reference-writes.ts +++ b/packages/compiler/src/backend/llvm/reference-writes.ts @@ -106,6 +106,7 @@ const INERT_LIB_CALLS = new Set([ "regex.groupParseInt", "process.cwd", "process.argv", + "process.execArgv", "process.platform", "process.execPath", "process.isTTY", diff --git a/packages/compiler/src/frontend/lowering/builtins/process.ts b/packages/compiler/src/frontend/lowering/builtins/process.ts index 2aa1a47ce..97bf1e963 100644 --- a/packages/compiler/src/frontend/lowering/builtins/process.ts +++ b/packages/compiler/src/frontend/lowering/builtins/process.ts @@ -362,10 +362,10 @@ export function lowerProcessProperty( if (member === "connected") { return { kind: "libCall", fn: "process.connected", args: [], type: BOOL, loc }; } - // process.execArgv: the extra CLI arguments Node itself consumed — a - // compiled binary consumed none, so the honest answer is a fresh []. + // process.execArgv: the Node runtime flags kept out of process.argv — + // a leading --test-update-snapshots in node:test programs, else []. if (member === "execArgv") { - return { kind: "arrayLit", elems: [], type: arrayOf(STRING), loc }; + return { kind: "libCall", fn: "process.execArgv", args: [], type: arrayOf(STRING), loc }; } // process._exiting — the runtime's exit-sequence flag (true while // 'exit' listeners run), Node's own undocumented member. diff --git a/packages/compiler/src/frontend/lowering/lower-test.ts b/packages/compiler/src/frontend/lowering/lower-test.ts index c616f3e73..d18aec305 100644 --- a/packages/compiler/src/frontend/lowering/lower-test.ts +++ b/packages/compiler/src/frontend/lowering/lower-test.ts @@ -21,12 +21,14 @@ import { type IrStmt, type IrType, type SrcLoc, + BOOL, + DYN, F64, STRING, VOID, isUnitType, } from "../../ir/ir.js"; -import { numLit, strLit } from "../../ir/build.js"; +import { dynUndefinedExpr, numLit, strLit, varRef } from "../../ir/build.js"; import { lowerMockContextCall, lowerMockContextProperty, @@ -518,7 +520,11 @@ export function lowerNodeTestModuleCall( ); break; case "snapshot": - lowerer.noLowering("test.snapshot", expr, "snapshot testing has no lowering"); + lowerer.noLowering( + "test.snapshot", + expr, + "t.assert.snapshot and t.assert.fileSnapshot are the supported snapshot surface", + ); break; default: lowerer.noLowering( @@ -557,6 +563,136 @@ export function lowerTestDirectCall( return lowerRegistration(lowerer, expr, "test(...)", loc, 0, null); } +/** t.assert.snapshot(value[, options]) and t.assert.fileSnapshot(value, + * path[, options]), Node's SnapshotManager assertions: the value runs + * through options.serializers, by default Node's JSON.stringify(value, + * null, 2), and String() of the result is compared with + * assert.strictEqual against the snapshot that scr_test.c reads from + * ".snapshot" or `path`, or records in update mode. A throw + * while serializing becomes Node's ERR_INVALID_STATE. */ +function lowerSnapshotAssert( + lowerer: Lowerer, + call: ts.CallExpression, + member: "snapshot" | "fileSnapshot", + testCtx: ts.Expression, +): IrExpr { + const loc = locOf(call); + const what = `t.assert.${member}`; + const t = lowerer.lowerExpr(testCtx); + const stmts: IrStmt[] = []; + const slot = (name: string, type: IrType, init: IrExpr): IrExpr => { + const local = lowerer.declareHiddenLocal(name, type); + stmts.push({ kind: "varDecl", localId: local.id, init, loc }); + return varRef(local.id, type, loc); + }; + // Arguments evaluate in order before the assertion serializes, as in Node. + const valueNode = call.arguments[0]; + const input = slot( + "%snapshotInput", + DYN, + valueNode ? lowerer.lowerExprExpecting(valueNode, DYN) : dynUndefinedExpr(loc), + ); + let path: IrExpr | null = null; + if (member === "fileSnapshot") { + const pathNode = call.arguments[1]; + path = slot( + "%snapshotPath", + STRING, + pathNode ? lowerer.lowerExprExpecting(pathNode, STRING) : strLit("", loc), + ); + } + const serializers = + snapshotSerializers(lowerer, call.arguments[member === "snapshot" ? 1 : 2], what)?.map((fn) => + slot("%snapshotSerializer", DYN, fn), + ) ?? null; + if (call.arguments.length > (member === "snapshot" ? 2 : 3)) { + lowerer.noLowering(`${what} with ${call.arguments.length} arguments`, call); + } + const text: IrExpr = { + kind: "toString", + operand: { + kind: "libCall", + fn: "test.snapshotSerialize", + args: [ + input, + serializers === null + ? dynUndefinedExpr(loc) + : { kind: "dynArrLit", elems: serializers, type: DYN, loc }, + ], + type: DYN, + loc, + }, + type: STRING, + loc, + }; + const actual = slot( + "%snapshotActual", + STRING, + member === "snapshot" + ? { kind: "libCall", fn: "test.snapshotValue", args: [text], type: STRING, loc } + : text, + ); + const expected: IrExpr = + member === "snapshot" + ? { + kind: "libCall", + fn: "test.ctxSnapshot", + args: [t, actual, strLit(`${lowerer.entry.fileName}.snapshot`, loc)], + type: STRING, + loc, + } + : { kind: "libCall", fn: "test.fileSnapshot", args: [actual, path!], type: STRING, loc }; + const no: IrExpr = { kind: "boolLit", value: false, type: BOOL, loc }; + return { + kind: "seqExpr", + stmts, + result: { + kind: "libCall", + fn: "assert.eqStr", + args: [actual, expected, no, no, strLit("", loc), no], + type: VOID, + loc, + }, + type: VOID, + loc, + }; +} + +/** The serializer functions of a snapshot options object literal, as + * checked-dynamic values in order; null without a serializers option. + * Options that are not an object literal, a serializers list that is not + * an array literal, and other options fence. */ +function snapshotSerializers( + lowerer: Lowerer, + options: ts.Expression | undefined, + what: string, +): IrExpr[] | null { + if (options === undefined) return null; + const hint = "pass the options as an object literal: { serializers: [(value) => ...] }"; + if (!ts.isObjectLiteralExpression(options)) { + lowerer.noLowering(`${what} options that are not an object literal`, options, hint); + } + let fns: IrExpr[] | null = null; + for (const prop of options.properties) { + const name = prop.name && ts.isIdentifier(prop.name) ? prop.name.text : null; + if ( + name !== "serializers" || + !(ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) + ) { + lowerer.noLowering(`${what} options other than serializers`, prop, hint); + } + const list = ts.isPropertyAssignment(prop) ? prop.initializer : prop.name; + if (!ts.isArrayLiteralExpression(list)) { + lowerer.noLowering(`${what} with a non-literal serializers list`, list, hint); + } + fns = list.elements.map((el) => { + if (ts.isSpreadElement(el)) lowerer.noLowering(`${what} with a spread serializer`, el, hint); + return lowerer.lowerExprExpecting(el, DYN); + }); + } + return fns; +} + /** `mock.timers` (tracker null) or `t.mock.timers` on a TestContext; * null for other expressions. */ function mockTimersReceiver( @@ -712,7 +848,10 @@ export function lowerTestMethodCall( lowerer.mapTypeOf(lowerer.typeOf(access.expression.expression))?.kind === "testCtx" && lowerer.isStdlibMember(access.expression) ) { - const served = lowerer.lowerAssertModuleCall(call, { module: "assert", member }, loc); + const served = + member === "snapshot" || member === "fileSnapshot" + ? lowerSnapshotAssert(lowerer, call, member, access.expression.expression) + : lowerer.lowerAssertModuleCall(call, { module: "assert", member }, loc); // Each t.assert call counts against the test's plan (t.plan). if (served) return { diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 717c87639..1bb9cbd14 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -18,6 +18,9 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "test.suite", // mock.timers: Node's ERR_INVALID_STATE and ERR_INVALID_ARG_VALUE, and // the throws of the timer callbacks tick and runAll run. + "test.ctxSnapshot", + "test.fileSnapshot", + "test.snapshotSerialize", "test.mockTimersEnable", "test.mockTimersTick", "test.mockTimersRunAll", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index b93490f9d..a9bc17ea6 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1475,6 +1475,18 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ // code per listed API ('T' setTimeout, 'I' setInterval), the `now` // value and its flags (1 given, 2 from a Date). enable, tick, runAll and // setTime throw Node's errors; tick and runAll run timer callbacks. + // t.assert.snapshot and fileSnapshot: the escaped, wrapped serialized + // value, and the stored value it is compared with (snapshot: the test, + // the value, the snapshot file; fileSnapshot: the value, the path). + // Both read or, in update mode, record; missing and unreadable + // snapshots throw Node's ERR_INVALID_STATE. + "test.snapshotValue": { argTypes: [STRING], result: STRING }, + "test.ctxSnapshot": { argTypes: [TESTCTX_T, STRING, STRING], result: STRING }, + "test.fileSnapshot": { argTypes: [STRING, STRING], result: STRING }, + // Node's serializeValue over a dyn array of serializers (undefined for + // the default JSON.stringify(value, null, 2)); a throw becomes Node's + // "The provided serializers did not generate a string." ERR_INVALID_STATE. + "test.snapshotSerialize": { argTypes: [DYN, DYN], result: DYN }, "test.mockTimersEnable": { argTypes: [STRING, F64, F64], result: VOID }, "test.mockTimersTick": { argTypes: [F64], result: VOID }, "test.mockTimersRunAll": { argTypes: [], result: VOID }, @@ -2885,6 +2897,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ }, "fileHandle.stat": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: STATS_T } }, "process.argv": { argTypes: [], result: arrayOf(STRING) }, + // The Node runtime flag a node:test binary took out of process.argv + // (--test-update-snapshots), or [] — a fresh array per read. + "process.execArgv": { argTypes: [], result: arrayOf(STRING) }, "process.platform": { argTypes: [], result: STRING }, // The one libCall whose result type is program-dependent (union ids are // per-module): the `result` here is a placeholder — the libCall case diff --git a/packages/compiler/src/library/ir-policy.ts b/packages/compiler/src/library/ir-policy.ts index 9fe80fdf3..3c3855e5c 100644 --- a/packages/compiler/src/library/ir-policy.ts +++ b/packages/compiler/src/library/ir-policy.ts @@ -196,6 +196,7 @@ export const LIB_NONDETERMINISTIC_PREFIXES: readonly [string, string][] = [ ["blob.fileNew", "the live clock (File lastModified)"], ["process.env", "environment reads"], ["process.argv", "process.argv"], + ["process.execArgv", "process.execArgv"], ["process.cwd", "process.cwd"], ["process.chdir", "process.chdir"], ["process.pid", "process identity"], diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/snapshot-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/snapshot-fences.ts.json new file mode 100644 index 000000000..7449cca82 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/snapshot-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/snapshot-fences.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index baabbe31e..b71f95a32 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -166,6 +166,13 @@ static SCR_TL char **scr_lib_argv_owned = NULL; static SCR_TL char *scr_lib_argv_utf8 = NULL; #endif static SCR_TL bool scr_lib_has_fork = false; +/* A leading Node runtime flag taken out of process.argv (scr_lib_take_flag), + * which process.execArgv reports; NULL without one. */ +static SCR_TL const char *scr_lib_exec_flag = NULL; +#if defined(_WIN32) && !defined(SCR_LIB) +/* The flag's index in the original Windows command line, -1 without one. */ +static SCR_TL int scr_lib_exec_flag_index = -1; +#endif #if !defined(_WIN32) && !defined(__wasi__) && !defined(SCR_LIB) static void scr_title_init(int argc, char **argv); #endif @@ -321,6 +328,7 @@ static void scr_lib_prepare_utf8_argv(void) { // scr_lib_init already consumed this private ASCII fork marker. Do not // reintroduce it when replacing the narrow argument storage. if (i == 1 && scr_lib_has_fork) continue; + if (i == scr_lib_exec_flag_index) continue; int size = WideCharToMultiByte(CP_UTF8, 0, wide[i], -1, NULL, 0, NULL, NULL); if (size == 0 || WideCharToMultiByte(CP_UTF8, 0, wide[i], -1, next, size, NULL, NULL) != size) { free(text); free(args); LocalFree(wide); @@ -565,6 +573,31 @@ const char *scr_lib_arg(int i) { return scr_lib_argv[i]; } +bool scr_lib_take_flag(const char *flag) { + if (scr_lib_argc < 2 || strcmp(scr_lib_argv[1], flag) != 0) return false; + char **args = malloc((size_t)scr_lib_argc * sizeof(char *)); + if (!args) scr_trap("out of memory"); + args[0] = scr_lib_argv[0]; + for (int i = 2; i < scr_lib_argc; i++) args[i - 1] = scr_lib_argv[i]; + args[scr_lib_argc - 1] = NULL; + free(scr_lib_argv_owned); + scr_lib_argv_owned = args; + scr_lib_argv = args; + scr_lib_argc--; +#if defined(_WIN32) && !defined(SCR_LIB) + scr_lib_exec_flag_index = scr_lib_has_fork ? 2 : 1; +#endif + scr_lib_exec_flag = flag; + return true; +} + +ScrArr *scr_process_exec_argv(void) { + ScrArr *arr = scr_arr_new(SCR_ELEM_STR, 1); + if (scr_lib_exec_flag) + scr_arr_push_ref(arr, scr_str_new(scr_lib_exec_flag, strlen(scr_lib_exec_flag))); + return arr; +} + bool scr_lib_fork_info(double *target, uintptr_t *read_handle, uintptr_t *write_handle) { if (!scr_lib_has_fork) return false; diff --git a/packages/runtime/src/scr_lib.h b/packages/runtime/src/scr_lib.h index d240aadbd..4c973e3e5 100644 --- a/packages/runtime/src/scr_lib.h +++ b/packages/runtime/src/scr_lib.h @@ -46,6 +46,13 @@ ScrArr *scr_module_cache_keys(void); int scr_lib_arg_count(void); const char *scr_lib_arg(int i); +/* Takes a leading `flag` argument out of process.argv, as Node keeps its + * runtime flags out of it, and reports it in process.execArgv. Called + * right after scr_lib_init, before process.argv is first read. True when + * the flag was there. */ +bool scr_lib_take_flag(const char *flag); +/* process.execArgv: the flag scr_lib_take_flag took, or [] (+1, fresh). */ +ScrArr *scr_process_exec_argv(void); /* Private self-reexec marker parsed and removed from process.argv by * scr_lib_init. False in an ordinary parent invocation. */ bool scr_lib_fork_info(double *target, uintptr_t *read_handle, diff --git a/packages/runtime/src/scr_test.c b/packages/runtime/src/scr_test.c index f8bca0cfa..9e6da5939 100644 --- a/packages/runtime/src/scr_test.c +++ b/packages/runtime/src/scr_test.c @@ -35,6 +35,7 @@ #include "scr_platform.h" #include "scr_runtime.h" +#include #include #include #include @@ -812,6 +813,575 @@ static void scr_test_print_failures(ScrTestCtx *t, bool *any) { } } +/* ── t.assert.snapshot and t.assert.fileSnapshot ─────────────────────── + * Node's SnapshotManager (lib/internal/test_runner/snapshot.js). A + * snapshot is the serialized value, template-escaped and wrapped in + * newlines, stored under " " in ".snapshot". + * Compare mode reads that file on the first assertion and returns the + * stored value, which the emitted assert.strictEqual compares; update + * mode records the value and writes every file, keys sorted, after the + * last test. The file is read in the form Node writes it: + * exports[`key`] = `value`; statements of template literals. */ + +typedef struct { + ScrStr *key; /* the snapshot id (cooked, as Node's exports keys) */ + ScrStr *value; /* the escaped, wrapped value */ +} ScrSnapEntry; + +typedef struct ScrSnapFile { + ScrStr *path; + ScrSnapEntry *entries; + size_t n, cap; + ScrStr **names; /* nextId's counters: test full names ... */ + long *counts; /* ... and the next number for each */ + size_t nnames, ncap; + bool loaded; + struct ScrSnapFile *next; +} ScrSnapFile; + +static SCR_TL ScrSnapFile *scr_snap_files = NULL; +/* Node's --test-update-snapshots: a leading argument of the binary, + * which scr_test_init takes out of process.argv. */ +static SCR_TL bool scr_test_update_snapshots = false; + +void scr_test_init(void) { + scr_test_update_snapshots = scr_lib_take_flag("--test-update-snapshots"); +} + +static void scr_snap_throw_state(const char *text, size_t len) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_puts(&b, "Invalid state: "); + scr_jb_write(&b, text, len); + ScrStr *msg = scr_jb_finish(&b); + scr_throw_error_msg_code(SCR_ERR_ERROR, msg->data, msg->len, "ERR_INVALID_STATE"); + scr_str_release(msg); +} + +/* "Cannot read snapshot file '.'", with the tip when it is missing. */ +static void scr_snap_throw_file(const char *verb, const ScrStr *file, bool missing) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_puts(&b, "Cannot "); + scr_jb_puts(&b, verb); + scr_jb_puts(&b, " snapshot file '"); + scr_jb_put_str(&b, file); + scr_jb_puts(&b, ".'"); + if (missing) + scr_jb_puts(&b, " Missing snapshots can be generated by rerunning the command with the " + "--test-update-snapshots flag."); + ScrStr *msg = scr_jb_finish(&b); + scr_snap_throw_state(msg->data, msg->len); + scr_str_release(msg); +} + +/* Node's templateEscape: \ ` and ${ escaped for a template literal. */ +static void scr_snap_put_escaped(ScrJsonBuf *b, const char *s, size_t n) { + for (size_t i = 0; i < n; i++) { + if (s[i] == '\\') scr_jb_puts(b, "\\\\"); + else if (s[i] == '`') scr_jb_puts(b, "\\`"); + else if (s[i] == '$' && i + 1 < n && s[i + 1] == '{') scr_jb_puts(b, "\\$"); + else scr_jb_putc(b, s[i]); + } +} + +/* Node's serializeValue: each serializer's result feeds the next; with no + * serializers, the default JSON.stringify(value, null, 2). A throw becomes + * Node's ERR_INVALID_STATE. Returns +1, or NULL after a throw. */ +ScrDyn *scr_test_snapshot_serialize(ScrDyn *value, ScrDyn *serializers) { + ScrDyn *v; + if (serializers->kind != SCR_DYN_ARR) { + ScrDyn *undef = scr_dyn_undefined(); + ScrDyn *space = scr_dyn_new_num(2); + v = scr_json_stringify_value(value, undef, space); + scr_dyn_release(undef); + scr_dyn_release(space); + } else { + v = scr_dyn_retain(value); + for (size_t i = 0; v && i < serializers->v.arr.len; i++) { + ScrDyn *next = scr_dyn_call(serializers->v.arr.items[i], &v, 1, "serializer"); + scr_dyn_release(v); + v = next; + } + } + if (v && !scr_exc_pending()) return v; + scr_dyn_release(v); + scr_exc_clear(); + static const char msg[] = "The provided serializers did not generate a string."; + scr_snap_throw_state(msg, sizeof msg - 1); + return NULL; +} + +ScrStr *scr_test_snapshot_value(ScrStr *serialized) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_putc(&b, '\n'); + scr_snap_put_escaped(&b, serialized->data, serialized->len); + scr_jb_putc(&b, '\n'); + return scr_jb_finish(&b); +} + +static ScrSnapFile *scr_snap_file(ScrStr *path) { + for (ScrSnapFile *f = scr_snap_files; f; f = f->next) { + if (f->path->len == path->len && memcmp(f->path->data, path->data, path->len) == 0) return f; + } + ScrSnapFile *f = calloc(1, sizeof *f); + if (!f) scr_test_oom(); + f->path = scr_str_retain(path); + f->loaded = scr_test_update_snapshots; + f->next = scr_snap_files; + scr_snap_files = f; + return f; +} + +/* nextId(name): " ", counting from 1 per name. */ +static ScrStr *scr_snap_next_id(ScrSnapFile *f, ScrStr *name) { + size_t i = 0; + while (i < f->nnames && + !(f->names[i]->len == name->len && memcmp(f->names[i]->data, name->data, name->len) == 0)) + i++; + if (i == f->nnames) { + if (f->nnames == f->ncap) { + f->ncap = f->ncap ? f->ncap * 2 : 8; + f->names = realloc(f->names, f->ncap * sizeof *f->names); + f->counts = realloc(f->counts, f->ncap * sizeof *f->counts); + if (!f->names || !f->counts) scr_test_oom(); + } + f->names[i] = scr_str_retain(name); + f->counts[i] = 1; + f->nnames++; + } + char num[24]; + int len = snprintf(num, sizeof num, " %ld", f->counts[i]++); + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_put_str(&b, name); + scr_jb_write(&b, num, (size_t)len); + return scr_jb_finish(&b); +} + +static ScrSnapEntry *scr_snap_find(ScrSnapFile *f, const ScrStr *key) { + for (size_t i = 0; i < f->n; i++) { + const ScrStr *k = f->entries[i].key; + if (k->len == key->len && memcmp(k->data, key->data, key->len) == 0) return &f->entries[i]; + } + return NULL; +} + +/* Sets key to value (both moved), replacing an earlier entry. */ +static void scr_snap_set(ScrSnapFile *f, ScrStr *key, ScrStr *value) { + ScrSnapEntry *e = scr_snap_find(f, key); + if (e) { + scr_str_release(key); + scr_str_release(e->value); + e->value = value; + return; + } + if (f->n == f->cap) { + f->cap = f->cap ? f->cap * 2 : 8; + f->entries = realloc(f->entries, f->cap * sizeof *f->entries); + if (!f->entries) scr_test_oom(); + } + f->entries[f->n].key = key; + f->entries[f->n].value = value; + f->n++; +} + +/* Appends the UTF-8 encoding of code point `cp`. */ +static void scr_snap_put_cp(ScrJsonBuf *b, unsigned long cp) { + char u[4]; + size_t n; + if (cp < 0x80) { + u[0] = (char)cp; + n = 1; + } else if (cp < 0x800) { + u[0] = (char)(0xC0 | (cp >> 6)); + u[1] = (char)(0x80 | (cp & 0x3F)); + n = 2; + } else if (cp < 0x10000) { + u[0] = (char)(0xE0 | (cp >> 12)); + u[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); + u[2] = (char)(0x80 | (cp & 0x3F)); + n = 3; + } else { + u[0] = (char)(0xF0 | (cp >> 18)); + u[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + u[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); + u[3] = (char)(0x80 | (cp & 0x3F)); + n = 4; + } + scr_jb_write(b, u, n); +} + +static int scr_snap_hex(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +/* Reads `count` hex digits at s[*i]. */ +static bool scr_snap_hex_run(const char *s, size_t n, size_t *i, int count, unsigned long *out) { + unsigned long v = 0; + for (int k = 0; k < count; k++) { + if (*i >= n) return false; + int h = scr_snap_hex(s[*i]); + if (h < 0) return false; + v = v * 16 + (unsigned long)h; + (*i)++; + } + *out = v; + return true; +} + +/* The cooked value of the template literal whose body starts at s[*i], + * past its opening backtick; *i ends past the closing one. Returns NULL + * for an unterminated literal, an invalid escape, or a substitution. */ +static ScrStr *scr_snap_template(const char *s, size_t n, size_t *i) { + ScrJsonBuf b; + scr_jb_init(&b); + while (*i < n) { + char c = s[(*i)++]; + if (c == '`') return scr_jb_finish(&b); + if (c == '$' && *i < n && s[*i] == '{') break; + if (c == '\r') { + /* Template literals cook CR and CRLF to LF. */ + if (*i < n && s[*i] == '\n') (*i)++; + scr_jb_putc(&b, '\n'); + continue; + } + if (c != '\\') { + scr_jb_putc(&b, c); + continue; + } + if (*i >= n) break; + char e = s[(*i)++]; + unsigned long cp; + switch (e) { + case 'n': + scr_jb_putc(&b, '\n'); + continue; + case 't': + scr_jb_putc(&b, '\t'); + continue; + case 'r': + scr_jb_putc(&b, '\r'); + continue; + case 'b': + scr_jb_putc(&b, '\b'); + continue; + case 'f': + scr_jb_putc(&b, '\f'); + continue; + case 'v': + scr_jb_putc(&b, '\v'); + continue; + case '0': + if (*i < n && s[*i] >= '0' && s[*i] <= '9') goto bad; + scr_jb_putc(&b, '\0'); + continue; + case '\r': + if (*i < n && s[*i] == '\n') (*i)++; + continue; /* line continuation */ + case '\n': + continue; + case 'x': + if (!scr_snap_hex_run(s, n, i, 2, &cp)) goto bad; + scr_snap_put_cp(&b, cp); + continue; + case 'u': + if (*i < n && s[*i] == '{') { + (*i)++; + cp = 0; + size_t start = *i; + while (*i < n && s[*i] != '}') { + int h = scr_snap_hex(s[*i]); + if (h < 0 || cp > 0x10FFFF) goto bad; + cp = cp * 16 + (unsigned long)h; + (*i)++; + } + if (*i >= n || *i == start || cp > 0x10FFFF) goto bad; + (*i)++; + } else if (!scr_snap_hex_run(s, n, i, 4, &cp)) { + goto bad; + } + if (cp >= 0xD800 && cp <= 0xDBFF && *i + 6 <= n && s[*i] == '\\' && s[*i + 1] == 'u') { + size_t j = *i + 2; + unsigned long lo; + if (scr_snap_hex_run(s, n, &j, 4, &lo) && lo >= 0xDC00 && lo <= 0xDFFF) { + cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00); + *i = j; + } + } + scr_snap_put_cp(&b, cp); + continue; + default: + if (e >= '1' && e <= '9') goto bad; + scr_jb_putc(&b, e); /* \\ \` \$ and identity escapes */ + continue; + } + } +bad: + scr_str_release(scr_jb_finish(&b)); + return NULL; +} + +static void scr_snap_skip_space(const char *s, size_t n, size_t *i) { + while (*i < n && (s[*i] == ' ' || s[*i] == '\t' || s[*i] == '\n' || s[*i] == '\r')) (*i)++; +} + +static bool scr_snap_expect(const char *s, size_t n, size_t *i, const char *text) { + size_t len = strlen(text); + if (*i + len > n || memcmp(s + *i, text, len) != 0) return false; + *i += len; + return true; +} + +/* Parses the file's exports[`key`] = `value`; statements. Values are + * escaped again, as Node escapes the exports it read. */ +static bool scr_snap_parse(ScrSnapFile *f, const char *s, size_t n) { + size_t i = 0; + for (;;) { + scr_snap_skip_space(s, n, &i); + if (i >= n) return true; + if (!scr_snap_expect(s, n, &i, "exports[`")) return false; + ScrStr *key = scr_snap_template(s, n, &i); + if (!key) return false; + scr_snap_skip_space(s, n, &i); + bool ok = scr_snap_expect(s, n, &i, "]"); + scr_snap_skip_space(s, n, &i); + ok = ok && scr_snap_expect(s, n, &i, "="); + scr_snap_skip_space(s, n, &i); + ok = ok && scr_snap_expect(s, n, &i, "`"); + ScrStr *raw = ok ? scr_snap_template(s, n, &i) : NULL; + if (!raw) { + scr_str_release(key); + return false; + } + scr_snap_skip_space(s, n, &i); + (void)scr_snap_expect(s, n, &i, ";"); + ScrJsonBuf b; + scr_jb_init(&b); + scr_snap_put_escaped(&b, raw->data, raw->len); + scr_str_release(raw); + scr_snap_set(f, key, scr_jb_finish(&b)); + } +} + +static bool scr_snap_read(ScrSnapFile *f) { + if (f->loaded) return true; + FILE *fp = fopen(f->path->data, "rb"); + if (!fp) { + scr_snap_throw_file("read", f->path, errno == ENOENT); + return false; + } + ScrJsonBuf b; + scr_jb_init(&b); + char chunk[8192]; + size_t got; + while ((got = fread(chunk, 1, sizeof chunk, fp)) > 0) scr_jb_write(&b, chunk, got); + bool read_ok = !ferror(fp); + fclose(fp); + ScrStr *text = scr_jb_finish(&b); + bool ok = read_ok && scr_snap_parse(f, text->data, text->len); + scr_str_release(text); + if (!ok) { + scr_snap_throw_file("read", f->path, false); + return false; + } + f->loaded = true; + return true; +} + +/* Node's escapeSnapshotKey: the JSON string body of the id, with ` and + * ${ escaped (+1). Update mode stores and sorts keys in this form. */ +static ScrStr *scr_snap_escape_key(const ScrStr *key) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_put_json_str(&b, key); + ScrStr *json = scr_jb_finish(&b); + const char *s = json->data + 1; + size_t n = json->len - 2; + ScrJsonBuf out; + scr_jb_init(&out); + for (size_t i = 0; i < n; i++) { + if (s[i] == '`') scr_jb_puts(&out, "\\`"); + else if (s[i] == '$' && i + 1 < n && s[i + 1] == '{') scr_jb_puts(&out, "\\$"); + else scr_jb_putc(&out, s[i]); + } + scr_str_release(json); + return scr_jb_finish(&out); +} + +/* t.assert.snapshot: the stored value for the test's next id (+1), or the + * recorded `value` in update mode. NULL after a throw. */ +ScrStr *scr_test_ctx_snapshot(ScrTestCtx *t, ScrStr *value, ScrStr *file) { + ScrSnapFile *f = scr_snap_file(file); + ScrStr *name = scr_test_ctx_full_name(t); + ScrStr *id = scr_snap_next_id(f, name); + scr_str_release(name); + if (scr_test_update_snapshots) { + scr_snap_set(f, scr_snap_escape_key(id), scr_str_retain(value)); + scr_str_release(id); + return scr_str_retain(value); + } + if (!scr_snap_read(f)) { + scr_str_release(id); + return NULL; + } + ScrSnapEntry *e = scr_snap_find(f, id); + if (!e) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_puts(&b, "Snapshot '"); + scr_jb_put_str(&b, id); + scr_jb_puts(&b, "' not found in '"); + scr_jb_put_str(&b, f->path); + scr_jb_puts(&b, ".' Missing snapshots can be generated by rerunning the command with the " + "--test-update-snapshots flag."); + ScrStr *msg = scr_jb_finish(&b); + scr_snap_throw_state(msg->data, msg->len); + scr_str_release(msg); + scr_str_release(id); + return NULL; + } + scr_str_release(id); + return scr_str_retain(e->value); +} + +static bool scr_snap_write_text(const ScrStr *path, const char *data, size_t len) { + FILE *fp = fopen(path->data, "wb"); + if (!fp) return false; + bool ok = fwrite(data, 1, len, fp) == len; + return fclose(fp) == 0 && ok; +} + +/* mkdirSync(dirname(path), { recursive: true }); false after an error. */ +static bool scr_snap_mkdir_parent(const ScrStr *path) { + size_t end = path->len; + while (end > 0 && path->data[end - 1] != '/' +#ifdef _WIN32 + && path->data[end - 1] != '\\' +#endif + ) + end--; + if (end <= 1) return true; + ScrStr *dir = scr_str_new(path->data, end - 1); + scr_fs_mkdir_recursive(dir); + scr_str_release(dir); + if (!scr_exc_pending()) return true; + scr_exc_clear(); + return false; +} + +/* t.assert.fileSnapshot: the file's contents (+1), or the recorded value + * in update mode, which writes the file. NULL after a throw. */ +ScrStr *scr_test_file_snapshot(ScrStr *value, ScrStr *path) { + if (scr_test_update_snapshots) { + if (!scr_snap_mkdir_parent(path) || !scr_snap_write_text(path, value->data, value->len)) { + scr_snap_throw_file("write", path, false); + return NULL; + } + return scr_str_retain(value); + } + FILE *fp = fopen(path->data, "rb"); + if (!fp) { + scr_snap_throw_file("read", path, errno == ENOENT); + return NULL; + } + ScrJsonBuf b; + scr_jb_init(&b); + char chunk[8192]; + size_t got; + while ((got = fread(chunk, 1, sizeof chunk, fp)) > 0) scr_jb_write(&b, chunk, got); + bool ok = !ferror(fp); + fclose(fp); + ScrStr *text = scr_jb_finish(&b); + if (!ok) { + scr_str_release(text); + scr_snap_throw_file("read", path, false); + return NULL; + } + return text; +} + +/* The next UTF-16 code unit of a UTF-8 key: *low carries the low + * surrogate of an astral character to the following call. */ +static unsigned long scr_snap_unit(const ScrStr *s, size_t *i, unsigned long *low) { + if (*low) { + unsigned long u = *low; + *low = 0; + return u; + } + const unsigned char *d = (const unsigned char *)s->data; + unsigned char c = d[*i]; + size_t len = c < 0x80 ? 1 : c < 0xE0 ? 2 : c < 0xF0 ? 3 : 4; + if (*i + len > s->len) len = s->len - *i; + unsigned long cp = len == 1 ? c : len == 2 ? (c & 0x1Fu) : len == 3 ? (c & 0x0Fu) : (c & 0x07u); + for (size_t k = 1; k < len; k++) cp = (cp << 6) | (d[*i + k] & 0x3Fu); + *i += len; + if (cp < 0x10000) return cp; + *low = 0xDC00 + ((cp - 0x10000) & 0x3FF); + return 0xD800 + ((cp - 0x10000) >> 10); +} + +/* Array.prototype.sort's default order: UTF-16 code units. */ +static int scr_snap_key_cmp(const void *a, const void *b) { + const ScrStr *x = ((const ScrSnapEntry *)a)->key, *y = ((const ScrSnapEntry *)b)->key; + size_t i = 0, j = 0; + unsigned long xl = 0, yl = 0; + while ((i < x->len || xl) && (j < y->len || yl)) { + unsigned long u = scr_snap_unit(x, &i, &xl), v = scr_snap_unit(y, &j, &yl); + if (u != v) return u < v ? -1 : 1; + } + bool xmore = i < x->len || xl, ymore = j < y->len || yl; + return xmore == ymore ? 0 : xmore ? 1 : -1; +} + + +/* writeSnapshotFiles(): every snapshot file of the run, in update mode. */ +static void scr_snap_write_all(void) { + if (!scr_test_update_snapshots) return; + for (ScrSnapFile *f = scr_snap_files; f; f = f->next) { + qsort(f->entries, f->n, sizeof *f->entries, scr_snap_key_cmp); + ScrJsonBuf b; + scr_jb_init(&b); + for (size_t i = 0; i < f->n; i++) { + if (i > 0) scr_jb_putc(&b, '\n'); + scr_jb_puts(&b, "exports[`"); + scr_jb_put_str(&b, f->entries[i].key); + scr_jb_puts(&b, "`] = `"); + scr_jb_put_str(&b, f->entries[i].value); + scr_jb_puts(&b, "`;\n"); + } + ScrStr *text = scr_jb_finish(&b); + if (!scr_snap_mkdir_parent(f->path) || !scr_snap_write_text(f->path, text->data, text->len)) { + fflush(stdout); + fprintf(stderr, "Error [ERR_INVALID_STATE]: Invalid state: Cannot write snapshot file '%.*s.'\n", + (int)f->path->len, f->path->data); + scr_test_suite_hook_failed = true; + } + scr_str_release(text); + } +} + +static void scr_snap_free_all(void) { + while (scr_snap_files) { + ScrSnapFile *f = scr_snap_files; + scr_snap_files = f->next; + for (size_t i = 0; i < f->n; i++) { + scr_str_release(f->entries[i].key); + scr_str_release(f->entries[i].value); + } + for (size_t i = 0; i < f->nnames; i++) scr_str_release(f->names[i]); + free(f->entries); + free(f->names); + free(f->counts); + scr_str_release(f->path); + free(f); + } +} + /* ── the runner fiber ────────────────────────────────────────────────── */ static void scr_test_runner_entry(ScrFiber *self, void *argpack) { @@ -823,6 +1393,7 @@ static void scr_test_runner_entry(ScrFiber *self, void *argpack) { ScrTestCtx *root = scr_test_root; scr_test_run_children(root); scr_test_run_done = true; + scr_snap_write_all(); scr_test_count(root); scr_test_info_line("tests", (double)scr_test_ct_tests); scr_test_info_line("suites", (double)scr_test_ct_suites); @@ -1618,6 +2189,7 @@ int scr_test_exit_code(void) { if (scr_exit_frees()) { scr_test_hooks_free(&scr_test_mocks); scr_mt_free_all(); + scr_snap_free_all(); } /* The runner never finished: a test awaited a promise nobody settles * and the loop exhausted (Node cancels the test and exits 1 — the diff --git a/packages/runtime/src/scr_test.h b/packages/runtime/src/scr_test.h index 3e60f6abd..b1078cccd 100644 --- a/packages/runtime/src/scr_test.h +++ b/packages/runtime/src/scr_test.h @@ -57,6 +57,20 @@ void scr_test_mock_reset(void); void scr_test_ctx_mock_track(ScrTestCtx *t, ScrClosure *restore); void scr_test_ctx_mock_restore_all(ScrTestCtx *t); void scr_test_ctx_mock_reset(ScrTestCtx *t); +/* Called by node:test programs right after scr_lib_init: a leading + * --test-update-snapshots argument, Node's flag, turns on snapshot update + * mode and moves from process.argv to process.execArgv. */ +void scr_test_init(void); +/* t.assert.snapshot and t.assert.fileSnapshot. snapshot_value escapes + * and wraps a serialized value (+1); ctx_snapshot returns the stored value + * for the test's next snapshot id in `file` and file_snapshot the + * contents of `path` (+1), or the recorded value in update mode. Both + * throw Node's ERR_INVALID_STATE for missing or unreadable snapshots and + * return NULL then. */ +ScrStr *scr_test_snapshot_value(ScrStr *serialized); +ScrDyn *scr_test_snapshot_serialize(ScrDyn *value, ScrDyn *serializers); +ScrStr *scr_test_ctx_snapshot(ScrTestCtx *t, ScrStr *value, ScrStr *file); +ScrStr *scr_test_file_snapshot(ScrStr *value, ScrStr *path); /* mock.timers on the module's `mock` and on t.mock: enable({ apis, now }) * (`apis` one code per listed API: 'T' setTimeout, 'I' setInterval, 'M' * setImmediate, 'D' Date, 'W' scheduler.wait, 'A' AbortSignal.timeout; diff --git a/tests/diagnostics/snapshot-fences.ts b/tests/diagnostics/snapshot-fences.ts new file mode 100644 index 000000000..afdf35b70 --- /dev/null +++ b/tests/diagnostics/snapshot-fences.ts @@ -0,0 +1,19 @@ +// t.assert.snapshot and t.assert.fileSnapshot lower with no options and +// with an options object literal whose serializers is an array literal. +// The rest is refused, each with a named diagnostic: options that are not +// an object literal, a serializers list that is not an array literal, and +// a spread serializer. +import { test } from "node:test"; + +test("snapshots", (t) => { + t.assert.snapshot({ a: 1 }); // lowers + t.assert.snapshot(1, { serializers: [(v: number) => `${v}`] }); // lowers + t.assert.fileSnapshot("text", "out.txt"); // lowers + + const options = { serializers: [(v: unknown) => String(v)] }; + t.assert.snapshot(1, options); // options that are not an object literal + + const serializers = [(v: unknown) => String(v)]; + t.assert.snapshot(1, { serializers }); // a serializers list that is not an array literal + t.assert.fileSnapshot(1, "out.txt", { serializers: [...serializers] }); // a spread serializer +}); diff --git a/tests/fixtures/node-test/cases/snapshot-files/value.json b/tests/fixtures/node-test/cases/snapshot-files/value.json new file mode 100644 index 000000000..bb44c02ab --- /dev/null +++ b/tests/fixtures/node-test/cases/snapshot-files/value.json @@ -0,0 +1,6 @@ +{ + "f": 1, + "list": [ + "a" + ] +} \ No newline at end of file diff --git a/tests/fixtures/node-test/cases/snapshot.ts b/tests/fixtures/node-test/cases/snapshot.ts new file mode 100644 index 000000000..eb5d97ce4 --- /dev/null +++ b/tests/fixtures/node-test/cases/snapshot.ts @@ -0,0 +1,72 @@ +// @exit: 1 +// t.assert.snapshot and t.assert.fileSnapshot in compare mode, against the +// snapshot.ts.snapshot file `node --test-update-snapshots` wrote (then +// edited so that one snapshot differs and one is missing). Values serialize +// with JSON.stringify(value, null, 2) unless options.serializers replace +// it; each test numbers its snapshots under its full name; a differing +// snapshot fails as assert.strictEqual does, and missing snapshots and +// files and throwing serializers throw ERR_INVALID_STATE. +import { describe, test } from "node:test"; + +describe("values", () => { + test("records and arrays", (t) => { + t.assert.snapshot({ zeta: 1, alpha: [1, "two", { b: true, a: null }] }); + t.assert.snapshot([{ id: 3, name: "n" }]); + }); + test("strings", (t) => { + t.assert.snapshot("plain"); + t.assert.snapshot("tick ` dollar ${x} backslash \\ newline \n tab \t"); + t.assert.snapshot("unicode é 漢 😀"); + }); + test("scalars", (t) => { + t.assert.snapshot(42); + t.assert.snapshot(-0.5); + t.assert.snapshot(true); + t.assert.snapshot(null); + t.assert.snapshot(undefined); + }); +}); + +test("name with `backticks` and ${braces}", (t) => { + t.assert.snapshot({ ok: true }); +}); + +describe("serializers", () => { + test("run in order", (t) => { + t.assert.snapshot({ n: 5 }, { serializers: [(v: { n: number }) => v.n * 2, (v: number) => `n is ${v}`] }); + t.assert.snapshot("x", { serializers: [(v: string) => v.toUpperCase()] }); + t.assert.snapshot(7, { serializers: [(v: number) => v + 1] }); + }); + test("a throwing serializer", (t) => { + t.assert.snapshot(1, { + serializers: [ + () => { + throw new Error("no"); + }, + ], + }); + }); + test("a circular value", (t) => { + const loop: { self?: unknown } = {}; + loop.self = loop; + t.assert.snapshot(loop); + }); +}); + +test("counts toward the plan", { plan: 2 }, (t) => { + t.assert.snapshot(1); + t.assert.ok(true); +}); + +test("differs from the stored snapshot", (t) => { + t.assert.snapshot({ count: 2 }); +}); + +test("missing from the snapshot file", (t) => { + t.assert.snapshot("new"); +}); + +test("file snapshots", (t) => { + t.assert.fileSnapshot({ f: 1, list: ["a"] }, "tests/fixtures/node-test/cases/snapshot-files/value.json"); + t.assert.fileSnapshot("text", "tests/fixtures/node-test/cases/snapshot-files/missing.txt"); +}); diff --git a/tests/fixtures/node-test/cases/snapshot.ts.snapshot b/tests/fixtures/node-test/cases/snapshot.ts.snapshot new file mode 100644 index 000000000..ba201eb68 --- /dev/null +++ b/tests/fixtures/node-test/cases/snapshot.ts.snapshot @@ -0,0 +1,82 @@ +exports[`counts toward the plan 1`] = ` +1 +`; + +exports[`differs from the stored snapshot 1`] = ` +{ + "count": 1 +} +`; + +exports[`name with \`backticks\` and \${braces} 1`] = ` +{ + "ok": true +} +`; + +exports[`serializers > run in order 1`] = ` +n is 10 +`; + +exports[`serializers > run in order 2`] = ` +X +`; + +exports[`serializers > run in order 3`] = ` +8 +`; + +exports[`values > records and arrays 1`] = ` +{ + "zeta": 1, + "alpha": [ + 1, + "two", + { + "b": true, + "a": null + } + ] +} +`; + +exports[`values > records and arrays 2`] = ` +[ + { + "id": 3, + "name": "n" + } +] +`; + +exports[`values > scalars 1`] = ` +42 +`; + +exports[`values > scalars 2`] = ` +-0.5 +`; + +exports[`values > scalars 3`] = ` +true +`; + +exports[`values > scalars 4`] = ` +null +`; + +exports[`values > scalars 5`] = ` +undefined +`; + +exports[`values > strings 1`] = ` +"plain" +`; + +exports[`values > strings 2`] = ` +"tick \` dollar \${x} backslash \\\\ newline \\n tab \\t" +`; + +exports[`values > strings 3`] = ` +"unicode é 漢 😀" +`; diff --git a/tests/fixtures/node-test/update/snapshot-update.ts b/tests/fixtures/node-test/update/snapshot-update.ts new file mode 100644 index 000000000..7d14509d1 --- /dev/null +++ b/tests/fixtures/node-test/update/snapshot-update.ts @@ -0,0 +1,27 @@ +// Run with --test-update-snapshots (before the program arguments): the +// snapshot assertions record their values, the run writes +// snapshot-update.ts.snapshot with sorted keys and out/value.json, and the +// flag is in process.execArgv instead of process.argv. +import { describe, test } from "node:test"; + +console.log(JSON.stringify(process.argv.slice(2)), JSON.stringify(process.execArgv)); + +describe("suite", () => { + test("values", (t) => { + t.assert.snapshot({ b: 1, a: "x`${y}\\z\n" }); + t.assert.snapshot([1, 2]); + t.assert.snapshot("é 😀 \u0001"); + }); + test("serializers", (t) => { + t.assert.snapshot(3, { serializers: [(v: number) => v * 2] }); + }); +}); + +test("zz last", (t) => { + t.assert.snapshot(undefined); +}); + +test("aa `first` ${x}", (t) => { + t.assert.snapshot(null); + t.assert.fileSnapshot({ f: [1] }, "out/value.json"); +}); diff --git a/tests/harness/__snapshots__/snapshot-fences.ts.txt b/tests/harness/__snapshots__/snapshot-fences.ts.txt new file mode 100644 index 000000000..3f71fd710 --- /dev/null +++ b/tests/harness/__snapshots__/snapshot-fences.ts.txt @@ -0,0 +1,26 @@ +snapshot-fences.ts:14:24 - error SC2020: 't.assert.snapshot options that are not an object literal' is part of the standard library types but has no scriptc lowering yet + + 13 | const options = { serializers: [(v: unknown) => String(v)] }; + 14 | t.assert.snapshot(1, options); // options that are not an object literal + | ^~~~~~~ + 15 | + + hint: pass the options as an object literal: { serializers: [(value) => ...] } + +snapshot-fences.ts:17:26 - error SC2020: 't.assert.snapshot with a non-literal serializers list' is part of the standard library types but has no scriptc lowering yet + + 16 | const serializers = [(v: unknown) => String(v)]; + 17 | t.assert.snapshot(1, { serializers }); // a serializers list that is not an array literal + | ^~~~~~~~~~~ + 18 | t.assert.fileSnapshot(1, "out.txt", { serializers: [...serializers] }); // a spread serializer + + hint: pass the options as an object literal: { serializers: [(value) => ...] } + +snapshot-fences.ts:18:55 - error SC2020: 't.assert.fileSnapshot with a spread serializer' is part of the standard library types but has no scriptc lowering yet + + 17 | t.assert.snapshot(1, { serializers }); // a serializers list that is not an array literal + 18 | t.assert.fileSnapshot(1, "out.txt", { serializers: [...serializers] }); // a spread serializer + | ^~~~~~~~~~~~~~ + 19 | }); + + hint: pass the options as an object literal: { serializers: [(value) => ...] } \ No newline at end of file diff --git a/tests/harness/node-test-normalize.ts b/tests/harness/node-test-normalize.ts index c150bb707..e02b5169b 100644 --- a/tests/harness/node-test-normalize.ts +++ b/tests/harness/node-test-normalize.ts @@ -2,10 +2,11 @@ * node-test.test.ts's function, extracted so the Linux lane applies the * IDENTICAL scrub to both of its in-container lanes. Node's spec reporter * embeds real durations in every line (raw byte-compare is impossible for - * ANY node:test program); stack frames and the inspect property block a - * frame opens are runner-internal output the compiled runtime - * deliberately omits (SEMANTICS.md). Everything else must match - * byte-exactly. */ + * ANY node:test program); stack frames, the "... N lines matching cause + * stack trace ..." line inspect folds an error cause's shared frames into, + * and the inspect property block a frame opens are runner-internal output + * the compiled runtime deliberately omits (SEMANTICS.md). Everything else + * must match byte-exactly. */ /** The documented normalization — durations, frames, the property block. */ export function normalizeNodeTestOutput(stdout: string): string { @@ -16,6 +17,7 @@ export function normalizeNodeTestOutput(stdout: string): string { if (/^\s*\}\s*$/.test(line)) inPropBlock = false; continue; } + if (/^\s+\.\.\. \d+ lines? matching cause stack trace \.\.\.$/.test(line)) continue; if (/^\s+at /.test(line)) { if (line.trimEnd().endsWith("{")) inPropBlock = true; continue; diff --git a/tests/harness/node-test.test.ts b/tests/harness/node-test.test.ts index 7cf10ac50..054a77aaa 100644 --- a/tests/harness/node-test.test.ts +++ b/tests/harness/node-test.test.ts @@ -11,10 +11,12 @@ * NORMALIZATIONS (both lanes): * - "(1.234ms)" duration parentheticals → "(Xms)" * - the "ℹ duration_ms N" summary line → "ℹ duration_ms X" - * - stack frames (" at ...") and the inspect property block a frame - * opens ("... {" through its closing "}") are dropped — Node prints - * its runner-internal frames and an error-property dump the compiled - * runtime deliberately omits (SEMANTICS.md). + * - stack frames (" at ..."), the "... N lines matching cause stack + * trace ..." line that folds an error cause's shared frames, and the + * inspect property block a frame opens ("... {" through its closing + * "}") are dropped — Node prints its runner-internal frames and an + * error-property dump the compiled runtime deliberately omits + * (SEMANTICS.md). * * Fixtures never console.log inside test bodies or hooks: Node's * reporter stream lags console output RACILY (its ordering varies run to @@ -25,7 +27,8 @@ * the RC audit over every case. */ import { spawn } from "node:child_process"; import { createHash } from "node:crypto"; -import { globSync, mkdirSync, readFileSync } from "node:fs"; +import { copyFileSync, globSync, mkdirSync, mkdtempSync, readFileSync } from "node:fs"; +import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, test } from "vitest"; import { compile } from "@scriptc/compiler"; @@ -41,11 +44,12 @@ interface ProgramRun { exitCode: number; } -function runLane(cmd: string, args: string[]): Promise { +function runLane(cmd: string, args: string[], cwd = repoRoot): Promise { return new Promise((resolve, reject) => { - // cwd pinned to the repo root: both reporters render "test at" paths - // relative to the working directory, so the lanes must share one. - const child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"], cwd: repoRoot }); + // cwd pinned to the repo root by default: both reporters render "test + // at" paths relative to the working directory, so the lanes must share + // one. + const child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"], cwd }); const out: Buffer[] = []; let errText = ""; const timer = setTimeout(() => { @@ -125,3 +129,48 @@ describe(`node:test differential (${cases.length} programs${sanitize ? ", saniti 120_000, ); }); + +/* Snapshot update mode: Node's --test-update-snapshots flag, which the + * compiled binary takes as its leading argument. Each lane runs the + * fixture from its own temporary copy (the snapshot file sits beside the + * entry file and fileSnapshot paths resolve against the working + * directory), writes the snapshot files, and then passes in compare mode + * against them. The written files and the printed argv/execArgv match. */ +describe(`node:test snapshot update mode${sanitize ? " (sanitized)" : ""}`, () => { + test("--test-update-snapshots writes the files Node writes", async () => { + const fixture = join(fixturesRoot, "update/snapshot-update.ts"); + const lanes = await Promise.all( + (["node", "native"] as const).map(async (lane) => { + const dir = mkdtempSync(join(tmpdir(), `scriptc-snapshot-${lane}-`)); + const entry = join(dir, "snapshot-update.ts"); + copyFileSync(fixture, entry); + const binary = lane === "native" ? await build(entry) : null; + const run = (update: boolean) => + binary + ? runLane(binary, [...(update ? ["--test-update-snapshots"] : []), "one", "two"], dir) + : runLane( + "node", + [...(update ? ["--test-update-snapshots"] : []), entry, "one", "two"], + dir, + ); + const update = await run(true); + const compare = await run(false); + return { + update, + compare, + snapshot: readFileSync(`${entry}.snapshot`, "utf8"), + file: readFileSync(join(dir, "out/value.json"), "utf8"), + }; + }), + ); + const [node, native] = lanes as [(typeof lanes)[number], (typeof lanes)[number]]; + expect(native.snapshot).toBe(node.snapshot); + expect(native.file).toBe(node.file); + expect(normalize(native.update.stdout)).toBe(normalize(node.update.stdout)); + expect(normalize(native.compare.stdout)).toBe(normalize(node.compare.stdout)); + for (const lane of lanes) { + expect(lane.update.exitCode).toBe(0); + expect(lane.compare.exitCode).toBe(0); + } + }, 120_000); +}); From d09b380098cf505db8db55696eeb08d3b57d06ca Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 05:35:23 -0500 Subject: [PATCH 060/117] Serialize checked-dynamic members of typed records like JSON.stringify The undeclared properties a checked record keeps from its source, and the entries of an `unknown` index signature, now follow SerializeJSONProperty: toJSON runs with the member's key, getters are read, a Buffer becomes its { type, data } form, undefined, function and symbol results are dropped, and a circular structure throws the circular-structure TypeError instead of overflowing the stack. Members whose writing cannot run program code are written directly; the others go through the JSON.stringify protocol walk. Index-signature entries are written from the overflow map in place, without building a key array. --- packages/compiler/src/backend/llvm/walkers.ts | 43 +- .../5841-json-typed-dyn-members.ts.json | 6 + packages/runtime/src/scr_json.c | 430 +++++++++++++----- packages/runtime/src/scr_json.h | 11 +- tests/corpus/5841-json-typed-dyn-members.ts | 76 ++++ tests/harness/corpus-costs.json | 2 + 6 files changed, 418 insertions(+), 150 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5841-json-typed-dyn-members.ts.json create mode 100644 tests/corpus/5841-json-typed-dyn-members.ts diff --git a/packages/compiler/src/backend/llvm/walkers.ts b/packages/compiler/src/backend/llvm/walkers.ts index d3c4f2990..9b8d80b87 100644 --- a/packages/compiler/src/backend/llvm/walkers.ts +++ b/packages/compiler/src/backend/llvm/walkers.ts @@ -64,9 +64,6 @@ export class LlWalkers { private get S(): "i32" | "i64" { return this.host.sizeType; } - private abiOffset(native64: number, wasm32: number): number { - return this.S === "i32" ? wasm32 : native64; - } /** The value-parameter LLVM type of a writer for `t`. */ private valTy(t: IrType): string { @@ -220,10 +217,10 @@ export class LlWalkers { B.line(`call void @scr_jb_put_json_str(ptr %b, ptr %v)`); break; case "dyn": - // Overflow values under an `unknown` index signature: the checked-dynamic tree - // serializes itself (runtime walker). Bare stringify of dyn stays - // frontend-fenced; this writer is reachable only through overflow - // entries. + // A checked-dynamic value serializes itself (runtime walker). + // Bare stringify of dyn stays frontend-fenced, and overflow + // entries under an `unknown` index signature go through + // scr_jb_put_dyn_entry, which also runs the value's toJSON. this.host.declare(`declare void @scr_jb_put_dyn(ptr, ptr)`); B.line(`call void @scr_jb_put_dyn(ptr %b, ptr %v)`); break; @@ -494,10 +491,13 @@ export class LlWalkers { } /** Whether the walker for `t` can leave an exception pending: cyclic - * values, and records serialized through a kept checked source. */ + * values, records serialized through a kept checked source, and + * checked-dynamic values (toJSON methods, getters, BigInts). */ jsonWriteMayThrow(t: IrType, seen = new Set()): boolean { if (traceAdapter(this.host, t) !== null) return true; switch (t.kind) { + case "dyn": + return true; case "array": return this.jsonWriteMayThrow(t.elem, seen); case "union": @@ -537,6 +537,15 @@ export class LlWalkers { `${ovfp} = getelementptr inbounds %${mangleRecordStruct(shape.id)}, ptr %v, i64 0, i32 ${shape.fields.length + 1}`, ); B.line(`${ovf} = load ptr, ptr ${ovfp} ; overflow map`); + if (iv.kind === "dyn") { + // The runtime writes every entry with JSON.stringify's member rules: + // each value's toJSON runs with its key before the entry is dropped + // or written, and containers below it join the circular-structure + // stack. It may leave an exception pending. + host.declare(`declare void @scr_jb_put_dyn_entries(ptr, ptr, ptr, ptr)`); + B.line(`call void @scr_jb_put_dyn_entries(ptr %b, ptr %v, ptr ${ovf}, ptr ${first})`); + return; + } host.declare(`declare ptr @scr_map_keys_js_order(ptr)`); host.declare(`declare double @scr_arr_len(ptr)`); host.declare(`declare ptr @scr_arr_get_ref(ptr, double)`); @@ -576,23 +585,9 @@ export class LlWalkers { B.line(`${val} = call ptr @scr_map_get_str_ref(ptr ${ovf}, ptr ${k}) ; value (+1)`); } // Undefined-valued entries drop, exactly the optional-field rule: a - // dyn value whose dyn kind follows its size_t RC word (enum - // member 6 — scr_runtime.h's ScrDynKind), or a union holding its - // undefined arm. + // union holding its undefined arm. let skipUndef: string | null = null; - if (iv.kind === "dyn") { - const kp = B.tmp(); - const kd = B.tmp(); - const isu = B.tmp(); - B.line( - `${kp} = getelementptr inbounds i8, ptr ${val}, i64 ${this.abiOffset(8, 4)} ; ->kind`, - ); - B.line(`${kd} = load i32, ptr ${kp}`); - B.line( - `${isu} = icmp eq i32 ${kd}, 6 ; SCR_DYN_UNDEF (NULL is 0 — null members DO serialize)`, - ); - skipUndef = isu; - } else if (iv.kind === "union" && undefinedArmTag(iv, this.host.unionsById) >= 0) { + if (iv.kind === "union" && undefinedArmTag(iv, this.host.unionsById) >= 0) { const tag = this.unionTag(B, val, iv.unionId); const isu = B.tmp(); B.line(`${isu} = icmp eq i32 ${tag}, ${undefinedArmTag(iv, this.host.unionsById)}`); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5841-json-typed-dyn-members.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5841-json-typed-dyn-members.ts.json new file mode 100644 index 000000000..08d5b62db --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5841-json-typed-dyn-members.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5841-json-typed-dyn-members.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 90b8f822e..0c5e98dc6 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -502,6 +502,7 @@ typedef struct ScrJsonSeenEnt { const void *ptr; bool is_array; const char *prop; /* static property edge (emitted C literal) */ + size_t prop_len; /* its length, or SIZE_MAX for a NUL-terminated name */ const ScrStr *prop_str; /* overflow-key edge (borrowed for the write) */ size_t index; /* array/tuple index edge */ } ScrJsonSeenEnt; @@ -509,7 +510,7 @@ typedef struct ScrJsonSeenEnt { static void scr_jb_put_edge(ScrJsonBuf *m, const ScrJsonSeenEnt *e) { if (e->prop || e->prop_str) { scr_jb_puts(m, "property '"); - if (e->prop) scr_jb_puts(m, e->prop); + if (e->prop) scr_jb_write(m, e->prop, e->prop_len == SIZE_MAX ? strlen(e->prop) : e->prop_len); else scr_jb_write(m, e->prop_str->data, e->prop_str->len); scr_jb_putc(m, '\''); return; @@ -559,6 +560,7 @@ bool scr_jb_enter(ScrJsonBuf *b, const void *v, bool is_array) { e->ptr = v; e->is_array = is_array; e->prop = NULL; + e->prop_len = SIZE_MAX; e->prop_str = NULL; e->index = 0; return true; @@ -571,6 +573,16 @@ void scr_jb_leave(ScrJsonBuf *b) { void scr_jb_edge_prop(ScrJsonBuf *b, const char *name) { ScrJsonSeenEnt *e = &b->seen[b->seen_len - 1]; e->prop = name; + e->prop_len = SIZE_MAX; + e->prop_str = NULL; +} + +/* A property edge whose name is not NUL-terminated (a declared field name + * from a record source's strided table). */ +static void scr_jb_edge_span(ScrJsonBuf *b, const char *name, size_t len) { + ScrJsonSeenEnt *e = &b->seen[b->seen_len - 1]; + e->prop = name; + e->prop_len = len; e->prop_str = NULL; } @@ -2666,54 +2678,116 @@ ScrDyn *scr_record_source_apply(ScrDyn *snapshot, const void *rec) { return merged; } +static ScrDyn *scr_json_member(const ScrDyn *holder, const ScrStr *key); +static bool scr_jb_try_pure_member(ScrJsonBuf *b, const char *key, size_t key_len, + const ScrStr *key_str, const ScrDyn *value, bool *first); +static bool scr_jb_put_member(ScrJsonBuf *b, const ScrStr *key, ScrDyn *value, bool *first, + void *rec); + /* JSON for a record that kept a source: the view's own-key order, declared * fields through the compiled writer (`field` writes the separator, key * and value of field `index` unless the record lacks it, and answers - * whether it wrote), every other enumerable property through the dyn - * writer with JSON.stringify's member rules, then declared fields the view - * had not seen. May leave an exception pending (a BigInt property). */ + * whether it wrote), every other enumerable property with JSON.stringify's + * member rules (accessors read, toJSON called with the key, undefined, + * function and symbol results dropped, circular structures rejected), then + * declared fields the view had not seen. May leave an exception pending + * (a BigInt property, a throwing toJSON or getter, a circular structure). */ void scr_jb_put_record_source(ScrJsonBuf *b, void *rec, bool (*field)(ScrJsonBuf *, void *, size_t, bool)) { if (!scr_jb_try_record_source(b, rec, field)) scr_jb_puts(b, "{}"); } +/* Writes declared field `index`; when the record is on the circular- + * structure stack, the field's name becomes its edge first. */ +static bool scr_jb_put_source_field(ScrJsonBuf *b, void *rec, const ScrRecordSource *source, + size_t index, bool first, bool on_stack, + bool (*field)(ScrJsonBuf *, void *, size_t, bool)) { + if (on_stack) { + size_t len; + memcpy(&len, source->lens + index * source->len_stride, sizeof len); + const char *name; + memcpy(&name, source->names + index * source->name_stride, sizeof name); + scr_jb_edge_span(b, name, len); + } + return field(b, rec, index, first); +} + /* The same in one lookup: writes the record and answers true when it kept * a source, otherwise writes nothing and answers false. */ bool scr_jb_try_record_source(ScrJsonBuf *b, void *rec, bool (*field)(ScrJsonBuf *, void *, size_t, bool)) { - ScrRecordSource *source = scr_record_source_find(rec); - if (!source) return false; + ScrRecordSource *found = scr_record_source_find(rec); + if (!found) return false; + /* Program code run by a member can add record sources and move the + * table's entries, so the walk keeps its own copy. */ + const ScrRecordSource source = *found; + /* Walkers over cycle-capable shapes have pushed the record already. + * Others push it before the first member that needs the protocol walk, + * so a member leading back to the record closes the circle at the + * record. */ + bool on_stack = b->seen_len && b->seen[b->seen_len - 1].ptr == rec; + bool entered = false; + ScrDyn *view = scr_dyn_retain(source.view); scr_jb_putc(b, '{'); bool first = true; - { - size_t count = source->count; - bool small[64] = { false }; - bool *seen = count <= 64 ? small : calloc(count, sizeof *seen); - if (!seen) scr_json_oom(); - const ScrDyn *view = source->view; - for (size_t i = 0; i < view->v.obj.len && !scr_exc_pending(); i++) { - const ScrDynEntry *entry = &view->v.obj.entries[i]; - size_t index = scr_record_source_index(source, entry->key, entry->key_len); + size_t count = source.count; + bool small[64] = { false }; + bool *seen = count <= 64 ? small : calloc(count, sizeof *seen); + if (!seen) scr_json_oom(); + /* Members whose writing cannot run program code are written in place. + * The first member that can (an accessor, a toJSON method, a getter below + * it) ends that loop: the remaining keys are taken first, as + * SerializeJSONObject takes them before reading any value. */ + size_t i = 0; + for (; i < view->v.obj.len && !scr_exc_pending(); i++) { + const ScrDynEntry *entry = &view->v.obj.entries[i]; + size_t index = scr_record_source_index(&source, entry->key, entry->key_len); + if (index < count) { + if (!seen[index] && scr_jb_put_source_field(b, rec, &source, index, first, on_stack, field)) + first = false; + seen[index] = true; + continue; + } + if (!entry->enumerable) continue; + if (entry->accessor || + !scr_jb_try_pure_member(b, entry->key, entry->key_len, NULL, entry->value, &first)) + break; + } + if (i < view->v.obj.len && !scr_exc_pending() && !on_stack) { + entered = scr_jb_enter(b, rec, false); + on_stack = entered; + } + if (i < view->v.obj.len && !scr_exc_pending()) { + ScrDyn *rest = scr_dyn_new_arr(); + for (size_t j = i; j < view->v.obj.len; j++) { + const ScrDynEntry *entry = &view->v.obj.entries[j]; + if (!entry->enumerable && !scr_record_source_declared(&source, entry->key, entry->key_len)) continue; + ScrStr *name = scr_str_new(entry->key, entry->key_len); + scr_dyn_arr_push(rest, scr_dyn_new_str(name)); + scr_str_release(name); + } + for (size_t j = 0; j < rest->v.arr.len && !scr_exc_pending(); j++) { + const ScrStr *key = rest->v.arr.items[j]->v.str; + size_t index = scr_record_source_index(&source, key->data, key->len); if (index < count) { - if (!seen[index] && field(b, rec, index, first)) first = false; + if (!seen[index] && scr_jb_put_source_field(b, rec, &source, index, first, on_stack, field)) + first = false; seen[index] = true; continue; } - if (!entry->enumerable || entry->accessor) continue; - ScrDynKind kind = entry->value->kind; - if (kind == SCR_DYN_UNDEF || kind == SCR_DYN_FUNC || kind == SCR_DYN_SYMBOL) continue; - if (!first) scr_jb_putc(b, ','); - first = false; - scr_jb_put_json_span(b, entry->key, entry->key_len); - scr_jb_putc(b, ':'); - scr_jb_put_dyn(b, entry->value); + ScrDyn *value = scr_json_member(view, key); + if (!value || !scr_jb_put_member(b, key, value, &first, NULL)) break; } - for (size_t index = 0; index < count && !scr_exc_pending(); index++) { - if (!seen[index] && field(b, rec, index, first)) first = false; - } - if (seen != small) free(seen); + scr_dyn_release(rest); } + for (size_t index = 0; index < count && !scr_exc_pending(); index++) { + if (!seen[index] && scr_jb_put_source_field(b, rec, &source, index, first, on_stack, field)) + first = false; + } + if (seen != small) free(seen); + scr_dyn_release(view); scr_jb_putc(b, '}'); + if (entered) scr_jb_leave(b); return true; } @@ -7156,99 +7230,6 @@ void scr_dyn_key_set_computed(ScrDyn *recv, ScrDyn *key, ScrDyn *value) { scr_str_release(name); } -/* Node's JSON.stringify over a dyn: object members holding undefined DROP, - * array slots holding undefined print null. A bare undefined never arrives - * (the record serializer drops the entry first); print null defensively. */ -void scr_jb_put_dyn(ScrJsonBuf *b, const ScrDyn *d) { - if (d->kind == SCR_DYN_PROXY) { scr_dyn_proxy_unsupported("JSON.stringify"); return; } - switch (d->kind) { - case SCR_DYN_NULL: - case SCR_DYN_UNDEF: - case SCR_DYN_SYMBOL: - case SCR_DYN_FUNC: /* JSON.stringify: functions serialize like undefined */ - scr_jb_puts(b, "null"); - return; - case SCR_DYN_BOOL: - scr_jb_puts(b, d->v.b ? "true" : "false"); - return; - case SCR_DYN_BIGINT: { - static const char message[] = "Do not know how to serialize a BigInt"; - scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); - return; - } - case SCR_DYN_NUM: - scr_jb_put_f64(b, d->v.num); - return; - case SCR_DYN_STR: - scr_jb_put_json_str(b, d->v.str); - return; - case SCR_DYN_BYTES: { - /* Node's JSON.stringify over a typed array: the index-keyed object - * form — {"0":1,"1":2}, using each view's numeric element kind. */ - scr_jb_putc(b, '{'); - for (size_t i = 0; i < d->v.bytes->len; i++) { - if (i > 0) scr_jb_putc(b, ','); - char idx[32]; - snprintf(idx, sizeof idx, "\"%zu\":", i); - scr_jb_puts(b, idx); - scr_jb_put_f64(b, scr_bytes_get(d->v.bytes, (double)i)); - } - scr_jb_putc(b, '}'); - return; - } - case SCR_DYN_ARR: - scr_jb_putc(b, '['); - for (size_t i = 0; i < d->v.arr.len; i++) { - if (i > 0) scr_jb_putc(b, ','); - scr_jb_put_dyn(b, d->v.arr.items[i]); - } - scr_jb_putc(b, ']'); - return; - case SCR_DYN_PROMISE: - /* No own enumerable properties — Node stringifies a promise as {}. */ - scr_jb_puts(b, "{}"); - return; - case SCR_DYN_HANDLE: { - /* Node's JSON.stringify over these classes throws the circular- - * structure TypeError with a V8 path dump we cannot reproduce — - * throw "not supported yet" instead of a wrong shape (SEMANTICS.md). */ - ScrJsonBuf m; - scr_jb_init(&m); - scr_jb_puts(&m, "JSON.stringify of a dynamic "); - scr_jb_puts(&m, scr_dyn_handle_cls(d)); - scr_jb_puts(&m, " is not supported yet"); - scr_throw_error(SCR_ERR_ERROR, scr_jb_finish(&m)); - scr_jb_puts(b, "null"); /* the buffer never surfaces: the pending throw wins */ - return; - } - - case SCR_DYN_TYPED_REF: { - ScrDyn *materialized = scr_dyn_typed_ref_materialize(d); - scr_jb_put_dyn(b, materialized); - scr_dyn_release(materialized); - return; - } - case SCR_DYN_OBJ: { - scr_jb_putc(b, '{'); - bool first = true; - for (size_t i = 0; i < d->v.obj.len; i++) { - const ScrDynEntry *e = &d->v.obj.entries[i]; - if (!e->enumerable) continue; - if (e->value->kind == SCR_DYN_UNDEF || e->value->kind == SCR_DYN_FUNC || e->value->kind == SCR_DYN_SYMBOL) continue; /* dropped, like Node */ - /* engine functions drop too */ - if (!first) scr_jb_putc(b, ','); - first = false; - scr_jb_put_json_span(b, e->key, e->key_len); - scr_jb_putc(b, ':'); - scr_jb_put_dyn(b, e->value); - } - scr_jb_putc(b, '}'); - return; - } - } - scr_trap("scriptc: internal error: invalid dyn kind\n"); -} - /* ── dynCheck failure path ─────────────────────────────────────────────── */ static void scr_dyn_path_render(ScrJsonBuf *b, const ScrDynPath *p) { @@ -9033,9 +9014,12 @@ static bool scr_json_live_container(const ScrDyn *value, bool inspect) { return true; } -static ScrDyn *scr_json_replace(const ScrDyn *holder, const ScrStr *key, const ScrDyn *replacer) { - ScrDyn *value = scr_json_member(holder, key); - if (!value) return NULL; +/* SerializeJSONProperty's toJSON step over a member value (consumed): Date, + * URL and net handles convert through their toJSON, a Buffer through its + * { type, data } view, and an object with a callable toJSON through that + * method, called with the key. Returns the value to serialize (+1), or NULL + * with an exception pending. */ +static ScrDyn *scr_json_to_json(ScrDyn *value, const ScrStr *key) { /* Inspect a typed reference without replacing its live identity. Later * members must read the source again after a callback mutates it. A live * array, or a live record without a `toJSON` field, needs no conversion. */ @@ -9070,6 +9054,13 @@ static ScrDyn *scr_json_replace(const ScrDyn *holder, const ScrStr *key, const S } else scr_dyn_release(method); } scr_dyn_release(view); + return value; +} + +static ScrDyn *scr_json_replace(const ScrDyn *holder, const ScrStr *key, const ScrDyn *replacer) { + ScrDyn *value = scr_json_member(holder, key); + if (!value) return NULL; + value = scr_json_to_json(value, key); if (!value) return NULL; ScrDyn *result = scr_json_callback(replacer, holder, key, value); scr_dyn_release(value); @@ -9365,6 +9356,197 @@ ScrStr *scr_util_format_j_text(ScrStr *text) { return scr_json_circular_or_rethrow(); } +/* The gap of a compact walk; the walks read only its length. */ +static const ScrStr scr_json_compact_gap = { .rc = SIZE_MAX, .len = 0 }; + +#define SCR_JSON_PURE_DEPTH 32 + +/* Writes `value` when writing it runs no program code and meets no cycle: + * JSON primitives, and objects and dense arrays with the default prototype + * whose members are such values, where objects hold only data properties + * under names that are neither array indexes nor "toJSON" (so their own + * key order is their insertion order and no toJSON step applies). Answers + * false, having written part of the value, for anything else, including + * nesting deeper than SCR_JSON_PURE_DEPTH; the caller then truncates the + * buffer and runs the protocol walk. */ +static bool scr_jb_put_pure(ScrJsonBuf *b, const ScrDyn *value, size_t depth) { + switch (value->kind) { + case SCR_DYN_NULL: scr_jb_puts(b, "null"); return true; + case SCR_DYN_BOOL: scr_jb_puts(b, value->v.b ? "true" : "false"); return true; + case SCR_DYN_NUM: scr_jb_put_f64(b, value->v.num); return true; + case SCR_DYN_STR: scr_jb_put_json_str(b, value->v.str); return true; + case SCR_DYN_ARR: + if (value->prototype || value->v.arr.presence || value->v.arr.properties || + depth == SCR_JSON_PURE_DEPTH) + return false; + scr_jb_putc(b, '['); + for (size_t i = 0; i < value->v.arr.len; i++) { + if (i > 0) scr_jb_putc(b, ','); + const ScrDyn *item = value->v.arr.items[i]; + if (scr_json_omitted(item)) scr_jb_puts(b, "null"); + else if (!scr_jb_put_pure(b, item, depth + 1)) return false; + } + scr_jb_putc(b, ']'); + return true; + case SCR_DYN_OBJ: { + if (value->prototype || depth == SCR_JSON_PURE_DEPTH) return false; + scr_jb_putc(b, '{'); + bool first = true; + for (size_t i = 0; i < value->v.obj.len; i++) { + const ScrDynEntry *entry = &value->v.obj.entries[i]; + if (!entry->enumerable) continue; + double index; + if (entry->accessor || (entry->key_len == 6 && memcmp(entry->key, "toJSON", 6) == 0) || + (entry->key_len && (unsigned char)(entry->key[0] - '0') < 10 && + scr_dyn_key_is_index(entry->key, entry->key_len, &index))) + return false; + if (scr_json_omitted(entry->value)) continue; + if (!first) scr_jb_putc(b, ','); + first = false; + scr_jb_put_json_span(b, entry->key, entry->key_len); + scr_jb_putc(b, ':'); + if (!scr_jb_put_pure(b, entry->value, depth + 1)) return false; + } + scr_jb_putc(b, '}'); + return true; + } + default: + return false; + } +} + +/* Writes the separator, key and value of an object member whose value + * scr_jb_put_pure can write, or drops a member holding undefined, a + * function or a symbol. `key_str`, when not NULL, is the key as a string. + * Answers false, with the buffer and `first` as they were, for a value + * that needs the protocol walk. */ +static inline __attribute__((always_inline)) bool scr_jb_try_pure_member( + ScrJsonBuf *b, const char *key, size_t key_len, const ScrStr *key_str, const ScrDyn *value, + bool *first) { + if (scr_json_omitted(value)) return true; + size_t mark = b->len; + if (!*first) scr_jb_putc(b, ','); + if (key_str) scr_jb_put_json_str(b, key_str); + else scr_jb_put_json_span(b, key, key_len); + scr_jb_putc(b, ':'); + if (scr_jb_put_pure(b, value, 0)) { + *first = false; + return true; + } + b->len = mark; + return false; +} + +/* Writes one object member of a typed container: `value` (consumed) goes + * through its toJSON step, an undefined, function or symbol result drops + * the member, and any other result is written after the separator and the + * key through the protocol walk, whose circular-structure checks share the + * buffer's stack. The container is the top of that stack, or `rec` is + * pushed for the walk when it is not; the key becomes the container's + * edge. Answers false with an exception pending. */ +static bool scr_jb_put_member_walk(ScrJsonBuf *b, const ScrStr *key, ScrDyn *value, + bool *first, void *rec) { + ScrDyn *child = scr_json_to_json(value, key); + if (!child) return false; + if (scr_json_omitted(child)) { + scr_dyn_release(child); + return true; + } + bool entered = rec && !(b->seen_len && b->seen[b->seen_len - 1].ptr == rec); + if (entered && !scr_jb_enter(b, rec, false)) { + scr_dyn_release(child); + return false; + } + if (!*first) scr_jb_putc(b, ','); + *first = false; + scr_jb_put_json_str(b, key); + scr_jb_putc(b, ':'); + scr_jb_edge_key(b, key); + bool ok = scr_json_replaced_write(b, child, scr_dyn_undefined(), NULL, &scr_json_compact_gap, + b->seen_len); + if (entered) scr_jb_leave(b); + scr_dyn_release(child); + return ok; +} + +/* scr_jb_put_member_walk, writing the member directly when scr_jb_put_pure + * can write its value. */ +static bool scr_jb_put_member(ScrJsonBuf *b, const ScrStr *key, ScrDyn *value, bool *first, + void *rec) { + if (scr_jb_try_pure_member(b, key->data, key->len, key, value, first)) { + scr_dyn_release(value); + return true; + } + return scr_jb_put_member_walk(b, key, value, first, rec); +} + +/* An entry of a record's `unknown` index signature, written after the + * record's earlier members with JSON.stringify's member rules + * (scr_jb_put_member). Walkers over cycle-capable shapes have pushed the + * record already; others push it for an entry that needs the protocol + * walk. May leave an exception pending. */ +static void scr_jb_put_dyn_entry(ScrJsonBuf *b, void *rec, const ScrStr *key, + const ScrDyn *value, bool *first) { + if (scr_jb_try_pure_member(b, key->data, key->len, key, value, first)) return; + scr_jb_put_member_walk(b, key, scr_dyn_retain((ScrDyn *)value), first, rec); +} + +/* The entries of record `rec`'s `unknown` index signature (`map`: string + * keys, checked-dynamic values) in JS own-key order, each with + * scr_jb_put_dyn_entry's rules. Without array-index keys that order is the + * map's insertion order, walked in place: the walk holds the map's + * iteration count so no compaction moves entries, rereads each entry by + * position, and stops at the entries present when it started, so a toJSON + * call that adds or deletes entries sees Node's result (keys taken first, + * deleted ones read as undefined). With array-index keys the walk takes the + * ordered key list first. May leave an exception pending. */ +void scr_jb_put_dyn_entries(ScrJsonBuf *b, void *rec, ScrMap *map, bool *first) { + uint32_t count = map->nentries; + bool indexed = false; + for (uint32_t i = 0; i < count && !indexed; i++) { + if (!map->entries[i].hash) continue; + const ScrStr *key = (const ScrStr *)(uintptr_t)map->entries[i].key; + uint32_t index; + indexed = scr_key_array_index(key->data, key->len, &index); + } + if (indexed) { + ScrArr *keys = scr_map_keys_js_order(map); + for (size_t i = 0; i < keys->len && !scr_exc_pending(); i++) { + ScrStr *key = scr_arr_get_ref(keys, (double)i); + ScrDyn *value = scr_map_get_str_ref(map, key); + if (value) { + scr_jb_put_dyn_entry(b, rec, key, value, first); + scr_dyn_release(value); + } + scr_str_release(key); + } + scr_arr_release(keys); + return; + } + map->iter_depth++; + for (uint32_t i = 0; i < count && !scr_exc_pending(); i++) { + const ScrMapEntry *entry = &map->entries[i]; + if (!entry->hash) continue; + const ScrStr *key = (const ScrStr *)(uintptr_t)entry->key; + const ScrDyn *value = (const ScrDyn *)(uintptr_t)entry->val; + if (scr_jb_try_pure_member(b, key->data, key->len, key, value, first)) continue; + /* The walk can run program code, which may replace this entry. */ + ScrStr *held_key = scr_str_retain((ScrStr *)key); + scr_jb_put_member_walk(b, held_key, scr_dyn_retain((ScrDyn *)value), first, rec); + scr_str_release(held_key); + } + map->iter_depth--; +} + +/* Writes a dyn value whose toJSON step has run through the protocol walk: + * undefined, functions and symbols as null (an array slot's rule), and + * containers with toJSON, accessor and circular-structure handling. May + * leave an exception pending. */ +void scr_jb_put_dyn(ScrJsonBuf *b, const ScrDyn *d) { + if (scr_json_omitted(d)) scr_jb_puts(b, "null"); + else scr_json_replaced_write(b, d, scr_dyn_undefined(), NULL, &scr_json_compact_gap, b->seen_len); +} + /* Untyped RC adapters (box/promise/exception-cell currency). */ void *scr_dyn_retain_v(void *d) { return scr_dyn_retain((ScrDyn *)d); } void scr_dyn_release_v(void *d) { scr_dyn_release((ScrDyn *)d); } diff --git a/packages/runtime/src/scr_json.h b/packages/runtime/src/scr_json.h index 03c9fb7cf..8a353f40a 100644 --- a/packages/runtime/src/scr_json.h +++ b/packages/runtime/src/scr_json.h @@ -162,9 +162,16 @@ void scr_jb_put_number(ScrJsonBuf *b, double v); void scr_jb_put_json_str(ScrJsonBuf *b, const ScrStr *s); /* JSON-serialize a dyn value into the buffer — the sc_jw_* walker for the - * dyn leaves the compiler cannot type: object members holding undefined - * DROP, array slots holding undefined print null (exactly Node). */ + * dyn leaves the compiler cannot type: undefined prints null (an array + * slot's rule); containers follow JSON.stringify (toJSON, accessors, + * circular structures). May leave an exception pending. */ void scr_jb_put_dyn(ScrJsonBuf *b, const ScrDyn *d); +/* The entries of record `rec`'s `unknown` index signature (its overflow + * map) after the record's earlier members: separators, keys and values in + * JS own-key order with JSON.stringify's member rules (toJSON called with + * the key, undefined, function and symbol results dropped). `first` is the + * record's first-member flag. May leave an exception pending. */ +void scr_jb_put_dyn_entries(ScrJsonBuf *b, void *rec, ScrMap *map, bool *first); /* Typed JSON for a record that kept a source: the kept key order, declared * fields through the compiled per-field writer. `try` writes nothing and * answers false for a record without one. */ diff --git a/tests/corpus/5841-json-typed-dyn-members.ts b/tests/corpus/5841-json-typed-dyn-members.ts new file mode 100644 index 000000000..e8f7f02bb --- /dev/null +++ b/tests/corpus/5841-json-typed-dyn-members.ts @@ -0,0 +1,76 @@ +// JSON.stringify over typed records whose members are checked-dynamic +// values: the undeclared properties a checked record keeps from its source, +// and the entries of an `unknown` index signature. Each member follows +// SerializeJSONProperty: toJSON runs with the member's key, getters are +// read, a Buffer becomes its { type, data } form, undefined, function and +// symbol results drop, and a circular structure throws V8's TypeError. +type Point = { a: number }; +type Bag = { a: number; [key: string]: unknown }; + +const report = (label: string, run: () => string | undefined): void => { + try { + console.log(label, run()); + } catch (error) { + const e = error as Error; + console.log(label, e.name); + console.log(e.message); + } +}; + +const source: any = JSON.parse('{"a":1,"b":"two"}'); +source.stamp = { toJSON: (key: string) => `stamp:${key}` }; +source.gone = { toJSON: () => undefined }; +source.bytes = Buffer.from("hi"); +Object.defineProperty(source, "computed", { get: () => 42, enumerable: true }); +source.list = [1, { toJSON: (key: string) => `item:${key}` }]; +const point = source as Point; +report("source", () => JSON.stringify(point)); +report("source pretty", () => JSON.stringify(point, null, 2)); +report("source nested", () => JSON.stringify({ point, n: 2 })); +report("source array", () => JSON.stringify([point, point])); + +const bag: Bag = { a: 1 }; +bag.stamp = { toJSON: (key: string) => `stamp:${key}` }; +bag.gone = { toJSON: () => undefined }; +bag.data = JSON.parse('{"x":[1,2,{"y":null}]}'); +bag.nothing = undefined; +bag.order = JSON.parse('{"b":1,"2":"two","a":2,"0":"zero"}'); +const layered: any = JSON.parse('{"level":{"items":[1,{"x":null}]}}'); +layered.level.items.push({ toJSON: (key: string) => `deep:${key}` }); +bag.deep = layered; +const hidden: any = JSON.parse('{"shown":1}'); +Object.defineProperty(hidden, "hidden", { value: 2, enumerable: false }); +bag.hidden = hidden; +let nested: any = JSON.parse('{"end":true}'); +for (let i = 0; i < 40; i++) nested = { i, nested }; +bag.nested = nested; +report("bag", () => JSON.stringify(bag)); +report("bag in array", () => JSON.stringify([bag])); + +const self: any = JSON.parse('{"k":1}'); +self.self = self; +const cyclic: any = JSON.parse('{"a":1,"x":{"k":2}}'); +cyclic.x.self = cyclic.x; +report("source circular", () => JSON.stringify(cyclic as Point)); +const deep: any = JSON.parse('{"a":1,"x":{"y":{"z":{"w":{"v":{}}}}}}'); +deep.x.y.z.w.v.back = deep.x; +report("source deep circular", () => JSON.stringify(deep as Point)); +const circular: Bag = { a: 1 }; +circular.loop = self; +report("bag circular", () => JSON.stringify(circular)); +report("bag circular nested", () => JSON.stringify({ outer: circular })); + +const shared: any = JSON.parse('{"v":1}'); +const twice: Bag = { a: 1, first: shared, second: shared }; +report("bag shared", () => JSON.stringify(twice)); + +const big: any = JSON.parse('{"a":1}'); +big.n = 1n; +report("source bigint", () => JSON.stringify(big as Point)); +const throwing: Bag = { a: 1 }; +throwing.bad = { + toJSON: () => { + throw new RangeError("from toJSON"); + }, +}; +report("bag throwing", () => JSON.stringify(throwing)); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index a70416b71..a70da246a 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1909,6 +1909,7 @@ "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, + "5841-json-typed-dyn-members.ts": 5467, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4601,6 +4602,7 @@ "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, + "5841-json-typed-dyn-members.ts": 3238, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 85fe87ffbf1b40e89390b1dd0ad6f18730bfaec4 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 05:40:08 -0500 Subject: [PATCH 061/117] Convert Date values into unknown slots as Dates A TypeScript Date placed in an `unknown` slot (an annotated binding, an object or array literal, a record or class field) becomes a Date holding the same time value. Before, a Date member of an `unknown` object literal became a function, and other conversions were refused. util.inspect prints these Dates in their ISO form or as Invalid Date, and their methods can be read as values through untyped references. Comparisons with a Date operand keep their fence: each conversion creates a new Date. --- .../content/limitations/builtin-apis/date.mdx | 2 +- packages/compiler/src/backend/llvm/dyn.ts | 9 +++ .../src/frontend/lowering/lower-exprs.ts | 18 +++++- .../src/frontend/lowering/lower-stmts.ts | 2 +- packages/compiler/src/ir/ir.ts | 1 + .../corpus/5844-date-unknown-values.ts.json | 6 ++ packages/runtime/src/scr_dyn.h | 1 + packages/runtime/src/scr_inspect.c | 1 + packages/runtime/src/scr_lib.c | 62 ++++++++++++++++++- tests/corpus/5844-date-unknown-values.ts | 57 +++++++++++++++++ tests/diagnostics/utility-types.ts | 6 +- .../__snapshots__/utility-types.ts.txt | 11 +--- tests/harness/corpus-costs.json | 2 + 13 files changed, 160 insertions(+), 18 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5844-date-unknown-values.ts.json create mode 100644 tests/corpus/5844-date-unknown-values.ts diff --git a/docs/content/limitations/builtin-apis/date.mdx b/docs/content/limitations/builtin-apis/date.mdx index 605de4511..db5278c53 100644 --- a/docs/content/limitations/builtin-apis/date.mdx +++ b/docs/content/limitations/builtin-apis/date.mdx @@ -1 +1 @@ -- **Date:** Date unions, year/month constructors, setters, statically typed TypeScript identity comparisons, thrown Date values, and locale/string formatters are unsupported. Zero-argument and single number/string constructors, storage and passing, `getTime`, `valueOf`, `toISOString`, `toJSON` (a `string | null`: null for an invalid date, as in Node), calendar getters, `getTimezoneOffset`, and single-string `Date.parse` compile. JavaScript Dates retain identity through checked storage and support Date-copy construction and JSON serialization. See [Dates and timezones](#dates-and-timezones) for parsing restrictions. +- **Date:** Date unions, year/month constructors, setters, statically typed TypeScript identity comparisons, thrown Date values, and locale/string formatters are unsupported. Zero-argument and single number/string constructors, storage and passing, `getTime`, `valueOf`, `toISOString`, `toJSON` (a `string | null`: null for an invalid date, as in Node), calendar getters, `getTimezoneOffset`, and single-string `Date.parse` compile. JavaScript Dates retain identity through checked storage and support Date-copy construction and JSON serialization. A TypeScript Date converted to `unknown` becomes a Date with the same time value; each conversion creates a new Date, so two `unknown` values converted from one TypeScript Date are not `===`. See [Dates and timezones](#dates-and-timezones) for parsing restrictions. diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index d16d8244c..bb35e70c2 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -2418,6 +2418,15 @@ export class LlDyn { const B = new BlockBuilder(); let sourceAccessor: { name: string; release: string } | null = null; switch (t.kind) { + case "date": { + // A Date handle holding the same time value; native Dates are + // immutable values, and so is the handle. + host.declare(`declare ptr @scr_dyn_native_date_from_ms(double)`); + const r = B.tmp(); + B.line(`${r} = call ptr @scr_dyn_native_date_from_ms(double %v)`); + B.terminate(`ret ptr ${r}`); + break; + } case "url": case "searchParams": { const native = t.kind === "url" ? "url" : "search_params"; diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 391dd7c88..6774de117 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -10576,7 +10576,14 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr loc, }; if (bothStr) return { kind: "strCmp", op: cmpOp, left, right, type: BOOL, loc }; - if (lowerer.dynConvertible(left.type) && lowerer.dynConvertible(right.type)) { + // A Date converts to a new checked-dynamic Date on each crossing, so + // comparisons keep their Date fence instead of comparing copies. + if ( + left.type.kind !== "date" && + right.type.kind !== "date" && + lowerer.dynConvertible(left.type) && + lowerer.dynConvertible(right.type) + ) { return { kind: "libCall", fn: "dyn.compare", @@ -10826,7 +10833,14 @@ export function lowerStrictEquality( loc, }; } - if (lowerer.dynConvertible(idLeft.type) && lowerer.dynConvertible(idRight.type)) { + // A Date converts to a new checked-dynamic Date on each crossing; its + // identity has no representation, so equality keeps the fence. + if ( + idLeft.type.kind !== "date" && + idRight.type.kind !== "date" && + lowerer.dynConvertible(idLeft.type) && + lowerer.dynConvertible(idRight.type) + ) { return { kind: "dynScalarEq", left: lowerer.coerceToExpected(idLeft, DYN), diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index a437a05c2..ad4fd5312 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -5302,7 +5302,7 @@ function lowerDynSwitch( loc: locOf(expression), }; } - if (!lowerer.dynConvertible(test.type)) { + if (test.type.kind === "date" || !lowerer.dynConvertible(test.type)) { lowerer.unsupported( "SC1100", expression, diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 9ba7a7321..9591c684a 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -4055,6 +4055,7 @@ function canBoxDynCompositeAt( case "regex": case "url": case "searchParams": + case "date": return true; case "func": return canBoxFuncIntoDyn(t, getRecord, getUnion, visiting); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5844-date-unknown-values.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5844-date-unknown-values.ts.json new file mode 100644 index 000000000..7331cf7f0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5844-date-unknown-values.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5844-date-unknown-values.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 416696717..667ceced0 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -600,6 +600,7 @@ ScrDyn *scr_dyn_native_search_params(ScrSearchParams *value); bool scr_dyn_native_search_params_is(const ScrDyn *value); bool scr_dyn_native_date_is(const ScrDyn *value); ScrDyn *scr_dyn_native_date_new(const ScrDyn *arguments); +ScrDyn *scr_dyn_native_date_from_ms(double ms); double scr_dyn_native_date_value(const ScrDyn *value); ScrDyn *scr_dyn_native_regex(ScrRegex *value); bool scr_dyn_native_regex_is(const ScrDyn *value); diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 7479cb548..34438353f 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -1243,6 +1243,7 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { if (d->v.handle.tag == SCR_DYNH_WEAK_MAP || d->v.handle.tag == SCR_DYNH_WEAK_SET) return scr_insp_weak_collection(d->v.handle.tag == SCR_DYNH_WEAK_MAP ? "WeakMap" : "WeakSet", recurse, depth); + if (d->v.handle.tag == SCR_DYNH_DATE) return scr_insp_date(scr_dyn_native_date_value(d)); const ScrDynHandleOps *ops = scr_dyn_handle_ops_of(d); if (ops->inspect_view) { /* Node's custom inspectors answer the bare class name beyond the diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index baabbe31e..f261d28cb 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -10883,9 +10883,69 @@ ScrDyn *scr_dyn_native_date_new(const ScrDyn *arguments) { else if (!scr_dyn_number_coerce_js(value, &ms)) return NULL; ms = scr_date_new_ms(ms); } + return scr_dyn_native_date_from_ms(ms); +} + +/* The Date.prototype methods scr_native_date_invoke answers. */ +static const char *const scr_native_date_methods[] = { + "getTime", "valueOf", "toISOString", "toJSON", "getFullYear", "getUTCFullYear", "getMonth", + "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", "getUTCHours", + "getMinutes", "getUTCMinutes", "getSeconds", "getUTCSeconds", "getMilliseconds", + "getUTCMilliseconds", "getTimezoneOffset", +}; +#define SCR_NATIVE_DATE_METHODS (sizeof scr_native_date_methods / sizeof scr_native_date_methods[0]) +static SCR_TL ScrDyn *scr_native_date_method_values[SCR_NATIVE_DATE_METHODS]; +static SCR_TL bool scr_native_date_methods_registered; + +static void scr_native_date_methods_cleanup(void) { + for (size_t i = 0; i < SCR_NATIVE_DATE_METHODS; i++) { + ScrDyn *function = scr_native_date_method_values[i]; + scr_native_date_method_values[i] = NULL; + scr_dyn_release(function); + } +} + +/* A Date method read as a value and called later: the closure's function + * slot holds the method's name, and the receiver must be a Date. */ +static ScrDyn *scr_native_date_method_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + const char *method = closure->fn; + ScrDyn *self = scr_dyn_this_get(); + ScrDyn *result = NULL; + if (scr_dyn_native_date_is(self)) { + result = scr_native_date_invoke(self->v.handle.ptr, self, method, args, argc, method); + } else { + static const char message[] = "this is not a Date object."; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + } + scr_dyn_release(self); + return result; +} + +/* Property reads of a Date: its methods as function values, one per name + * and thread, and NULL (undefined) for other names. */ +static ScrDyn *scr_native_date_get(void *ptr, const char *key, size_t key_len) { + (void)ptr; + for (size_t i = 0; i < SCR_NATIVE_DATE_METHODS; i++) { + const char *name = scr_native_date_methods[i]; + if (strlen(name) != key_len || memcmp(name, key, key_len) != 0) continue; + if (!scr_native_date_methods_registered) { + scr_native_date_methods_registered = true; + scr_atexit(scr_native_date_methods_cleanup); + } + if (!scr_native_date_method_values[i]) { + scr_native_date_method_values[i] = scr_dyn_new_func( + scr_closure_new((void *)name, 0), scr_native_date_method_call, 0, "native:Date", name); + } + return scr_dyn_retain(scr_native_date_method_values[i]); + } + return NULL; +} + +/* A Date handle holding the time value `ms` (already TimeClip'd). */ +ScrDyn *scr_dyn_native_date_from_ms(double ms) { static const ScrDynHandleOps ops = { "Date", &scr_native_date_retain, &scr_native_date_release, &scr_native_date_invoke, - NULL, NULL, NULL, NULL, + &scr_native_date_get, NULL, NULL, NULL, }; scr_dyn_handle_install(SCR_DYNH_DATE, &ops); ScrNativeDate *date = malloc(sizeof *date); diff --git a/tests/corpus/5844-date-unknown-values.ts b/tests/corpus/5844-date-unknown-values.ts new file mode 100644 index 000000000..e5b1aed5f --- /dev/null +++ b/tests/corpus/5844-date-unknown-values.ts @@ -0,0 +1,57 @@ +// Date values converted into `unknown` slots stay Dates: typeof answers +// "object", instanceof Date holds, util.inspect prints the ISO form or +// "Invalid Date", JSON.stringify calls toJSON (null for an invalid date), +// a method read through an untyped reference is a function that takes a +// Date receiver, and the value converts back to a typed Date with the same +// time value. +import { inspect } from "node:util"; + +const epoch = new Date(0); +const bare: unknown = epoch; +const record: unknown = { when: new Date(86_400_000), n: 1 }; +const list: unknown = [new Date(Date.UTC(2024, 1, 29, 12, 30)), new Date(Number.NaN)]; +const bag: Record = { at: epoch }; + +console.log(typeof bare, bare instanceof Date, inspect(bare), JSON.stringify(bare)); +console.log(record, JSON.stringify(record), Object.keys(record as object)); +console.log(list, JSON.stringify(list)); +console.log(bag, JSON.stringify(bag)); + +const when = (record as { when: unknown }).when; +console.log(typeof when, when instanceof Date); +if (when instanceof Date) console.log(when.getTime(), when.toISOString(), when.getUTCDate()); +const back = bare as Date; +console.log(back.getTime(), back.toISOString()); +const dynamic = record as any; +console.log(dynamic.when.getTime(), dynamic.when.getUTCFullYear(), String(dynamic.when instanceof Date)); +const read = dynamic.when.getUTCHours; +console.log(typeof read, read.name, read.call(dynamic.when), dynamic.when.missing); +try { + read.call({}); +} catch (error) { + console.log((error as Error).name, (error as Error).message); +} + +type Event = { at: Date; tags: string[] }; +const events: Event[] = [ + { at: new Date(0), tags: ["a"] }, + { at: new Date(7), tags: [] }, +]; +const eventsUnknown: unknown = events; +console.log(eventsUnknown, JSON.stringify(eventsUnknown)); +console.log((eventsUnknown as Event[])[1]!.at.toISOString()); +class Holder { + value: unknown = null; +} +const holder = new Holder(); +holder.value = new Date(1000); +console.log(holder, JSON.stringify(holder.value)); +const invalid: any = { d: new Date(Number.NaN) } as unknown; +try { + console.log(invalid.d.toISOString()); +} catch (error) { + console.log((error as Error).name, (error as Error).message); +} +console.log(invalid.d.getTime(), JSON.stringify(invalid)); +const stamped: Readonly = new Date(0); +console.log(stamped.getTime(), stamped.toISOString()); diff --git a/tests/diagnostics/utility-types.ts b/tests/diagnostics/utility-types.ts index d22a8f969..c6d10648b 100644 --- a/tests/diagnostics/utility-types.ts +++ b/tests/diagnostics/utility-types.ts @@ -7,9 +7,9 @@ // differential corpus); what stays rejected: // - symbol-keyed index signatures (no lowering for symbol keys); // - index-signature value types outside the overflow-map slice (Dates and -// other lib API objects, even when the value itself has a representation); -// - utility types over LIB interfaces stay a type world, not data shapes. -// (Dot access/writes to index-signature keys compile now — the overflow +// other lib API objects, even when the value itself has a representation). +// (Readonly bindings compile, holding the Date as a checked value. +// Dot access/writes to index-signature keys compile now — the overflow // path in dot spelling — and self-referential mapped types intern as // named recursive shapes; differential corpus covers both.) const bySymbol: { [s: symbol]: string } = {}; diff --git a/tests/harness/__snapshots__/utility-types.ts.txt b/tests/harness/__snapshots__/utility-types.ts.txt index f8209335a..71f4d3083 100644 --- a/tests/harness/__snapshots__/utility-types.ts.txt +++ b/tests/harness/__snapshots__/utility-types.ts.txt @@ -32,13 +32,4 @@ utility-types.ts:19:14 - error SC2004: uses of 'dateBag' inherit the blocker on | ^~~~~~~ 20 | console.log(boot); - hint: the declaration of 'dateBag' did not compile — fix the diagnostic reported there and these sites clear with it - -utility-types.ts:22:33 - error SC1101: converting typed values to 'unknown' is not supported yet - - 21 | - 22 | const stamped: Readonly = new Date(0); - | ^~~~~~~~~~~ - 23 | console.log(stamped.getTime()); - - hint: numbers, strings, booleans, JSON-safe records/arrays/unions (a deep copy), functions, program class instances, and supported native handles convert into 'unknown' slots; functions, exact-class round trips, and handles preserve identity, while this value's type has no dynamic representation yet \ No newline at end of file + hint: the declaration of 'dateBag' did not compile — fix the diagnostic reported there and these sites clear with it \ No newline at end of file diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index c08267e2d..e15f6ac9f 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1909,6 +1909,7 @@ "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, + "5844-date-unknown-values.ts": 3969, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4602,6 +4603,7 @@ "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, + "5844-date-unknown-values.ts": 4543, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 74702ac4be7b39158b888b466c95c6a70a03cc29 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 05:42:55 -0500 Subject: [PATCH 062/117] Run a full cycle pass when a structure dies outside passes Full passes are scheduled by heap growth, and the fraction they wait for widens while growth-triggered passes find nothing, up to 16 times the heap after the last full pass. That keeps a large live heap that keeps growing (a compiler checking a large program) from being walked again and again. But growth alone cannot tell such a heap from one that keeps garbage: a program that drops a large structure and builds another, as a compiler rebuilding in watch mode does, holds the dead structures' cyclic parts until the heap has grown to 17 times its size. Ten rebuilds of benchmarks/regions/compiler.ts without lifetime regions reached 1.3 GB that way. The acyclic parts of such a structure go by reference counting, and that shows: the live count falls between passes. The collector now sums those falls since the last full pass. Once they reach 1/32 of the heap that pass left and have stopped (a structure torn down by reference counting falls over several checks, and a pass in the middle would find its rest still referenced), a full pass is due as soon as the heap has grown the base quarter past it, whatever the growth fraction. One that finds fewer older objects than had died doubles the fall the next one needs, up to 256 times, and a productive one restores it. A full pass that the growth rule did not choose (this one, a backlog pass, a scheduled-age pass) now raises the growth baselines of the levels it walked but does not lower them. After such a pass reclaims a dropped structure, the heap regrowing to where it was is the program rebuilding what it had. From the low point, growth passes at both levels would walk the rebuilt live heap and find nothing. On the ten rebuilds that was a third of the collector's added time. A heap that only grows never falls, so its schedule is unchanged. The checks run where the release path and the event loop already decide which pass to run. --- packages/runtime/src/scr_cycle.c | 100 +++++++++++++++++++++++++++-- packages/runtime/test/test_cycle.c | 79 +++++++++++++++++++++++ 2 files changed, 172 insertions(+), 7 deletions(-) diff --git a/packages/runtime/src/scr_cycle.c b/packages/runtime/src/scr_cycle.c index 6cadfcda6..69485dd6c 100644 --- a/packages/runtime/src/scr_cycle.c +++ b/packages/runtime/src/scr_cycle.c @@ -94,6 +94,25 @@ * objects that are not garbage. A pass that frees almost * nothing therefore doubles this fraction, and a productive * one restores it. + * full, death live objects have died outside passes since the last + * full pass (the live count fell between passes, by at + * least 1/32 of the heap that pass left) and have stopped + * dying, and the heap has grown the base fraction since. + * Growth alone cannot tell a heap that keeps live data + * from one that keeps garbage, and once full passes stop + * finding anything the fraction widens to the cap. A + * program that drops a large structure and builds another + * (a compiler rebuilding in watch mode) would then hold + * the dead structures' cyclic parts until the heap had + * grown to the cap. The acyclic parts of such a structure + * go by reference counting, which shows as the fall. One + * that finds fewer older objects than had died doubles the + * fall the next one needs, and a productive one restores + * it. Like every full pass the growth rule did not choose + * (backlog, scheduled age), it can raise the levels' + * growth baselines but not lower them: the heap regrowing + * to where it was before such a pass reclaimed a dropped + * structure is a rebuild, not growth. * mature the same two rules one level down: a growth fraction * measured from the last mature-or-full pass and scheduled * by everything mature passes free, and a backlog rule over @@ -196,6 +215,12 @@ typedef struct { unsigned char growth_shift[SCR_CYC_NGENS]; unsigned char growth_streak[SCR_CYC_NGENS]; unsigned backlog_shift[SCR_CYC_NGENS]; + size_t fallen; + size_t live_seen; + size_t full_after; + unsigned char death_shift; + bool falling; + bool keep_base; size_t nbuffered; size_t trigger; size_t alloc_trigger; @@ -234,6 +259,12 @@ static _Thread_local ScrCycThread scr_cyc_thread = {.gen_limit = SCR_CYC_OLD}; #define scr_cyc_scheduled_mature_age (scr_cyc_thread.scheduled_mature_age) #define scr_xg_freed (scr_cyc_thread.xg_freed) #define scr_cyc_mature_dead (scr_cyc_thread.mature_dead) +#define scr_cyc_fallen (scr_cyc_thread.fallen) +#define scr_cyc_live_seen (scr_cyc_thread.live_seen) +#define scr_cyc_full_after (scr_cyc_thread.full_after) +#define scr_cyc_death_shift (scr_cyc_thread.death_shift) +#define scr_cyc_falling (scr_cyc_thread.falling) +#define scr_cyc_keep_base (scr_cyc_thread.keep_base) #define scr_cyc_kinds (scr_cyc_thread.kinds) #define scr_cyc_kinds_cap (scr_cyc_thread.kinds_cap) #endif @@ -475,6 +506,22 @@ static SCR_TL unsigned scr_cyc_backlog_shift[SCR_CYC_NGENS]; static SCR_TL size_t scr_cyc_mature_dead = 0; #endif +/* The death rule (see the scheduling notes above). `fallen`: how far the + * live count fell between passes since the last full pass; `live_seen`: the + * live count at the end of the last pass or check; `full_after`: the live + * count after the last full pass; `falling`: whether it fell since the + * previous check; `death_shift`: doublings of the fall a pass needs, earned + * by passes that found less than had died; `keep_base`: the pass running + * is a full pass the growth rule did not choose, which may raise the + * levels' growth baselines but not lower them. */ +#define SCR_CYC_DEATH_DIV 32 +#define SCR_CYC_DEATH_MAX_SHIFT 8 +#ifndef SCR_WORKERS +static SCR_TL size_t scr_cyc_fallen = 0, scr_cyc_live_seen = 0, scr_cyc_full_after = 0; +static SCR_TL unsigned char scr_cyc_death_shift = 0; +static SCR_TL bool scr_cyc_falling = false, scr_cyc_keep_base = false; +#endif + static size_t scr_cyc_nursery_threshold(void) { static SCR_TL size_t cached = 0; if (cached == 0) { @@ -621,6 +668,27 @@ static void scr_cyc_adapt_growth(unsigned gen, size_t growth, } } +/* How far the live count fell since the last check: what died outside + * passes, less what was allocated meanwhile. Every pass ends with a fresh + * reading, so what passes free does not count. */ +static void scr_cyc_note_fall(void) { + scr_cyc_falling = scr_cyc_live < scr_cyc_live_seen; + if (scr_cyc_falling) scr_cyc_fallen += scr_cyc_live_seen - scr_cyc_live; + scr_cyc_live_seen = scr_cyc_live; +} + +/* The death rule: enough has died since the last full pass, it has stopped + * dying (a structure torn down by reference counting falls over several + * checks, and a pass in the middle would find its rest still referenced), + * and the heap has grown the base fraction since. */ +static SCR_CYC_SCHEDULING bool scr_cyc_died(void) { + if (scr_cyc_falling) return false; + size_t base = scr_cyc_growth_base(scr_cyc_full_after); + size_t need = base / SCR_CYC_DEATH_DIV; + need = need > (SIZE_MAX >> scr_cyc_death_shift) ? SIZE_MAX : need << scr_cyc_death_shift; + return scr_cyc_fallen >= need && scr_cyc_live > base + base / SCR_CYC_GROWTH_DIV; +} + /* One scheduled pass at `gen`. A mature or old pass adapts that level's * backlog threshold to its yield; the explicit sweep (scr_collect_cycles) is * not a scheduling decision and leaves the thresholds alone. Productive means @@ -630,11 +698,14 @@ static void scr_cyc_adapt_growth(unsigned gen, size_t growth, * * Every level shares this one body, so a program that links the collector * carries a single copy of the scheduling logic. */ -static SCR_CYC_SCHEDULING void scr_cyc_scheduled_pass(unsigned gen, bool by_growth) { +static SCR_CYC_SCHEDULING void scr_cyc_scheduled_pass(unsigned gen, bool by_growth, bool by_death) { size_t base = scr_cyc_growth_base(scr_cyc_live_after[gen]); size_t growth = scr_cyc_live > base ? scr_cyc_live - base : 0; + size_t fallen = scr_cyc_fallen; size_t old_freed_before = scr_cyc_old_freed; + scr_cyc_keep_base = gen == SCR_CYC_OLD && !by_growth; size_t freed = scr_cyc_pass(gen); + scr_cyc_keep_base = false; size_t old_reclaimed = scr_cyc_old_freed - old_freed_before + scr_cyc_mature_dead; if (gen == SCR_CYC_NURSERY) return; if (scr_cands.n != 0) { @@ -643,7 +714,10 @@ static SCR_CYC_SCHEDULING void scr_cyc_scheduled_pass(unsigned gen, bool by_grow else if (scr_cyc_backlog_shift[gen] < SCR_CYC_BACKLOG_MAX_SHIFT) scr_cyc_backlog_shift[gen]++; } - if (by_growth) + if (by_death) { + if (old_reclaimed >= fallen) scr_cyc_death_shift = 0; + else if (scr_cyc_death_shift < SCR_CYC_DEATH_MAX_SHIFT) scr_cyc_death_shift++; + } else if (by_growth) scr_cyc_adapt_growth(gen, growth, gen == SCR_CYC_OLD ? old_reclaimed : freed); } @@ -652,15 +726,17 @@ static SCR_CYC_SCHEDULING void scr_cyc_scheduled_pass(unsigned gen, bool by_grow * per pass, so it is kept out of line and built for size, which leaves the * hot buffering path in scr_cyc_on_release small. */ static SCR_CYC_SCHEDULING void scr_cyc_collect_due(void) { + scr_cyc_note_fall(); unsigned gen = SCR_CYC_OLD; bool by_growth = scr_cyc_grown(SCR_CYC_OLD); - if (!by_growth && scr_roots[SCR_CYC_OLD].n < scr_cyc_backlog_threshold(SCR_CYC_OLD)) { + bool by_death = !by_growth && scr_cyc_died(); + if (!by_growth && !by_death && scr_roots[SCR_CYC_OLD].n < scr_cyc_backlog_threshold(SCR_CYC_OLD)) { gen = SCR_CYC_MATURE; by_growth = scr_cyc_grown(SCR_CYC_MATURE); if (!by_growth && scr_roots[SCR_CYC_MATURE].n < scr_cyc_backlog_threshold(SCR_CYC_MATURE)) gen = SCR_CYC_NURSERY; } - scr_cyc_scheduled_pass(gen, by_growth); + scr_cyc_scheduled_pass(gen, by_growth, by_death); } /* One scheduled pass, for callers that reach a natural collection point @@ -669,6 +745,7 @@ static SCR_CYC_SCHEDULING void scr_cyc_collect_due(void) { * per turn would walk the whole live heap every turn — which is exactly the * cost the generations exist to avoid. */ void scr_cyc_collect_scheduled(void) { + scr_cyc_note_fall(); if (scr_cyc_buffered() == 0) { scr_cyc_scheduled_mature_age = 0; return; @@ -677,7 +754,7 @@ void scr_cyc_collect_scheduled(void) { scr_cyc_scheduled_mature_age = 0; } else if (++scr_cyc_scheduled_mature_age >= scr_cyc_nursery_threshold()) { - scr_cyc_scheduled_pass(SCR_CYC_OLD, false); + scr_cyc_scheduled_pass(SCR_CYC_OLD, false, false); return; } scr_cyc_collect_due(); @@ -1167,11 +1244,20 @@ static SCR_CYC_COMPACT size_t scr_cyc_settle(unsigned gen_limit) { /* A limited pass walked only some of the candidates: the schedule's * baselines stay those of the last pass over them all. */ + scr_cyc_live_seen = scr_cyc_live; if (scr_cyc_take == NULL) { - if (gen_limit >= SCR_CYC_MATURE) scr_cyc_live_after[SCR_CYC_MATURE] = scr_cyc_live; + /* A full pass the growth rule did not choose (death, backlog, scheduled + * age) may raise the growth baselines but not lower them. After it + * reclaims a dropped structure, the heap regrowing to where it was is + * the program rebuilding what it had, not growth: from the low point, + * the next growth passes would walk the rebuilt live heap for nothing, + * at both levels. */ + for (unsigned g = SCR_CYC_MATURE; g <= gen_limit; g++) + if (!scr_cyc_keep_base || scr_cyc_live > scr_cyc_live_after[g]) scr_cyc_live_after[g] = scr_cyc_live; if (gen_limit >= SCR_CYC_OLD) { - scr_cyc_live_after[SCR_CYC_OLD] = scr_cyc_live; scr_cyc_scheduled_mature_age = 0; + scr_cyc_fallen = 0; + scr_cyc_full_after = scr_cyc_live; } } /* markRoots drained buffers in bulk and teardowns moved the count around; diff --git a/packages/runtime/test/test_cycle.c b/packages/runtime/test/test_cycle.c index ba0bc0819..8fdac2d13 100644 --- a/packages/runtime/test/test_cycle.c +++ b/packages/runtime/test/test_cycle.c @@ -1187,6 +1187,84 @@ static void check_large_old_buffer_with_nursery_candidates(void) { } } +/* The death rule: once objects have died outside passes (the live count + * fell by 1/32 of the heap the last full pass left, here the floor's), a + * full pass is due as soon as the heap has grown the base quarter past it, + * however wide the growth fraction has become. With the old level's + * fraction at the cap, the dead old ring below would otherwise wait until + * the heap had grown to the cap. A fall that the pass it brings finds + * nothing behind doubles the fall the next one needs. */ +static size_t watched_freed; +static void watched_free(void *obj) { + watched_freed++; + node_free(obj); +} + +/* Fresh live leaves that are never released, each followed by a dead + * one-node ring, which keeps the release path running its passes without + * buffering the leaves, until the watched ring is freed or `limit` leaves + * have been made. Returns how many it made. */ +static size_t grow_until_watched(Node **keep, size_t limit, size_t watched) { + size_t n = 0; + while (watched_freed < watched && n < limit) { + keep[n++] = make_leaf(); + release_live(make_ring(1)); + } + return n; +} + +static void check_death_brings_full_pass(void) { + enum { FLOOR = 4096, RING = 64, LEAVES = 1024 }; + static ScrCycType watched_type = { &node_trace, &watched_free, 0 }; + size_t cap = configured_growth_cap(); + if (cap < 4) return; /* growth alone is due about as soon */ + size_t limit = FLOOR + FLOOR / 4 + 2 * configured_nursery_threshold() + 2; + Node **leaves = calloc(LEAVES, sizeof(*leaves)); + Node **keep = calloc(limit, sizeof(*keep)); + if (!leaves || !keep) scr_trap("cycle test: out of memory\n"); + /* Growth passes that find nothing widen the old fraction to the cap. */ + for (int i = 0; i < 4; i++) grow_dead_cycle_until_full_pass(0, false); + + Node *ring = make_ring_of(RING, &watched_type); + age_to_old(ring); + for (size_t i = 0; i < LEAVES; i++) leaves[i] = make_leaf(); + scr_collect_cycles(); + check(scr_cyc_live < FLOOR - LEAVES, "live heap did not start below the growth floor"); + watched_freed = 0; + drop_leaves(leaves, LEAVES); /* gone by reference counting: the live count falls */ + scr_cyc_collect_scheduled(); /* a check reads the whole fall */ + release_live(ring); /* a dead old cycle */ + size_t grown = grow_until_watched(keep, limit, RING); + check(watched_freed == RING, "the fall did not bring a full pass by the base fraction"); + drop_leaves(keep, grown); + scr_collect_cycles(); + + /* A fall with nothing behind it: the pass it brings finds nothing. */ + for (size_t i = 0; i < LEAVES; i++) leaves[i] = make_leaf(); + scr_collect_cycles(); + drop_leaves(leaves, LEAVES); + scr_cyc_collect_scheduled(); + grown = grow_until_watched(keep, limit, 1); + drop_leaves(keep, grown); + /* So the next death pass needs twice the fall: 1/32 of the floor, enough + * before, no longer is. */ + ring = make_ring_of(RING, &watched_type); + age_to_old(ring); + for (size_t i = 0; i < FLOOR / 32; i++) leaves[i] = make_leaf(); + scr_collect_cycles(); + watched_freed = 0; + drop_leaves(leaves, FLOOR / 32); + scr_cyc_collect_scheduled(); + release_live(ring); + grown = grow_until_watched(keep, limit, RING); + check(watched_freed == 0, "a fall smaller than the backed-off one brought a full pass"); + drop_leaves(keep, grown); + scr_collect_cycles(); + check(watched_freed == RING, "the full sweep did not reclaim the dead old ring"); + free(leaves); + free(keep); +} + int main(void) { check_old_garbage_reclaimed_while_growing(); check_older_rings_into_old(); @@ -1207,6 +1285,7 @@ int main(void) { check_growth_schedule_follows_yield(); check_growth_cap_bounds_floating_garbage(); check_mixed_dead_structure_narrows(); + check_death_brings_full_pass(); check_nursery_bypass(); check_mature_bypass(); check_probe_sees_candidate_rings(); From f676f5ad2d92e4337ccf3e95cf3e4d8d4fcf9090 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 06:13:12 -0500 Subject: [PATCH 063/117] Select a new property bag's prototype through one helper per class A class's property-bag branch created the bag from the prototype data of the most derived constructible class the receiver is an instance of. That selection was an instanceOf chain over the class's whole subclass tree, inlined into the branch, and each nested subclass repeated it for its own subtree, so the dispatch functions grew with the square of the hierarchy's depth. In the three.js nodes fixture they reached 350,000 lines of LLVM IR, and register allocation of the read-only copies set the native build's longest partition. A class with constructible subclasses that have prototype data now selects through %class.bagPrototype:, which tests its subclasses from the last to the first and calls their helpers. Other classes read their prototype data directly, as before. --- .../lowering/class-dynamic-dispatch.ts | 127 +++++++++++++----- 1 file changed, 91 insertions(+), 36 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index d14aaf924..444a9cf23 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -698,6 +698,8 @@ export class ClassDynamicDispatch { private readonly bagClasses = new Set(); private readonly bagInitializers = new Map[]>(); private readonly typedPropertyBags = new Map(); + /** Per-class prototype selection for new property bags (bagPrototypeHelper). */ + private readonly bagPrototypeHelpers = new Map(); private readonly readPropertyBags: { helper: IrFunction; initialize: Extract; @@ -1127,38 +1129,8 @@ export class ClassDynamicDispatch { current.subclasses.some( (child) => lowerer.classCanBeConstructed(child) && needsPrototype(child), ); - const prototypeFor = (current: ClassInfo, receiver: IrExpr, loc: SrcLoc): IrExpr | null => { - const currentReceiver: IrExpr = - receiver.type.kind === "object" && receiver.type.className !== current.def.name - ? { - kind: "downcast", - value: receiver, - type: { kind: "object", className: current.def.name }, - loc, - } - : receiver; - let result = classPrototypeData(lowerer, current, loc, currentReceiver); - for (const child of current.subclasses) { - if (!lowerer.classCanBeConstructed(child)) continue; - const selected = prototypeFor(child, receiver, loc); - if (selected && result) - result = { - kind: "ternary", - cond: { - kind: "instanceOf", - value: receiver, - className: child.def.name, - type: BOOL, - loc, - }, - then: selected, - else_: result, - type: DYN, - loc, - }; - } - return result; - }; + const prototypeFor = (current: ClassInfo, receiver: IrExpr, loc: SrcLoc): IrExpr | null => + this.bagPrototype(lowerer, current, receiver, loc); for (const existingInit of this.bagInitializers.get(className) ?? []) { if (existingInit.value.kind === "dynObjLit" && needsPrototype(info)) { const prototype = prototypeFor(info, existingInit.obj, existingInit.loc); @@ -3922,10 +3894,20 @@ export class ClassDynamicDispatch { obj: receiver, value: transformExpr(initializers[0]!.value, { stmt: (stmt) => stmt, - expr: (expr) => - expr.kind === "dynCheck" && expr.value.kind === "varRef" && expr.value.localId === "p.0" - ? receiver - : expr, + expr: (expr) => { + const checked = (e: IrExpr): boolean => + e.kind === "dynCheck" && e.value.kind === "varRef" && e.value.localId === "p.0"; + // The checked receiver, possibly cast to this class (the prototype + // helper's argument), is the typed parameter itself. + if ( + expr.kind === "downcast" && + checked(expr.value) && + expr.type.kind === "object" && + expr.type.className === type.className + ) + return receiver; + return checked(expr) ? receiver : expr; + }, }), loc, }; @@ -3954,6 +3936,79 @@ export class ClassDynamicDispatch { return helper; } + /** The prototype a new property bag of `current` (or of the subclass the + * receiver is) starts from, or null when `current` has no prototype data. + * A class with constructible subclasses that have prototype data selects + * it through its `%class.bagPrototype` helper; any other class reads its + * own prototype data. */ + private bagPrototype( + lowerer: Lowerer, + current: ClassInfo, + receiver: IrExpr, + loc: SrcLoc, + ): IrExpr | null { + const arg: IrExpr = + receiver.type.kind === "object" && receiver.type.className !== current.def.name + ? { + kind: "downcast", + value: receiver, + type: { kind: "object", className: current.def.name }, + loc, + } + : receiver; + const helper = this.bagPrototypeHelper(lowerer, current, loc); + return helper + ? { kind: "call", callee: helper.name, args: [arg], type: DYN, loc } + : classPrototypeData(lowerer, current, loc, arg); + } + + /** `%class.bagPrototype:(this)`: the prototype data of the most + * derived constructible class `this` is an instance of, tested from the + * last subclass to the first and then the class itself. One helper per + * class, calling its subclasses' helpers, keeps every property-bag branch + * a single call: a whole hierarchy inlined into each branch grows with the + * square of its depth. Null when the class has no prototype data, in which + * case its subclasses are not tested either, or while no constructible + * subclass has any. The body is rebuilt on each use, as classes become + * constructible. */ + private bagPrototypeHelper(lowerer: Lowerer, current: ClassInfo, loc: SrcLoc): IrFunction | null { + const type: IrType = { kind: "object", className: current.def.name }; + const self = varRef("this", type, loc); + const own = classPrototypeData(lowerer, current, loc, self); + if (!own) return null; + const body: IrStmt[] = []; + const children = current.subclasses.filter((child) => lowerer.classCanBeConstructed(child)); + for (const child of children.reverse()) { + const selected = this.bagPrototype(lowerer, child, self, loc); + if (!selected) continue; + body.push({ + kind: "if", + cond: { kind: "instanceOf", value: self, className: child.def.name, type: BOOL, loc }, + then: [{ kind: "return", value: selected, loc }], + else_: null, + loc, + }); + } + let helper = this.bagPrototypeHelpers.get(current.def.name); + if (!helper && body.length === 0) return null; + body.push({ kind: "return", value: own, loc }); + if (!helper) { + helper = { + name: `%class.bagPrototype:${current.def.name}`, + params: [{ localId: "this", name: "this", type }], + returnType: DYN, + locals: [{ id: "this", name: "this", type, mutable: false }], + body, + loc, + }; + this.bagPrototypeHelpers.set(current.def.name, helper); + this.generated.add(helper); + lowerer.liftedFns.push(helper); + } + helper.body = body; + return helper; + } + /** Prototype state may appear in a later reachable body, so read-only bags * settle only after the dispatch worklist closes. A read never stores: an * absent empty bag stays undefined (callers test it), and an absent From f62275dec00607d9e2390f45c494cbd636358c86 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 06:32:10 -0500 Subject: [PATCH 064/117] Add the process.execArgv surface to the manifest process.execArgv now lowers to its own libCall, which the determinism attestation treats as a process input like process.argv. The node-builtin.process.execArgv surface entry lets a library fence deny it, and surface-manifest.json is regenerated with the entry. --- packages/compiler/src/frontend/lowering/surfaces.ts | 6 ++++++ packages/compiler/surface-manifest.json | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 8ad735791..848b34afe 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2456,6 +2456,12 @@ export const AMBIENT_SURFACE_FNS: readonly AmbientSurfaceRow[] = [ name: "process.argv0", fns: ["process.argv0"], }, + { + id: "node-builtin.process.execArgv", + kind: "node-builtin", + name: "process.execArgv", + fns: ["process.execArgv"], + }, { id: "node-builtin.process.execPath", kind: "node-builtin", diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 683df3777..219095bc0 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -1944,6 +1944,12 @@ "status": "static", "note": "reads, writes, deletes, and enumeration of the process environment (the process global)" }, + { + "id": "node-builtin.process.execArgv", + "kind": "node-builtin", + "name": "process.execArgv", + "status": "static" + }, { "id": "node-builtin.process.execPath", "kind": "node-builtin", From 0ee069f094d4aa7c880e0b1282250659c4abefc1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 06:53:41 -0500 Subject: [PATCH 065/117] Answer typeof for builtin module functions and classes `typeof zlib.Inflate` and `typeof zlib.createGzip` stopped at SC1090 or SC2020, because the operand lowered as a library function or class value. A typeof of a function or class exported by a Node builtin module, read through a plain binding, now folds to "function" as in Node: the read has no side effects to preserve. --- .../src/frontend/lowering/lower-exprs.ts | 41 +++++++++++++++++++ .../5974-typeof-module-exports.cjs.json | 6 +++ tests/corpus/5974-typeof-module-exports.cjs | 9 ++++ tests/harness/corpus-costs.json | 2 + 4 files changed, 58 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5974-typeof-module-exports.cjs.json create mode 100644 tests/corpus/5974-typeof-module-exports.cjs diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 6774de117..f0538bb71 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -648,6 +648,30 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { // have non-stdlib symbols and keep the ordinary path. let tested = expr.expression; while (ts.isParenthesizedExpression(tested)) tested = tested.expression; + // `typeof zlib.Inflate` / `typeof zlib.createGzip`: an export of a + // Node builtin module read through a plain binding (an import or + // require result). The read has no side effects, and Node's answer for + // every exported function and class is "function". + if ( + ts.isPropertyAccessExpression(tested) && + ts.isIdentifier(tested.expression) && + lowerer.isStdlibMember(tested) + ) { + const sym = lowerer.checker.getSymbolAtLocation(tested.name); + const decls = sym ? lowerer.checker.declarationsOf(sym) : []; + if ( + decls.some(isBuiltinModuleValueDecl) && + decls.every((decl) => builtinModuleExportParent(decl) !== undefined) + ) { + const t = lowerer.typeOf(tested); + if ( + lowerer.checker.getCallSignatures(t).length > 0 || + lowerer.checker.getConstructSignatures(t).length > 0 + ) { + return { kind: "strLit", value: "function", type: STRING, loc }; + } + } + } if (ts.isIdentifier(tested)) { const sym = lowerer.checker.getSymbolAtLocation(tested); if (!sym) { @@ -15825,3 +15849,20 @@ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, loc: SrcLoc): IrE } return { kind: "call", callee: name, args: [source], type: DYN, loc }; } + +/** The `declare module "..."` body (or nested namespace body) a module + * export's declaration sits directly in, or undefined. */ +function builtinModuleExportParent(decl: ts.Node): ts.ModuleBlock | undefined { + const parent = ts.isVariableDeclaration(decl) ? decl.parent?.parent?.parent : decl.parent; + return parent !== undefined && ts.isModuleBlock(parent) ? parent : undefined; +} + +/** A function, class or variable exported by a builtin module's body. */ +function isBuiltinModuleValueDecl(decl: ts.Node): boolean { + return ( + builtinModuleExportParent(decl) !== undefined && + (ts.isFunctionDeclaration(decl) || + ts.isClassDeclaration(decl) || + ts.isVariableDeclaration(decl)) + ); +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5974-typeof-module-exports.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5974-typeof-module-exports.cjs.json new file mode 100644 index 000000000..469ee3272 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5974-typeof-module-exports.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5974-typeof-module-exports.cjs" + ], + "diags": [] +} diff --git a/tests/corpus/5974-typeof-module-exports.cjs b/tests/corpus/5974-typeof-module-exports.cjs new file mode 100644 index 000000000..7e209f147 --- /dev/null +++ b/tests/corpus/5974-typeof-module-exports.cjs @@ -0,0 +1,9 @@ +// typeof on functions and classes exported by Node builtin modules, read +// through require bindings: Node answers "function" for each. +const zlib = require("node:zlib"); +const path = require("node:path"); +const fs = require("node:fs"); +console.log(typeof zlib.createGzip, typeof zlib.createBrotliDecompress, typeof zlib.gunzipSync); +console.log(typeof zlib.Inflate, typeof zlib.Gzip, typeof zlib.DeflateRaw); +console.log(typeof path.join, typeof path.posix.join, typeof fs.readFileSync); +console.log(typeof path.sep); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 2c2eeab31..25f00b1f7 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1908,6 +1908,7 @@ "5970-net-connect-host-name.ts": 2400, "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, + "5974-typeof-module-exports.cjs": 2000, "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, @@ -4603,6 +4604,7 @@ "5970-net-connect-host-name.ts": 2800, "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, + "5974-typeof-module-exports.cjs": 2500, "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, From 1cd06fda4c969f512a26b8e18fb59a1c0f44b778 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 07:44:23 -0500 Subject: [PATCH 066/117] Read events.defaultMaxListeners from the ES module namespace copy Reads of defaultMaxListeners through an ES module namespace import or a named import answer the namespace's copy of the export, which keeps its value from program start until module.syncBuiltinESMExports() refreshes it, as in Node. The default import, the EventEmitter class and CommonJS module bindings keep reading the current default. A destructured CommonJS binding of defaultMaxListeners, which held a placeholder string in JavaScript files, is refused. --- .../limitations/builtin-apis/eventemitter.mdx | 2 +- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 10 ++--- .../generated/node-v24-backlog.json | 45 ++++++++++++------- .../generated/node-v24-internal.json | 41 ++++++++++++----- internal/compatibility/static-support.json | 4 +- .../compiler/src/backend/llvm/lib-shared.ts | 2 + .../lowering/builtins/module-bindings.ts | 18 ++++++++ .../lowering/builtins/module-resolution.ts | 9 ++-- .../src/frontend/lowering/lower-exprs.ts | 15 +++++++ .../src/frontend/lowering/lower-stmts.ts | 14 ++++-- .../compiler/src/frontend/lowering/lowerer.ts | 15 ++++++- .../src/frontend/lowering/surfaces.ts | 2 +- .../compiler/src/ir/builtin-signatures.ts | 4 ++ packages/compiler/src/ir/validate.ts | 2 + packages/compiler/surface-manifest.json | 2 +- .../5846-events-esm-default-max.ts.json | 6 +++ .../5847-events-cjs-default-max.cjs.json | 6 +++ packages/runtime/src/scr_events_emitter.c | 8 ++++ packages/runtime/src/scr_events_emitter.h | 2 + tests/corpus/5846-events-esm-default-max.ts | 28 ++++++++++++ tests/corpus/5847-events-cjs-default-max.cjs | 10 +++++ tests/harness/corpus-costs.json | 4 ++ 23 files changed, 204 insertions(+), 47 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5846-events-esm-default-max.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5847-events-cjs-default-max.cjs.json create mode 100644 tests/corpus/5846-events-esm-default-max.ts create mode 100644 tests/corpus/5847-events-cjs-default-max.cjs diff --git a/docs/content/limitations/builtin-apis/eventemitter.mdx b/docs/content/limitations/builtin-apis/eventemitter.mdx index 0b44cd549..c4435f4c7 100644 --- a/docs/content/limitations/builtin-apis/eventemitter.mdx +++ b/docs/content/limitations/builtin-apis/eventemitter.mdx @@ -1 +1 @@ -- **EventEmitter:** Literal event names use fixed argument tuples. Computed string names require a constant prefix or suffix that excludes `error`, meta events, and stream-internal events; their arguments must match the exact arity and support checked conversion. Unrestricted names, symbols, names that may reach internal events, and typed `listeners()`/`rawListeners()` results for names with possible computed registrations are unsupported. +- **EventEmitter:** Literal event names use fixed argument tuples. Computed string names require a constant prefix or suffix that excludes `error`, meta events, and stream-internal events; their arguments must match the exact arity and support checked conversion. Unrestricted names, symbols, names that may reach internal events, and typed `listeners()`/`rawListeners()` results for names with possible computed registrations are unsupported. Reading `defaultMaxListeners` through a CommonJS destructured or member binding (`const { defaultMaxListeners } = require("events")`) is unsupported. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 500876593..db36cdb52 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "56f660f5e2eb7391a048", + "artifactVersion": "cade1b8e6e0c5c42fcc9", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 568cdb4c9..dadc9e836 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -569,9 +569,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -57593,9 +57593,9 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 683d477a5..1b7d28783 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1142, - "verify-gap": 2187, + "audit-partial": 1143, + "verify-gap": 2186, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -25009,7 +25009,9 @@ "confidence": "high", "source": "compiler-dedicated:events.getEventListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] } } @@ -25036,7 +25038,9 @@ "confidence": "high", "source": "compiler-dedicated:events.getMaxListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] } } @@ -25091,7 +25095,9 @@ "confidence": "high", "source": "compiler-dedicated:events.listenerCount", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] } } @@ -25143,7 +25149,9 @@ "confidence": "high", "source": "compiler-dedicated:events.setMaxListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] } } @@ -25197,7 +25205,9 @@ "confidence": "high", "source": "compiler-dedicated:events.defaultMaxListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] } } @@ -48430,7 +48440,8 @@ "confidence": "high", "source": "compiler-feature:module.module.isBuiltin", "tests": [ - "tests/corpus/2932-create-require-program/main.ts" + "tests/corpus/2932-create-require-program/main.ts", + "tests/corpus/5846-events-esm-default-max.ts" ] } } @@ -48527,7 +48538,8 @@ "confidence": "high", "source": "compiler-feature:module.module.syncBuiltinESMExports", "tests": [ - "tests/corpus/2932-create-require-program/main.ts" + "tests/corpus/2932-create-require-program/main.ts", + "tests/corpus/5846-events-esm-default-max.ts" ] } } @@ -57507,12 +57519,15 @@ "priority": "normal", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:process", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 393955bc0..8463d1292 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -596,9 +596,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -41819,6 +41819,8 @@ "tests/corpus/5245-event-target-subclass-signals.ts", "tests/corpus/5247-event-target-subclass-lifetimes.ts", "tests/corpus/5248-event-target-subclass-warnings.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs", "tests/corpus/5885-events-max-listener-helpers.ts" ] }, @@ -43739,7 +43741,9 @@ "status": "partial", "evidence": "compiler-dedicated:events.getEventListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] }, "anchorSource": "exact" @@ -43765,7 +43769,9 @@ "status": "partial", "evidence": "compiler-dedicated:events.getMaxListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] }, "anchorSource": "exact" @@ -43841,7 +43847,9 @@ "status": "partial", "evidence": "compiler-dedicated:events.listenerCount", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] }, "anchorSource": "exact" @@ -43890,7 +43898,9 @@ "status": "partial", "evidence": "compiler-dedicated:events.setMaxListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] }, "anchorSource": "exact" @@ -43942,7 +43952,9 @@ "status": "partial", "evidence": "compiler-dedicated:events.defaultMaxListeners", "tests": [ - "tests/corpus/5885-events-max-listener-helpers.ts" + "tests/corpus/5885-events-max-listener-helpers.ts", + "tests/corpus/5846-events-esm-default-max.ts", + "tests/corpus/5847-events-cjs-default-max.cjs" ] }, "anchorSource": "exact" @@ -69416,6 +69428,7 @@ "tests/corpus/2637-create-require-bare/main.ts", "tests/corpus/2675-create-require-nested-esm.js", "tests/corpus/2932-create-require-program/main.ts", + "tests/corpus/5846-events-esm-default-max.ts", "tests/harness/npm-static.test.ts" ] }, @@ -69503,7 +69516,8 @@ "status": "partial", "evidence": "compiler-feature:module.module.isBuiltin", "tests": [ - "tests/corpus/2932-create-require-program/main.ts" + "tests/corpus/2932-create-require-program/main.ts", + "tests/corpus/5846-events-esm-default-max.ts" ] }, "anchorSource": "exact" @@ -69593,7 +69607,8 @@ "status": "partial", "evidence": "compiler-feature:module.module.syncBuiltinESMExports", "tests": [ - "tests/corpus/2932-create-require-program/main.ts" + "tests/corpus/2932-create-require-program/main.ts", + "tests/corpus/5846-events-esm-default-max.ts" ] }, "anchorSource": "exact" @@ -80949,8 +80964,12 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:process" + "status": "partial", + "evidence": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] }, "anchorSource": "chapter" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index cdd025b72..e3aec2645 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -311,7 +311,7 @@ { "chapter": "modules", "symbols": ["cache", "children", "id", "isPreloading", "loaded", "parent", "path", "paths", "Module"], "status": "partial", "evidence": ["tests/corpus/2880-cjs-module-graph/main.cjs"] }, { "chapter": "modules", "symbols": ["extensions"], "status": "not-implemented" }, { "chapter": "module", "symbols": ["module.createRequire"], "status": "partial", "evidence": ["tests/corpus/2631-create-require/main.ts", "tests/corpus/2637-create-require-bare/main.ts", "tests/corpus/2675-create-require-nested-esm.js", "tests/corpus/2932-create-require-program/main.ts", "tests/harness/npm-static.test.ts"] }, - { "chapter": "module", "symbols": ["module.isBuiltin", "module.syncBuiltinESMExports"], "status": "partial", "evidence": ["tests/corpus/2932-create-require-program/main.ts"] }, + { "chapter": "module", "symbols": ["module.isBuiltin", "module.syncBuiltinESMExports"], "status": "partial", "evidence": ["tests/corpus/2932-create-require-program/main.ts", "tests/corpus/5846-events-esm-default-max.ts"] }, { "chapter": "module", "symbols": ["builtinModules"], "status": "partial", "evidence": ["tests/corpus/2631-create-require/main.ts", "tests/corpus/2637-create-require-bare/main.ts", "tests/corpus/2932-create-require-program/main.ts"] }, { "chapter": "modules", "symbols": ["node:", "node_modules"], "status": "partial", "evidence": ["tests/corpus/1598-cjs-builtin-require/main.js", "tests/corpus/1596-cjs-modules/main.js"] }, { "chapter": "esm", "symbols": ["import", "file:", "node:", "await"], "status": "partial", "evidence": ["tests/corpus/950-modules-basic/main.ts", "tests/corpus/2646-top-level-await.ts", "tests/corpus/2933-static-dynamic-import/main.ts", "tests/corpus/2934-static-import-stored.ts", "tests/corpus/2935-module-namespace-values/main.ts"] }, @@ -390,7 +390,7 @@ { "symbols": ["crypto.randomInt"], "status": "partial", "evidence": ["tests/corpus/5442-crypto-random-values.ts", "tests/corpus/2890-crypto-static-utility.ts"] }, { "symbols": ["crypto.hkdf", "crypto.hkdfSync", "crypto.scrypt", "crypto.scryptSync"], "status": "partial", "evidence": ["tests/corpus/node24-crypto-kdf.ts", "tests/corpus/node24-crypto-kdf-errors.ts", "tests/corpus/node24-crypto-kdf-options.ts", "tests/corpus/5438-crypto-kdf-digests.ts"] }, { "symbols": ["EventEmitter", "emitter.on", "emitter.addListener", "emitter.once", "emitter.prependListener", "emitter.prependOnceListener", "emitter.off", "emitter.removeListener", "emitter.removeAllListeners", "emitter.emit", "emitter.listenerCount", "emitter.listeners", "emitter.rawListeners", "emitter.eventNames", "emitter.setMaxListeners", "emitter.getMaxListeners", "events.once"], "status": "partial", "evidence": ["tests/corpus/1677-emitter-listeners.ts", "tests/corpus/2620-ee-override-once-order.ts"] }, - { "symbols": ["events.getEventListeners", "events.getMaxListeners", "events.listenerCount", "events.setMaxListeners", "events.defaultMaxListeners"], "status": "partial", "evidence": ["tests/corpus/5885-events-max-listener-helpers.ts"] }, + { "symbols": ["events.getEventListeners", "events.getMaxListeners", "events.listenerCount", "events.setMaxListeners", "events.defaultMaxListeners"], "status": "partial", "evidence": ["tests/corpus/5885-events-max-listener-helpers.ts", "tests/corpus/5846-events-esm-default-max.ts", "tests/corpus/5847-events-cjs-default-max.cjs"] }, { "symbols": ["AsyncLocalStorage", "asyncLocalStorage.run", "asyncLocalStorage.exit", "asyncLocalStorage.getStore", "asyncLocalStorage.enterWith", "asyncLocalStorage.disable"], "status": "partial", "evidence": ["tests/corpus/2213-async-local-storage.cjs"] }, { "symbols": ["StringDecoder", "stringDecoder.write", "stringDecoder.end"], "status": "partial", "evidence": ["tests/corpus/1662-string-decoder-encodings.ts", "tests/corpus/node24-string-decoder.ts", "tests/corpus/5882-string-decoder-runtime-encoding.ts"] }, { "symbols": ["setImmediate", "setInterval", "setTimeout", "clearImmediate", "clearInterval", "clearTimeout", "timersPromises.setTimeout", "timersPromises.setImmediate", "timersPromises.setInterval", "immediate.hasRef", "immediate.ref", "immediate.unref", "timeout.hasRef", "timeout.ref", "timeout.unref", "timeout.refresh"], "status": "partial", "evidence": ["tests/corpus/1804-timers-module.ts", "tests/corpus/1805-timer-callback-args.ts", "tests/corpus/2093-timers-promises.ts", "tests/corpus/2852-timers-promises-interval.ts", "tests/corpus/5830-timers-promises-signal.ts"] }, diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 6a85a8eb3..f69c96e6e 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -978,6 +978,8 @@ export const LIB_FN_SYMS: Record = { "emitter.getMax": "scr_emitter_get_max", "emitter.setDefaultMax": "scr_emitter_set_default_max", "emitter.getDefaultMax": "scr_emitter_get_default_max", + "emitter.esmDefaultMax": "scr_emitter_esm_default_max_get", + "emitter.esmSync": "scr_emitter_esm_sync", "emitter.errorMonitor": "scr_emitter_error_monitor", // node:stream (scr_stream.c): receivers borrowed, chunks borrowed, // chaining forms answer the receiver +1. The throwing members diff --git a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts index 3fa6eb0c9..c0e178fcd 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts @@ -114,6 +114,24 @@ export function builtinImportOf( return null; } +/** The ES module binding kind of `ident`: "namespace" for a namespace + * import (`import * as events from "node:events"`), "named" for a named + * import (`import { defaultMaxListeners } from "node:events"`, also through + * a re-exporting module), null otherwise. Namespace members and named + * imports of a builtin read its ES module namespace, which holds copies of + * the module's exports (module.syncBuiltinESMExports refreshes them), where + * default imports and CommonJS bindings read the module object itself. */ +export function esmImportBindingKind( + lowerer: Lowerer, + ident: ts.Identifier, +): "namespace" | "named" | null { + const symbol = lowerer.checker.getSymbolAtLocation(ident); + const decl = symbol ? lowerer.checker.declarationsOf(symbol)[0] : undefined; + if (decl === undefined) return null; + if (ts.isNamespaceImport(decl)) return "namespace"; + return ts.isImportSpecifier(decl) ? "named" : null; +} + /** True for `const = require("").` — the * member-binding require import builtinImportOf resolves. Both * declaration walks (lowerVarDecl, collectGlobals) skip these: like a diff --git a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts index f1b36e3c6..5fcf35541 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts @@ -42,9 +42,10 @@ import { stripTypeCasts } from "./arguments.js"; /** node:module's two compiler-only calls. isBuiltin compares one evaluated * string against the pinned Node 24 list (bare builtins also accept their * node: spelling; prefix-only entries do not gain a bare alias). - * syncBuiltinESMExports is observably a no-op inside the static surface: - * builtin exports cannot be mutated, so its only supported behavior is - * evaluating no arguments and returning undefined. */ + * syncBuiltinESMExports takes no arguments and returns undefined; as a + * statement it refreshes the events module's ES module namespace copy of + * defaultMaxListeners (lowerExprStatement), the one builtin export a program + * can change. */ export function lowerNodeModuleCall( lowerer: Lowerer, expr: ts.CallExpression, @@ -64,7 +65,7 @@ export function lowerNodeModuleCall( lowerer.noLowering( "module.syncBuiltinESMExports used as a value", expr, - "call syncBuiltinESMExports() as its own statement; the supported static effect is a no-op", + "call syncBuiltinESMExports() as its own statement", ); } return { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }; diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index f0538bb71..d2d990e16 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -8,6 +8,7 @@ import { lowerEventStaticProperty } from "./builtins/numbers.js"; import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js"; import { isOptionalProcessStreamProperty } from "./builtins/process.js"; import { lowerWorkerMetadata } from "./builtins/workers.js"; +import { esmImportBindingKind } from "./builtins/module-bindings.js"; import { lowerReadlineProperty } from "./builtins/readline.js"; import { lowerBlobInstanceof } from "./builtins/blob.js"; import { lowerKeyObjectInstanceof } from "./builtins/key-object.js"; @@ -1174,6 +1175,20 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { const value = lowerWorkerMetadata(bi.member, loc); if (value) return value; } + // A named import of defaultMaxListeners reads the ES module + // namespace's copy. A CommonJS destructured or member binding holds + // the value read when its declaration ran, which these bindings do + // not store. + if (bi.module === "events" && bi.member === "defaultMaxListeners") { + if (esmImportBindingKind(lowerer, expr) === "named") { + return { kind: "libCall", fn: "emitter.esmDefaultMax", args: [], type: F64, loc }; + } + lowerer.noLowering( + "events.defaultMaxListeners through a CommonJS destructured or member binding", + expr, + "read require('events').defaultMaxListeners or EventEmitter.defaultMaxListeners where the value is needed", + ); + } const c = builtinModuleConstOf(lowerer, bi.module, bi.member); if (c !== undefined) return builtinConstLit(c, loc); // module.builtinModules — the baked Node v24 list, a fresh diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index ad4fd5312..cffe4c661 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -6055,16 +6055,22 @@ export function lowerExprStatement(lowerer: Lowerer, expr: ts.Expression): IrStm ); } // syncBuiltinESMExports() is the other compiler-only statement: the - // call validates its zero-argument shape, then emits no code because - // the static builtin surface is immutable. + // call validates its zero-argument shape, then refreshes the events + // module's ES module namespace copy of defaultMaxListeners, the one + // builtin export a program can change. const bi = ts.isIdentifier(expr.expression) ? lowerer.builtinImportOf(expr.expression) : ts.isPropertyAccessExpression(expr.expression) ? lowerer.builtinMemberOf(expr.expression) : null; if (bi?.module === "module" && bi.member === "syncBuiltinESMExports") { - lowerNodeModuleCall(lowerer, expr, bi, locOf(expr)); - return { kind: "block", body: [], loc: locOf(expr) }; + const loc = locOf(expr); + lowerNodeModuleCall(lowerer, expr, bi, loc); + return { + kind: "exprStmt", + expr: { kind: "libCall", fn: "emitter.esmSync", args: [], type: VOID, loc }, + loc, + }; } } if ( diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 12deec7ad..087b4e628 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -388,6 +388,7 @@ import { createRequireProgramModuleOf, createRequireSpecOf, fencedBuiltinImportOf, + esmImportBindingKind, } from "./builtins/module-bindings.js"; import { stripTypeCasts } from "./builtins/arguments.js"; import { lowerBuiltinModuleCall } from "./builtins/module-calls.js"; @@ -11462,9 +11463,19 @@ export class Lowerer { return pathModuleValue(this, `path/${bi.member}`, loc); } // events.defaultMaxListeners READS the process-wide default (its - // write twin routes through emitter.setDefaultMaxChk). + // write twin routes through emitter.setDefaultMaxChk). Through an ES + // module namespace it reads the namespace's copy instead. if (bi.module === "events" && bi.member === "defaultMaxListeners") { - return { kind: "libCall", fn: "emitter.getDefaultMax", args: [], type: F64, loc }; + const esm = + ts.isIdentifier(expr.expression) && + esmImportBindingKind(this, expr.expression) === "namespace"; + return { + kind: "libCall", + fn: esm ? "emitter.esmDefaultMax" : "emitter.getDefaultMax", + args: [], + type: F64, + loc, + }; } if (bi.module === "worker_threads") { const value = lowerWorkerMetadata(bi.member, loc); diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 848b34afe..d50fc8be3 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2890,7 +2890,7 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record< isBuiltin: "the lowered call checks a string against the baked Node v24 list, including bare/node: aliases and prefix-only builtins", syncBuiltinESMExports: - "the direct zero-argument call is a no-op because compiled builtin exports are immutable and cannot become stale", + "the direct zero-argument call statement refreshes the ES module namespace copy of events.defaultMaxListeners, the one builtin export a program can change", }, child_process: { execFile: diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index a9bc17ea6..7f31c5205 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3411,6 +3411,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "emitter.getMax": { argTypes: [null], result: F64 }, "emitter.setDefaultMax": { argTypes: [F64], result: VOID }, "emitter.getDefaultMax": { argTypes: [], result: F64 }, + // The ES module namespace's copy of defaultMaxListeners, and + // module.syncBuiltinESMExports() refreshing it. + "emitter.esmDefaultMax": { argTypes: [], result: F64 }, + "emitter.esmSync": { argTypes: [], result: VOID }, /** The events.errorMonitor event key: an immortal string the runtime * registry matches by identity, so no string event name reaches it. */ "emitter.errorMonitor": { argTypes: [], result: STRING }, diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 388abf0a7..f7d30a1bb 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -5695,6 +5695,8 @@ function validateFunction( e.fn !== "emitter.setDefaultMax" && e.fn !== "emitter.setDefaultMaxChk" && e.fn !== "emitter.getDefaultMax" && + e.fn !== "emitter.esmDefaultMax" && + e.fn !== "emitter.esmSync" && e.fn !== "emitter.errorMonitor" && e.fn !== "emitter.checkListener" ) { diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 219095bc0..c01101f6f 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -1367,7 +1367,7 @@ "name": "module.syncBuiltinESMExports", "status": "unsupported", "code": "SC2020", - "note": "the direct zero-argument call is a no-op because compiled builtin exports are immutable and cannot become stale" + "note": "the direct zero-argument call statement refreshes the ES module namespace copy of events.defaultMaxListeners, the one builtin export a program can change" }, { "id": "node-builtin.net", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5846-events-esm-default-max.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5846-events-esm-default-max.ts.json new file mode 100644 index 000000000..f1867c914 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5846-events-esm-default-max.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5846-events-esm-default-max.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5847-events-cjs-default-max.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5847-events-cjs-default-max.cjs.json new file mode 100644 index 000000000..1464ab2cc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5847-events-cjs-default-max.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5847-events-cjs-default-max.cjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_events_emitter.c b/packages/runtime/src/scr_events_emitter.c index 4f934ce24..ceecb15e3 100644 --- a/packages/runtime/src/scr_events_emitter.c +++ b/packages/runtime/src/scr_events_emitter.c @@ -1115,3 +1115,11 @@ void scr_emitter_set_default_max(double n) { scr_emitter_default_max = n; } double scr_emitter_get_default_max(void) { return scr_emitter_default_max; } + +/* The events module's ES module namespace holds a copy of + * defaultMaxListeners, taken when the program starts; ESM namespace + * and named-import reads answer it. module.syncBuiltinESMExports() copies + * the current value into it. */ +static SCR_TL double scr_emitter_esm_default_max = 10; +double scr_emitter_esm_default_max_get(void) { return scr_emitter_esm_default_max; } +void scr_emitter_esm_sync(void) { scr_emitter_esm_default_max = scr_emitter_default_max; } diff --git a/packages/runtime/src/scr_events_emitter.h b/packages/runtime/src/scr_events_emitter.h index c7edcf107..99da57a50 100644 --- a/packages/runtime/src/scr_events_emitter.h +++ b/packages/runtime/src/scr_events_emitter.h @@ -143,6 +143,8 @@ ScrEmitter *scr_emitter_set_max(ScrEmitter *em, double n); /* returns em +1 */ double scr_emitter_get_max(ScrEmitter *em); void scr_emitter_set_default_max(double n); double scr_emitter_get_default_max(void); +double scr_emitter_esm_default_max_get(void); +void scr_emitter_esm_sync(void); /* True when the emitter has at least one listener for `name` — the * stream unit's registration probe (and anyone else's). */ bool scr_emitter_has(ScrEmitter *em, const char *name); diff --git a/tests/corpus/5846-events-esm-default-max.ts b/tests/corpus/5846-events-esm-default-max.ts new file mode 100644 index 000000000..acc57328a --- /dev/null +++ b/tests/corpus/5846-events-esm-default-max.ts @@ -0,0 +1,28 @@ +// events.defaultMaxListeners through the module's ES module namespace and +// named imports reads the namespace's copy, which keeps the value from +// program start until module.syncBuiltinESMExports() refreshes it. The +// default import and the EventEmitter class read the current default. +import EventEmitterDefault, { defaultMaxListeners, EventEmitter, setMaxListeners } from "node:events"; +import * as events from "node:events"; +import { syncBuiltinESMExports } from "node:module"; + +const show = (label: string): void => { + console.log( + label, + events.defaultMaxListeners, + defaultMaxListeners, + EventEmitterDefault.defaultMaxListeners, + EventEmitter.defaultMaxListeners, + ); +}; +show("start"); +setMaxListeners(20); +show("after setMaxListeners"); +EventEmitter.defaultMaxListeners = 7; +show("after assignment"); +syncBuiltinESMExports(); +show("after sync"); +events.setMaxListeners(3); +show("after namespace setMaxListeners"); +const emitter = new EventEmitter(); +console.log(emitter.getMaxListeners(), events.getMaxListeners(emitter)); diff --git a/tests/corpus/5847-events-cjs-default-max.cjs b/tests/corpus/5847-events-cjs-default-max.cjs new file mode 100644 index 000000000..9edbe811d --- /dev/null +++ b/tests/corpus/5847-events-cjs-default-max.cjs @@ -0,0 +1,10 @@ +// CommonJS bindings of node:events read defaultMaxListeners from the module +// object, which is the EventEmitter class: every read sees the current +// default. +const events = require("node:events"); +const { EventEmitter, setMaxListeners } = require("node:events"); +console.log(events.defaultMaxListeners, EventEmitter.defaultMaxListeners); +setMaxListeners(15); +console.log(events.defaultMaxListeners, EventEmitter.defaultMaxListeners, require("events").defaultMaxListeners); +events.defaultMaxListeners = 4; +console.log(events.defaultMaxListeners, EventEmitter.defaultMaxListeners, new EventEmitter().getMaxListeners()); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 25f00b1f7..7ff735533 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1912,6 +1912,8 @@ "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, + "5846-events-esm-default-max.ts": 2633, + "5847-events-cjs-default-max.cjs": 2823, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4608,6 +4610,8 @@ "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, + "5846-events-esm-default-max.ts": 3102, + "5847-events-cjs-default-max.cjs": 3039, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 201857eb6c811b4c31b7bd087d17c1e7ff062d10 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 07:54:21 -0500 Subject: [PATCH 067/117] Read the class base after the callable-base case in super calls superCallStmt asserted the class base before checking for a callable base. A class that extends an ordinary function constructor has no base class info, so the assertion held null. Node ignores the unused value; the native compiler throws the TypeError of a non-null assertion that held null, and failed to compile programs with such classes (for example the Effect stream fixtures). The base is now read after that case returns. --- .../limitations/runtime-type-checks.mdx | 2 ++ .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 10 +++--- .../generated/node-v24-backlog.json | 19 ++++++----- .../generated/node-v24-internal.json | 12 ++++--- .../src/frontend/lowering/lower-classes.ts | 3 +- ...class-extends-function-constructor.js.json | 6 ++++ ...6020-class-extends-function-constructor.js | 27 ++++++++++++++++ tests/harness/corpus-costs.json | 2 ++ tests/harness/dyncheck.test.ts | 32 +++++++++++++++++++ tests/harness/native-frontend.ts | 1 + 11 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6020-class-extends-function-constructor.js.json create mode 100644 tests/corpus/6020-class-extends-function-constructor.js diff --git a/docs/content/limitations/runtime-type-checks.mdx b/docs/content/limitations/runtime-type-checks.mdx index 5514fb41e..ee7b953ce 100644 --- a/docs/content/limitations/runtime-type-checks.mdx +++ b/docs/content/limitations/runtime-type-checks.mdx @@ -3,3 +3,5 @@ Casts from values whose type is only known at runtime validate the value. For ex Casts between program classes are checked too: casting an instance to a class it does not extend throws a `TypeError`, where Node.js reads the members structurally. `SC6004` reports calls that pass such an instance to a function that casts it. A Promise converted from `unknown` to a typed result validates its fulfilled value. A mismatch rejects with a `TypeError`. Rejection reasons and reference equality are preserved across conversions. + +A non-null assertion (`value!`) checks the value when it extracts an object, array or other non-nullable member from a union. If the value holds `null` or `undefined`, the assertion throws a `TypeError`, even when the result is never used; Node.js continues until a property of the value is read. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 500876593..db36cdb52 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "56f660f5e2eb7391a048", + "artifactVersion": "cade1b8e6e0c5c42fcc9", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 568cdb4c9..dadc9e836 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -569,9 +569,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -57593,9 +57593,9 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 683d477a5..12b12d63b 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1142, - "verify-gap": 2187, + "audit-partial": 1143, + "verify-gap": 2186, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -57507,12 +57507,15 @@ "priority": "normal", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:process", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 393955bc0..2b97f675e 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -596,9 +596,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -80949,8 +80949,12 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:process" + "status": "partial", + "evidence": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] }, "anchorSource": "chapter" }, diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 8856ae9b5..06739166c 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -7861,7 +7861,6 @@ export function superCallStmt( args: IrExpr[], loc: SrcLoc, ): IrStmt { - const base = superBaseOf(info)!; const thisRef: IrExpr = { kind: "varRef", localId: thisLocal.id, @@ -7906,6 +7905,8 @@ export function superCallStmt( }, loc, }; + // A callable base has no class info, so the base is read after that case. + const base = superBaseOf(info)!; if (base.builtinError) { // super(message) into the runtime-provided Error constructor: stamps // name/message on the (already-allocated) object. Receiver + message diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6020-class-extends-function-constructor.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6020-class-extends-function-constructor.js.json new file mode 100644 index 000000000..b2fa4c986 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6020-class-extends-function-constructor.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6020-class-extends-function-constructor.js" + ], + "diags": [] +} diff --git a/tests/corpus/6020-class-extends-function-constructor.js b/tests/corpus/6020-class-extends-function-constructor.js new file mode 100644 index 000000000..d98d22a55 --- /dev/null +++ b/tests/corpus/6020-class-extends-function-constructor.js @@ -0,0 +1,27 @@ +// Classes whose base is an ordinary function constructor, with a declared +// constructor calling super and with the implicit derived constructor. +function Shape(name, sides) { + this.name = name; + this.sides = sides; +} +Shape.prototype.describe = function () { + return `${this.name} with ${this.sides} sides`; +}; + +class Polygon extends Shape { + constructor(name, sides, length) { + super(name, sides); + this.length = length; + } + perimeter() { + return this.sides * this.length; + } +} + +class Unnamed extends Shape {} + +const square = new Polygon("square", 4, 3); +console.log(square.describe(), square.perimeter()); +console.log(square instanceof Polygon); +const shape = new Unnamed("triangle", 3); +console.log(shape.describe(), Object.keys(shape).join(",")); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 25f00b1f7..a4a12bf4c 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1915,6 +1915,7 @@ "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, + "6020-class-extends-function-constructor.js": 4300, "603-closures-rc-stress.ts": 1832, "604-closures-for-of.ts": 2639, "605-closures-forward-capture-tdz.ts": 3277, @@ -4611,6 +4612,7 @@ "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, + "6020-class-extends-function-constructor.js": 7500, "603-closures-rc-stress.ts": 2589, "604-closures-for-of.ts": 3514, "605-closures-forward-capture-tdz.ts": 4638, diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index ca597c0db..2ab323f37 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -764,6 +764,38 @@ console.log("recovered"); expect(r.stdout).toBe("TypeError true\narray: TypeError\nfunc: TypeError\nrecovered\n"); }); + test("a non-null assertion on a null object result throws at the assertion, even when the binding is never read", async () => { + // Node lets the null ride until a member read; the compiled program + // throws the stranded TypeError where `!` extracts the object. + const r = await compileAndRun( + "asserted-null-object-result", + `interface Info { + name: string; + base: Info | null; + callable: boolean; +} +function baseOf(info: Info): Info | null { + return info.base; +} +function describe(info: Info): string { + const base = baseOf(info)!; + if (info.callable) return info.name + ": callable base"; + return info.name + " extends " + base.name; +} +const root: Info = { name: "Root", base: null, callable: false }; +console.log(describe({ name: "Child", base: root, callable: false })); +try { + console.log("unreachable", describe({ name: "Wrapped", base: null, callable: true })); +} catch (e) { + console.log((e as Error).name, (e as Error).message.includes("not representable in the target union")); +} +console.log("recovered"); +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe("Child extends Root\nTypeError true\nrecovered\n"); + }); + test("a checker-approved function mismatch strands per piece: mismatched params compile at the flow, void results trap after the call", async () => { // funcCoerceAdapter's stranded dispositions. Param strand: an array // literal of arrows collapses to one element signature — the diff --git a/tests/harness/native-frontend.ts b/tests/harness/native-frontend.ts index feee2f591..475db54aa 100644 --- a/tests/harness/native-frontend.ts +++ b/tests/harness/native-frontend.ts @@ -65,6 +65,7 @@ export const programs = [ "nullish-long-chain.ts", "class-array-optional-return.ts", "contextual-array-union-write.ts", + "6020-class-extends-function-constructor.js", ]; interface LowerRequest { From fc68a582d0614932dc360d7bc38e168f361cd134 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 07:59:03 -0500 Subject: [PATCH 068/117] Remove the last element of a packed array inline on pop pop and a discarded pop (the length - 1 store) branch on the array's length and hole-free prefix bound. When the bound equals the length, the last element is a present dense value: the emitted code clears its slot and state, lowers the bound and the length, and moves the slot out (or releases it for a discarded pop). An empty array answers undefined without a call. Holes, present undefined and sparse storage keep the runtime call. --- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 10 +- .../generated/node-v24-backlog.json | 19 ++- .../generated/node-v24-internal.json | 12 +- .../backend/llvm/dense-array-access.test.ts | 79 +++++++++- .../src/backend/llvm/dense-array-access.ts | 69 +++++++++ packages/compiler/src/backend/llvm/emitter.ts | 29 +++- .../src/backend/llvm/expr-containers.ts | 39 ++++- .../corpus/5681-array-pop-and-length.ts.json | 6 + tests/corpus/5681-array-pop-and-length.ts | 143 ++++++++++++++++++ tests/harness/corpus-costs.json | 2 + 11 files changed, 382 insertions(+), 28 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5681-array-pop-and-length.ts.json create mode 100644 tests/corpus/5681-array-pop-and-length.ts diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 500876593..db36cdb52 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "56f660f5e2eb7391a048", + "artifactVersion": "cade1b8e6e0c5c42fcc9", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 568cdb4c9..dadc9e836 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -569,9 +569,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -57593,9 +57593,9 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 683d477a5..12b12d63b 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1142, - "verify-gap": 2187, + "audit-partial": 1143, + "verify-gap": 2186, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -57507,12 +57507,15 @@ "priority": "normal", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:process", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 393955bc0..2b97f675e 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -596,9 +596,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -80949,8 +80949,12 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:process" + "status": "partial", + "evidence": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] }, "anchorSource": "chapter" }, diff --git a/packages/compiler/src/backend/llvm/dense-array-access.test.ts b/packages/compiler/src/backend/llvm/dense-array-access.test.ts index dc23ceae2..31680a518 100644 --- a/packages/compiler/src/backend/llvm/dense-array-access.test.ts +++ b/packages/compiler/src/backend/llvm/dense-array-access.test.ts @@ -3,6 +3,7 @@ import { BOOL, F64, STRING, + UNDEFINED_T, VOID, arrayOf, type IrExpr, @@ -23,11 +24,17 @@ const ref = (localId: string, type: IrExpr["type"]): IrExpr => ({ }); const index = ref("i", F64); -function module(name: string, returnType: IrExpr["type"], body: IrStmt[]): IrModule { +function module( + name: string, + returnType: IrExpr["type"], + body: IrStmt[], + unions: IrModule["unions"] = [], +): IrModule { return { irVersion: 16, sourceFile: loc.file, entry: "__main", + unions, functions: [ { name: "__main", params: [], returnType: VOID, locals: [], body: [], loc }, { @@ -174,6 +181,76 @@ test.each([32, 64] as const)( }, ); +test.each([32, 64] as const)( + "pop removes the last element of a packed array inline and keeps a cold runtime pop (%i-bit)", + (bits) => { + const maybe = { kind: "union", unionId: "maybe" } as const; + const pop: IrExpr = { + kind: "arrIntrinsic", + method: "pop", + receiver: ref("a", nums), + args: [], + type: maybe, + loc, + }; + const llvm = emitLlvmModule( + module( + "take", + maybe, + [{ kind: "return", value: pop, loc }], + [{ id: "maybe", arms: [F64, UNDEFINED_T] }], + ), + { pointerBits: bits }, + ); + const fn = body(llvm, "take"); + const size = bits === 32 ? "i32" : "i64"; + // An empty array answers undefined without a call. + expect(fn).toMatch(new RegExp(`icmp eq ${size} %t\\d+, 0\\n br i1 %t\\d+, label %remove\\.a`)); + expect(fn).toMatch(new RegExp(`sub nuw ${size} %t\\d+, 1`)); + expect(fn).toMatch(/store i64 0, ptr /); + expect(fn).toMatch(/store i8 0, ptr /); + expect(fn).toMatch(/phi i64 /); + expect(fn).toMatch(/call zeroext i8 @scr_arr_pop_state\(.*\) cold$/m); + }, +); + +test("a discarded pop releases the removed element inline", () => { + const words = ref("s", arrayOf(STRING)); + const length: IrExpr = { + kind: "arrIntrinsic", + method: "length", + receiver: words, + args: [], + type: F64, + loc, + }; + const llvm = emitLlvmModule( + module("drop", VOID, [ + { + kind: "arraySetLength", + arr: words, + length: { + kind: "bin", + op: "-", + left: length, + right: { kind: "numLit", value: 1, type: F64, loc }, + type: F64, + loc, + }, + loc, + pop: true, + }, + ]), + ); + const fn = body(llvm, "drop"); + expect(fn).toMatch(/fsub double %t\d+, 1\.0/); + expect(fn).toMatch(/load i64, ptr .*\n(?:.*\n)*? store i64 0, ptr /); + expect(fn).toMatch(/inttoptr i64 %t\d+ to ptr/); + expect(fn).toContain("call void @scr_str_release("); + // Holes, sparse storage, and every other length keep the runtime call. + expect(fn).toContain("call void @scr_arr_set_len("); +}); + test.each([32, 64] as const)( "indices below the hole-free prefix bound skip the state bytes (%i-bit)", (bits) => { diff --git a/packages/compiler/src/backend/llvm/dense-array-access.ts b/packages/compiler/src/backend/llvm/dense-array-access.ts index aeaf3e70f..183bb8239 100644 --- a/packages/compiler/src/backend/llvm/dense-array-access.ts +++ b/packages/compiler/src/backend/llvm/dense-array-access.ts @@ -508,6 +508,75 @@ export function emitDenseArraySet( B.startBlock(join); } +/** The dense half of `pop`. An empty array branches to `empty` (the + * runtime's pop returns a hole state there and changes nothing). When the + * hole-free prefix bound equals the length, the last element is a present + * value in dense storage, and the runtime's pop is exactly: clear its slot + * and state, lower the bound and the length to its index, and move the + * slot out. That block is left open and its slot bits are returned as an + * i64 (a boolean's 0 or 1, zero-extended); every other array branches to + * `slow`, which keeps the runtime call. */ +export function emitDenseArrayPop( + host: LlvmEmitterContext, + array: string, + acc: ArrayAccess, + empty: string, + slow: string, +): string { + const B = host.B; + const size = host.sizeType; + const header = (field: number): string => { + const ptr = B.tmp(); + B.line(`${ptr} = getelementptr inbounds %ScrArr, ptr ${array}, i32 0, i32 ${field}`); + host.markMemoryPointer(ptr, "array:header"); + return ptr; + }; + const lenPtr = header(SCR_ARR_FIELD.len), + len = B.tmp(), + none = B.tmp(); + B.line(`${len} = load ${size}, ptr ${lenPtr}${host.fieldAliasAttachment(lenPtr)}`); + B.line(`${none} = icmp eq ${size} ${len}, 0`); + const check = B.newLabel("arr.pop.check"), + dense = B.newLabel("arr.pop.dense"); + B.condBr(none, empty, check); + B.startBlock(check); + const filledPtr = header(SCR_ARR_FIELD.filled), + filled = B.tmp(), + packed = B.tmp(); + B.line(`${filled} = load i32, ptr ${filledPtr}${host.fieldAliasAttachment(filledPtr)}`); + B.line(`${packed} = icmp eq ${size} ${sizedFilled(host, filled)}, ${len}`); + B.condBr(packed, dense, slow); + B.startBlock(dense); + const last = B.tmp(); + B.line(`${last} = sub nuw ${size} ${len}, 1`); + const dataPtr = header(SCR_ARR_FIELD.data), + data = B.tmp(), + statesPtr = header(SCR_ARR_FIELD.present), + states = B.tmp(); + B.line(`${data} = load ptr, ptr ${dataPtr}${host.fieldAliasAttachment(dataPtr)}`); + B.line(`${states} = load ptr, ptr ${statesPtr}${host.fieldAliasAttachment(statesPtr)}`); + const valuePtr = valuePointer(host, { offset: last, data }, acc); + const statePtr = statePointer(host, { offset: last, states }); + const slotTy = slotType(acc); + let raw = B.tmp(); + B.line(`${raw} = load ${slotTy}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + if (slotTy === "i8") { + const wide = B.tmp(); + B.line(`${wide} = zext i8 ${raw} to i64`); + raw = wide; + } + B.line(`store ${slotTy} 0, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + B.line(`store i8 0, ptr ${statePtr}${host.fieldAliasAttachment(statePtr)}`); + let last32 = last; + if (size === "i64") { + last32 = B.tmp(); + B.line(`${last32} = trunc i64 ${last} to i32`); + } + B.line(`store i32 ${last32}, ptr ${filledPtr}${host.fieldAliasAttachment(filledPtr)}`); + B.line(`store ${size} ${last}, ptr ${lenPtr}${host.fieldAliasAttachment(lenPtr)}`); + return raw; +} + /** `scr_arr_push_*` (the array takes the value's reference) returning the * new length as a double. When `len < cap` the runtime's append is exactly * a dense store at `len` plus `len + 1`: no sparse entry can exist past the diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 8bae1abaf..79ad75d02 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -199,7 +199,12 @@ import { type LocalArrayRead, } from "./local-array-reads.js"; import { CheckedNarrows, emitCheckedNarrowReceiver } from "./checked-narrows.js"; -import { emitDenseArrayGet, emitDenseArraySet, emitDenseSlotUnlink } from "./dense-array-access.js"; +import { + emitDenseArrayGet, + emitDenseArrayPop, + emitDenseArraySet, + emitDenseSlotUnlink, +} from "./dense-array-access.js"; import { emitStackMapRead, findMapReadLifetimes, @@ -8130,6 +8135,28 @@ export class LlEmitter { B.line(`${same} = fcmp oeq double ${length.name}, ${lenNumber}`); B.condBr(same, done, resize); B.startBlock(resize); + if (s.pop === true) { + // A discarded pop's `length - 1` on a packed array removes the + // last element inline, then releases it. + const call = B.newLabel("arr.len.call"), + pop = B.newLabel("arr.len.pop"); + const lastNumber = B.tmp(), + dropsLast = B.tmp(); + B.line(`${lastNumber} = fsub double ${lenNumber}, 1.0`); + B.line(`${dropsLast} = fcmp oeq double ${length.name}, ${lastNumber}`); + B.condBr(dropsLast, pop, call); + B.startBlock(pop); + const elem = s.arr.type.elem; + const acc = elemAccess(elem); + const raw = emitDenseArrayPop(this, arr.name, acc, call, call); + if (acc === "ref" && isRefCounted(elem)) { + const old = B.tmp(); + B.line(`${old} = inttoptr i64 ${raw} to ptr`); + this.releaseValue(old, elem); + } + B.br(done); + B.startBlock(call); + } B.line(`call void @scr_arr_set_len(ptr ${arr.name}, double ${length.name})`); this.emitPendingCheck(); B.br(done); diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index a2d5fd35a..9c77690f8 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -49,7 +49,11 @@ import { STRING_UTF16_LEN_DECL, } from "./string-reads.js"; import { exactInteger, widenInteger } from "./integer-values.js"; -import { emitDenseArrayNumber, emitDenseArrayPush } from "./dense-array-access.js"; +import { + emitDenseArrayNumber, + emitDenseArrayPop, + emitDenseArrayPush, +} from "./dense-array-access.js"; import { emitUnionWiden } from "./expr-records.js"; export function resolveThunkFor(host: LlvmEmitterContext, inner: IrType): string { @@ -667,19 +671,38 @@ export function emitArrIntrinsic( const rawSlot = B.slot(); const resultSlot = B.slot(); B.entryAllocas.push(`${rawSlot} = alloca i64`, `${resultSlot} = alloca ptr`); - B.line(`store i64 0, ptr ${rawSlot}`); - const state = B.tmp(); - const has = B.tmp(); - B.line(`${state} = call zeroext i8 @scr_arr_${method}_state(ptr ${r.name}, ptr ${rawSlot})`); - B.line(`${has} = icmp eq i8 ${state}, 1`); const lp = B.newLabel("remove.p"); const la = B.newLabel("remove.a"); const lj = B.newLabel("remove.j"); + // pop answers an empty or packed array inline; shift and every other + // pop take the runtime call. + let denseRaw: string | null = null; + let denseLabel = ""; + let slowLabel = ""; + if (method === "pop") { + slowLabel = B.newLabel("remove.slow"); + denseRaw = emitDenseArrayPop(host, r.name, acc, la, slowLabel); + denseLabel = B.currentLabel(); + B.br(lp); + B.startBlock(slowLabel); + } + B.line(`store i64 0, ptr ${rawSlot}`); + const state = B.tmp(); + const has = B.tmp(); + const slowRaw = B.tmp(); + B.line( + `${state} = call zeroext i8 @scr_arr_${method}_state(ptr ${r.name}, ptr ${rawSlot})${denseRaw === null ? "" : " cold"}`, + ); + B.line(`${slowRaw} = load i64, ptr ${rawSlot}`); + B.line(`${has} = icmp eq i8 ${state}, 1`); B.condBr(has, lp, la); B.startBlock(lp); - const raw = B.tmp(); + let raw = slowRaw; const value = B.tmp(); - B.line(`${raw} = load i64, ptr ${rawSlot}`); + if (denseRaw !== null) { + raw = B.tmp(); + B.line(`${raw} = phi i64 [ ${denseRaw}, %${denseLabel} ], [ ${slowRaw}, %${slowLabel} ]`); + } if (into) { // Slot bits for f64; a canonical 0/1 for bool, like scr_union_new_bool. let bits = raw; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5681-array-pop-and-length.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5681-array-pop-and-length.ts.json new file mode 100644 index 000000000..d20701cae --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5681-array-pop-and-length.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5681-array-pop-and-length.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5681-array-pop-and-length.ts b/tests/corpus/5681-array-pop-and-length.ts new file mode 100644 index 000000000..451b32576 --- /dev/null +++ b/tests/corpus/5681-array-pop-and-length.ts @@ -0,0 +1,143 @@ +// Removing the last element with a statement-level pop() or `length = n`, +// for every element kind, on dense arrays, arrays with holes and present +// undefined values, sparse arrays and arrays shared between bindings. +// Removed references are released; the remaining elements, the length and +// later appends match Node. + +class Item { + readonly id: number; + constructor(id: number) { + this.id = id; + } +} + +function show(label: string, values: unknown[]): void { + const parts: string[] = []; + for (let i = 0; i < values.length; i++) { + if (!(i in values)) parts.push(""); + else { + const v = values[i]; + parts.push(v instanceof Item ? `I${v.id}` : (JSON.stringify(v) ?? "undefined")); + } + } + console.log(label, values.length, parts.join(" ")); +} + +const numbers = [1.5, 2.5, 3.5, 4.5]; +numbers.pop(); +numbers.length = numbers.length - 1; +numbers.push(9); +show("numbers", numbers); + +const flags = [true, false, true]; +flags.pop(); +flags.length = 1; +flags.push(false); +show("flags", flags); + +const words = ["a", "b", "c", "d"]; +const alias = words; +words.pop(); +alias.length = alias.length - 1; +words.push("z"); +show("words", words); +show("alias", alias); + +const items = [new Item(1), new Item(2), new Item(3)]; +const kept = items[2]!; +items.pop(); +items.length = 1; +items.push(new Item(4)); +show("items", items); +console.log("kept", kept.id); + +// Holes and present undefined at the end. +const holes: (number | undefined)[] = [1, 2]; +holes[4] = 5; +holes.length = 4; +show("holes trimmed", holes); +holes.length = 3; +show("holes trimmed again", holes); +const undef: (string | undefined)[] = ["x", undefined, undefined]; +undef.pop(); +undef.length = undef.length - 1; +show("undefined", undef); + +// A sparse array: a far index then shrinking past it and back by one. +const sparse: number[] = [1, 2, 3]; +sparse[2000000] = 4; +sparse.length = 2000000; +show("sparse cut", sparse.slice(0, 4)); +console.log("sparse length", sparse.length, 1999999 in sparse); +sparse.length = sparse.length - 1; +console.log("sparse length", sparse.length); + +// A stack used the way a checker pushes and pops contextual entries. +const stack: Item[] = []; +const top: number[] = []; +let checksum = 0; +for (let i = 0; i < 20000; i++) { + stack.push(new Item(i)); + top.push(i); + if (i % 3 === 2) { + stack.pop(); + top.length = top.length - 1; + } + if (stack.length > 50) { + stack.length = stack.length - 1; + top.pop(); + } + checksum = (checksum + stack[stack.length - 1]!.id + top[top.length - 1]!) % 1000003; +} +console.log("stack", stack.length, top.length, checksum); + +// Lengths that are not one less: unchanged, longer, invalid. +const other = [1, 2, 3]; +other.length = 3; +other.length = 5; +show("longer", other); +other.length = 1; +show("shorter by many", other); +try { + other.length = -1; +} catch (e) { + console.log("invalid", (e as Error).name, other.length); +} +try { + other.length = 0.5; +} catch (e) { + console.log("fraction", (e as Error).name, other.length); +} +const empty: number[] = []; +empty.pop(); +empty.length = 0; +show("empty", empty); + +// pop() results: the last element, undefined for an empty array, a hole or a +// present undefined, and values taken from sparse storage. +const nums = [0.5, -0, 7]; +console.log("pop number", nums.pop(), Object.is(nums.pop(), -0), nums.pop(), nums.pop(), nums.length); +const bools = [false, true]; +console.log("pop bool", bools.pop(), bools.pop(), bools.pop(), bools.length); +const strs = ["p", "q"]; +const strAlias = strs; +console.log("pop string", strs.pop(), strAlias.pop(), strs.pop(), strAlias.length); +const objs = [new Item(7), new Item(8)]; +const popped = objs.pop(); +console.log("pop item", popped?.id, objs.pop()?.id, objs.pop(), objs.length); +const gaps: number[] = [1]; +gaps[3] = 4; +console.log("pop gaps", gaps.pop(), gaps.pop(), gaps.pop(), gaps.pop(), gaps.pop(), gaps.length); +const maybe: (number | undefined)[] = [1, undefined]; +console.log("pop present undefined", maybe.pop(), maybe.length, maybe.pop(), maybe.length); +const far: string[] = ["a"]; +far[100000] = "b"; +console.log("pop sparse", far.pop(), far.length, far.pop(), far.length); +let popTotal = 0; +const work: number[] = []; +for (let i = 0; i < 10000; i++) { + work.push(i, i + 1); + popTotal += work.pop()!; + if (i % 5 === 0) popTotal += work.pop() ?? -1; +} +console.log("pop loop", work.length, popTotal); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 25f00b1f7..ebaa91179 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1841,6 +1841,7 @@ "5648-dns-lookup-forms.ts": 2992, "5649-dns-service-servers.ts": 2712, "5650-dns-lookup-errors-untyped.cjs": 2822, + "5681-array-pop-and-length.ts": 3754, "5800-broadcast-channel.ts": 2899, "5801-broadcast-channel.cjs": 2727, "5802-broadcast-channel-workers.ts": 2809, @@ -4537,6 +4538,7 @@ "5648-dns-lookup-forms.ts": 3416, "5649-dns-service-servers.ts": 4916, "5650-dns-lookup-errors-untyped.cjs": 3889, + "5681-array-pop-and-length.ts": 3216, "5800-broadcast-channel.ts": 28374, "5801-broadcast-channel.cjs": 27251, "5802-broadcast-channel-workers.ts": 27251, From 0dc6e05e82f3a9d23238c7d71236cb236e4bcf90 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 20:47:16 -0700 Subject: [PATCH 069/117] Expect the tighter strided-loop bound in the self-hosted range cases The native range analysis now admits one fewer pass for a strict bound, so the failing condition of `for (x = 0; x < 100; x += 24)` reads at most 123 (the last pass enters at 99 at most). Co-Authored-By: Claude Opus 5.5 --- tests/harness/self-hosting-range-cases.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/harness/self-hosting-range-cases.ts b/tests/harness/self-hosting-range-cases.ts index 05d6a1fe6..ed2b24ca9 100644 --- a/tests/harness/self-hosting-range-cases.ts +++ b/tests/harness/self-hosting-range-cases.ts @@ -375,7 +375,8 @@ export function integerRangeCases(): RangeCase[] { ], }, ], - [proof(cursor, 0, 80), proof(decoded, 0, 4294967295), proof(head, 0, 124)], + // Passes enter at 0, 24, 48, 72 and 96 (at most 99), so the failing test reads at most 123. + [proof(cursor, 0, 80), proof(decoded, 0, 4294967295), proof(head, 0, 123)], (func) => { for (const id of ["cursor", "decoded"]) func.locals.push({ id, name: id, type: F64, mutable: true }); From 9118cbc2587d2cc568bb1ee27ab65a4ff8d2f338 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 20:34:49 -0700 Subject: [PATCH 070/117] Record corpus 5973's preflight baseline and skip the scaling test under ASan The order-parity baseline for the new corpus program records its module order and empty preflight diagnostics. Uncached sanitized builds rebuild the runtime for every compile, which takes longer than either measured size, so the compile-time growth test runs in the plain lane only. Co-Authored-By: Claude Opus 5.5 --- .../5973-large-closure-environment.ts.json | 6 +++ .../closure-environment-scaling.test.ts | 41 +++++++++---------- 2 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5973-large-closure-environment.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5973-large-closure-environment.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5973-large-closure-environment.ts.json new file mode 100644 index 000000000..545536285 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5973-large-closure-environment.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5973-large-closure-environment.ts" + ], + "diags": [] +} diff --git a/tests/harness/closure-environment-scaling.test.ts b/tests/harness/closure-environment-scaling.test.ts index c6f3a09fe..785f07349 100644 --- a/tests/harness/closure-environment-scaling.test.ts +++ b/tests/harness/closure-environment-scaling.test.ts @@ -14,6 +14,8 @@ import { expect, test } from "vitest"; const execFileAsync = promisify(execFile); const repoRoot = join(import.meta.dirname, "../.."); +// Sanitized builds compile the runtime with each uncached build, which +// dwarfs both sizes; the growth this test bounds is the same in every lane. const sanitize = process.env["SCRIPTC_SAN"] === "1"; /** `n` number bindings plus n/20 objects and strings, all captured by a @@ -83,14 +85,7 @@ async function compileTime(dir: string, n: number): Promise { writeFileSync(entry, source); const { stderr } = await execFileAsync( process.execPath, - [ - join(repoRoot, "packages/cli/dist/main.js"), - "build", - entry, - "-o", - binary, - ...(sanitize ? ["--sanitize"] : []), - ], + [join(repoRoot, "packages/cli/dist/main.js"), "build", entry, "-o", binary], { env: { ...process.env, SCRIPTC_TIMING: "1", SCRIPTC_NO_CACHE: "1" }, maxBuffer: 16 * 1024 * 1024, @@ -113,16 +108,20 @@ async function compileTime(dir: string, n: number): Promise { return complete - loaded; } -test("compile time grows linearly with a shared closure environment", async () => { - const dir = mkdtempSync(join(tmpdir(), "scriptc-closure-scaling-")); - try { - const small = await compileTime(dir, 500); - const large = await compileTime(dir, 4000); - // Eight times the bindings. Linear growth stays at or below 8x (fixed - // costs keep it near 5x); the quadratic analyses and code generation - // measured 24x at these sizes, and every doubling beyond adds 4x. - expect(large / small, `${small.toFixed(0)} ms -> ${large.toFixed(0)} ms`).toBeLessThan(16); - } finally { - rmSync(dir, { recursive: true, force: true }); - } -}, 300_000); +test.skipIf(sanitize)( + "compile time grows linearly with a shared closure environment", + async () => { + const dir = mkdtempSync(join(tmpdir(), "scriptc-closure-scaling-")); + try { + const small = await compileTime(dir, 500); + const large = await compileTime(dir, 4000); + // Eight times the bindings. Linear growth stays at or below 8x (fixed + // costs keep it near 5x); the quadratic analyses and code generation + // measured 24x at these sizes, and every doubling beyond adds 4x. + expect(large / small, `${small.toFixed(0)} ms -> ${large.toFixed(0)} ms`).toBeLessThan(16); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }, + 300_000, +); From ae91df908ec41876a8394375961c83c9bc1c12f9 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 21:53:01 -0700 Subject: [PATCH 071/117] Admit require cycles whose modules settle their exports first A require cycle was always refused (SC1016). Node answers a require of a module that is still evaluating with its exports as they stand, while the compiled bindings alias the final declarations; the two agree when every module of the cycle assigns all of its exports before its first statement that can run another module's code, every other use of its export object is a plain member read, and no module's top-level code can reach its binding of another member. Each module then initializes exactly as it would outside the cycle. This admits semver's comparator/range cycle ("hoisted class for cyclic dependency"); other cycles keep SC1016 with a reason naming the offending statement. The require reachability scan no longer treats a declaration's own name as a read (esbuild's `var X = class {...}` before its requires), treats a plain write of an export member as running only a setter published for it (on-finished's `module.exports.isFinished = isFinished`), and keeps the conservative scan for writes of __proto__, __esModule and members of a replaced export object. Evidence: corpus 6145 (the cycle), 6142 gains the esbuild layout; the npm-static harness compiles the published fs.realpath@1.0.0, on-finished@2.4.1 (with ee-first@1.1.1) and statuses@2.0.1 statically; program.test.ts pins the TDZ analysis through var bindings plus the cycle admission and refusals. Preflight/order baselines recorded for the new fixtures; a full re-record changed no other fixture. Dependencies and limitations docs describe the supported require forms. Co-Authored-By: Claude Opus 5.5 --- docs/content/docs/dependencies.mdx | 4 + docs/content/docs/limitations.mdx | 2 + .../language-features/commonjs-require.mdx | 1 + .../compiler/src/frontend/program.test.ts | 97 +++++- packages/compiler/src/frontend/program.ts | 256 ++++++++++++++- .../6140-cjs-require-tdz-throws/main.js.json | 7 + .../6141-cjs-require-tdz-checked/main.js.json | 8 + .../main.js.json | 13 + .../corpus/6143-cjs-require-json/main.js.json | 7 + .../main.js.json | 6 + .../6145-cjs-require-cycle/main.js.json | 9 + .../cjs-require-cycle/main.js.json | 2 +- .../cjs-require-tdz-unchecked/main.js.json | 7 + .../diagnostics/cjs-require-tdz/main.js.json | 6 +- .../bundle.js | 17 + .../6142-cjs-require-published-early/core.js | 10 + .../6142-cjs-require-published-early/main.js | 2 + .../6145-cjs-require-cycle/comparator.js | 29 ++ tests/corpus/6145-cjs-require-cycle/main.js | 15 + .../6145-cjs-require-cycle/package.json | 1 + tests/corpus/6145-cjs-require-cycle/range.js | 24 ++ tests/corpus/6145-cjs-require-cycle/util.js | 10 + tests/diagnostics/cjs-require-cycle/main.js | 6 +- tests/fixtures/npm-static/cjs-interop-cli.ts | 9 + .../npm-static/node_modules/ee-first/LICENSE | 22 ++ .../npm-static/node_modules/ee-first/index.js | 95 ++++++ .../node_modules/ee-first/package.json | 29 ++ .../node_modules/fs.realpath/LICENSE | 43 +++ .../node_modules/fs.realpath/index.js | 66 ++++ .../node_modules/fs.realpath/old.js | 303 ++++++++++++++++++ .../node_modules/fs.realpath/package.json | 26 ++ .../node_modules/on-finished/LICENSE | 23 ++ .../node_modules/on-finished/index.js | 234 ++++++++++++++ .../node_modules/on-finished/package.json | 39 +++ .../npm-static/node_modules/statuses/LICENSE | 23 ++ .../node_modules/statuses/codes.json | 65 ++++ .../npm-static/node_modules/statuses/index.js | 146 +++++++++ .../node_modules/statuses/package.json | 49 +++ .../cjs-require-cycle/main.js.txt | 2 +- tests/harness/npm-static.test.ts | 18 ++ 40 files changed, 1717 insertions(+), 14 deletions(-) create mode 100644 docs/content/limitations/language-features/commonjs-require.mdx create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6140-cjs-require-tdz-throws/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6141-cjs-require-tdz-checked/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6142-cjs-require-published-early/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6143-cjs-require-json/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6144-cjs-require-builtin-nested/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6145-cjs-require-cycle/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz-unchecked/main.js.json create mode 100644 tests/corpus/6142-cjs-require-published-early/bundle.js create mode 100644 tests/corpus/6142-cjs-require-published-early/core.js create mode 100644 tests/corpus/6145-cjs-require-cycle/comparator.js create mode 100644 tests/corpus/6145-cjs-require-cycle/main.js create mode 100644 tests/corpus/6145-cjs-require-cycle/package.json create mode 100644 tests/corpus/6145-cjs-require-cycle/range.js create mode 100644 tests/corpus/6145-cjs-require-cycle/util.js create mode 100644 tests/fixtures/npm-static/cjs-interop-cli.ts create mode 100644 tests/fixtures/npm-static/node_modules/ee-first/LICENSE create mode 100644 tests/fixtures/npm-static/node_modules/ee-first/index.js create mode 100644 tests/fixtures/npm-static/node_modules/ee-first/package.json create mode 100644 tests/fixtures/npm-static/node_modules/fs.realpath/LICENSE create mode 100644 tests/fixtures/npm-static/node_modules/fs.realpath/index.js create mode 100644 tests/fixtures/npm-static/node_modules/fs.realpath/old.js create mode 100644 tests/fixtures/npm-static/node_modules/fs.realpath/package.json create mode 100644 tests/fixtures/npm-static/node_modules/on-finished/LICENSE create mode 100644 tests/fixtures/npm-static/node_modules/on-finished/index.js create mode 100644 tests/fixtures/npm-static/node_modules/on-finished/package.json create mode 100644 tests/fixtures/npm-static/node_modules/statuses/LICENSE create mode 100644 tests/fixtures/npm-static/node_modules/statuses/codes.json create mode 100644 tests/fixtures/npm-static/node_modules/statuses/index.js create mode 100644 tests/fixtures/npm-static/node_modules/statuses/package.json diff --git a/docs/content/docs/dependencies.mdx b/docs/content/docs/dependencies.mdx index f93952221..5ecc144c6 100644 --- a/docs/content/docs/dependencies.mdx +++ b/docs/content/docs/dependencies.mdx @@ -69,6 +69,10 @@ $ scriptc build app.ts --npm-static=three -o app >/dev/null Naming a package skips the declaration requirement above, but the package still has to compile. `--npm-static=auto` uses the default automatic selection. The option accepts a comma-separated list and can be repeated. +## CommonJS packages + +CommonJS packages compile with Node.js's module semantics. Each `require()` evaluates its module at the call, once, and later calls return the cached exports. A package can assign `module.exports` and run code before it requires its dependencies. If that code reads a `const` or `let` require binding before its `require` runs, the read throws the same `ReferenceError` as Node.js. A `var` binding that earlier code can reach is reported at build time. A `require()` of a JSON file, such as a package's own `package.json`, returns one object parsed at build time, shared by every module that requires it. A require cycle compiles when each of its modules assigns its exports before requiring anything, as semver's classes do, and uses the other modules only inside functions that its top-level code can't call. Other require cycles are reported at build time. The [limitations](/docs/limitations) page lists the supported `require` forms. + ## Unsupported code inside a package A JavaScript package can contain operations scriptc can't compile, often in functions your program never calls. These don't fail the build: each one compiles to code that throws a runtime error if it ever runs. Coverage reports list them as deferred sites, so review the list and test the parts of the package your program uses. diff --git a/docs/content/docs/limitations.mdx b/docs/content/docs/limitations.mdx index ed2c5b1ec..544bd2b2d 100644 --- a/docs/content/docs/limitations.mdx +++ b/docs/content/docs/limitations.mdx @@ -32,6 +32,8 @@ title: "Limitations" ../limitations/language-features/dynamic-imports.mdx +../limitations/language-features/commonjs-require.mdx + ### Types and class definitions ../limitations/types-and-class-definitions/bigint.mdx diff --git a/docs/content/limitations/language-features/commonjs-require.mdx b/docs/content/limitations/language-features/commonjs-require.mdx new file mode 100644 index 000000000..578499410 --- /dev/null +++ b/docs/content/limitations/language-features/commonjs-require.mdx @@ -0,0 +1 @@ +- **CommonJS `require`:** Literal `require()` calls of compiled modules, supported builtins, and JSON documents compile. Reading a top-level `const` or `let` require binding before its `require` runs throws the same `ReferenceError` as Node.js. A `var` binding that code above its `require` can reach is unsupported, and so is a read that compiles to no checkable expression, such as exporting the binding before the `require`. JSON documents are parsed at build time, and every `require()` of a document returns the same object. Destructuring the exports of a module supports plain and renamed properties, plus nested patterns for builtin sub-modules such as `util.types`. Any pattern works on a JSON document. Defaults, rest elements, and nested patterns over other modules are unsupported. A require cycle compiles when each of its modules assigns all of its exports before its first `require` and uses the other modules of the cycle only inside functions that its top-level code can't call. Other require cycles are rejected with `SC1016`. diff --git a/packages/compiler/src/frontend/program.test.ts b/packages/compiler/src/frontend/program.test.ts index 33abf6d67..8fec2f486 100644 --- a/packages/compiler/src/frontend/program.test.ts +++ b/packages/compiler/src/frontend/program.test.ts @@ -126,10 +126,12 @@ test.for([ ["replacement export property", "module.exports = read; module.exports.name = read;"], ["non-export assignment chain", "const box = {}; exports.alias = box.read = read;"], ])("require still refuses an early read through %s", ([, early]) => { + // A var binding keeps the fence (Node reads undefined there); a const + // compiles with initialization checks instead, from the same analysis. const diagnostics = requireOrderDiagnostics(` exports.read = read; ${early} -const dep = require('./dep.cjs'); +var dep = require('./dep.cjs'); function read() { return dep.value; } `); expect( @@ -140,13 +142,43 @@ function read() { return dep.value; } test("publishing a require binding itself still reads it before initialization", () => { const diagnostics = requireOrderDiagnostics(` exports.read = read; -const { read } = require('./dep.cjs'); +var { read } = require('./dep.cjs'); `); expect( diagnostics.some((diag) => diag.code === "SC1013" && diag.message.includes("binding 'read'")), ).toBe(true); }); +test("an early-reachable const require binding compiles with initialization checks", () => { + // Preflight admits it; the lowering checks every reference that can run + // before the require (require-initialization.ts). + expect( + requireOrderDiagnostics(` +exports.read = read; +read(); +const dep = require('./dep.cjs'); +function read() { return dep.value; } +`), + ).toEqual([]); +}); + +test.for([ + ["a class whose methods read it", "class Reader { read() { return dep.value; } }"], + ["a stored class expression", "var Reader = class { read() { return dep.value; } };"], + ["a later-job callback", "setTimeout(() => dep.value, 0);"], + ["a published getter", "Object.defineProperty(exports, 'value', { get: () => dep.value });"], + ["a property stored on a published function", "module.exports = read; read.again = again;"], +])("code that cannot run before the require does not reach it: %s", ([, early]) => { + expect( + requireOrderDiagnostics(` +${early} +var dep = require('./dep.cjs'); +function read() { return dep.value; } +function again() { return dep.value; } +`), + ).toEqual([]); +}); + test.for([ "var Object = null; Object.defineProperty(exports, '__esModule', { value: true }); exports.read = read;", "var exports = null; exports.read = read;", @@ -154,7 +186,7 @@ test.for([ ])("source bindings cannot masquerade as a CommonJS prologue: %s", (prefix) => { const diagnostics = requireOrderDiagnostics(` ${prefix} -const dep = require('./dep.cjs'); +var dep = require('./dep.cjs'); function read() { return dep.value; } `); expect( @@ -165,7 +197,7 @@ function read() { return dep.value; } test("an earlier declarator can call an export before the require initializes", () => { const diagnostics = requireOrderDiagnostics(` exports.read = read; -const before = read(), dep = require('./dep.cjs'); +var before = read(), dep = require('./dep.cjs'); function read() { return dep.value; } `); expect( @@ -183,6 +215,63 @@ function read() { return dep.value; } ).toEqual([]); }); +test("a member added to a replaced export does not run the replacement (on-finished)", () => { + expect( + requireOrderDiagnostics(` +module.exports = read; +module.exports.check = check; +var hooks = probe(); +var dep = require('./dep.cjs'); +function read() { return dep.value; } +function check() { return 1; } +function probe() { return check(); } +`), + ).toEqual([]); +}); + +test("a require cycle whose modules export first and use each other only later is admitted", () => { + expect( + requireOrderDiagnostics( + ` +const ANY = Symbol('ANY'); +class Main { dep() { return new Dep(); } } +module.exports = Main; +const Dep = require('./dep.cjs'); +`, + "class Dep { main() { return new Main(); } }\nmodule.exports = Dep;\nconst Main = require('./main.cjs');\n", + ), + ).toEqual([]); +}); + +test.for([ + [ + "an export after the require", + "const Main = require('./main.cjs');\nmodule.exports = { Dep: 1 };\n", + ], + [ + "a top-level use of the cycle binding", + "module.exports = 1;\nconst Main = require('./main.cjs');\nnew Main();\n", + ], + [ + "an escaping export object", + "module.exports = 1;\nconst Main = require('./main.cjs');\nObject.assign(exports, {});\n", + ], + [ + "a call before the export", + "setup();\nmodule.exports = 1;\nconst Main = require('./main.cjs');\nfunction setup() {}\n", + ], +])("a require cycle keeps SC1016 for %s", ([, dependency]) => { + const diagnostics = requireOrderDiagnostics( + ` +class Main {} +module.exports = Main; +const dep = require('./dep.cjs'); +`, + dependency, + ); + expect(diagnostics.some((diag) => diag.code === "SC1016")).toBe(true); +}); + test("function publication does not admit CommonJS cycles", () => { const diagnostics = requireOrderDiagnostics( ` diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index 82b2cb5e0..df0cb673e 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -1477,11 +1477,13 @@ export function requireBindingEarlyUse7( isWrapperName(e, "exports") || isModuleThis(e) || (isModuleExportsAccess(e) && isWrapperName(e.expression, "module")); + const replacesExports = stmts.some((st) => cjsExportAssignmentOf(st)?.kind === "table"); // Published values: by export name ("*" for a whole replacement), and by // the stored callable whose properties hold them. const exportLinks = new Map(); const ownerLinks = new Map(); const reachedKeys = new Set(); + const writtenKeys = new Set(); const reachedUnits = new Set(); const work: ts.Node[] = []; let hit: ts.Identifier | null = null; @@ -1521,6 +1523,24 @@ export function requireBindingEarlyUse7( } if (ts.isTypeOfExpression(parent)) return; if (ts.isPropertyAccessExpression(parent) && parent.expression === use) { + let target: ts.Node = parent; + while (ts.isParenthesizedExpression(target.parent)) target = target.parent; + const assignment = target.parent; + if ( + ts.isBinaryExpression(assignment) && + assignment.left === target && + assignment.operatorToken.kind === ts.SyntaxKind.EqualsToken + ) { + // A plain write reads no member. It can still run a setter: one + // published for that name (now or later), or a static one of a + // replacing class. + writtenKeys.add(parent.name.text); + for (const node of exportLinks.get(parent.name.text) ?? []) reachUnit(node); + for (const node of exportLinks.get("*") ?? []) { + if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) reachUnit(node); + } + return; + } reachKey(parent.name.text); return; } @@ -1566,6 +1586,8 @@ export function requireBindingEarlyUse7( ) { return undefined; } + // A declaration's own name reads nothing. + if (named !== undefined && declaredName7(named) === n) return undefined; if (cjs && isWrapperName(n, "exports")) { exportRead(n); return undefined; @@ -1674,7 +1696,13 @@ export function requireBindingEarlyUse7( } else break; } if (names.length === 0) return null; - if (isExportObject(e)) return { kind: "key", key: names[0]! }; + if (isExportObject(e)) { + // __proto__ and the interop marker are not plain data slots, and a + // member of a replaced export may be a read-only function property: + // those writes keep the conservative scan. + if (names[0] === "__proto__" || names[0] === "__esModule" || replacesExports) return null; + return { kind: "key", key: names[0]! }; + } if (ts.isIdentifier(e)) { const sym = symbolOf(e); if (sym !== undefined && units.has(sym) && !bindings.has(sym)) @@ -1684,7 +1712,13 @@ export function requireBindingEarlyUse7( }; const linkTo = (target: Target, node: ts.Node): void => { if (target.kind === "key") { - if (keyReached(target.key)) reachUnit(node); + const replacingClass = + target.key === "*" && + writtenKeys.size > 0 && + (ts.isClassDeclaration(node) || ts.isClassExpression(node)); + if (keyReached(target.key) || writtenKeys.has(target.key) || replacingClass) { + reachUnit(node); + } const list = exportLinks.get(target.key); if (list) list.push(node); else exportLinks.set(target.key, [node]); @@ -2777,8 +2811,19 @@ export function makeCycleAdmission( bindingUses.set(sf, uses); return uses; }; + // The CommonJS cluster verdict, same keying (cjsCycleRefusal7). + const cjsVerdict = new Map(); return (importer: ts.SourceFile, e: CycleEdge): string | null => { - if (e.stmt === undefined) return "the cycle closes through a require() edge"; + if (e.stmt === undefined) { + if (!index.has(importer)) strongconnect(importer); + const comp = sccOf.get(e.dep); + if (comp === undefined || comp.length < 2 || !comp.includes(importer)) { + return "the cycle closes through a require() edge"; + } + if (!cjsVerdict.has(comp)) cjsVerdict.set(comp, cjsCycleRefusal7(program, comp, lineOf)); + const reason = cjsVerdict.get(comp) ?? null; + return reason === null ? null : `the cycle closes through a require() edge: ${reason}`; + } // Cheap per-edge admission: nothing readable binds through the edge. if (ts.isImportDeclaration(e.stmt)) { const clause = e.stmt.importClause; @@ -2824,6 +2869,211 @@ export function makeCycleAdmission( }; } +/** The reason a strongly-connected cluster of CommonJS modules cannot be + * initialized exactly through its require() cycle, or null when it can. + * Node answers a require of a module that is still evaluating with that + * module's exports object as it stands, while the compiled bindings alias + * the exporter's final declarations. The two agree when: + * - every member settles its exports before anything can enter the + * cycle: all of its export statements come before its first top-level + * statement that can run another module's code (a require, or anything + * but literals, plain reads, function and class values, and + * standard-library globals called with literal arguments), and every + * other use of its export object is a plain member read; and + * - no member's top-level code can reach its binding of another member, + * so no member runs another member's code while the cluster is still + * initializing. Each module then initializes exactly as it would + * outside the cycle, and its own require bindings keep the acyclic + * analysis (requireEarlyReference). + * Other cycles keep the SC1016 fence. */ +function cjsCycleRefusal7( + program: ts.Program, + comp: readonly ts.SourceFile[], + lineOf: (node: ts.Node) => string, +): string | null { + const members = new Set(comp); + const builtinRoot = (e: ts.Expression): boolean => { + while (ts.isPropertyAccessExpression(e)) e = e.expression; + return ts.isIdentifier(e) && !sourceBinding7(program, e); + }; + const literal = (e: ts.Node): boolean => + ts.isStringLiteralLike(e) || + ts.isNumericLiteral(e) || + ts.isRegularExpressionLiteral(e) || + e.kind === ts.SyntaxKind.TrueKeyword || + e.kind === ts.SyntaxKind.FalseKeyword || + e.kind === ts.SyntaxKind.NullKeyword; + /** An expression whose evaluation runs no user code and requires + * nothing: literals, plain reads, function and class values, literal + * containers of those, and standard-library globals called with + * literal arguments. */ + const inertExpr = (e: ts.Node): boolean => { + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (literal(e) || ts.isIdentifier(e)) return true; + if (ts.isFunctionExpression(e) || ts.isArrowFunction(e)) return true; + if (ts.isClassExpression(e)) return classSyncParts7(e).every(inertPart); + if (ts.isObjectLiteralExpression(e)) { + return e.properties.every((p) => + ts.isShorthandPropertyAssignment(p) + ? true + : ts.isPropertyAssignment(p) + ? !ts.isComputedPropertyName(p.name) && inertExpr(p.initializer) + : (ts.isMethodDeclaration(p) || + ts.isGetAccessorDeclaration(p) || + ts.isSetAccessorDeclaration(p)) && + !ts.isComputedPropertyName(p.name), + ); + } + if (ts.isArrayLiteralExpression(e)) { + return e.elements.every((el) => !ts.isSpreadElement(el) && inertExpr(el)); + } + if (ts.isPropertyAccessExpression(e)) return builtinRoot(e); + if (ts.isVoidExpression(e)) return literal(e.expression); + if (ts.isCallExpression(e) || ts.isNewExpression(e)) { + return ( + requireSpecOf7(e) === null && + builtinRoot(e.expression) && + (e.arguments ?? []).every(literal) + ); + } + return false; + }; + const inertPart = (part: ts.Node): boolean => { + if (ts.isHeritageClause(part)) return part.types.every((t) => inertExpr(t.expression)); + if (ts.isComputedPropertyName(part)) return inertExpr(part.expression); + return ts.isExpression(part) && inertExpr(part); + }; + const exportObject = (e: ts.Expression): boolean => + (ts.isIdentifier(e) && e.text === "exports" && !sourceBinding7(program, e)) || + (isModuleExportsAccess(e) && + ts.isIdentifier(e.expression) && + !sourceBinding7(program, e.expression)); + /** A top-level statement that only publishes inert values. */ + const exportStatement = (stmt: ts.Statement): boolean => { + if (!ts.isExpressionStatement(stmt)) return false; + if (isEsModuleStamp(stmt.expression)) return true; + const cjs = cjsExportAssignmentOf(stmt); + if (cjs !== null) { + let value: ts.Expression = cjs.expr; + while ( + ts.isBinaryExpression(value) && + value.operatorToken.kind === ts.SyntaxKind.EqualsToken + ) { + const left = value.left; + if ( + !isModuleExportsAccess(left) && + !(ts.isPropertyAccessExpression(left) && exportObject(left.expression)) + ) + return false; + value = value.right; + } + return inertExpr(value); + } + const call = stmt.expression; + return ( + ts.isCallExpression(call) && + ts.isPropertyAccessExpression(call.expression) && + ts.isIdentifier(call.expression.expression) && + call.expression.expression.text === "Object" && + !sourceBinding7(program, call.expression.expression) && + call.expression.name.text === "defineProperty" && + call.arguments.length === 3 && + exportObject(call.arguments[0]!) && + ts.isStringLiteralLike(call.arguments[1]!) && + inertExpr(call.arguments[2]!) + ); + }; + for (const m of comp) { + if (!isCjsJsFile7(m, program)) { + return `${m.fileName} is not a CommonJS module — require cycles are admitted between CommonJS modules only`; + } + const stmts = m.statements; + // The first statement that can run another module's code. + let firstEntry = stmts.length; + for (let i = 0; i < stmts.length; i++) { + const st = stmts[i]!; + const inert = + ts.isFunctionDeclaration(st) || + ts.isEmptyStatement(st) || + (ts.isExpressionStatement(st) && ts.isStringLiteral(st.expression)) || + (ts.isClassDeclaration(st) && classSyncParts7(st).every(inertPart)) || + (ts.isVariableStatement(st) && + st.declarationList.declarations.every( + (d) => + ts.isIdentifier(d.name) && (d.initializer === undefined || inertExpr(d.initializer)), + )) || + exportStatement(st); + if (!inert) { + firstEntry = i; + break; + } + } + // Every other use of the export object must be a plain member read: + // anything else can change what a module of the cycle observes. + let stray: ts.Node | null = null; + const settled = new Set(stmts.slice(0, firstEntry).filter(exportStatement)); + ts.walkPreorder(m, (n) => { + if (stray !== null) return "stop"; + if (ts.isStatement(n) && settled.has(n)) return "skip"; + let use: ts.Expression | null = null; + if (n.kind === ts.SyntaxKind.ThisKeyword) { + let moduleThis = true; + for (let p = n.parent; p !== undefined && !ts.isSourceFile(p); p = p.parent) { + if ( + (ts.isFunctionLike(p) && !ts.isArrowFunction(p)) || + ts.isClassDeclaration(p) || + ts.isClassExpression(p) + ) { + moduleThis = false; + break; + } + } + if (moduleThis) use = n as ts.Expression; + } else if ( + ts.isIdentifier(n) && + (n.text === "exports" || n.text === "module") && + !(ts.isPropertyAccessExpression(n.parent) && n.parent.name === n) && + !sourceBinding7(program, n) + ) { + if (n.text === "exports") use = n; + else if (!ts.isPropertyAccessExpression(n.parent) || n.parent.expression !== n) stray = n; + else if (n.parent.name.text === "exports") use = n.parent; + } + if (use === null) return undefined; + const parent = use.parent; + const read = + ts.isPropertyAccessExpression(parent) && + parent.expression === use && + !( + ts.isBinaryExpression(parent.parent) && + parent.parent.left === parent && + parent.parent.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && + parent.parent.operatorToken.kind <= ts.SyntaxKind.LastAssignment + ) && + !(ts.isCallExpression(parent.parent) && parent.parent.expression === parent) && + !ts.isDeleteExpression(parent.parent); + if (!read) stray = use; + return undefined; + }); + if (stray !== null) { + return `${m.fileName} uses its exports at ${lineOf(stray)} outside the export statements that precede its first require, so a module of the cycle can observe them before they settle`; + } + // Bindings of other members must stay unreachable from top-level code. + for (const st of stmts) { + for (const req of requiresOf7(st)) { + if (req.decl === null) continue; + const dep = resolveImport7(program, m, req.spec, "require"); + if (dep === null || !members.has(dep)) continue; + const reached = requireBindingEarlyUse7(program, m, stmts.length, req.decl, []); + if (reached !== null) { + return `the top-level code of ${m.fileName} can use its binding '${reached.text}' of a module of the cycle (${lineOf(reached)}) while the cycle initializes`; + } + } + } + } + return null; +} + /* ── exact cyclic initialization ───────────────────────────────────────── * Cycles that fail the declaration-only rule still evaluate exactly like * Node when their shape is representable: the guarded %init calls already diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6140-cjs-require-tdz-throws/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6140-cjs-require-tdz-throws/main.js.json new file mode 100644 index 000000000..db768b31b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6140-cjs-require-tdz-throws/main.js.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6140-cjs-require-tdz-throws/lib.js", + "/tests/corpus/6140-cjs-require-tdz-throws/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6141-cjs-require-tdz-checked/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6141-cjs-require-tdz-checked/main.js.json new file mode 100644 index 000000000..b074bf18d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6141-cjs-require-tdz-checked/main.js.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/tests/corpus/6141-cjs-require-tdz-checked/lib.js", + "/tests/corpus/6141-cjs-require-tdz-checked/counter.js", + "/tests/corpus/6141-cjs-require-tdz-checked/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6142-cjs-require-published-early/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6142-cjs-require-published-early/main.js.json new file mode 100644 index 000000000..55720ef1a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6142-cjs-require-published-early/main.js.json @@ -0,0 +1,13 @@ +{ + "order": [ + "/tests/corpus/6142-cjs-require-published-early/parse-options.js", + "/tests/corpus/6142-cjs-require-published-early/debug.js", + "/tests/corpus/6142-cjs-require-published-early/comparator.js", + "/tests/corpus/6142-cjs-require-published-early/helpers.js", + "/tests/corpus/6142-cjs-require-published-early/glob.js", + "/tests/corpus/6142-cjs-require-published-early/core.js", + "/tests/corpus/6142-cjs-require-published-early/bundle.js", + "/tests/corpus/6142-cjs-require-published-early/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6143-cjs-require-json/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6143-cjs-require-json/main.js.json new file mode 100644 index 000000000..92fe169c3 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6143-cjs-require-json/main.js.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6143-cjs-require-json/counter.js", + "/tests/corpus/6143-cjs-require-json/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6144-cjs-require-builtin-nested/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6144-cjs-require-builtin-nested/main.js.json new file mode 100644 index 000000000..df78ca9ed --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6144-cjs-require-builtin-nested/main.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6144-cjs-require-builtin-nested/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6145-cjs-require-cycle/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6145-cjs-require-cycle/main.js.json new file mode 100644 index 000000000..3e8122d1f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6145-cjs-require-cycle/main.js.json @@ -0,0 +1,9 @@ +{ + "order": [ + "/tests/corpus/6145-cjs-require-cycle/range.js", + "/tests/corpus/6145-cjs-require-cycle/util.js", + "/tests/corpus/6145-cjs-require-cycle/comparator.js", + "/tests/corpus/6145-cjs-require-cycle/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-cycle/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-cycle/main.js.json index a54923bcf..67d01f47e 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-cycle/main.js.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-cycle/main.js.json @@ -7,7 +7,7 @@ "diags": [ { "code": "SC1016", - "message": "circular imports (/tests/diagnostics/cjs-require-cycle/a.js → /tests/diagnostics/cjs-require-cycle/b.js → /tests/diagnostics/cjs-require-cycle/a.js; the cycle closes through a require() edge) are not supported yet", + "message": "circular imports (/tests/diagnostics/cjs-require-cycle/a.js → /tests/diagnostics/cjs-require-cycle/b.js → /tests/diagnostics/cjs-require-cycle/a.js; the cycle closes through a require() edge: /tests/diagnostics/cjs-require-cycle/a.js uses its exports at /tests/diagnostics/cjs-require-cycle/a.js:6 outside the export statements that precede its first require, so a module of the cycle can observe them before they settle) are not supported yet", "loc": { "file": "/tests/diagnostics/cjs-require-cycle/a.js", "start": 0, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz-unchecked/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz-unchecked/main.js.json new file mode 100644 index 000000000..aaeea4cf2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz-unchecked/main.js.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/diagnostics/cjs-require-tdz-unchecked/lib.js", + "/tests/diagnostics/cjs-require-tdz-unchecked/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz/main.js.json index d15d404ae..205a8cd6e 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz/main.js.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-require-tdz/main.js.json @@ -5,11 +5,11 @@ "diags": [ { "code": "SC1013", - "message": "require() below code that can reach its binding 'greet' (Node initializes the binding AT the require and throws ReferenceError on any earlier access, which is not modeled — move the require above the code that can run first) is not supported yet", + "message": "var require() binding 'lib' below code that can reach it (Node reads undefined before the require runs, which is not modeled — declare it with const or let, or move the require above the code that can run first) is not supported yet", "loc": { "file": "/tests/diagnostics/cjs-require-tdz/main.js", - "start": 336, - "end": 367 + "start": 402, + "end": 427 }, "milestone": "later" } diff --git a/tests/corpus/6142-cjs-require-published-early/bundle.js b/tests/corpus/6142-cjs-require-published-early/bundle.js new file mode 100644 index 000000000..c12387219 --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/bundle.js @@ -0,0 +1,17 @@ +'use strict'; + +// The esbuild CommonJS layout: stored class expressions and the export +// table come before the var requires their methods use. Publishing the +// classes runs none of their methods. +const Provider = class { + /** @param {string} name */ + constructor(name) { + this.name = name; + } + describe() { + return core.label(this.name); + } +}; +const REASON = 'default'; +module.exports = { Provider, REASON }; +var core = require('./core.js'); diff --git a/tests/corpus/6142-cjs-require-published-early/core.js b/tests/corpus/6142-cjs-require-published-early/core.js new file mode 100644 index 000000000..9e3a9a565 --- /dev/null +++ b/tests/corpus/6142-cjs-require-published-early/core.js @@ -0,0 +1,10 @@ +'use strict'; + +console.log('core: init'); + +/** @param {string} name */ +function label(name) { + return `<${name}>`; +} + +module.exports = { label }; diff --git a/tests/corpus/6142-cjs-require-published-early/main.js b/tests/corpus/6142-cjs-require-published-early/main.js index 9182f1cf5..310dacdb0 100644 --- a/tests/corpus/6142-cjs-require-published-early/main.js +++ b/tests/corpus/6142-cjs-require-published-early/main.js @@ -6,8 +6,10 @@ console.log('main: start'); const Comparator = require('./comparator.js'); const glob = require('./glob.js'); +const { Provider, REASON } = require('./bundle.js'); const c = new Comparator(' a.txt ', { loose: true }); console.log(c.mode, c.text, c.test('/x/a.txt'), Comparator.ANY.toString()); console.log(new Comparator('b').mode, Comparator.describe()); console.log(glob('a//b'), glob.sync('c//d')); +console.log(new Provider('custom').describe(), REASON); diff --git a/tests/corpus/6145-cjs-require-cycle/comparator.js b/tests/corpus/6145-cjs-require-cycle/comparator.js new file mode 100644 index 000000000..1f0d4eb9d --- /dev/null +++ b/tests/corpus/6145-cjs-require-cycle/comparator.js @@ -0,0 +1,29 @@ +'use strict'; + +// semver's layout: the class and its export come first ("hoisted class for +// cyclic dependency"), the requires — one of them closing the cycle with +// range.js — after it. When range.js requires this module mid-evaluation, +// Node hands it the exports as they stand: already the class. +const ANY = Symbol('ANY'); + +class Comparator { + /** @param {string} value */ + constructor(value) { + this.value = value; + } + + /** @param {string} other */ + within(other) { + return new Range(other).has(this.value); + } + + static get ANY() { + return ANY; + } +} + +module.exports = Comparator; + +const Range = require('./range.js'); +const { trim } = require('./util.js'); +console.log('comparator: loaded', trim(' done ')); diff --git a/tests/corpus/6145-cjs-require-cycle/main.js b/tests/corpus/6145-cjs-require-cycle/main.js new file mode 100644 index 000000000..90cbc8824 --- /dev/null +++ b/tests/corpus/6145-cjs-require-cycle/main.js @@ -0,0 +1,15 @@ +// A require cycle (comparator.js ↔ range.js) whose modules settle their +// exports before they require anything, and use each other only inside +// methods: the cycle evaluates in Node's order and each binding is the +// other module's class. +'use strict'; + +console.log('main: start'); +const Comparator = require('./comparator.js'); +const Range = require('./range.js'); + +const range = new Range('1.0.0 2.0.0'); +console.log(range.has('2.0.0'), range.has('3.0.0')); +const first = range.first(); +console.log(first instanceof Comparator, first.value, first.within('2.0.0 1.0.0')); +console.log(new Comparator('9').within('1 2'), String(Comparator.ANY)); diff --git a/tests/corpus/6145-cjs-require-cycle/package.json b/tests/corpus/6145-cjs-require-cycle/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/corpus/6145-cjs-require-cycle/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/corpus/6145-cjs-require-cycle/range.js b/tests/corpus/6145-cjs-require-cycle/range.js new file mode 100644 index 000000000..ab71e4a52 --- /dev/null +++ b/tests/corpus/6145-cjs-require-cycle/range.js @@ -0,0 +1,24 @@ +'use strict'; + +const SEPARATOR = /\s+/; + +class Range { + /** @param {string} spec */ + constructor(spec) { + this.parts = spec.split(SEPARATOR).map((part) => new Comparator(part)); + } + + /** @param {string} value */ + has(value) { + return this.parts.some((part) => part.value === value); + } + + first() { + return this.parts[0]; + } +} + +module.exports = Range; + +const Comparator = require('./comparator.js'); +console.log('range: loaded'); diff --git a/tests/corpus/6145-cjs-require-cycle/util.js b/tests/corpus/6145-cjs-require-cycle/util.js new file mode 100644 index 000000000..4e13760cd --- /dev/null +++ b/tests/corpus/6145-cjs-require-cycle/util.js @@ -0,0 +1,10 @@ +'use strict'; + +console.log('util: loaded'); + +/** @param {string} s */ +function trim(s) { + return s.trim(); +} + +module.exports = { trim }; diff --git a/tests/diagnostics/cjs-require-cycle/main.js b/tests/diagnostics/cjs-require-cycle/main.js index 619117b91..376aa0a36 100644 --- a/tests/diagnostics/cjs-require-cycle/main.js +++ b/tests/diagnostics/cjs-require-cycle/main.js @@ -1,6 +1,8 @@ -// A require cycle: Node hands B the PARTIAL exports of A mid-init, a +// A require cycle whose module exports only after requiring into the +// cycle: Node hands B the PARTIAL exports of A mid-init, a // partially-initialized-module observation the export-global model cannot -// represent — cycles keep the named SC1016 fence. +// represent — the cycle keeps the named SC1016 fence. (A cycle whose +// modules export first compiles: tests/corpus/6145-cjs-require-cycle.) 'use strict'; console.log('main: start'); diff --git a/tests/fixtures/npm-static/cjs-interop-cli.ts b/tests/fixtures/npm-static/cjs-interop-cli.ts new file mode 100644 index 000000000..2b9a88f63 --- /dev/null +++ b/tests/fixtures/npm-static/cjs-interop-cli.ts @@ -0,0 +1,9 @@ +// npm-static pilots: real CommonJS packages that preflight refused before. +// fs.realpath@1.0.0 and on-finished@2.4.1 assign module.exports and run +// code before they require their dependencies (each binding is reachable +// only after its require ran); statuses@2.0.1 requires its codes.json. +import realpath from "fs.realpath"; +import onFinished from "on-finished"; +import status from "statuses"; + +console.log(typeof realpath.realpathSync, typeof onFinished, typeof status); diff --git a/tests/fixtures/npm-static/node_modules/ee-first/LICENSE b/tests/fixtures/npm-static/node_modules/ee-first/LICENSE new file mode 100644 index 000000000..a7ae8ee9b --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/ee-first/LICENSE @@ -0,0 +1,22 @@ + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/tests/fixtures/npm-static/node_modules/ee-first/index.js b/tests/fixtures/npm-static/node_modules/ee-first/index.js new file mode 100644 index 000000000..501287cd3 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/ee-first/index.js @@ -0,0 +1,95 @@ +/*! + * ee-first + * Copyright(c) 2014 Jonathan Ong + * MIT Licensed + */ + +'use strict' + +/** + * Module exports. + * @public + */ + +module.exports = first + +/** + * Get the first event in a set of event emitters and event pairs. + * + * @param {array} stuff + * @param {function} done + * @public + */ + +function first(stuff, done) { + if (!Array.isArray(stuff)) + throw new TypeError('arg must be an array of [ee, events...] arrays') + + var cleanups = [] + + for (var i = 0; i < stuff.length; i++) { + var arr = stuff[i] + + if (!Array.isArray(arr) || arr.length < 2) + throw new TypeError('each array member must be [ee, events...]') + + var ee = arr[0] + + for (var j = 1; j < arr.length; j++) { + var event = arr[j] + var fn = listener(event, callback) + + // listen to the event + ee.on(event, fn) + // push this listener to the list of cleanups + cleanups.push({ + ee: ee, + event: event, + fn: fn, + }) + } + } + + function callback() { + cleanup() + done.apply(null, arguments) + } + + function cleanup() { + var x + for (var i = 0; i < cleanups.length; i++) { + x = cleanups[i] + x.ee.removeListener(x.event, x.fn) + } + } + + function thunk(fn) { + done = fn + } + + thunk.cancel = cleanup + + return thunk +} + +/** + * Create the event listener. + * @private + */ + +function listener(event, done) { + return function onevent(arg1) { + var args = new Array(arguments.length) + var ee = this + var err = event === 'error' + ? arg1 + : null + + // copy args to prevent arguments escaping scope + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i] + } + + done(err, ee, event, args) + } +} diff --git a/tests/fixtures/npm-static/node_modules/ee-first/package.json b/tests/fixtures/npm-static/node_modules/ee-first/package.json new file mode 100644 index 000000000..b6d0b7d67 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/ee-first/package.json @@ -0,0 +1,29 @@ +{ + "name": "ee-first", + "description": "return the first event in a set of ee/event pairs", + "version": "1.1.1", + "author": { + "name": "Jonathan Ong", + "email": "me@jongleberry.com", + "url": "http://jongleberry.com", + "twitter": "https://twitter.com/jongleberry" + }, + "contributors": [ + "Douglas Christopher Wilson " + ], + "license": "MIT", + "repository": "jonathanong/ee-first", + "devDependencies": { + "istanbul": "0.3.9", + "mocha": "2.2.5" + }, + "files": [ + "index.js", + "LICENSE" + ], + "scripts": { + "test": "mocha --reporter spec --bail --check-leaks test/", + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/" + } +} diff --git a/tests/fixtures/npm-static/node_modules/fs.realpath/LICENSE b/tests/fixtures/npm-static/node_modules/fs.realpath/LICENSE new file mode 100644 index 000000000..5bd884c25 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/fs.realpath/LICENSE @@ -0,0 +1,43 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---- + +This library bundles a version of the `fs.realpath` and `fs.realpathSync` +methods from Node.js v0.10 under the terms of the Node.js MIT license. + +Node's license follows, also included at the header of `old.js` which contains +the licensed code: + + Copyright Joyent, Inc. and other Node contributors. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. diff --git a/tests/fixtures/npm-static/node_modules/fs.realpath/index.js b/tests/fixtures/npm-static/node_modules/fs.realpath/index.js new file mode 100644 index 000000000..b09c7c7e6 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/fs.realpath/index.js @@ -0,0 +1,66 @@ +module.exports = realpath +realpath.realpath = realpath +realpath.sync = realpathSync +realpath.realpathSync = realpathSync +realpath.monkeypatch = monkeypatch +realpath.unmonkeypatch = unmonkeypatch + +var fs = require('fs') +var origRealpath = fs.realpath +var origRealpathSync = fs.realpathSync + +var version = process.version +var ok = /^v[0-5]\./.test(version) +var old = require('./old.js') + +function newError (er) { + return er && er.syscall === 'realpath' && ( + er.code === 'ELOOP' || + er.code === 'ENOMEM' || + er.code === 'ENAMETOOLONG' + ) +} + +function realpath (p, cache, cb) { + if (ok) { + return origRealpath(p, cache, cb) + } + + if (typeof cache === 'function') { + cb = cache + cache = null + } + origRealpath(p, cache, function (er, result) { + if (newError(er)) { + old.realpath(p, cache, cb) + } else { + cb(er, result) + } + }) +} + +function realpathSync (p, cache) { + if (ok) { + return origRealpathSync(p, cache) + } + + try { + return origRealpathSync(p, cache) + } catch (er) { + if (newError(er)) { + return old.realpathSync(p, cache) + } else { + throw er + } + } +} + +function monkeypatch () { + fs.realpath = realpath + fs.realpathSync = realpathSync +} + +function unmonkeypatch () { + fs.realpath = origRealpath + fs.realpathSync = origRealpathSync +} diff --git a/tests/fixtures/npm-static/node_modules/fs.realpath/old.js b/tests/fixtures/npm-static/node_modules/fs.realpath/old.js new file mode 100644 index 000000000..b40305e73 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/fs.realpath/old.js @@ -0,0 +1,303 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var pathModule = require('path'); +var isWindows = process.platform === 'win32'; +var fs = require('fs'); + +// JavaScript implementation of realpath, ported from node pre-v6 + +var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); + +function rethrow() { + // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and + // is fairly slow to generate. + var callback; + if (DEBUG) { + var backtrace = new Error; + callback = debugCallback; + } else + callback = missingCallback; + + return callback; + + function debugCallback(err) { + if (err) { + backtrace.message = err.message; + err = backtrace; + missingCallback(err); + } + } + + function missingCallback(err) { + if (err) { + if (process.throwDeprecation) + throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs + else if (!process.noDeprecation) { + var msg = 'fs: missing callback ' + (err.stack || err.message); + if (process.traceDeprecation) + console.trace(msg); + else + console.error(msg); + } + } + } +} + +function maybeCallback(cb) { + return typeof cb === 'function' ? cb : rethrow(); +} + +var normalize = pathModule.normalize; + +// Regexp that finds the next partion of a (partial) path +// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] +if (isWindows) { + var nextPartRe = /(.*?)(?:[\/\\]+|$)/g; +} else { + var nextPartRe = /(.*?)(?:[\/]+|$)/g; +} + +// Regex to find the device root, including trailing slash. E.g. 'c:\\'. +if (isWindows) { + var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/; +} else { + var splitRootRe = /^[\/]*/; +} + +exports.realpathSync = function realpathSync(p, cache) { + // make p is absolute + p = pathModule.resolve(p); + + if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { + return cache[p]; + } + + var original = p, + seenLinks = {}, + knownHard = {}; + + // current character position in p + var pos; + // the partial path so far, including a trailing slash if any + var current; + // the partial path without a trailing slash (except when pointing at a root) + var base; + // the partial path scanned in the previous round, with slash + var previous; + + start(); + + function start() { + // Skip over roots + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstatSync(base); + knownHard[base] = true; + } + } + + // walk down the path, swapping out linked pathparts for their real + // values + // NB: p.length changes. + while (pos < p.length) { + // find the next part + nextPartRe.lastIndex = pos; + var result = nextPartRe.exec(p); + previous = current; + current += result[0]; + base = previous + result[1]; + pos = nextPartRe.lastIndex; + + // continue if not a symlink + if (knownHard[base] || (cache && cache[base] === base)) { + continue; + } + + var resolvedLink; + if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { + // some known symbolic link. no need to stat again. + resolvedLink = cache[base]; + } else { + var stat = fs.lstatSync(base); + if (!stat.isSymbolicLink()) { + knownHard[base] = true; + if (cache) cache[base] = base; + continue; + } + + // read the link if it wasn't read before + // dev/ino always return 0 on windows, so skip the check. + var linkTarget = null; + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks.hasOwnProperty(id)) { + linkTarget = seenLinks[id]; + } + } + if (linkTarget === null) { + fs.statSync(base); + linkTarget = fs.readlinkSync(base); + } + resolvedLink = pathModule.resolve(previous, linkTarget); + // track this, if given a cache. + if (cache) cache[base] = resolvedLink; + if (!isWindows) seenLinks[id] = linkTarget; + } + + // resolve the link, then start over + p = pathModule.resolve(resolvedLink, p.slice(pos)); + start(); + } + + if (cache) cache[original] = p; + + return p; +}; + + +exports.realpath = function realpath(p, cache, cb) { + if (typeof cb !== 'function') { + cb = maybeCallback(cache); + cache = null; + } + + // make p is absolute + p = pathModule.resolve(p); + + if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { + return process.nextTick(cb.bind(null, null, cache[p])); + } + + var original = p, + seenLinks = {}, + knownHard = {}; + + // current character position in p + var pos; + // the partial path so far, including a trailing slash if any + var current; + // the partial path without a trailing slash (except when pointing at a root) + var base; + // the partial path scanned in the previous round, with slash + var previous; + + start(); + + function start() { + // Skip over roots + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstat(base, function(err) { + if (err) return cb(err); + knownHard[base] = true; + LOOP(); + }); + } else { + process.nextTick(LOOP); + } + } + + // walk down the path, swapping out linked pathparts for their real + // values + function LOOP() { + // stop if scanned past end of path + if (pos >= p.length) { + if (cache) cache[original] = p; + return cb(null, p); + } + + // find the next part + nextPartRe.lastIndex = pos; + var result = nextPartRe.exec(p); + previous = current; + current += result[0]; + base = previous + result[1]; + pos = nextPartRe.lastIndex; + + // continue if not a symlink + if (knownHard[base] || (cache && cache[base] === base)) { + return process.nextTick(LOOP); + } + + if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { + // known symbolic link. no need to stat again. + return gotResolvedLink(cache[base]); + } + + return fs.lstat(base, gotStat); + } + + function gotStat(err, stat) { + if (err) return cb(err); + + // if not a symlink, skip to the next path part + if (!stat.isSymbolicLink()) { + knownHard[base] = true; + if (cache) cache[base] = base; + return process.nextTick(LOOP); + } + + // stat & read the link if not read before + // call gotTarget as soon as the link target is known + // dev/ino always return 0 on windows, so skip the check. + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks.hasOwnProperty(id)) { + return gotTarget(null, seenLinks[id], base); + } + } + fs.stat(base, function(err) { + if (err) return cb(err); + + fs.readlink(base, function(err, target) { + if (!isWindows) seenLinks[id] = target; + gotTarget(err, target); + }); + }); + } + + function gotTarget(err, target, base) { + if (err) return cb(err); + + var resolvedLink = pathModule.resolve(previous, target); + if (cache) cache[base] = resolvedLink; + gotResolvedLink(resolvedLink); + } + + function gotResolvedLink(resolvedLink) { + // resolve the link, then start over + p = pathModule.resolve(resolvedLink, p.slice(pos)); + start(); + } +}; diff --git a/tests/fixtures/npm-static/node_modules/fs.realpath/package.json b/tests/fixtures/npm-static/node_modules/fs.realpath/package.json new file mode 100644 index 000000000..3edc57d21 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/fs.realpath/package.json @@ -0,0 +1,26 @@ +{ + "name": "fs.realpath", + "version": "1.0.0", + "description": "Use node's fs.realpath, but fall back to the JS implementation if the native one fails", + "main": "index.js", + "dependencies": {}, + "devDependencies": {}, + "scripts": { + "test": "tap test/*.js --cov" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/isaacs/fs.realpath.git" + }, + "keywords": [ + "realpath", + "fs", + "polyfill" + ], + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "license": "ISC", + "files": [ + "old.js", + "index.js" + ] +} diff --git a/tests/fixtures/npm-static/node_modules/on-finished/LICENSE b/tests/fixtures/npm-static/node_modules/on-finished/LICENSE new file mode 100644 index 000000000..5931fd23e --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/on-finished/LICENSE @@ -0,0 +1,23 @@ +(The MIT License) + +Copyright (c) 2013 Jonathan Ong +Copyright (c) 2014 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/fixtures/npm-static/node_modules/on-finished/index.js b/tests/fixtures/npm-static/node_modules/on-finished/index.js new file mode 100644 index 000000000..e68df7bde --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/on-finished/index.js @@ -0,0 +1,234 @@ +/*! + * on-finished + * Copyright(c) 2013 Jonathan Ong + * Copyright(c) 2014 Douglas Christopher Wilson + * MIT Licensed + */ + +'use strict' + +/** + * Module exports. + * @public + */ + +module.exports = onFinished +module.exports.isFinished = isFinished + +/** + * Module dependencies. + * @private + */ + +var asyncHooks = tryRequireAsyncHooks() +var first = require('ee-first') + +/** + * Variables. + * @private + */ + +/* istanbul ignore next */ +var defer = typeof setImmediate === 'function' + ? setImmediate + : function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) } + +/** + * Invoke callback when the response has finished, useful for + * cleaning up resources afterwards. + * + * @param {object} msg + * @param {function} listener + * @return {object} + * @public + */ + +function onFinished (msg, listener) { + if (isFinished(msg) !== false) { + defer(listener, null, msg) + return msg + } + + // attach the listener to the message + attachListener(msg, wrap(listener)) + + return msg +} + +/** + * Determine if message is already finished. + * + * @param {object} msg + * @return {boolean} + * @public + */ + +function isFinished (msg) { + var socket = msg.socket + + if (typeof msg.finished === 'boolean') { + // OutgoingMessage + return Boolean(msg.finished || (socket && !socket.writable)) + } + + if (typeof msg.complete === 'boolean') { + // IncomingMessage + return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable)) + } + + // don't know + return undefined +} + +/** + * Attach a finished listener to the message. + * + * @param {object} msg + * @param {function} callback + * @private + */ + +function attachFinishedListener (msg, callback) { + var eeMsg + var eeSocket + var finished = false + + function onFinish (error) { + eeMsg.cancel() + eeSocket.cancel() + + finished = true + callback(error) + } + + // finished on first message event + eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish) + + function onSocket (socket) { + // remove listener + msg.removeListener('socket', onSocket) + + if (finished) return + if (eeMsg !== eeSocket) return + + // finished on first socket event + eeSocket = first([[socket, 'error', 'close']], onFinish) + } + + if (msg.socket) { + // socket already assigned + onSocket(msg.socket) + return + } + + // wait for socket to be assigned + msg.on('socket', onSocket) + + if (msg.socket === undefined) { + // istanbul ignore next: node.js 0.8 patch + patchAssignSocket(msg, onSocket) + } +} + +/** + * Attach the listener to the message. + * + * @param {object} msg + * @return {function} + * @private + */ + +function attachListener (msg, listener) { + var attached = msg.__onFinished + + // create a private single listener with queue + if (!attached || !attached.queue) { + attached = msg.__onFinished = createListener(msg) + attachFinishedListener(msg, attached) + } + + attached.queue.push(listener) +} + +/** + * Create listener on message. + * + * @param {object} msg + * @return {function} + * @private + */ + +function createListener (msg) { + function listener (err) { + if (msg.__onFinished === listener) msg.__onFinished = null + if (!listener.queue) return + + var queue = listener.queue + listener.queue = null + + for (var i = 0; i < queue.length; i++) { + queue[i](err, msg) + } + } + + listener.queue = [] + + return listener +} + +/** + * Patch ServerResponse.prototype.assignSocket for node.js 0.8. + * + * @param {ServerResponse} res + * @param {function} callback + * @private + */ + +// istanbul ignore next: node.js 0.8 patch +function patchAssignSocket (res, callback) { + var assignSocket = res.assignSocket + + if (typeof assignSocket !== 'function') return + + // res.on('socket', callback) is broken in 0.8 + res.assignSocket = function _assignSocket (socket) { + assignSocket.call(this, socket) + callback(socket) + } +} + +/** + * Try to require async_hooks + * @private + */ + +function tryRequireAsyncHooks () { + try { + return require('async_hooks') + } catch (e) { + return {} + } +} + +/** + * Wrap function with async resource, if possible. + * AsyncResource.bind static method backported. + * @private + */ + +function wrap (fn) { + var res + + // create anonymous resource + if (asyncHooks.AsyncResource) { + res = new asyncHooks.AsyncResource(fn.name || 'bound-anonymous-fn') + } + + // incompatible node.js + if (!res || !res.runInAsyncScope) { + return fn + } + + // return bound function + return res.runInAsyncScope.bind(res, fn, null) +} diff --git a/tests/fixtures/npm-static/node_modules/on-finished/package.json b/tests/fixtures/npm-static/node_modules/on-finished/package.json new file mode 100644 index 000000000..644cd814b --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/on-finished/package.json @@ -0,0 +1,39 @@ +{ + "name": "on-finished", + "description": "Execute a callback when a request closes, finishes, or errors", + "version": "2.4.1", + "contributors": [ + "Douglas Christopher Wilson ", + "Jonathan Ong (http://jongleberry.com)" + ], + "license": "MIT", + "repository": "jshttp/on-finished", + "dependencies": { + "ee-first": "1.1.1" + }, + "devDependencies": { + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.4", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "5.2.0", + "eslint-plugin-standard": "4.1.0", + "mocha": "9.2.1", + "nyc": "15.1.0" + }, + "engines": { + "node": ">= 0.8" + }, + "files": [ + "HISTORY.md", + "LICENSE", + "index.js" + ], + "scripts": { + "lint": "eslint .", + "test": "mocha --reporter spec --bail --check-leaks test/", + "test-ci": "nyc --reporter=lcovonly --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" + } +} diff --git a/tests/fixtures/npm-static/node_modules/statuses/LICENSE b/tests/fixtures/npm-static/node_modules/statuses/LICENSE new file mode 100644 index 000000000..28a316182 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/statuses/LICENSE @@ -0,0 +1,23 @@ + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/tests/fixtures/npm-static/node_modules/statuses/codes.json b/tests/fixtures/npm-static/node_modules/statuses/codes.json new file mode 100644 index 000000000..1333ed10b --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/statuses/codes.json @@ -0,0 +1,65 @@ +{ + "100": "Continue", + "101": "Switching Protocols", + "102": "Processing", + "103": "Early Hints", + "200": "OK", + "201": "Created", + "202": "Accepted", + "203": "Non-Authoritative Information", + "204": "No Content", + "205": "Reset Content", + "206": "Partial Content", + "207": "Multi-Status", + "208": "Already Reported", + "226": "IM Used", + "300": "Multiple Choices", + "301": "Moved Permanently", + "302": "Found", + "303": "See Other", + "304": "Not Modified", + "305": "Use Proxy", + "307": "Temporary Redirect", + "308": "Permanent Redirect", + "400": "Bad Request", + "401": "Unauthorized", + "402": "Payment Required", + "403": "Forbidden", + "404": "Not Found", + "405": "Method Not Allowed", + "406": "Not Acceptable", + "407": "Proxy Authentication Required", + "408": "Request Timeout", + "409": "Conflict", + "410": "Gone", + "411": "Length Required", + "412": "Precondition Failed", + "413": "Payload Too Large", + "414": "URI Too Long", + "415": "Unsupported Media Type", + "416": "Range Not Satisfiable", + "417": "Expectation Failed", + "418": "I'm a Teapot", + "421": "Misdirected Request", + "422": "Unprocessable Entity", + "423": "Locked", + "424": "Failed Dependency", + "425": "Too Early", + "426": "Upgrade Required", + "428": "Precondition Required", + "429": "Too Many Requests", + "431": "Request Header Fields Too Large", + "451": "Unavailable For Legal Reasons", + "500": "Internal Server Error", + "501": "Not Implemented", + "502": "Bad Gateway", + "503": "Service Unavailable", + "504": "Gateway Timeout", + "505": "HTTP Version Not Supported", + "506": "Variant Also Negotiates", + "507": "Insufficient Storage", + "508": "Loop Detected", + "509": "Bandwidth Limit Exceeded", + "510": "Not Extended", + "511": "Network Authentication Required" +} diff --git a/tests/fixtures/npm-static/node_modules/statuses/index.js b/tests/fixtures/npm-static/node_modules/statuses/index.js new file mode 100644 index 000000000..ea351c553 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/statuses/index.js @@ -0,0 +1,146 @@ +/*! + * statuses + * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2016 Douglas Christopher Wilson + * MIT Licensed + */ + +'use strict' + +/** + * Module dependencies. + * @private + */ + +var codes = require('./codes.json') + +/** + * Module exports. + * @public + */ + +module.exports = status + +// status code to message map +status.message = codes + +// status message (lower-case) to code map +status.code = createMessageToStatusCodeMap(codes) + +// array of status codes +status.codes = createStatusCodeList(codes) + +// status codes for redirects +status.redirect = { + 300: true, + 301: true, + 302: true, + 303: true, + 305: true, + 307: true, + 308: true +} + +// status codes for empty bodies +status.empty = { + 204: true, + 205: true, + 304: true +} + +// status codes for when you should retry the request +status.retry = { + 502: true, + 503: true, + 504: true +} + +/** + * Create a map of message to status code. + * @private + */ + +function createMessageToStatusCodeMap (codes) { + var map = {} + + Object.keys(codes).forEach(function forEachCode (code) { + var message = codes[code] + var status = Number(code) + + // populate map + map[message.toLowerCase()] = status + }) + + return map +} + +/** + * Create a list of all status codes. + * @private + */ + +function createStatusCodeList (codes) { + return Object.keys(codes).map(function mapCode (code) { + return Number(code) + }) +} + +/** + * Get the status code for given message. + * @private + */ + +function getStatusCode (message) { + var msg = message.toLowerCase() + + if (!Object.prototype.hasOwnProperty.call(status.code, msg)) { + throw new Error('invalid status message: "' + message + '"') + } + + return status.code[msg] +} + +/** + * Get the status message for given code. + * @private + */ + +function getStatusMessage (code) { + if (!Object.prototype.hasOwnProperty.call(status.message, code)) { + throw new Error('invalid status code: ' + code) + } + + return status.message[code] +} + +/** + * Get the status code. + * + * Given a number, this will throw if it is not a known status + * code, otherwise the code will be returned. Given a string, + * the string will be parsed for a number and return the code + * if valid, otherwise will lookup the code assuming this is + * the status message. + * + * @param {string|number} code + * @returns {number} + * @public + */ + +function status (code) { + if (typeof code === 'number') { + return getStatusMessage(code) + } + + if (typeof code !== 'string') { + throw new TypeError('code must be a number or string') + } + + // '403' + var n = parseInt(code, 10) + if (!isNaN(n)) { + return getStatusMessage(n) + } + + return getStatusCode(code) +} diff --git a/tests/fixtures/npm-static/node_modules/statuses/package.json b/tests/fixtures/npm-static/node_modules/statuses/package.json new file mode 100644 index 000000000..8c3e719b5 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/statuses/package.json @@ -0,0 +1,49 @@ +{ + "name": "statuses", + "description": "HTTP status utility", + "version": "2.0.1", + "contributors": [ + "Douglas Christopher Wilson ", + "Jonathan Ong (http://jongleberry.com)" + ], + "repository": "jshttp/statuses", + "license": "MIT", + "keywords": [ + "http", + "status", + "code" + ], + "files": [ + "HISTORY.md", + "index.js", + "codes.json", + "LICENSE" + ], + "devDependencies": { + "csv-parse": "4.14.2", + "eslint": "7.17.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.22.1", + "eslint-plugin-markdown": "1.0.2", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "4.2.1", + "eslint-plugin-standard": "4.1.0", + "mocha": "8.2.1", + "nyc": "15.1.0", + "raw-body": "2.4.1", + "stream-to-array": "2.3.0" + }, + "engines": { + "node": ">= 0.8" + }, + "scripts": { + "build": "node scripts/build.js", + "fetch": "node scripts/fetch-apache.js && node scripts/fetch-iana.js && node scripts/fetch-nginx.js && node scripts/fetch-node.js", + "lint": "eslint --plugin markdown --ext js,md .", + "test": "mocha --reporter spec --check-leaks --bail test/", + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test", + "update": "npm run fetch && npm run build", + "version": "node scripts/version-history.js && git add HISTORY.md" + } +} diff --git a/tests/harness/__snapshots__/cjs-require-cycle/main.js.txt b/tests/harness/__snapshots__/cjs-require-cycle/main.js.txt index ad55be524..8916284c3 100644 --- a/tests/harness/__snapshots__/cjs-require-cycle/main.js.txt +++ b/tests/harness/__snapshots__/cjs-require-cycle/main.js.txt @@ -1,4 +1,4 @@ -cjs-require-cycle/a.js:1:1 - error SC1016: circular imports (cjs-require-cycle/a.js → cjs-require-cycle/b.js → cjs-require-cycle/a.js; the cycle closes through a require() edge) are not supported yet +cjs-require-cycle/a.js:1:1 - error SC1016: circular imports (cjs-require-cycle/a.js → cjs-require-cycle/b.js → cjs-require-cycle/a.js; the cycle closes through a require() edge: cjs-require-cycle/a.js uses its exports at cjs-require-cycle/a.js:6 outside the export statements that precede its first require, so a module of the cycle can observe them before they settle) are not supported yet 1 | 'use strict'; | ^ diff --git a/tests/harness/npm-static.test.ts b/tests/harness/npm-static.test.ts index 9324d1c7f..a3d557b83 100644 --- a/tests/harness/npm-static.test.ts +++ b/tests/harness/npm-static.test.ts @@ -878,6 +878,24 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { expect(nativeRes.exitCode).toBe(nodeRes.exitCode); }, 180_000); + // Real CommonJS packages whose require() placement (a binding required + // below code that only reaches it after the require ran) or JSON + // require preflight refused before. + test("export-first CommonJS packages and JSON requires compile statically", () => { + const { coverage } = analyze(join(pilotRoot, "cjs-interop-cli.ts"), { + npmStatic: ["fs.realpath", "on-finished", "ee-first", "statuses"], + }); + expect(coverage.preflightFailed).toBe(false); + expect( + [...(coverage.npmStatic ?? [])].sort((a, b) => a.package.localeCompare(b.package)), + ).toEqual([ + { package: "ee-first", status: "static" }, + { package: "fs.realpath", status: "static" }, + { package: "on-finished", status: "static" }, + { package: "statuses", status: "static" }, + ]); + }, 120_000); + // A package preflight failure stays visible as a package-specific refusal. test("a preflight-refused package reports its native refusal", () => { const { coverage } = analyze(join(fixturesRoot, "npm/divergent/lazybuiltin.ts"), { From d49fcf3c6674d20f1b86faa291c0555bb6a980de Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 06:26:10 -0700 Subject: [PATCH 072/117] Record CI costs for the array length loop corpus programs The shard harness requires measured costs for more than 90% of the corpus. Take the costs of programs 5993-5995 from this branch's green Linux shard logs the way scripts/ci-corpus-costs.mjs computes them. Co-Authored-By: Claude Opus 5.5 --- tests/harness/corpus-costs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 88b9415bd..dd3a0b00a 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1913,6 +1913,9 @@ "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, + "5993-array-length-loop-resizing.ts": 3187, + "5994-array-length-sparse-loops.ts": 3292, + "5995-array-dense-loop-boundaries.ts": 2596, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4611,6 +4614,9 @@ "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, + "5993-array-length-loop-resizing.ts": 4127, + "5994-array-length-sparse-loops.ts": 2815, + "5995-array-dense-loop-boundaries.ts": 4171, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 04297f3064af603d9c854d3d8b2637332fbe32c8 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 06:56:24 -0700 Subject: [PATCH 073/117] Keep the preflight batching test on a fenced require binding The test asserts that the TDZ analysis batches symbol queries over the roots it scans, observed through an SC1013 refusal. Its const binding now compiles with initialization checks instead of a refusal, so the test uses a var binding, which keeps the fence and runs the same scan. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/test/ts7/program-adapter.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/compiler/test/ts7/program-adapter.test.ts b/packages/compiler/test/ts7/program-adapter.test.ts index 660394a6f..e7479c749 100644 --- a/packages/compiler/test/ts7/program-adapter.test.ts +++ b/packages/compiler/test/ts7/program-adapter.test.ts @@ -119,7 +119,7 @@ ${uses} return required.value + value; } before(); -const required = require("./dep.cjs"); +var required = require("./dep.cjs"); console.log(required.value); `, ); @@ -144,6 +144,8 @@ console.log(required.value); }) as Checker; program.checkerFacade = new CheckerFacade(proxy, { project: program.project.checker.project }); + // A var binding keeps the SC1013 fence (Node reads undefined there); a + // const would compile with initialization checks from the same scan. expect(checkPreflight(load).map((diag) => diag.code)).toContain("SC1013"); expect(calls.some(([arg]) => Array.isArray(arg) && arg.length > 24)).toBe(true); expect(calls.some(([arg]) => !Array.isArray(arg))).toBe(false); From 9d0012ddabdc269f4729927e6817a5108946470a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 09:05:09 -0500 Subject: [PATCH 074/117] Lower child_process.exec's callback forms exec(command, callback) and exec(command, { encoding, maxBuffer }, callback) lower like execFile's callback slice. The command line runs with /bin/sh -c, as execSync runs it, the call returns the live ChildProcess, and the error-first callback receives the captured utf8 stdout and stderr. A non-zero exit, including the shell's 127 for a missing command, reports Node's "Command failed: \n": scr_exec_file takes a shell flag so the message shows the command line. Under @types/node, child_process.ExecException maps to Error, as ExecFileException does. Its code member is the child's numeric exit status, which the runtime error's string code slot does not hold, so reading it, testing it with `in`, or testing its typeof is a named refusal. --- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 10 +-- .../generated/node-v24-backlog.json | 20 +++--- .../generated/node-v24-internal.json | 18 +++-- internal/compatibility/static-support.json | 1 + .../ambient/scriptc-node-fallback.d.ts | 8 +-- .../compiler/src/backend/llvm/lib-process.ts | 5 +- .../src/frontend/lowering/builtin-calls.ts | 4 +- .../lowering/builtins/child-process.ts | 72 +++++++++++++------ .../src/frontend/lowering/builtins/errors.ts | 25 +++++++ .../src/frontend/lowering/lower-exprs.ts | 5 ++ .../compiler/src/frontend/lowering/lowerer.ts | 4 +- packages/compiler/src/frontend/type-mapper.ts | 17 +++++ .../compiler/src/ir/builtin-signatures.ts | 5 +- packages/compiler/src/ir/validate.test.ts | 1 + .../tests/corpus/5627-exec-callback.ts.json | 6 ++ .../node-types/child-exec-code-fences.ts.json | 6 ++ .../fixtures/node-types/child-exec.ts.json | 6 ++ packages/runtime/src/scr_child.c | 8 +-- packages/runtime/src/scr_child.h | 6 +- tests/corpus/5627-exec-callback.ts | 36 ++++++++++ .../node-types/child-exec-code-fences.ts | 8 +++ tests/fixtures/node-types/child-exec.ts | 9 +++ tests/harness/corpus-costs.json | 2 + tests/harness/project-config.test.ts | 34 +++++++++ tests/harness/windows-differential.test.ts | 2 + 26 files changed, 261 insertions(+), 59 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5627-exec-callback.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec-code-fences.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec.ts.json create mode 100644 tests/corpus/5627-exec-callback.ts create mode 100644 tests/fixtures/node-types/child-exec-code-fences.ts create mode 100644 tests/fixtures/node-types/child-exec.ts diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index db36cdb52..f2bb89f6e 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "cade1b8e6e0c5c42fcc9", + "artifactVersion": "be8d5b094695385e34ea", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index dadc9e836..3c0350dc3 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -164,9 +164,9 @@ "apiEntries": 39, "static": { "supported": 0, - "partial": 17, + "partial": 18, "refused": 0, - "not-implemented": 22, + "not-implemented": 21, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -9312,9 +9312,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 1b7d28783..24821377e 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1143, - "verify-gap": 2186, + "audit-partial": 1144, + "verify-gap": 2185, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -3941,12 +3941,16 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:child_process", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:child_process.child_process.exec", + "tests": [ + "tests/corpus/5627-exec-callback.ts", + "tests/fixtures/node-types/child-exec.ts", + "tests/harness/project-config.test.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 8463d1292..3587ae2cb 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -131,9 +131,9 @@ "apiEntries": 39, "static": { "supported": 0, - "partial": 17, + "partial": 18, "refused": 0, - "not-implemented": 22, + "not-implemented": 21, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -11663,7 +11663,10 @@ "tests/corpus/3127-spawn-runtime-options.ts", "tests/corpus/3130-child-generic-streams.ts", "tests/corpus/3131-child-rest-listeners.js", - "tests/corpus/3132-child-generic-stream-completion.ts" + "tests/corpus/3132-child-generic-stream-completion.ts", + "tests/corpus/5627-exec-callback.ts", + "tests/fixtures/node-types/child-exec.ts", + "tests/harness/project-config.test.ts" ] }, "anchorSource": "chapter" @@ -11732,8 +11735,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:child_process" + "status": "partial", + "evidence": "compiler-feature:child_process.child_process.exec", + "tests": [ + "tests/corpus/5627-exec-callback.ts", + "tests/fixtures/node-types/child-exec.ts", + "tests/harness/project-config.test.ts" + ] }, "anchorSource": "exact" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index e3aec2645..fded9de97 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -322,6 +322,7 @@ { "chapter": "packages", "symbols": ["--input-type"], "status": "not-applicable" }, { "chapter": "child_process", "signatures": ["`subprocess[Symbol.dispose]()`"], "status": "partial", "evidence": ["tests/corpus/2844-node-disposable-resources.ts"] }, { "chapter": "child_process", "signatures": ["`child_process.execFile(file[, args][, options][, callback])`"], "status": "partial", "evidence": ["tests/corpus/2911-execfile-callback.ts"] }, + { "chapter": "child_process", "signatures": ["`child_process.exec(command[, options][, callback])`"], "status": "partial", "evidence": ["tests/corpus/5627-exec-callback.ts", "tests/fixtures/node-types/child-exec.ts", "tests/harness/project-config.test.ts"] }, { "chapter": "child_process", "signatures": ["`child_process.fork(modulePath[, args][, options])`", "`subprocess.send(message[, sendHandle[, options]][, callback])`", "`subprocess.disconnect()`", "`connected` Type: {boolean} Set to `false` after `subprocess.disconnect()` is called.", "Event: `'message'`", "Event: `'disconnect'`"], "status": "partial", "evidence": ["tests/corpus/2946-child-fork-ipc/main.ts"] }, { "chapter": "child_process", "signatures": ["Event: `'close'`"], "status": "partial", "evidence": ["tests/corpus/2939-child-shell-text.ts", "tests/corpus/3131-child-rest-listeners.js"] }, { "chapter": "child_process", "signatures": ["`stdout` Type: {stream.Readable|null|undefined}", "`stderr` Type: {stream.Readable|null|undefined}"], "status": "partial", "evidence": ["tests/corpus/1565-spawn-pipe-streams.ts", "tests/corpus/2939-child-shell-text.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 8cb8c972f..69093a600 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3033,10 +3033,10 @@ declare module "child_process" { args?: string[] | null, options?: ExecSyncOptions, ): unknown; - /* The async shell form — declared surface without full lowering (the - * type-level tolerance story): harness code on paths tests don't reach - * must typecheck; a reached call fences at its site. util.promisify - * recognizes it statically, as it does execFile. */ + /* The async shell form. The callback forms lower like execFile's, with + * the command line run by /bin/sh -c, and util.promisify recognizes it + * statically, as it does execFile; reached calls without a callback + * fence at their site. */ export function exec( command: string, options?: ExecSyncOptions | ((error: Error | null, stdout: string, stderr: string) => void), diff --git a/packages/compiler/src/backend/llvm/lib-process.ts b/packages/compiler/src/backend/llvm/lib-process.ts index b30c65b8d..546c9a209 100644 --- a/packages/compiler/src/backend/llvm/lib-process.ts +++ b/packages/compiler/src/backend/llvm/lib-process.ts @@ -19,12 +19,13 @@ export function emitChildProcessLibCall(host: LlvmEmitterContext, e: LibCallExpr const argv = host.emitExpr(e.args[1]!); const cb = host.emitExpr(callbackArg); host.moveTemp(cb); + const shell = host.emitExpr(e.args[3]!); const adapter = host.execFileThunkFor(cbT); host.usesTimers = true; - host.declare(`declare ptr @scr_exec_file(ptr, ptr, ptr, ptr)`); + host.declare(`declare ptr @scr_exec_file(ptr, ptr, ptr, ptr, i1)`); const out = B.tmp(); B.line( - `${out} = call ptr @scr_exec_file(ptr ${cmd.name}, ptr ${argv.name}, ptr ${cb.name}, ptr @${adapter})`, + `${out} = call ptr @scr_exec_file(ptr ${cmd.name}, ptr ${argv.name}, ptr ${cb.name}, ptr @${adapter}, i1 ${shell.name})`, ); return host.own({ name: out, type: e.type }); } diff --git a/packages/compiler/src/frontend/lowering/builtin-calls.ts b/packages/compiler/src/frontend/lowering/builtin-calls.ts index 037b3e5a7..7bb5f3e62 100644 --- a/packages/compiler/src/frontend/lowering/builtin-calls.ts +++ b/packages/compiler/src/frontend/lowering/builtin-calls.ts @@ -62,8 +62,8 @@ export function lowerBuiltinCall( loc: SrcLoc, namespaceMember?: ts.MemberName, ): IrExpr { - if (bi.module === "child_process" && bi.member === "execFile") { - return lowerer.lowerExecFileCall(expr, loc); + if (bi.module === "child_process" && (bi.member === "execFile" || bi.member === "exec")) { + return lowerer.lowerExecFileCall(expr, loc, bi.member === "exec"); } if (bi.module === "events" && bi.member === "addAbortListener") { return lowerAddAbortListener(lowerer, expr, loc); diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process.ts b/packages/compiler/src/frontend/lowering/builtins/child-process.ts index 8c06a28df..ecec14fc5 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process.ts @@ -725,35 +725,57 @@ export function lowerForkCall(lowerer: Lowerer, expr: ts.CallExpression, loc: Sr } /** `execFile(file[, args][, options], callback)` — the asynchronous callback - * slice. The child starts immediately with stdin/stdout/stderr piped; the - * runtime captures both outputs and invokes the error-first callback after - * settlement. The callback may ignore a suffix of `(error, stdout, + * slice. With `shell`, `exec(command[, options], callback)`: the command + * line runs with /bin/sh -c, as execSync runs it, and failure messages show + * the command line as Node's do. The child starts immediately with + * stdin/stdout/stderr piped; the runtime captures both outputs and invokes + * the error-first callback after settlement. The callback may ignore a suffix of `(error, stdout, * stderr)`, but every declared parameter must have the Node shape. Inline * `encoding: "utf8"` and a pure numeric `maxBuffer` are accepted; the latter * is not enforced by the growing native capture, as * with the synchronous and promisified capture forms. Other options remain * fenced until their lifecycle can share this asynchronous core. */ -export function lowerExecFileCall(lowerer: Lowerer, expr: ts.CallExpression, loc: SrcLoc): IrExpr { +export function lowerExecFileCall( + lowerer: Lowerer, + expr: ts.CallExpression, + loc: SrcLoc, + shell = false, +): IrExpr { + const what = shell ? "exec" : "execFile"; if ( expr.arguments.some(ts.isSpreadElement) || expr.arguments.length < 2 || - expr.arguments.length > 4 + expr.arguments.length > (shell ? 3 : 4) ) { lowerer.noLowering( - `execFile with ${expr.arguments.length} arguments`, + `${what} with ${expr.arguments.length} arguments`, expr, - "the supported callback forms are execFile(file, callback), execFile(file, args, callback), and execFile(file, args, { encoding: 'utf8', maxBuffer: N }, callback)", + shell + ? "the supported callback forms are exec(command, callback) and exec(command, { encoding: 'utf8', maxBuffer: N }, callback)" + : "the supported callback forms are execFile(file, callback), execFile(file, args, callback), and execFile(file, args, { encoding: 'utf8', maxBuffer: N }, callback)", ); } - const cmd = lowerer.lowerExprExpecting(expr.arguments[0]!, STRING); - const argsNode = expr.arguments.length >= 3 ? expr.arguments[1] : undefined; + const first = lowerer.lowerExprExpecting(expr.arguments[0]!, STRING); const callbackNode = expr.arguments[expr.arguments.length - 1]!; - const argv = lowerChildArgsArg(lowerer, argsNode, loc); - if (expr.arguments.length === 4) { - const options = expr.arguments[2]!; + // exec: /bin/sh -c , execSync's lowering (the runtime reads the + // command line back from argv[1] for failure messages); execFile: the + // file and its args list. + const cmd: IrExpr = shell ? { kind: "strLit", value: "/bin/sh", type: STRING, loc } : first; + const argv: IrExpr = shell + ? { + kind: "arrayLit", + elems: [{ kind: "strLit", value: "-c", type: STRING, loc }, first], + type: arrayOf(STRING), + loc, + } + : lowerChildArgsArg(lowerer, expr.arguments.length >= 3 ? expr.arguments[1] : undefined, loc); + const optionsNode = + expr.arguments.length === (shell ? 3 : 4) ? expr.arguments[shell ? 1 : 2] : undefined; + if (optionsNode) { + const options = optionsNode; if (!ts.isObjectLiteralExpression(options)) { lowerer.noLowering( - "execFile with a non-literal options argument", + `${what} with a non-literal options argument`, options, "pass encoding and maxBuffer in an inline object literal", ); @@ -774,7 +796,7 @@ export function lowerExecFileCall(lowerer: Lowerer, expr: ts.CallExpression, loc const member = optionMember(property); if (!member) lowerer.noLowering( - "execFile with this options shape", + `${what} with this options shape`, property, "use plain encoding and maxBuffer properties without spreads or computed keys", ); @@ -784,7 +806,7 @@ export function lowerExecFileCall(lowerer: Lowerer, expr: ts.CallExpression, loc (member.value.text !== "utf8" && member.value.text !== "utf-8") ) { lowerer.noLowering( - "execFile with a non-literal utf8 encoding", + `${what} with a non-literal utf8 encoding`, member.value, "pass the literal 'utf8' or 'utf-8' (other expressions might have side effects)", ); @@ -792,14 +814,14 @@ export function lowerExecFileCall(lowerer: Lowerer, expr: ts.CallExpression, loc } else if (member.name === "maxBuffer") { if (!pureNumber(member.value)) { lowerer.noLowering( - "execFile with a non-literal maxBuffer", + `${what} with a non-literal maxBuffer`, member.value, "pass a numeric literal or literal arithmetic (the native capture grows without enforcing this limit)", ); } } else { lowerer.noLowering( - `execFile option '${member.name}'`, + `${what} option '${member.name}'`, property, "only encoding: 'utf8' and a pure numeric maxBuffer are supported in the callback form", ); @@ -815,14 +837,14 @@ export function lowerExecFileCall(lowerer: Lowerer, expr: ts.CallExpression, loc lowerer.unsupported( "SC1090", callbackNode, - "execFile callbacks take (error), (error, stdout), (error, stdout, stderr), or no parameters", + `${what} callbacks take (error), (error, stdout), (error, stdout, stderr), or no parameters`, ); } if (callback.type.ret.kind !== "void") { lowerer.unsupported( "SC1090", callbackNode, - "execFile callbacks returning a value (make the callback body a block, or return nothing)", + `${what} callbacks returning a value (make the callback body a block, or return nothing)`, ); } const errorParam = callback.type.params[0]; @@ -837,7 +859,7 @@ export function lowerExecFileCall(lowerer: Lowerer, expr: ts.CallExpression, loc lowerer.unsupported( "SC1090", callbackNode, - `execFile callbacks whose first parameter is not 'Error | null' (got '${lowerer.fmt(errorParam)}')`, + `${what} callbacks whose first parameter is not 'Error | null' (got '${lowerer.fmt(errorParam)}')`, ); } } @@ -846,9 +868,15 @@ export function lowerExecFileCall(lowerer: Lowerer, expr: ts.CallExpression, loc lowerer.unsupported( "SC1090", callbackNode, - `execFile callbacks whose ${i === 1 ? "stdout" : "stderr"} parameter is not 'string'`, + `${what} callbacks whose ${i === 1 ? "stdout" : "stderr"} parameter is not 'string'`, ); } } - return { kind: "libCall", fn: "cp.execFile", args: [cmd, argv, callback], type: CHILD_T, loc }; + return { + kind: "libCall", + fn: "cp.execFile", + args: [cmd, argv, callback, boolLit(shell, loc)], + type: CHILD_T, + loc, + }; } diff --git a/packages/compiler/src/frontend/lowering/builtins/errors.ts b/packages/compiler/src/frontend/lowering/builtins/errors.ts index 5947f3714..50a97cead 100644 --- a/packages/compiler/src/frontend/lowering/builtins/errors.ts +++ b/packages/compiler/src/frontend/lowering/builtins/errors.ts @@ -11,6 +11,28 @@ const ASSERTION_ERROR_PROPERTIES: ReadonlySet = new Set([ "diff", ]); +/** True for child_process.ExecException, exec's callback error. Its + * `code` is the child's numeric exit status (null after a signal), which + * the runtime error's string code slot does not hold, so reads, `in` tests + * and typeof tests of `code` refuse instead of answering from the slot. */ +export function isExecExceptionType(lowerer: Lowerer, t: ts.Type): boolean { + const sym = t.getSymbol(); + return ( + sym?.name === "ExecException" && + lowerer.checker + .declarationsOf(sym) + .some((d) => ts.isInterfaceDeclaration(d) && lowerer.isStdlibFile(d.getSourceFile())) + ); +} + +export function refuseExecExceptionCode(lowerer: Lowerer, node: ts.Node): never { + return lowerer.noLowering( + "ExecException.code", + node, + "spawn reports the exit status through its 'close' event", + ); +} + /** `.code` and `.cause` on an error-hierarchy receiver. The latter reads * the hidden dyn slot installed by constructor options. The former is NodeJS.ErrnoException's * member (the fallback declares the same shape): the runtime Error's @@ -122,6 +144,9 @@ export function lowerErrorCodeProperty( !(recvT.className === "%Error" && lowerer.typeOf(expr.expression).isIntersectionType()) ) return null; + if (expr.name.text === "code" && isExecExceptionType(lowerer, lowerer.typeOf(expr.expression))) { + refuseExecExceptionCode(lowerer, expr); + } const rawReceiver = lowerer.lowerExpr(expr.expression); const receiver = rawReceiver.type.kind === "dyn" diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index d2d990e16..0fb81e2da 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -13,6 +13,7 @@ import { lowerReadlineProperty } from "./builtins/readline.js"; import { lowerBlobInstanceof } from "./builtins/blob.js"; import { lowerKeyObjectInstanceof } from "./builtins/key-object.js"; import { lowerNetAddressInstanceof, lowerNetAddressStaticRead } from "./builtins/net-address.js"; +import { isExecExceptionType, refuseExecExceptionCode } from "./builtins/errors.js"; import { STATS_TYPE_TESTS } from "./builtins/filesystem.js"; import { threadsImportOf } from "../threads-import.js"; import { experimentalImportOf, lifetimeRegionMemberOf } from "../experimental-import.js"; @@ -11326,6 +11327,7 @@ function lowerErrorCodeTypeofTest( recv = recv.expression; const errT = errorRootedObjectOf(lowerer, lowerer.typeOf(recv)); if (!errT) continue; + if (isExecExceptionType(lowerer, lowerer.typeOf(recv))) refuseExecExceptionCode(lowerer, prop); const caught = lowerer.caughtLocalOf(recv); let receiver: IrExpr; if (caught) { @@ -12928,6 +12930,9 @@ function lowerInExpression(lowerer: Lowerer, expr: ts.BinaryExpression, loc: Src loc, }; } + if (key === "code" && isExecExceptionType(lowerer, lowerer.typeOf(expr.right))) { + refuseExecExceptionCode(lowerer, expr); + } let recv = lowerer.lowerExpr(expr.right); const classInfo = recv.type.kind === "classval" ? lowerer.classes.get(recv.type.className) : undefined; diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 087b4e628..adb16233d 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -11720,8 +11720,8 @@ export class Lowerer { return lowerSpawnCall(this, expr, loc); } - lowerExecFileCall(expr: ts.CallExpression, loc: SrcLoc): IrExpr { - return lowerExecFileCall(this, expr, loc); + lowerExecFileCall(expr: ts.CallExpression, loc: SrcLoc, shell = false): IrExpr { + return lowerExecFileCall(this, expr, loc, shell); } lowerExecSyncCall(expr: ts.CallExpression, shell: boolean, loc: SrcLoc): IrExpr { diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 52964e1bd..8157d8c04 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1386,6 +1386,23 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { ) { return { kind: "object", className: "%Error" }; } + // child_process.ExecException, exec's callback error, is an interface + // extending Error with optional metadata members; the value is one + // ordinary Error as well. + const execException = type.getSymbol(); + if ( + execException?.name === "ExecException" && + checker + .declarationsOf(execException) + .some( + (decl) => + ts.isInterfaceDeclaration(decl) && + ctx.isStdlibFile(decl.getSourceFile()) && + isDeclaredInAmbientModule(decl, "child_process"), + ) + ) { + return { kind: "object", className: "%Error" }; + } if (isOsConstantsType(type, ctx) || isLegacyUrlType(type, ctx)) return DYN; // Immutable (@scriptc/types) is a deep-readonly view: the value is // still the T it maps. diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 7f31c5205..ca2749591 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2343,8 +2343,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ /** child_process.execFile's callback slice: starts an all-piped child, * captures stdout/stderr, and moves the error-first callback into the * child registry. The callback shape is program-dependent and checked - * by the validator/backends. */ - "cp.execFile": { argTypes: [STRING, arrayOf(STRING), null], result: CHILD_T }, + * by the validator/backends. The last argument is exec's shell flag: + * the argv is ["-c", command] and failure messages show the command. */ + "cp.execFile": { argTypes: [STRING, arrayOf(STRING), null, BOOL], result: CHILD_T }, // spawn's options form: per-slot stdio modes (0 ignore / 1 inherit / // 2 fd) with the out/err fds for mode 2, detached, env replacement // pairs, cwd ("" = inherit). diff --git a/packages/compiler/src/ir/validate.test.ts b/packages/compiler/src/ir/validate.test.ts index d44a187f4..b7caf8c41 100644 --- a/packages/compiler/src/ir/validate.test.ts +++ b/packages/compiler/src/ir/validate.test.ts @@ -951,6 +951,7 @@ test("library callbacks retain child, specialized, and generic result diagnostic { kind: "strLit", value: "tool", type: STRING, loc }, { kind: "arrayLit", elems: [], type: arrayOf(STRING), loc }, { kind: "boolLit", value: true, type: F64, loc }, + { kind: "boolLit", value: false, type: BOOL, loc }, ], }; expect(validateModule(expressionModule(expr, [])).map((error) => error.message)).toEqual([ diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5627-exec-callback.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5627-exec-callback.ts.json new file mode 100644 index 000000000..cbefe8acc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5627-exec-callback.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5627-exec-callback.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec-code-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec-code-fences.ts.json new file mode 100644 index 000000000..8f8a2a4b8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec-code-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/child-exec-code-fences.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec.ts.json new file mode 100644 index 000000000..73db22aca --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-exec.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/child-exec.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_child.c b/packages/runtime/src/scr_child.c index 2d72c21d2..1235001ba 100644 --- a/packages/runtime/src/scr_child.c +++ b/packages/runtime/src/scr_child.c @@ -2266,14 +2266,14 @@ static void scr_exec_file_fire(ScrChild *c) { } ScrChild *scr_exec_file(ScrStr *cmd, ScrArr *args, ScrClosure *cb, - ScrExecFileFn fn) { + ScrExecFileFn fn, bool shell) { ScrStr *empty = scr_str_new("", 0); ScrChild *c = scr_spawn_opts(cmd, args, 3, 3, 3, 0, 0, false, false, false, NULL, empty); scr_str_release(empty); c->exec_cb = cb; c->exec_fn = fn; - char *display = scr_exec_display(cmd, args, false); + char *display = scr_exec_display(cmd, args, shell); c->exec_display = scr_str_new(display, strlen(display)); free(display); scr_child_stream_capture_begin(c->out_stream); @@ -4911,14 +4911,14 @@ static void scr_exec_file_fire(ScrChild *c) { } ScrChild *scr_exec_file(ScrStr *cmd, ScrArr *args, ScrClosure *cb, - ScrExecFileFn fn) { + ScrExecFileFn fn, bool shell) { ScrStr *empty = scr_str_new("", 0); ScrChild *c = scr_spawn_opts(cmd, args, 3, 3, 3, 0, 0, false, false, false, NULL, empty); scr_str_release(empty); c->exec_cb = cb; c->exec_fn = fn; - char *display = scr_exec_display(cmd, args, false); + char *display = scr_exec_display(cmd, args, shell); c->exec_display = scr_str_new(display, strlen(display)); free(display); scr_child_stream_capture_begin(c->out_stream); diff --git a/packages/runtime/src/scr_child.h b/packages/runtime/src/scr_child.h index 350995e31..1819b9c53 100644 --- a/packages/runtime/src/scr_child.h +++ b/packages/runtime/src/scr_child.h @@ -155,9 +155,11 @@ ScrChild *scr_spawn_dynamic(ScrStr *cmd, ScrArr *args, const ScrDyn *options); void scr_child_on_spawn(ScrChild *child, ScrClosure *cb); /* moves zero-argument callback */ /* The callback slice: file + args, default options. The returned child has * all three stdio slots piped; stdout/stderr are captured internally and - * the callback moves into the child registry until settlement. */ + * the callback moves into the child registry until settlement. With shell + * (exec), args is ["-c", command] for /bin/sh and failure messages show + * the command, as for scr_exec_sync. */ ScrChild *scr_exec_file(ScrStr *cmd, ScrArr *args, ScrClosure *cb /*moves*/, - ScrExecFileFn fn); + ScrExecFileFn fn, bool shell); ScrChild *scr_child_retain(ScrChild *c); void scr_child_release(ScrChild *c); void *scr_child_retain_v(void *p); diff --git a/tests/corpus/5627-exec-callback.ts b/tests/corpus/5627-exec-callback.ts new file mode 100644 index 000000000..eed79e738 --- /dev/null +++ b/tests/corpus/5627-exec-callback.ts @@ -0,0 +1,36 @@ +// child_process.exec's callback forms: the command line runs with +// /bin/sh -c, the call returns a live ChildProcess immediately, utf8 +// stdout/stderr are captured, and the error-first callback fires after the +// current turn. A non-zero exit (a missing command is the shell's 127) +// reports "Command failed: \n". +import { exec } from "node:child_process"; +import * as childProcess from "node:child_process"; + +const child = exec("printf out; printf err >&2", (error, stdout, stderr) => { + console.log("ok", error === null, JSON.stringify(stdout), JSON.stringify(stderr)); + exec("printf 'a\\nb\\nc\\n' | wc -l", (pipeError, lines) => { + console.log("pipe", pipeError === null, lines.trim()); + exec(`printf '%s|' "a b" 'c d' e`, { encoding: "utf8", maxBuffer: 1024 * 1024 }, (_, quoted) => { + console.log("quoting", quoted); + exec("printf partial; printf failed >&2; exit 3", (failed, failedOut, failedErr) => { + console.log("fail", failed !== null, JSON.stringify(failedOut), JSON.stringify(failedErr)); + console.log("fail-message", JSON.stringify(failed === null ? "" : failed.message)); + exec("exit 1", (silent) => { + console.log("silent", JSON.stringify(silent === null ? "" : silent.message)); + exec("scriptc-definitely-not-a-command", (missing, missingOut) => { + const message = missing === null ? "" : missing.message; + console.log("missing", missing !== null, JSON.stringify(missingOut)); + console.log("missing-message", message.split("\n")[0]); + exec("true", () => { + console.log("zero-parameter callback"); + childProcess.exec("printf namespace", (_, out) => console.log(out)); + }); + }); + }); + }); + }); + }); +}); + +console.log("returned", child.pid !== undefined, child.stdout !== null, child.stderr !== null); +console.log("scheduled"); diff --git a/tests/fixtures/node-types/child-exec-code-fences.ts b/tests/fixtures/node-types/child-exec-code-fences.ts new file mode 100644 index 000000000..71f627df4 --- /dev/null +++ b/tests/fixtures/node-types/child-exec-code-fences.ts @@ -0,0 +1,8 @@ +import { exec } from "node:child_process"; + +exec("exit 3", (error) => { + if (error === null) return; + console.log(error.code); + console.log("code" in error); + console.log(typeof error.code === "number"); +}); diff --git a/tests/fixtures/node-types/child-exec.ts b/tests/fixtures/node-types/child-exec.ts new file mode 100644 index 000000000..97e9c546d --- /dev/null +++ b/tests/fixtures/node-types/child-exec.ts @@ -0,0 +1,9 @@ +import { exec } from "node:child_process"; + +exec("printf typed-exec; printf err >&2", (error, stdout, stderr) => { + if (error !== null) throw error; + console.log(stdout, stderr); + exec("exit 2", { encoding: "utf8" }, (failed) => { + console.log(JSON.stringify(failed === null ? "" : failed.message)); + }); +}); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 2c80c39a2..9e0ad8cc4 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1834,6 +1834,7 @@ "5566-fs-dirent-dyn-boundaries/main.mjs": 2607, "5585-record-results-inlined.ts": 2922, "5595-net-ref-unref.ts": 2593, + "5627-exec-callback.ts": 1900, "5644-net-socket-addresses.ts": 2220, "5645-net-socket-callbacks.ts": 2442, "5646-net-server-connections.ts": 2389, @@ -4534,6 +4535,7 @@ "5566-fs-dirent-dyn-boundaries/main.mjs": 3333, "5585-record-results-inlined.ts": 3681, "5595-net-ref-unref.ts": 3036, + "5627-exec-callback.ts": 2500, "5644-net-socket-addresses.ts": 2393, "5645-net-socket-callbacks.ts": 2060, "5646-net-server-connections.ts": 2755, diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index bbd6045e5..f5e80beb8 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -462,6 +462,40 @@ test("node-types: unsupported child stdin forms remain named fences", async () = ]); }); +test("node-types: callback exec uses the typed ExecException overloads", async () => { + const dir = outDirFor("node-child-exec"); + const entry = join(nodeTypesDir, "child-exec.ts"); + const result = await compile(entry, { + outPath: join(dir, "child-exec"), + outDir: dir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const { stdout } = await execFileAsync(result.binaryPath); + expect(stdout).toBe('typed-exec err\n"Command failed: exit 2\\n"\n'); +}); + +test("node-types: exec's numeric ExecException.code remains a named fence", async () => { + const dir = outDirFor("node-child-exec-code-fences"); + const entry = join(nodeTypesDir, "child-exec-code-fences.ts"); + const result = await compile(entry, { + outPath: join(dir, "child-exec-code-fences"), + outDir: dir, + sanitize, + }); + expect(result.ok).toBe(false); + if (result.ok) return; + expect(result.diagnostics.map((diagnostic) => diagnostic.code)).toEqual([ + "SC2020", + "SC2020", + "SC2020", + ]); + for (const diagnostic of result.diagnostics) { + expect(diagnostic.message).toContain("ExecException.code"); + } +}); + test("node-types: path and os lower statically under @types/node's shapes", async () => { const outDir = outDirFor("node-path-os"); const result = await compile(join(nodeTypesDir, "path-os.ts"), { diff --git a/tests/harness/windows-differential.test.ts b/tests/harness/windows-differential.test.ts index 7e6ed205d..dc199d38f 100644 --- a/tests/harness/windows-differential.test.ts +++ b/tests/harness/windows-differential.test.ts @@ -149,6 +149,8 @@ const WINDOWS_SKIPS: Record = { "posix-shaped: the uncaught sh ENOENT throw crashes both sides, rendered differently (1645 covers env here)", "1464-env-writes.ts": 'posix-shaped: the observing child is ENOENT on Windows, exposing the documented spawn-failure ""-vs-null stance', + "5627-exec-callback.ts": + "posix-shaped: exec runs /bin/sh -c (execSync's static shell lowering); Windows Node runs cmd.exe", // Two programs the events unit's win32 arm surfaced (they compiled for // the first time once the events gate lifted): both drive their signal // listeners through a /bin/sh child, ENOENT on Windows Node too. From 22cbd7623b44530bc2446867a1ad493706a22446 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 07:07:37 -0700 Subject: [PATCH 075/117] Compile TypeScript redeclarations of Error.cause A TypeScript subclass of Error that declared `cause` was refused with SC1090, although the same field in a JavaScript class already compiled. The declaration now lowers like the JavaScript field: it defines the error's own enumerable `cause` after super() returns, undefined without an initializer, replacing a cause passed through the options exactly as Node does. `declare` and `abstract` declarations are erased and define nothing. Reads of `.cause` on Error-rooted classes are always the checked-dynamic property, so only declarations typed `unknown` or `object` are accepted. Other declared types, parameter properties and accessors named `cause` keep named refusals. This unblocks the source of @openfeature/core, whose abstract error base declares `cause?: unknown`. Co-Authored-By: Claude Opus 5.5 --- .../language-features/error-causes.mdx | 2 +- .../src/frontend/lowering/lower-classes.ts | 31 +++++++-- .../6041-error-cause-redeclared.ts.json | 6 ++ .../error-cause-redeclared-fences.ts.json | 6 ++ tests/corpus/6041-error-cause-redeclared.ts | 64 +++++++++++++++++++ .../error-cause-redeclared-fences.ts | 20 ++++++ .../error-cause-redeclared-fences.ts.txt | 41 ++++++++++++ 7 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6041-error-cause-redeclared.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/error-cause-redeclared-fences.ts.json create mode 100644 tests/corpus/6041-error-cause-redeclared.ts create mode 100644 tests/diagnostics/error-cause-redeclared-fences.ts create mode 100644 tests/harness/__snapshots__/error-cause-redeclared-fences.ts.txt diff --git a/docs/content/limitations/language-features/error-causes.mdx b/docs/content/limitations/language-features/error-causes.mdx index 2238a4e5b..c4691a3d2 100644 --- a/docs/content/limitations/language-features/error-causes.mdx +++ b/docs/content/limitations/language-features/error-causes.mdx @@ -1 +1 @@ -- **Error causes:** Accessor constructor options and explicit subclass redeclarations of `cause` are unsupported. `Error`, `TypeError`, `RangeError`, and `SyntaxError` otherwise accept `{ cause }`, including through inherited constructors. Reads, writes, deletion, and `"cause" in error` distinguish an absent cause from an explicitly undefined cause. Constructor causes are non-enumerable; assignment to an absent cause creates an enumerable property. Property descriptors and checked-value aliases share the cause, including getters and setters installed after construction. +- **Error causes:** Accessor constructor options are unsupported. Subclasses may redeclare `cause` as `unknown` or `object` (for example `cause?: unknown`), which defines the own property after `super()` returns as Node does; redeclarations with other types, parameter properties, and accessors named `cause` are unsupported. `Error`, `TypeError`, `RangeError`, and `SyntaxError` otherwise accept `{ cause }`, including through inherited constructors. Reads, writes, deletion, and `"cause" in error` distinguish an absent cause from an explicitly undefined cause. Constructor causes are non-enumerable; assignment to an absent cause creates an enumerable property. Property descriptors and checked-value aliases share the cause, including getters and setters installed after construction. diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 06739166c..d2f8a3a81 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -2419,12 +2419,29 @@ export function collectClassShapeInner( ts.isPropertyDeclaration(member) && !member.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ) { - if (!isJsSourceFile(member.getSourceFile())) - lowerer.unsupported( - "SC1090", - memberName, - "redeclaring Error.cause (pass the cause in the Error constructor options)", - ); + // A TypeScript redeclaration is the JavaScript field: Node + // defines the Error's own `cause` (undefined without an + // initializer) after super() returns. `declare` and `abstract` + // declarations are erased and define nothing. Every `.cause` + // read of an Error-rooted class is the checked-dynamic property + // (fieldTarget's errorCause container), so only types that read + // back unchanged from it are accepted. + if (!isJsSourceFile(member.getSourceFile())) { + if ( + modifiers?.some( + (m) => + m.kind === ts.SyntaxKind.DeclareKeyword || + m.kind === ts.SyntaxKind.AbstractKeyword, + ) + ) + continue; + if (!lowerer.classFieldStoresDyn(lowerer.typeOf(member.name))) + lowerer.unsupported( + "SC1090", + memberName, + "redeclaring Error.cause with a type other than 'unknown' or 'object' (declare it 'cause?: unknown' and narrow at the read)", + ); + } fieldOrder.push({ name: "cause", type: DYN, @@ -2914,7 +2931,7 @@ export function collectClassShapeInner( lowerer.unsupported( "SC1090", p.name, - "redeclaring Error.cause (pass the cause in the Error constructor options)", + "redeclaring Error.cause as a parameter property (declare 'cause?: unknown' and assign it in the constructor)", ); } const shape = lowerer.paramShape(p); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6041-error-cause-redeclared.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6041-error-cause-redeclared.ts.json new file mode 100644 index 000000000..c8ffa4fc7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6041-error-cause-redeclared.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6041-error-cause-redeclared.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/error-cause-redeclared-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/error-cause-redeclared-fences.ts.json new file mode 100644 index 000000000..437c1da66 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/error-cause-redeclared-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/error-cause-redeclared-fences.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6041-error-cause-redeclared.ts b/tests/corpus/6041-error-cause-redeclared.ts new file mode 100644 index 000000000..862006414 --- /dev/null +++ b/tests/corpus/6041-error-cause-redeclared.ts @@ -0,0 +1,64 @@ +// TypeScript subclasses of Error may redeclare `cause` as `unknown` or +// `object`. The declaration defines the error's own enumerable `cause` after +// super() returns, exactly as Node does: without an initializer it replaces a +// cause passed through the options with undefined. `declare` and `abstract` +// declarations are erased and define nothing. +class Base extends Error { + cause?: unknown; + constructor(message?: string, options?: { cause?: unknown }) { + super(message, options); + } +} +const viaOptions = new Base("a", { cause: 1 }); +console.log("cause" in viaOptions, viaOptions.cause, Object.keys(viaOptions)); +console.log(Object.getOwnPropertyDescriptor(viaOptions, "cause")); +class Init extends Error { + override cause: unknown = "init"; +} +const init = new Init("b", { cause: "options" }); +console.log(init.cause, Object.getOwnPropertyDescriptor(init, "cause")); +class Declared extends Error { + declare cause: unknown; +} +const d1 = new Declared("c"); +const d2 = new Declared("c", { cause: "kept" }); +console.log("cause" in d1, d1.cause, "cause" in d2, d2.cause); +abstract class Abstract extends Error { + abstract override cause: unknown; +} +class Concrete extends Abstract { + override cause: object | null = null; +} +console.log(new Concrete("d").cause); +class Assign extends Error { + cause?: unknown; + constructor(message: string, cause?: unknown) { + super(message); + this.cause = cause; + } +} +const a = new Assign("e", new Error("inner")); +const inner = a.cause; +if (inner instanceof Error) console.log(inner.message); +delete a.cause; +console.log("cause" in a, a.cause); +class Sub extends Assign { + override cause: unknown = "sub"; +} +const s = new Sub("f", "x"); +console.log("cause" in s, s.cause); +try { + throw new Base("thrown", { cause: { code: 7 } }); +} catch (e) { + if (e instanceof Base) console.log(e.message, e.cause); +} +class OpenFeatureStyle extends Error { + cause?: unknown; + constructor(message?: string, options?: { cause?: unknown }) { + super(message); + this.name = "OpenFeatureStyle"; + this.cause = options?.cause; + } +} +const o = new OpenFeatureStyle("flag", { cause: "network" }); +console.log(o.name, o.message, o.cause, o instanceof OpenFeatureStyle, o instanceof Error); diff --git a/tests/diagnostics/error-cause-redeclared-fences.ts b/tests/diagnostics/error-cause-redeclared-fences.ts new file mode 100644 index 000000000..38309b619 --- /dev/null +++ b/tests/diagnostics/error-cause-redeclared-fences.ts @@ -0,0 +1,20 @@ +// Redeclared Error causes compile when declared `unknown` or `object`. A +// narrower declared type would claim more than the checked-dynamic `cause` +// property proves, and a parameter property or an accessor named `cause` +// has no lowering. +class Typed extends Error { + override cause?: Error; +} +class FromParameter extends Error { + constructor(public override cause: unknown) { + super("parameter"); + } +} +class Accessor extends Error { + override get cause(): unknown { + return "accessor"; + } +} +console.log(new Typed("typed").cause); +console.log(new FromParameter(1).cause); +console.log(new Accessor("a").cause); diff --git a/tests/harness/__snapshots__/error-cause-redeclared-fences.ts.txt b/tests/harness/__snapshots__/error-cause-redeclared-fences.ts.txt new file mode 100644 index 000000000..67b26e2ed --- /dev/null +++ b/tests/harness/__snapshots__/error-cause-redeclared-fences.ts.txt @@ -0,0 +1,41 @@ +error-cause-redeclared-fences.ts:6:12 - error SC1090: redeclaring Error.cause with a type other than 'unknown' or 'object' (declare it 'cause?: unknown' and narrow at the read) is not supported yet + + 5 | class Typed extends Error { + 6 | override cause?: Error; + | ^~~~~ + 7 | } + +error-cause-redeclared-fences.ts:9:31 - error SC1090: redeclaring Error.cause as a parameter property (declare 'cause?: unknown' and assign it in the constructor) is not supported yet + + 8 | class FromParameter extends Error { + 9 | constructor(public override cause: unknown) { + | ^~~~~ + 10 | super("parameter"); + +error-cause-redeclared-fences.ts:14:16 - error SC1090: Error.cause accessors are not supported yet + + 13 | class Accessor extends Error { + 14 | override get cause(): unknown { + | ^~~~~ + 15 | return "accessor"; + +error-cause-redeclared-fences.ts:18:13 - error SC1090: constructing through a class value whose class has no lowering (the class declaration itself was rejected — see its own diagnostic) is not supported yet + + 17 | } + 18 | console.log(new Typed("typed").cause); + | ^~~~~~~~~~~~~~~~~~ + 19 | console.log(new FromParameter(1).cause); + +error-cause-redeclared-fences.ts:19:13 - error SC1090: constructing through a class value whose class has no lowering (the class declaration itself was rejected — see its own diagnostic) is not supported yet + + 18 | console.log(new Typed("typed").cause); + 19 | console.log(new FromParameter(1).cause); + | ^~~~~~~~~~~~~~~~~~~~ + 20 | console.log(new Accessor("a").cause); + +error-cause-redeclared-fences.ts:20:13 - error SC1090: constructing through a class value whose class has no lowering (the class declaration itself was rejected — see its own diagnostic) is not supported yet + + 19 | console.log(new FromParameter(1).cause); + 20 | console.log(new Accessor("a").cause); + | ^~~~~~~~~~~~~~~~~ + 21 | \ No newline at end of file From 56269bdad802dc727988e3bdfc0e43159dfb32ff Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 07:07:44 -0700 Subject: [PATCH 076/117] Destructure regex match results with object patterns `const { 0: path, index } = re.exec(s)` was refused with SC1031 because a match result lowers to an honest string[] slice, and object patterns only accepted records. Object patterns whose source the checker types as RegExpExecArray or RegExpMatchArray now lower each element to the read its member expression already has: numeric keys are the positional reads of the equivalent array pattern (defaults included), `index` and `input` are the result's own properties, and `groups` is the named-group projection when the regex is statically known. Rest elements, defaults on `index` and `input`, and other keys keep named refusals. This is path-to-regexp's regexpToFunction shape. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-stmts.ts | 126 ++++++++++++++++++ ...2-regex-match-object-destructuring.ts.json | 6 + .../regex-match-destructuring-fences.ts.json | 6 + .../6042-regex-match-object-destructuring.ts | 51 +++++++ .../regex-match-destructuring-fences.ts | 9 ++ .../regex-match-destructuring-fences.ts.txt | 36 +++++ 6 files changed, 234 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6042-regex-match-object-destructuring.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/regex-match-destructuring-fences.ts.json create mode 100644 tests/corpus/6042-regex-match-object-destructuring.ts create mode 100644 tests/diagnostics/regex-match-destructuring-fences.ts create mode 100644 tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index cffe4c661..6c7f34bcf 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -2700,6 +2700,14 @@ export function lowerBindingPattern( } return; } + if ( + srcType.kind === "array" && + isMatchSliceType(lowerer, srcType) && + isRegexMatchResultPattern(lowerer, pattern) + ) { + lowerMatchResultObjectPattern(lowerer, pattern, srcRef, srcType, isLet, out); + return; + } if (srcType.kind !== "record") { lowerer.unsupported( "SC1031", @@ -2968,6 +2976,124 @@ function patternKeyNameOf(lowerer: Lowerer, prop: ts.PropertyName): string | nul return null; } +/** True when an object pattern destructures a regex match result: the + * checker types its source as the standard library's RegExpExecArray or + * RegExpMatchArray. */ +function isRegexMatchResultPattern(lowerer: Lowerer, pattern: ts.ObjectBindingPattern): boolean { + const parent = pattern.parent; + const source = + ts.isVariableDeclaration(parent) && parent.initializer !== undefined + ? lowerer.typeOf(parent.initializer) + : lowerer.typeOf(pattern); + const type = lowerer.checker.getNonNullableType(source); + const symbol = type.getAliasSymbol() ?? type.getSymbol(); + return ( + symbol !== undefined && + (symbol.name === "RegExpExecArray" || symbol.name === "RegExpMatchArray") && + lowerer.isStdlibSymbol(symbol) + ); +} + +/** `const { 0: whole, 1: first, index, input, groups } = re.exec(s)!`: an + * object pattern over a regex match result. The result is an honest + * string[] slice whose `index` and `input` are the special-form reads that + * `m.index` and `m.input` lower to; numeric keys are the positional reads + * of the equivalent array pattern, and `groups` is the projection `m.groups` + * builds when the regex is statically known. Rest elements, defaults on + * the special properties, and every other key keep a named fence. */ +function lowerMatchResultObjectPattern( + lowerer: Lowerer, + pattern: ts.ObjectBindingPattern, + srcRef: () => IrExpr, + srcType: IrType & { kind: "array" }, + isLet: boolean, + out: IrStmt[], +): void { + let groups: { name: string; index: number }[] | null | undefined; + for (const el of pattern.elements) { + if (el.name === undefined) continue; + const loc = locOf(el); + if (el.dotDotDotToken) { + lowerer.unsupported( + "SC1031", + el, + "rest bindings over regex match results (the rest copies the positions and the index, input and groups properties — destructure them by name)", + ); + } + const prop = el.propertyName ?? el.name; + const propName = + ts.isIdentifier(prop) || + ts.isComputedPropertyName(prop) || + ts.isStringLiteralLike(prop) || + ts.isNumericLiteral(prop) + ? patternKeyNameOf(lowerer, prop as ts.PropertyName) + : null; + if (propName === null) { + lowerer.unsupported( + "SC1031", + el, + "destructuring with computed keys that do not fold to one property name", + ); + } + let value: IrExpr; + if (/^(?:0|[1-9]\d{0,8})$/.test(propName)) { + const index = Number(propName); + const position: IrExpr = { kind: "numLit", value: index, type: F64, loc }; + value = lowerSafeIndexRead(lowerer, srcRef(), position, loc) ?? { + kind: "arrayGet", + arr: srcRef(), + index: position, + type: srcType.elem, + loc, + }; + if (el.initializer) { + value = arrayPositionDefault(lowerer, el, value, srcRef, index, srcType.elem, out); + } + } else if (propName === "index" || propName === "input") { + if (el.initializer) { + lowerer.unsupported( + "SC1031", + el, + `binding defaults on the '${propName}' of a regex match result`, + ); + } + value = lowerer.maybeNarrow( + { + kind: "dynKeyGet", + value: lowerer.coerceToExpected(srcRef(), DYN), + key: { kind: "strLit", value: propName, type: STRING, loc }, + type: DYN, + loc, + }, + el.name, + ); + } else if (propName === "groups") { + if (groups === undefined) { + const parent = pattern.parent; + groups = + ts.isVariableDeclaration(parent) && parent.initializer !== undefined + ? matchResultNamedGroupsOf(lowerer, parent.initializer) + : null; + } + if (groups === null || groups.length === 0 || el.initializer) { + lowerer.unsupported( + "SC1031", + el, + "destructuring 'groups' from this regex match result (it lowers when the regex is statically known and has named groups, without a default)", + ); + } + value = lowerGroupsProjection(lowerer, srcRef(), groups, loc); + } else { + lowerer.unsupported( + "SC1031", + el, + `destructuring the property '${propName}' of a regex match result (numeric positions, index, input and groups compile)`, + ); + } + lowerer.bindPatternTarget(el.name, value, isLet, out); + } +} + /** Decode one non-rest object-assignment property into its static source * field, destination expression, and optional default initializer. */ function destructuringPropertyOf( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6042-regex-match-object-destructuring.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6042-regex-match-object-destructuring.ts.json new file mode 100644 index 000000000..bbe177602 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6042-regex-match-object-destructuring.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6042-regex-match-object-destructuring.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/regex-match-destructuring-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/regex-match-destructuring-fences.ts.json new file mode 100644 index 000000000..1f104f489 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/regex-match-destructuring-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/regex-match-destructuring-fences.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6042-regex-match-object-destructuring.ts b/tests/corpus/6042-regex-match-object-destructuring.ts new file mode 100644 index 000000000..160ce027a --- /dev/null +++ b/tests/corpus/6042-regex-match-object-destructuring.ts @@ -0,0 +1,51 @@ +// Object patterns over regex match results: numeric keys read the match +// positions (an unmatched optional group is undefined, a position past the +// end takes its default), `index` and `input` are the result's own +// properties, and `groups` is the named-group object when the regex is known. +const re = /(\d+)-(\d+)?/; +function first(text: string): string { + const m = re.exec(text); + if (!m) return "none"; + const { 0: whole, 1: a, 2: b, index, input } = m; + return `${whole}|${a}|${b}|${index}|${input}`; +} +console.log(first("x 12-34 y"), first("ab 7- c"), first("none")); + +const matched = "key=value".match(/(?\w+)=(?\w+)/); +if (matched) { + const { index, input, groups } = matched; + console.log(index, input, groups?.k, groups?.v); + const { 1: key, groups: named } = matched; + console.log(key, named?.v); +} + +const exec = /b/.exec("abc")!; +const { index: at, input: text, 0: hit, 3: missing = "default" } = exec; +console.log(at, text, hit, missing); + +function viaParam({ index, 0: s }: RegExpExecArray): string { + return `${index}:${s}`; +} +console.log(viaParam(/c/.exec("abc")!)); + +let total = 0; +for (const word of ["aa1", "b22", "333"]) { + const r = /\d+/.exec(word); + if (r) { + const { index, 0: digits } = r; + total += index + digits.length; + } +} +console.log(total); + +// path-to-regexp's regexpToFunction shape. +function matcher(pattern: RegExp): (pathname: string) => false | { path: string; index: number } { + return function (pathname: string) { + const m = pattern.exec(pathname); + if (!m) return false; + const { 0: path, index } = m; + return { path, index }; + }; +} +const match = matcher(/\/users\/(\d+)/); +console.log(match("/api/users/42"), match("/other")); diff --git a/tests/diagnostics/regex-match-destructuring-fences.ts b/tests/diagnostics/regex-match-destructuring-fences.ts new file mode 100644 index 000000000..dc8671b89 --- /dev/null +++ b/tests/diagnostics/regex-match-destructuring-fences.ts @@ -0,0 +1,9 @@ +// Object patterns over regex match results compile for numeric positions, +// index, input and groups. A rest element would copy the result's own +// properties, a default on index or input has no lowering, and other array +// members are not data on the result. +const m = /(a)(b)?/.exec("ab")!; +const { index, ...rest } = m; +const { input = "none" } = m; +const { length } = m; +console.log(index, rest, input, length); diff --git a/tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt b/tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt new file mode 100644 index 000000000..d4eb59168 --- /dev/null +++ b/tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt @@ -0,0 +1,36 @@ +regex-match-destructuring-fences.ts:6:16 - error SC1031: rest bindings over regex match results (the rest copies the positions and the index, input and groups properties — destructure them by name) are not supported yet + + 5 | const m = /(a)(b)?/.exec("ab")!; + 6 | const { index, ...rest } = m; + | ^~~~~~~ + 7 | const { input = "none" } = m; + +regex-match-destructuring-fences.ts:6:19 - error SC2001: values of type '{ [n: number]: string; input: string; 0: string; length: number; toString(): string; toLocaleString(): string; toLocaleString(locales: string | string[], options?: (NumberFormatOptions & DateTimeFormatOptions) | undefined): string; ... 39 more ...; with(index: number, value: string): string[]; }' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') + + 5 | const m = /(a)(b)?/.exec("ab")!; + 6 | const { index, ...rest } = m; + | ^~~~ + 7 | const { input = "none" } = m; + +regex-match-destructuring-fences.ts:7:9 - error SC1031: binding defaults on the 'input' of a regex match result is not supported yet + + 6 | const { index, ...rest } = m; + 7 | const { input = "none" } = m; + | ^~~~~~~~~~~~~~ + 8 | const { length } = m; + +regex-match-destructuring-fences.ts:8:9 - error SC1031: destructuring the property 'length' of a regex match result (numeric positions, index, input and groups compile) is not supported yet + + 7 | const { input = "none" } = m; + 8 | const { length } = m; + | ^~~~~~ + 9 | console.log(index, rest, input, length); + +regex-match-destructuring-fences.ts:9:20 - error SC2004: uses of 'rest' inherit the blocker on its declaration + + 8 | const { length } = m; + 9 | console.log(index, rest, input, length); + | ^~~~ + 10 | + + hint: the declaration of 'rest' did not compile — fix the diagnostic reported there and these sites clear with it \ No newline at end of file From 07b44cd4b134d61ffaa853c50cc64950b5ba89d9 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 07:07:44 -0700 Subject: [PATCH 077/117] Index strings whose binding still stores a union `const w = words[i]; w[w.length - 1]` and the narrowed form `typeof t === "string" ? t[t.length - 1] : ...` were refused with SC1090 ("string indexing with this index/result shape"), in `if` statements as well as in conditional expressions. A binding read from an array keeps an undefined arm in its storage, and a typeof guard narrows only the checker's type, so the receiver reached the string-index lowering as the storage union rather than a string. The refused path now captures the union and the index and reads the string arm. A missing value performs the checked-dynamic keyed read on the unit, which throws Node's "Cannot read properties of undefined (reading '')" with the evaluated key; a value arm the checker excluded fails the checked extraction. Receivers that compiled before take the paths they took before. This is path-to-regexp's tokensToRegexp shape. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-exprs.ts | 15 +++- .../src/frontend/lowering/string-index.ts | 87 ++++++++++++++++++- .../6043-string-index-narrowed-union.ts.json | 6 ++ .../6043-string-index-narrowed-union.ts | 59 +++++++++++++ 4 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6043-string-index-narrowed-union.ts.json create mode 100644 tests/corpus/6043-string-index-narrowed-union.ts diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index d2d990e16..49ffda803 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -130,7 +130,7 @@ import { lowerSafeBytesRead, } from "./array-values.js"; import { strCharsCall } from "./containers/array-construction.js"; -import { lowerOptionalStringIndex } from "./string-index.js"; +import { lowerOptionalStringIndex, lowerUnionStringIndex } from "./string-index.js"; import { tryLowerIndexedComparison } from "./indexed-comparison.js"; import { npmStaticPackageOfPath } from "../npm-static.js"; import { unsupportedModuleFeatureOf } from "../builtin-modules.js"; @@ -6879,6 +6879,19 @@ export function lowerElementAccess(lowerer: Lowerer, expr: ts.ElementAccessExpre locOf(expr), ); } + // The checker narrowed the receiver to string, but its stored value + // is still the union (an array-derived binding, a typeof guard). + if (index.type.kind === "f64") { + const read = lowerUnionStringIndex( + lowerer, + recv, + index, + expr.argumentExpression, + lowerer.withUndefinedArm(STRING), + locOf(expr), + ); + if (read) return read; + } lowerer.unsupported( "SC1090", expr, diff --git a/packages/compiler/src/frontend/lowering/string-index.ts b/packages/compiler/src/frontend/lowering/string-index.ts index e9755742a..dd086cd73 100644 --- a/packages/compiler/src/frontend/lowering/string-index.ts +++ b/packages/compiler/src/frontend/lowering/string-index.ts @@ -1,4 +1,15 @@ -import { BOOL, F64, STRING, type IrExpr, type IrType, type SrcLoc } from "../../ir/ir.js"; +import type * as ts from "../ts7/adapter.js"; +import { + BOOL, + DYN, + F64, + STRING, + isUnitType, + type IrExpr, + type IrStmt, + type IrType, + type SrcLoc, +} from "../../ir/ir.js"; import { numLit, varRef } from "../../ir/build.js"; import type { Lowerer } from "./lowerer.js"; @@ -66,3 +77,77 @@ export function lowerOptionalStringIndex( loc, }; } + +/** A number-keyed read of a receiver the checker narrowed to string whose + * stored value is still a union: an array-derived binding keeps its + * undefined arm (`const t = tokens[i]`), and a `typeof t === "string"` + * guard narrows the checker's type without retagging the storage. Both + * operands are captured first, as for a plain string receiver. A unit arm + * performs the checked-dynamic keyed read on that unit, which throws Node's + * "Cannot read properties of undefined (reading '')"; another value + * arm, which the checker has excluded, fails the checked extraction; the + * string arm reads like any string receiver. Null when the union has no + * string arm. */ +export function lowerUnionStringIndex( + lowerer: Lowerer, + receiver: IrExpr, + index: IrExpr, + keyNode: ts.Node, + type: IrType, + loc: SrcLoc, +): IrExpr | null { + if (receiver.type.kind !== "union") return null; + const unionType = receiver.type; + const unionId = unionType.unionId; + const def = lowerer.unions.get(unionId); + const stringTag = lowerer.armTag(unionId, STRING); + if (!def || stringTag < 0) return null; + const receiverLocal = lowerer.declareHiddenLocal("%indexedUnion", unionType); + const indexLocal = lowerer.declareHiddenLocal("%unionStringIndex", F64); + const stored = (): IrExpr => varRef(receiverLocal.id, unionType, loc); + const key = (): IrExpr => varRef(indexLocal.id, F64, loc); + const stmts: IrStmt[] = [ + { kind: "varDecl", localId: receiverLocal.id, init: receiver, loc }, + { kind: "varDecl", localId: indexLocal.id, init: index, loc }, + ]; + let text: IrExpr; + if (def.arms.every((arm, tag) => tag === stringTag || isUnitType(arm))) { + text = { kind: "unionNarrow", unionId, tag: stringTag, value: stored(), type: STRING, loc }; + } else { + const helper = lowerer.narrowedArmHelper(unionId, STRING, loc); + if (helper === null) return null; + text = lowerer.checkedNarrowCall(helper, stored(), STRING, loc); + } + let result = lowerOptionalStringIndex(lowerer, text, key(), type, loc); + for (let tag = def.arms.length - 1; tag >= 0; tag--) { + const arm = def.arms[tag]!; + if (!isUnitType(arm)) continue; + const unit = arm.kind === "nullT" ? "null" : "undefined"; + const thrown: IrExpr = { + kind: "dynCheck", + value: { + kind: "dynKeyGet", + value: { + kind: "dynFrom", + value: { kind: "unitLit", unit, type: arm, loc }, + type: DYN, + loc, + }, + key: lowerer.ensureString(key(), keyNode), + type: DYN, + loc, + }, + type: STRING, + loc, + }; + result = { + kind: "ternary", + cond: { kind: "unionIsTag", unionId, tag, negated: false, value: stored(), type: BOOL, loc }, + then: lowerer.coerceToExpected(thrown, type), + else_: result, + type, + loc, + }; + } + return { kind: "seqExpr", stmts, result, type, loc }; +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6043-string-index-narrowed-union.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6043-string-index-narrowed-union.ts.json new file mode 100644 index 000000000..3ff98a72a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6043-string-index-narrowed-union.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6043-string-index-narrowed-union.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6043-string-index-narrowed-union.ts b/tests/corpus/6043-string-index-narrowed-union.ts new file mode 100644 index 000000000..6fee639eb --- /dev/null +++ b/tests/corpus/6043-string-index-narrowed-union.ts @@ -0,0 +1,59 @@ +// Indexing a string whose binding was read from an array or narrowed from a +// union with typeof. The receiver's stored value keeps its other arms, so an +// out-of-bounds array read throws Node's TypeError at the index, naming the +// key. +interface Key { + name: string; +} +type Token = string | Key; + +// path-to-regexp's tokensToRegexp shape. +function endDelimited(tokens: Token[], delimiters: string): boolean { + const endToken = tokens[tokens.length - 1]; + return typeof endToken === "string" + ? delimiters.indexOf(endToken[endToken.length - 1]) > -1 + : endToken === undefined; +} +console.log( + endDelimited(["a/", { name: "x" }], "/"), + endDelimited(["a/"], "/"), + endDelimited([], "/"), + endDelimited(["ab"], "/"), +); + +function lastChar(tokens: Token[]): string { + const t = tokens[0]; + if (typeof t === "string") return t[t.length - 1]; + return "-"; +} +console.log(lastChar(["xyz"]), lastChar([{ name: "k" }])); + +function lastLetter(words: string[], i: number): string { + const w = words[i]; + return w[w.length - 1]; +} +console.log(lastLetter(["ab", "cd"], 1)); + +function at(words: string[], i: number, j: number): string | undefined { + const w = words[i]; + return w[j]; +} +console.log(at(["abc"], 0, 1), at(["abc"], 0, 7), at(["abc"], 0, 1.5), at(["abc"], 0, -1)); +for (const j of [2, -0.5, 1e21]) { + try { + at(["abc"], 3, j); + } catch (e) { + console.log(e instanceof TypeError, (e as Error).message); + } +} + +let calls = 0; +function key(): number { + calls++; + return 0; +} +function viaCall(words: string[]): string { + const w = words[0]; + return w[key()]; +} +console.log(viaCall(["q"]), calls); From 542f6573bcb555417c958bbf17238168b39f4344 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 07:07:45 -0700 Subject: [PATCH 078/117] Name the declared type in refused class field diagnostics TypeScript class fields declared `unknown` or `object` compile since #1147, but every other field type without a typed representation was still reported as "'unknown'-typed class fields": `any`, `Array`, and `WeakMap` alike. The refusal now names the declared type, for example "'any'-typed class fields", so the blocker reads as what it is. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-classes.ts | 26 ++++++++++++++++--- .../deferred-class-binding/main.ts.txt | 2 +- .../deferred-class-receiver/main.ts.txt | 2 +- ...ed-engine-1587-any-field-unassigned.ts.txt | 2 +- tests/harness/coverage.test.ts | 4 ++- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index d2f8a3a81..297ecfc1c 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -2344,7 +2344,11 @@ export function collectClassShapeInner( (member.type !== undefined || (lowerer.typeOf(member.name).flags & ts.TypeFlags.Any) === 0) ) { - lowerer.unsupported("SC1090", member.name, "'unknown'-typed static fields"); + lowerer.unsupported( + "SC1090", + member.name, + `${dynFieldTypeSpelling(lowerer, member.name)}-typed static fields`, + ); } staticFields.push({ name: member.name.text, @@ -2805,7 +2809,11 @@ export function collectClassShapeInner( !isJsSourceFile(member.getSourceFile()) && !lowerer.classFieldStoresDyn(lowerer.typeOf(member.name)) ) { - lowerer.unsupported("SC1090", member.name, "'unknown'-typed class fields"); + lowerer.unsupported( + "SC1090", + member.name, + `${dynFieldTypeSpelling(lowerer, member.name)}-typed class fields`, + ); } const undefinedInitializer = type.kind === "dyn" && !member.initializer ? locOf(member) : undefined; @@ -2939,7 +2947,11 @@ export function collectClassShapeInner( if (type.kind === "void") lowerer.badType(p.name, lowerer.typeOf(p.name)); // The class-field dyn rule verbatim (KEEP NARROW). if (type.kind === "dyn" && !lowerer.classFieldStoresDyn(lowerer.typeOf(p))) { - lowerer.unsupported("SC1090", p.name, "'unknown'-typed class fields"); + lowerer.unsupported( + "SC1090", + p.name, + `${dynFieldTypeSpelling(lowerer, p)}-typed class fields`, + ); } // `override x` (and any same-named inherited member) would // redeclare a base slot — the declared-field rule verbatim. @@ -7544,6 +7556,14 @@ export function throwingSetterFn(lowerer: Lowerer, info: ClassInfo, prop: string }; } +/** The declared type a refused checked-dynamic class field names in its + * diagnostic (`'any'`, `'WeakMap'`): `unknown` and + * `object` fields store checked-dynamic values, so the refusal is about + * whatever else the declaration spells. */ +function dynFieldTypeSpelling(lowerer: Lowerer, node: ts.Node): string { + return `'${lowerer.checker.typeToString(lowerer.typeOf(node))}'`; +} + /** The base a constructor chain actually CALLS into: generic FAMILIES are * never constructed (no `%.constructor` exists), so an * instantiation's construction-relevant base is the family's own base — diff --git a/tests/harness/__snapshots__/deferred-class-binding/main.ts.txt b/tests/harness/__snapshots__/deferred-class-binding/main.ts.txt index c80ae94e9..381d1a0a4 100644 --- a/tests/harness/__snapshots__/deferred-class-binding/main.ts.txt +++ b/tests/harness/__snapshots__/deferred-class-binding/main.ts.txt @@ -1,4 +1,4 @@ -deferred-class-binding/crate.ts:3:3 - error SC1090: 'unknown'-typed class fields are not supported yet +deferred-class-binding/crate.ts:3:3 - error SC1090: 'any'-typed class fields are not supported yet 2 | readonly label: string; 3 | contents: any; diff --git a/tests/harness/__snapshots__/deferred-class-receiver/main.ts.txt b/tests/harness/__snapshots__/deferred-class-receiver/main.ts.txt index 4431445ce..0e9cab090 100644 --- a/tests/harness/__snapshots__/deferred-class-receiver/main.ts.txt +++ b/tests/harness/__snapshots__/deferred-class-receiver/main.ts.txt @@ -5,7 +5,7 @@ deferred-class-receiver/main.ts:4:10 - error SC1090: constructing through a clas | ^~~~~~~~~~~~~~~ 5 | } -deferred-class-receiver/shelf.ts:3:20 - error SC1090: 'unknown'-typed class fields are not supported yet +deferred-class-receiver/shelf.ts:3:20 - error SC1090: 'WeakMap'-typed class fields are not supported yet 2 | readonly name: string; 3 | private readonly notes = new WeakMap(); diff --git a/tests/harness/__snapshots__/retired-engine-1587-any-field-unassigned.ts.txt b/tests/harness/__snapshots__/retired-engine-1587-any-field-unassigned.ts.txt index f5d79bffb..fd5bb3ecc 100644 --- a/tests/harness/__snapshots__/retired-engine-1587-any-field-unassigned.ts.txt +++ b/tests/harness/__snapshots__/retired-engine-1587-any-field-unassigned.ts.txt @@ -1,4 +1,4 @@ -retired-engine-1587-any-field-unassigned.ts:5:3 - error SC1090: 'unknown'-typed class fields are not supported yet +retired-engine-1587-any-field-unassigned.ts:5:3 - error SC1090: 'any'-typed class fields are not supported yet 4 | class Holder { 5 | x: any; diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index d4582d151..06f0e75a8 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -285,7 +285,9 @@ test("runtime-optional refined unions report blockers without crashing", () => { test("a rejected class reached only through a receiver probe reports its own diagnostic once", () => { const { coverage } = analyze(join(repoRoot, "tests/diagnostics/deferred-class-receiver/main.ts")); const messages = coverage.diagnostics.map((d) => d.message); - expect(messages.filter((m) => m.startsWith("'unknown'-typed class fields"))).toHaveLength(1); + expect( + messages.filter((m) => m.startsWith("'WeakMap'-typed class fields")), + ).toHaveLength(1); expect(messages.some((m) => m.startsWith("constructing through a class value"))).toBe(true); expect(coverage.unreached?.diagnostics ?? []).toEqual([]); }); From 1a007e9a2b61f493c29ec27aca8a30fd9462ddd3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 09:09:03 -0500 Subject: [PATCH 079/117] Lower util.promisify over the crypto callback functions and dns lookups promisify(crypto.randomBytes), pbkdf2, scrypt, hkdf, randomFill, randomInt and generateKey, and promisify(dns.lookup) and dns.lookupService, over a named or namespace import, now lower. A call through the binding runs the callback form with a runtime callback that settles the returned promise where the callback would run: fulfilled with the callback's value, or rejected with its error. An argument error the callback form throws rejects the promise instead, as the throw inside Node's promisify wrapper does. The crypto promise's value follows the declared result type: a Buffer, the filled view (the same object), a number, or a checked-dynamic value where @types/node declares unknown (scrypt, randomFill, randomInt) and for ArrayBuffer and KeyObject results. The runtime adds a callback closure that owns the promise and settle adapters for each representation, next to the existing callback forms in scr_crypto_async.c. dns.lookup's promise fulfills with { address, family }, or the address array with options.all, and lookupService's with { hostname, service }, as Node's custom promisified forms do. The runtime builds the checked-dynamic result; a declared record type is reached through an async helper that awaits it and checks the value. The type mapper maps the promisified lookupService result literal like the promisified exec result. The fallback declarations gain the matching util.promisify overloads. --- .../limitations/builtin-function-values.mdx | 2 +- .../generated/node-v24-backlog.json | 4 + .../generated/node-v24-internal.json | 8 + internal/compatibility/static-support.json | 2 +- .../ambient/scriptc-node-fallback.d.ts | 63 +++++++ .../compiler/src/backend/llvm/lib-datagram.ts | 2 + .../compiler/src/backend/llvm/lib-dispatch.ts | 88 +++++++++ .../lowering/builtins/callable-aliases.ts | 10 +- .../src/frontend/lowering/builtins/crypto.ts | 174 ++++++++++++++++++ .../src/frontend/lowering/lower-calls.ts | 13 +- .../src/frontend/lowering/lower-dgram.ts | 96 ++++++++++ .../src/frontend/lowering/lower-exprs.ts | 4 +- .../compiler/src/frontend/lowering/lowerer.ts | 4 +- .../src/frontend/lowering/surfaces.ts | 19 +- packages/compiler/src/frontend/type-mapper.ts | 45 +++-- .../compiler/src/ir/builtin-signatures.ts | 19 ++ packages/compiler/src/ir/validate.ts | 25 +++ packages/compiler/surface-manifest.json | 2 +- .../corpus/5631-promisify-crypto.ts.json | 6 + .../tests/corpus/5632-promisify-dns.ts.json | 6 + .../node-types/promisify-crypto.ts.json | 6 + .../fixtures/node-types/promisify-dns.ts.json | 6 + packages/runtime/src/scr_crypto.h | 17 ++ packages/runtime/src/scr_crypto_async.c | 80 ++++++++ packages/runtime/src/scr_dgram.c | 60 ++++++ packages/runtime/src/scr_dgram.h | 5 + tests/corpus/5631-promisify-crypto.ts | 118 ++++++++++++ tests/corpus/5632-promisify-dns.ts | 57 ++++++ tests/fixtures/node-types/promisify-crypto.ts | 22 +++ tests/fixtures/node-types/promisify-dns.ts | 18 ++ tests/harness/corpus-costs.json | 4 + tests/harness/project-config.test.ts | 36 ++++ 32 files changed, 995 insertions(+), 26 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5631-promisify-crypto.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5632-promisify-dns.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-crypto.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-dns.ts.json create mode 100644 tests/corpus/5631-promisify-crypto.ts create mode 100644 tests/corpus/5632-promisify-dns.ts create mode 100644 tests/fixtures/node-types/promisify-crypto.ts create mode 100644 tests/fixtures/node-types/promisify-dns.ts diff --git a/docs/content/limitations/builtin-function-values.mdx b/docs/content/limitations/builtin-function-values.mdx index 69a8ff1b1..4fd093e47 100644 --- a/docs/content/limitations/builtin-function-values.mdx +++ b/docs/content/limitations/builtin-function-values.mdx @@ -5,7 +5,7 @@ Some builtins can be stored and passed as functions: - `util.isDeepStrictEqual`, `styleText`, `stripVTControlCharacters`, `toUSVString`, `inherits`, `deprecate`, `callbackify`, `debuglog`, and `debug`. - `fs.existsSync`, `unlinkSync`, `chmodSync`, `chownSync`, `renameSync`, and `closeSync`, and `fs/promises.unlink`, `chmod`, and `rename`. -Other immutable aliases of table-backed Node builtins support direct calls, but cannot be passed elsewhere. `util.promisify` supports compile-time conversions of `child_process.execFile`, `child_process.exec`, `setTimeout` and `setImmediate` (to the `timers/promises` functions, as in Node), `stream.finished` and `stream.pipeline` (to the `stream/promises` functions, as in Node), the `zlib` callback one-shots `deflate`, `inflate`, `deflateRaw`, `inflateRaw`, `gzip`, `gunzip` and `unzip` (with or without options), and the `fs` callback functions that have an `fs/promises` counterpart (`access`, `appendFile`, `chmod`, `chown`, `copyFile`, `lchown`, `link`, `lstat`, `lutimes`, `mkdir`, `mkdtemp`, `readFile`, `readdir`, `readlink`, `realpath`, `rename`, `rm`, `rmdir`, `stat`, `statfs`, `symlink`, `truncate`, `unlink`, `utimes`, and `writeFile`); calls through the converted function lower as the `fs/promises` call. +Other immutable aliases of table-backed Node builtins support direct calls, but cannot be passed elsewhere. `util.promisify` supports compile-time conversions of `child_process.execFile`, `child_process.exec`, `setTimeout` and `setImmediate` (to the `timers/promises` functions, as in Node), `stream.finished` and `stream.pipeline` (to the `stream/promises` functions, as in Node), the `zlib` callback one-shots `deflate`, `inflate`, `deflateRaw`, `inflateRaw`, `gzip`, `gunzip` and `unzip` (with or without options), the `crypto` callback functions `randomBytes`, `pbkdf2`, `scrypt`, `hkdf`, `randomFill`, `randomInt` and `generateKey`, `dns.lookup` (settling with `{ address, family }`, or the address array with `all: true`) and `dns.lookupService` (settling with `{ hostname, service }`), and the `fs` callback functions that have an `fs/promises` counterpart (`access`, `appendFile`, `chmod`, `chown`, `copyFile`, `lchown`, `link`, `lstat`, `lutimes`, `mkdir`, `mkdtemp`, `readFile`, `readdir`, `readlink`, `realpath`, `rename`, `rm`, `rmdir`, `stat`, `statfs`, `symlink`, `truncate`, `unlink`, `utimes`, and `writeFile`); calls through the converted function lower as the `fs/promises` call. `util.styleText` supports standard formats and aliases, `#RGB` and `#RRGGBB` hex colors, arrays of formats, nested ANSI resets, and explicit color enabling with `{ validateStream: false }`. Native calls accept standard process streams; custom native streams and mutations to `util.inspect.colors` remain unsupported. diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 1b7d28783..f5a5195d7 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -76089,6 +76089,10 @@ "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", "tests/fixtures/node-types/promisify-zlib.ts", + "tests/corpus/5631-promisify-crypto.ts", + "tests/fixtures/node-types/promisify-crypto.ts", + "tests/corpus/5632-promisify-dns.ts", + "tests/fixtures/node-types/promisify-dns.ts", "tests/harness/project-config.test.ts" ] } diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 8463d1292..eed6ff2b1 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -101001,6 +101001,8 @@ "tests/corpus/5628-promisify-timers.ts", "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", + "tests/corpus/5631-promisify-crypto.ts", + "tests/corpus/5632-promisify-dns.ts", "tests/corpus/5831-util-types-brands.ts", "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/5835-util-format-integer-specifiers.ts", @@ -101031,6 +101033,8 @@ "tests/corpus/text-codec-values/main.ts", "tests/fixtures/node-types/deep-equality.ts", "tests/fixtures/node-types/env-files.ts", + "tests/fixtures/node-types/promisify-crypto.ts", + "tests/fixtures/node-types/promisify-dns.ts", "tests/fixtures/node-types/promisify-fs.ts", "tests/fixtures/node-types/promisify-timers.ts", "tests/fixtures/node-types/promisify-zlib.ts", @@ -102683,6 +102687,10 @@ "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", "tests/fixtures/node-types/promisify-zlib.ts", + "tests/corpus/5631-promisify-crypto.ts", + "tests/fixtures/node-types/promisify-crypto.ts", + "tests/corpus/5632-promisify-dns.ts", + "tests/fixtures/node-types/promisify-dns.ts", "tests/harness/project-config.test.ts" ] }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index e3aec2645..76b768d3d 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -363,7 +363,7 @@ { "chapter": "test", "parent": "Class: `MockFunctionContext`", "symbols": ["calls", "ctx.callCount", "ctx.mockImplementation", "ctx.mockImplementationOnce", "ctx.resetCalls", "ctx.restore"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/fixtures/node-test/cases/mock-method.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.before", "context.after", "context.beforeEach", "context.afterEach", "context.plan", "context.fullName"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/ctx-hooks.ts", "tests/fixtures/node-test/cases/ctx-plan.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "symbols": ["describe.skip", "describe.todo", "describe.only", "suite.skip", "suite.todo", "suite.only", "it.skip", "it.todo", "it.only"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/suite-variants.ts", "tests/fixtures/node-test/cases/only-nested.ts", "tests/fixtures/node-test/cases/todo-suites.ts", "tests/harness/node-test.test.ts"] }, - { "chapter": "util", "signatures": ["`util.promisify(original)`"], "status": "partial", "evidence": ["tests/corpus/1473-promisify-execfile.ts", "tests/corpus/1573-promisify-execfile-env-spread.ts", "tests/corpus/2912-promisify-fs-readfile.ts", "tests/corpus/5625-promisify-exec.ts", "tests/corpus/5626-promisify-forms.ts", "tests/fixtures/node-types/promisify-fs.ts", "tests/corpus/5628-promisify-timers.ts", "tests/fixtures/node-types/promisify-timers.ts", "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", "tests/fixtures/node-types/promisify-zlib.ts", "tests/harness/project-config.test.ts"] }, + { "chapter": "util", "signatures": ["`util.promisify(original)`"], "status": "partial", "evidence": ["tests/corpus/1473-promisify-execfile.ts", "tests/corpus/1573-promisify-execfile-env-spread.ts", "tests/corpus/2912-promisify-fs-readfile.ts", "tests/corpus/5625-promisify-exec.ts", "tests/corpus/5626-promisify-forms.ts", "tests/fixtures/node-types/promisify-fs.ts", "tests/corpus/5628-promisify-timers.ts", "tests/fixtures/node-types/promisify-timers.ts", "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", "tests/fixtures/node-types/promisify-zlib.ts", "tests/corpus/5631-promisify-crypto.ts", "tests/fixtures/node-types/promisify-crypto.ts", "tests/corpus/5632-promisify-dns.ts", "tests/fixtures/node-types/promisify-dns.ts", "tests/harness/project-config.test.ts"] }, { "chapter": "typescript", "symbols": ["type"], "status": "supported", "evidence": ["tests/corpus/2702-type-import-link-static/main.ts", "tests/corpus/2703-type-import-link-static-reexport/main.ts", "tests/corpus/2704-type-import-link-static-success/main.ts", "tests/corpus/2707-type-import-link-static-default-reexport/main.ts", "tests/harness/errors.test.ts"] }, { "chapter": "zlib", "signatures": ["Class: `zlib.Deflate`", "Class: `zlib.Inflate`", "Class: `zlib.Gzip`", "Class: `zlib.Gunzip`", "Class: `zlib.DeflateRaw`", "Class: `zlib.InflateRaw`", "Class: `zlib.Unzip`", "Class: `zlib.ZlibBase`", "`zlib.close([callback])`", "`zlib.flush([kind, ]callback)`", "`zlib.params(level, strategy, callback)`", "`zlib.reset()`", "`bytesWritten` Type: {number}", "Class: `Options`"], "status": "partial", "evidence": ["tests/corpus/5370-zlib-stream-roundtrip.ts", "tests/corpus/5371-zlib-stream-chunking.cjs", "tests/corpus/5372-zlib-stream-errors.cjs", "tests/corpus/5373-zlib-stream-options.cjs", "tests/corpus/5374-zlib-stream-flush-params.ts", "tests/corpus/5375-zlib-stream-promises.ts", "tests/corpus/5377-zlib-stream-backpressure.cjs"] }, { "chapter": "zlib", "signatures": ["`zlib.constants`"], "status": "partial", "evidence": ["tests/corpus/5376-zlib-constants.cjs", "tests/corpus/5374-zlib-stream-flush-params.ts"] } diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 8cb8c972f..d7c683997 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3174,6 +3174,69 @@ declare module "util" { export function promisify( fn: typeof import("node:stream").finished, ): typeof import("node:stream/promises").finished; + /* The crypto callback functions: the promise settles with the callback's + * value. */ + export function promisify( + fn: typeof import("node:crypto").randomBytes, + ): (size: number) => Promise; + export function promisify( + fn: typeof import("node:crypto").pbkdf2, + ): ( + password: string | Uint8Array, + salt: string | Uint8Array, + iterations: number, + keylen: number, + digest: string, + ) => Promise; + export function promisify( + fn: typeof import("node:crypto").scrypt, + ): ( + password: import("node:crypto").BinaryLike, + salt: import("node:crypto").BinaryLike, + keylen: number, + options?: import("node:crypto").ScryptOptions, + ) => Promise; + export function promisify( + fn: typeof import("node:crypto").hkdf, + ): ( + digest: string, + ikm: import("node:crypto").BinaryLike | import("node:crypto").KeyObject, + salt: import("node:crypto").BinaryLike, + info: import("node:crypto").BinaryLike, + keylen: number, + ) => Promise; + export function promisify( + fn: typeof import("node:crypto").randomFill, + ): ( + buffer: T, + offset?: number, + size?: number, + ) => Promise; + export function promisify(fn: typeof import("node:crypto").randomInt): { + (max: number): Promise; + (min: number, max: number): Promise; + }; + export function promisify( + fn: typeof import("node:crypto").generateKey, + ): ( + type: "hmac" | "aes", + options: { length: number }, + ) => Promise; + /* dns.lookup's promise settles with { address, family } (the address + * array with options.all), and lookupService's with { hostname, service }. */ + export function promisify(fn: typeof import("node:dns").lookup): { + ( + hostname: string, + options: import("node:dns").LookupAllOptions, + ): Promise; + ( + hostname: string, + options?: number | import("node:dns").LookupOneOptions, + ): Promise; + }; + export function promisify( + fn: typeof import("node:dns").lookupService, + ): (address: string, port: number) => Promise<{ hostname: string; service: string }>; /* Declared surface without full lowering (the type-level tolerance * story: guarded/diagnostic-path code must TYPECHECK; a reached use * without a lowering fences at its site). inspect's options carry the diff --git a/packages/compiler/src/backend/llvm/lib-datagram.ts b/packages/compiler/src/backend/llvm/lib-datagram.ts index 1553ecf4f..c97744f64 100644 --- a/packages/compiler/src/backend/llvm/lib-datagram.ts +++ b/packages/compiler/src/backend/llvm/lib-datagram.ts @@ -121,6 +121,8 @@ export function emitDatagramLibCall(host: LlvmEmitterContext, e: LibCallExpr): L "dgram.getSendQueueSize": "scr_dgram_get_send_queue_size", "dgram.getSendQueueCount": "scr_dgram_get_send_queue_count", "dgram.disconnect": "scr_dgram_disconnect", + "dns.lookupPromise": "scr_dns_lookup_promise", + "dns.lookupServicePromise": "scr_dns_lookup_service_promise", }; const symbol = direct[e.fn]; if (symbol !== undefined) return finishRuntimeCall(host, e, symbol, a); diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index 4a9f4017a..fdfe723d2 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -327,6 +327,94 @@ export function emitGenericLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll host.emitPendingCheck(); return { name: "", type: e.type }; } + if (e.fn.startsWith("crypto.") && e.fn.includes("Promise")) { + // util.promisify over the callback forms: the callback form runs with + // a runtime callback that owns the +1 promise and settles it in the + // promise's value representation; an argument error the callback form + // threw moves into the promise as its rejection. + host.usesTimers = true; + if (e.type.kind !== "promise") + throw new InternalCompilerError("llvm emitter bug: crypto promise result not a promise"); + const inner = e.type.inner; + const dyn = inner.kind === "dyn"; + const args = e.args.map((arg) => host.emitExpr(arg)); + const settle = + e.fn === "crypto.randomIntPromise" + ? dyn + ? "scr_crypto_promise_settle_number_dyn" + : "scr_crypto_promise_settle_number" + : e.fn === "crypto.hkdfPromise" + ? "scr_crypto_promise_settle_array_buffer" + : e.fn === "crypto.generateKeyPromise" || e.fn === "crypto.randomFillPromiseDyn" + ? "scr_crypto_promise_settle_dyn" + : !dyn + ? "scr_crypto_promise_settle_bytes" + : e.fn === "crypto.randomFillPromise" + ? "scr_crypto_promise_settle_view_dyn" + : "scr_crypto_promise_settle_buffer_dyn"; + host.declare(`declare ptr @scr_promise_new()`); + host.declare(`declare ptr @scr_crypto_promise_callback(ptr)`); + host.declare(`declare void @scr_crypto_promise_reject_thrown(ptr)`); + host.declare( + e.fn === "crypto.randomIntPromise" + ? `declare void @${settle}(ptr, double)` + : `declare void @${settle}(ptr, ptr, ptr)`, + ); + const promise = B.tmp(); + const cb = B.tmp(); + B.line(`${promise} = call ptr @scr_promise_new()`); + B.line(`${cb} = call ptr @scr_crypto_promise_callback(ptr ${promise})`); + const a = (i: number, type = "ptr") => `${type} ${args[i]!.name}`; + const call = (symbol: string, params: string[], values: string[]) => { + host.declare(`declare void @${symbol}(${[...params, "ptr", "ptr"].join(", ")})`); + B.line(`call void @${symbol}(${[...values, `ptr ${cb}`, `ptr @${settle}`].join(", ")})`); + }; + if (e.fn === "crypto.randomBytesPromise") { + call("scr_crypto_random_bytes_async", ["double"], [a(0, "double")]); + } else if (e.fn === "crypto.pbkdf2Promise") { + call( + "scr_crypto_pbkdf2_async", + ["ptr", "ptr", "double", "double", "ptr"], + [a(0), a(1), a(2, "double"), a(3, "double"), a(4)], + ); + } else if (e.fn === "crypto.scryptPromise") { + call( + "scr_crypto_scrypt_async", + ["ptr", "ptr", "double", "ptr"], + [a(0), a(1), a(2, "double"), a(3)], + ); + } else if (e.fn === "crypto.hkdfPromise") { + call( + "scr_crypto_hkdf_async", + ["ptr", "ptr", "ptr", "ptr", "double"], + [a(0), a(1), a(2), a(3), a(4, "double")], + ); + } else if (e.fn === "crypto.randomFillPromise") { + call( + "scr_crypto_random_fill_async", + ["ptr", "double", "double", "double"], + [a(0), a(1, "double"), a(2, "double"), a(3, "double")], + ); + } else if (e.fn === "crypto.randomFillPromiseDyn") { + call( + "scr_crypto_random_fill_async_dyn", + ["ptr", "ptr", "ptr", "double"], + [a(0), a(1), a(2), a(3, "double")], + ); + } else if (e.fn === "crypto.randomIntPromise") { + call( + "scr_crypto_random_int_async", + ["double", "double", "double"], + [a(0, "double"), a(1, "double"), a(2, "double")], + ); + } else if (e.fn === "crypto.generateKeyPromise") { + call("scr_crypto_generate_key_async", ["ptr", "ptr"], [a(0), a(1)]); + } else { + throw new InternalCompilerError(`llvm emitter bug: unknown crypto promise ${e.fn}`); + } + B.line(`call void @scr_crypto_promise_reject_thrown(ptr ${promise})`); + return host.own({ name: promise, type: e.type }); + } if ( e.fn === "crypto.randomBytesCb" || e.fn === "crypto.pbkdf2Cb" || diff --git a/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts b/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts index d4574b41c..cf19b4003 100644 --- a/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts +++ b/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts @@ -4,6 +4,8 @@ import { isJsSourceFile } from "../../program.js"; import { builtinModuleFnOf } from "../surfaces.js"; import { registerHttpClientFnBinding } from "../lower-server.js"; import { isPromisifiedZlibMember } from "./compression.js"; +import { isPromisifiedCryptoMember } from "./crypto.js"; +import { isPromisifiedDnsMember } from "../lower-dgram.js"; /** Compile-time util.promisify projections. The immutable result binding * owns no runtime slot: calls rewrite to the target's promise lowering, @@ -157,12 +159,16 @@ export function registerPromisifiedBuiltinDecl( } : target?.module === "zlib" && isPromisifiedZlibMember(target.member) ? { kind: "promisified-zlib" as const, member: target.member } - : null; + : target?.module === "crypto" && isPromisifiedCryptoMember(target.member) + ? { kind: "promisified-crypto" as const, member: target.member } + : target?.module === "dns" && isPromisifiedDnsMember(target.member) + ? { kind: "promisified-dns" as const, member: target.member } + : null; if (!projection) { lowerer.noLowering( "util.promisify of this target", argNode ?? e, - "child_process.exec, child_process.execFile, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots and the fs callback functions with an fs/promises counterpart are the supported targets", + "child_process.exec, child_process.execFile, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions (randomBytes, pbkdf2, scrypt, hkdf, randomFill, randomInt, generateKey), dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart are the supported targets", ); } const symbol = lowerer.checker.getSymbolAtLocation(nameNode); diff --git a/packages/compiler/src/frontend/lowering/builtins/crypto.ts b/packages/compiler/src/frontend/lowering/builtins/crypto.ts index 2202088fa..a492a0da7 100644 --- a/packages/compiler/src/frontend/lowering/builtins/crypto.ts +++ b/packages/compiler/src/frontend/lowering/builtins/crypto.ts @@ -15,6 +15,7 @@ import { F64, type IrExpr, type IrLibFn, + type IrType, type IrStmt, STRING, type SrcLoc, @@ -1090,3 +1091,176 @@ export function lowerCryptoHashMethodCall( lowerer.checker.getSymbolAtLocation(access.name), ); } + +/** The crypto callback functions util.promisify converts. */ +const PROMISIFIED_CRYPTO_ARITY: Readonly> = { + randomBytes: [1, 1], + pbkdf2: [5, 5], + scrypt: [3, 4], + hkdf: [5, 5], + randomFill: [1, 3], + randomInt: [1, 2], + generateKey: [1, 2], +}; + +export function isPromisifiedCryptoMember(member: string): boolean { + return PROMISIFIED_CRYPTO_ARITY[member] !== undefined; +} + +/** A call through `promisify(crypto.randomBytes)` and the other callback + * functions: the callback form runs with a callback that settles the + * returned promise, so the value or error arrives where the callback + * would run. An argument error rejects the promise instead of throwing, + * as the throw inside Node's promisify wrapper does. The promise's value + * type follows the declared result: a Buffer or the filled view, or a + * checked-dynamic value where the declarations give `unknown`. */ +export function lowerPromisifiedCryptoCall( + lowerer: Lowerer, + expr: ts.CallExpression, + member: string, + loc: SrcLoc, +): IrExpr { + const args = expr.arguments; + if (args.some(ts.isSpreadElement)) { + lowerer.noLowering(`the promisified crypto.${member} with spread arguments`, expr); + } + const [min, max] = PROMISIFIED_CRYPTO_ARITY[member]!; + if (args.length < min || args.length > max) { + lowerer.noLowering( + `the promisified crypto.${member} with ${args.length} arguments`, + expr, + `the promisified form takes the callback form's arguments without the callback`, + ); + } + const declared = lowerer.mapTypeOf(lowerer.typeOf(expr)); + const inner = declared?.kind === "promise" ? declared.inner : null; + const promise = ( + fn: IrLibFn, + values: IrExpr[], + accepts: (t: IrType) => boolean, + what: string, + ): IrExpr => { + if (inner === null || !accepts(inner)) { + lowerer.noLowering( + `the promisified crypto.${member} with a '${declared ? lowerer.fmt(declared) : "?"}' result`, + expr, + `the promise's value type must be ${what} or unknown`, + ); + } + return { kind: "libCall", fn, args: values, type: { kind: "promise", inner }, loc }; + }; + const bufferOrDyn = (t: IrType) => t.kind === "dyn" || (t.kind === "bytes" && t.elem === "u8"); + if (member === "randomBytes") { + return promise( + "crypto.randomBytesPromise", + [lowerer.lowerExprExpecting(args[0]!, F64)], + bufferOrDyn, + "Buffer", + ); + } + if (member === "pbkdf2") { + return promise( + "crypto.pbkdf2Promise", + [ + lowerBuiltinByteInput(lowerer, args[0]!, locOf(args[0]!), "crypto"), + lowerBuiltinByteInput(lowerer, args[1]!, locOf(args[1]!), "crypto"), + lowerer.lowerExprExpecting(args[2]!, F64), + lowerer.lowerExprExpecting(args[3]!, F64), + cryptoAlgorithm(lowerer, args[4]!), + ], + bufferOrDyn, + "Buffer", + ); + } + if (member === "scrypt") { + return promise( + "crypto.scryptPromise", + [ + cryptoKdfInput(lowerer, args[0]!), + cryptoKdfInput(lowerer, args[1]!), + lowerer.lowerExprExpecting(args[2]!, F64), + args[3] + ? lowerer.coerceInto(args[3], lowerer.lowerExpr(args[3]), DYN) + : dynUndefinedExpr(loc), + ], + bufferOrDyn, + "Buffer", + ); + } + if (member === "hkdf") { + return promise( + "crypto.hkdfPromise", + [ + cryptoAlgorithm(lowerer, args[0]!), + isKeyObjectValue(lowerer, args[1]!) + ? { + kind: "libCall", + fn: "crypto.keyObjectInput", + args: [lowerer.lowerExprExpecting(args[1]!, DYN)], + type: BYTES_U8, + loc, + } + : cryptoKdfInput(lowerer, args[1]!), + cryptoKdfInput(lowerer, args[2]!), + cryptoKdfInput(lowerer, args[3]!), + lowerer.lowerExprExpecting(args[4]!, F64), + ], + (t) => t.kind === "dyn", + "ArrayBuffer", + ); + } + if (member === "randomFill") { + // Node's randomFill counts the arguments before the callback. + const form: IrExpr = { kind: "numLit", value: args.length, type: F64, loc }; + const buffer = lowerer.lowerExpr(args[0]!); + if (buffer.type.kind === "bytes" && cryptoNumberArgs(lowerer, args.slice(1))) { + const view = buffer.type; + return promise( + "crypto.randomFillPromise", + [ + buffer, + args.length >= 2 + ? lowerer.lowerExprExpecting(args[1]!, F64) + : { kind: "numLit", value: 0, type: F64, loc }, + args.length === 3 + ? lowerer.lowerExprExpecting(args[2]!, F64) + : { kind: "numLit", value: 0, type: F64, loc }, + form, + ], + (t) => t.kind === "dyn" || (t.kind === "bytes" && t.elem === view.elem), + "the buffer's own view", + ); + } + return promise( + "crypto.randomFillPromiseDyn", + [ + lowerer.coerceInto(args[0]!, buffer, DYN), + dynArg(lowerer, args[1], loc), + dynArg(lowerer, args[2], loc), + form, + ], + (t) => t.kind === "dyn", + "the buffer's own type", + ); + } + if (member === "randomInt") { + return promise( + "crypto.randomIntPromise", + [ + args.length === 2 + ? lowerer.lowerExprExpecting(args[0]!, F64) + : { kind: "numLit", value: 0, type: F64, loc }, + lowerer.lowerExprExpecting(args[args.length - 1]!, F64), + { kind: "numLit", value: args.length === 2 ? 1 : 0, type: F64, loc }, + ], + (t) => t.kind === "dyn" || t.kind === "f64", + "number", + ); + } + return promise( + "crypto.generateKeyPromise", + [lowerer.lowerExprExpecting(args[0]!, DYN), dynArg(lowerer, args[1], loc)], + (t) => t.kind === "dyn", + "KeyObject", + ); +} diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 56c639397..7ced0c99a 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -105,8 +105,13 @@ import { lowerImportMetaResolveCall, lowerRequireResolveCall, } from "./builtins/module-resolution.js"; -import { lowerCipherMethodCall, lowerCryptoHashMethodCall } from "./builtins/crypto.js"; +import { + lowerCipherMethodCall, + lowerCryptoHashMethodCall, + lowerPromisifiedCryptoCall, +} from "./builtins/crypto.js"; import { lowerErrorIsErrorCall } from "./builtins/errors.js"; +import { lowerPromisifiedDnsCall } from "./lower-dgram.js"; import { lowerDisposableStackUseCall } from "./builtins/disposable-stack.js"; import { lowerDirentMethodCall, @@ -801,6 +806,12 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { if (projection?.kind === "promisified-zlib") { return lowerPromisifiedZlibCall(lowerer, expr, projection.member, loc); } + if (projection?.kind === "promisified-crypto") { + return lowerPromisifiedCryptoCall(lowerer, expr, projection.member, loc); + } + if (projection?.kind === "promisified-dns") { + return lowerPromisifiedDnsCall(lowerer, expr, projection.member, loc); + } if (projection?.kind === "promisified-builtin") { return lowerBuiltinCall( lowerer, diff --git a/packages/compiler/src/frontend/lowering/lower-dgram.ts b/packages/compiler/src/frontend/lowering/lower-dgram.ts index 17dab01ab..06c83da44 100644 --- a/packages/compiler/src/frontend/lowering/lower-dgram.ts +++ b/packages/compiler/src/frontend/lowering/lower-dgram.ts @@ -14,6 +14,7 @@ import { isJsSourceFile, locOf } from "../program.js"; import { BOOL, canBoxFuncIntoDyn, + canDynCheckTo, DGRAMSOCK_T, DYN, F64, @@ -655,3 +656,98 @@ export function lowerDgramMethodCall( lowerer.checker.getSymbolAtLocation(access.name), ); } + +/** True for a dns callback function util.promisify converts. */ +export function isPromisifiedDnsMember(member: string): boolean { + return member === "lookup" || member === "lookupService"; +} + +/** A call through `promisify(dns.lookup)` or `promisify(dns.lookupService)`: + * the callback form runs with a callback that settles a promise of the + * checked-dynamic `{ address, family }` (the address array with + * options.all) or `{ hostname, service }`, which Node's custom promisified + * forms produce. An argument error rejects the promise instead of + * throwing. A declared result type other than `unknown` is reached through + * an async helper that awaits that promise and checks the value. */ +export function lowerPromisifiedDnsCall( + lowerer: Lowerer, + expr: ts.CallExpression, + member: string, + loc: SrcLoc, +): IrExpr { + const args = expr.arguments; + if (args.some(ts.isSpreadElement)) { + lowerer.noLowering(`the promisified dns.${member} with spread arguments`, expr); + } + const service = member === "lookupService"; + if (service ? args.length !== 2 : args.length < 1 || args.length > 2) { + lowerer.noLowering( + `the promisified dns.${member} with ${args.length} arguments`, + expr, + service + ? "the form is lookupService(address, port)" + : "the supported forms are lookup(hostname) and lookup(hostname, options)", + ); + } + const dyn = (node: ts.Expression | undefined): IrExpr => + node ? lowerer.coerceToExpected(lowerer.lowerExpr(node), DYN) : dynUndefinedExpr(loc); + const promiseDyn: IrType = { kind: "promise", inner: DYN }; + const call: IrExpr = { + kind: "libCall", + fn: service ? "dns.lookupServicePromise" : "dns.lookupPromise", + args: [dyn(args[0]), dyn(args[1])], + type: promiseDyn, + loc, + }; + const declared = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (declared?.kind !== "promise") { + lowerer.noLowering(`the promisified dns.${member} with this result type`, expr); + } + const value = declared.inner; + if (value.kind === "dyn") return call; + if ( + !canDynCheckTo( + value, + (id) => lowerer.shapes.get(id), + (id) => lowerer.unions.get(id), + ) + ) { + lowerer.noLowering( + `the promisified dns.${member} with a '${lowerer.fmt(declared)}' result`, + expr, + "the result type must have a checked conversion from the lookup's value", + ); + } + const key = `dnsPromise:${JSON.stringify(value)}`; + let name = lowerer.valueHelpers.get(key); + if (!name) { + name = `%dnsPromise.${lowerer.valueHelpers.size}`; + lowerer.valueHelpers.set(key, name); + lowerer.liftedFns.push({ + name, + params: [{ localId: "p.0", name: "p", type: promiseDyn }], + returnType: value, + async: true, + locals: [{ id: "p.0", name: "p", type: promiseDyn, mutable: false }], + body: [ + { + kind: "return", + value: { + kind: "dynCheck", + value: { + kind: "awaitExpr", + value: { kind: "varRef", localId: "p.0", type: promiseDyn, loc }, + type: DYN, + loc, + }, + type: value, + loc, + }, + loc, + }, + ], + loc, + }); + } + return { kind: "call", callee: name, args: [call], type: declared, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index d2d990e16..57d119d67 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -841,7 +841,9 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { projection?.kind === "promisified-exec-file" || projection?.kind === "promisified-exec" || projection?.kind === "promisified-builtin" || - projection?.kind === "promisified-zlib" + projection?.kind === "promisified-zlib" || + projection?.kind === "promisified-crypto" || + projection?.kind === "promisified-dns" ) { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 087b4e628..326f6d435 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -602,7 +602,9 @@ export type StaticCallableProjection = | { kind: "promisified-exec-file" } | { kind: "promisified-exec" } | { kind: "promisified-builtin"; module: string; member: string } - | { kind: "promisified-zlib"; member: string }; + | { kind: "promisified-zlib"; member: string } + | { kind: "promisified-crypto"; member: string } + | { kind: "promisified-dns"; member: string }; /** Own-property lookup for the surface tables. They are plain object * literals, so a bare `table[name]` would also find Object.prototype diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index d50fc8be3..1cd12f9c6 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2047,8 +2047,13 @@ export const BUILTIN_MODULE_FN_ALIASES: Record< crypto: { // The composed randomBytes(n).toString(enc) chain keeps its one-libCall // lowering (lowerCryptoComposedCall), while the callback overload has - // its own adapter spelling. Both remain the randomBytes surface. - randomBytes: ["crypto.randomBytesToString", "crypto.randomBytesCb"], + // its own adapter spelling. Both remain the randomBytes surface, as does + // the util.promisify form. + randomBytes: [ + "crypto.randomBytesToString", + "crypto.randomBytesCb", + "crypto.randomBytesPromise", + ], // Omitting size fills from offset through the rest of the Buffer and // uses a separate runtime entry point for Node's exact bounds checks. // Views of every kind return themselves; other buffers take the Dyn form. @@ -2058,9 +2063,13 @@ export const BUILTIN_MODULE_FN_ALIASES: Record< "crypto.randomFillViewRest", "crypto.randomFillSyncDyn", ], - randomFill: ["crypto.randomFillCbDyn"], + randomFill: [ + "crypto.randomFillCbDyn", + "crypto.randomFillPromise", + "crypto.randomFillPromiseDyn", + ], timingSafeEqual: ["crypto.timingSafeEqualDyn"], - randomInt: ["crypto.randomIntMax", "crypto.randomIntCb"], + randomInt: ["crypto.randomIntMax", "crypto.randomIntCb", "crypto.randomIntPromise"], randomUUID: ["crypto.randomUUIDOpts"], }, os: { @@ -2874,7 +2883,7 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record< }, util: { promisify: - "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots and the fs callback functions with an fs/promises counterpart; call the bound function directly", + "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions, dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart; call the bound function directly", }, "stream/consumers": { blob: diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 52964e1bd..b766a27a7 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -3543,12 +3543,14 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { ), }; } - // The promisified exec/execFile result `{ stdout: string; stderr: string }`: - // an anonymous type literal (@types/node's __promisify__ overloads in - // child_process, the shipped fallback's promisify overloads in util), - // so it maps by provenance and exact shape, interned as the - // %execFileAsync/%execAsync helpers build it. Node builds the object as - // { stdout, stderr }. The Buffer-typed literals do not match and stay + // The promisified exec/execFile result `{ stdout: string; stderr: string }` + // and the promisified dns.lookupService result `{ hostname: string; + // service: string }`: anonymous type literals (@types/node's + // __promisify__ overloads in child_process and dns, the shipped + // fallback's promisify overloads in util), so they map by provenance and + // exact shape. The exec result is interned as the %execFileAsync/ + // %execAsync helpers build it; Node builds { stdout, stderr } and + // { hostname, service }. The Buffer-typed literals do not match and stay // unmapped. if ( psym && @@ -3558,21 +3560,38 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { (d) => ts.isTypeLiteralNode(d) && ctx.isStdlibFile(d.getSourceFile()) && - (isDeclaredInAmbientModule(d, "child_process") || isDeclaredInAmbientModule(d, "util")), + (isDeclaredInAmbientModule(d, "child_process") || + isDeclaredInAmbientModule(d, "util") || + isDeclaredInAmbientModule(d, "dns")), ) ) { const props = checker.getPropertiesOfType(widened); - if ( + const names = props.length === 2 && props.every( (p) => - (p.name === "stdout" || p.name === "stderr") && (p.flags & ts.SymbolFlags.Optional) === 0 && (checker.getTypeOfSymbol(p).flags & ts.TypeFlags.String) !== 0, - ) && - props[0]!.name !== props[1]!.name - ) { - return { kind: "record", shapeId: execResultShape(ctx.shapes) }; + ) + ? props + .map((p) => p.name) + .sort() + .join(",") + : ""; + if (names === "stderr,stdout") return { kind: "record", shapeId: execResultShape(ctx.shapes) }; + if (names === "hostname,service") { + return { + kind: "record", + shapeId: ctx.shapes.intern( + [ + { name: "hostname", type: STRING }, + { name: "service", type: STRING }, + ], + false, + undefined, + ["hostname", "service"], + ), + }; } } // crypto.X509Certificate — the Dirent-style data record: THREE visible diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 7f31c5205..3b8f6a72b 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2583,6 +2583,25 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "crypto.hkdfCb": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64, null], result: VOID }, "crypto.scrypt": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN], result: BYTES_U8 }, "crypto.scryptCb": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN, null], result: VOID }, + /** util.promisify over the callback forms: the callback form's + * arguments without the callback → a promise the callback form settles, + * or rejected with an argument error; never throws. The result's value + * type is the declared one (a Buffer, the filled view, a number, or a + * checked-dynamic value); the validator checks it. */ + "crypto.randomBytesPromise": { argTypes: [F64], result: VOID }, + "crypto.pbkdf2Promise": { argTypes: [BYTES_U8, BYTES_U8, F64, F64, STRING], result: VOID }, + "crypto.scryptPromise": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN], result: VOID }, + "crypto.hkdfPromise": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64], result: VOID }, + "crypto.randomFillPromise": { argTypes: [null, F64, F64, F64], result: VOID }, + "crypto.randomFillPromiseDyn": { argTypes: [DYN, DYN, DYN, F64], result: VOID }, + "crypto.randomIntPromise": { argTypes: [F64, F64, F64], result: VOID }, + "crypto.generateKeyPromise": { argTypes: [DYN, DYN], result: VOID }, + /** util.promisify(dns.lookup) and util.promisify(dns.lookupService): + * [hostname, options] and [address, port] → a promise of the + * checked-dynamic result object (the address array with options.all), + * or rejected with the error; never throws. */ + "dns.lookupPromise": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "dns.lookupServicePromise": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, // The Buffer statics and the fs/zlib Buffer forms: fixed always-u8 // signatures (Buffer IS a Uint8Array — one bytes kind). /** The Buffer statics with fixed (always-u8) signatures. fromStr is diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index f7d30a1bb..e3549b80e 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -60,6 +60,18 @@ import { DYN_CLASS_PROPERTIES } from "./ir.js"; import { unionWideningTags } from "./analysis.js"; import { alwaysReturns } from "./control-flow.js"; import { LIB_FN_SIGS } from "./builtin-signatures.js"; + +/** The promisified crypto calls' value kinds besides checked-dynamic. */ +const CRYPTO_PROMISE_VALUES: Readonly> = { + "crypto.randomBytesPromise": "buffer", + "crypto.pbkdf2Promise": "buffer", + "crypto.scryptPromise": "buffer", + "crypto.hkdfPromise": "dyn", + "crypto.randomFillPromise": "view", + "crypto.randomFillPromiseDyn": "dyn", + "crypto.randomIntPromise": "number", + "crypto.generateKeyPromise": "dyn", +}; import { REGEX_INTRINSIC_SIGS, STR_INTRINSIC_SIGS } from "./intrinsic-signatures.js"; /** True for an object type naming a runtime-provided error class. */ @@ -4097,6 +4109,19 @@ function validateFunction( } function checkLibValueCall(e: IrExpr & { kind: "libCall" }): boolean { + const cryptoPromise = CRYPTO_PROMISE_VALUES[e.fn]; + if (cryptoPromise) { + const inner = e.type.kind === "promise" ? e.type.inner : undefined; + const view = e.fn === "crypto.randomFillPromise" ? e.args[0]?.type : undefined; + const ok = + inner !== undefined && + (inner.kind === "dyn" || + (cryptoPromise === "buffer" && inner.kind === "bytes" && inner.elem === "u8") || + (cryptoPromise === "view" && view !== undefined && typeEquals(inner, view)) || + (cryptoPromise === "number" && inner.kind === "f64")); + if (!ok) err(`libCall ${e.fn} must be a promise of its ${cryptoPromise} value`, e.loc); + return true; + } if (e.fn === "events.once") { const [recv, , boxer, errorBoxer] = e.args; const arrayT = e.type.kind === "promise" ? e.type.inner : null; diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index c01101f6f..f5313f12d 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -2462,7 +2462,7 @@ "name": "util.promisify", "status": "unsupported", "code": "SC2020", - "note": "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots and the fs callback functions with an fs/promises counterpart; call the bound function directly" + "note": "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions, dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart; call the bound function directly" }, { "id": "node-builtin.util.stripVTControlCharacters", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5631-promisify-crypto.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5631-promisify-crypto.ts.json new file mode 100644 index 000000000..cf5c25558 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5631-promisify-crypto.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5631-promisify-crypto.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5632-promisify-dns.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5632-promisify-dns.ts.json new file mode 100644 index 000000000..b96c90a82 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5632-promisify-dns.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5632-promisify-dns.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-crypto.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-crypto.ts.json new file mode 100644 index 000000000..c340af28b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-crypto.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/promisify-crypto.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-dns.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-dns.ts.json new file mode 100644 index 000000000..08a2faf82 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-dns.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/promisify-dns.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_crypto.h b/packages/runtime/src/scr_crypto.h index 6b70a7fab..5abfeaa48 100644 --- a/packages/runtime/src/scr_crypto.h +++ b/packages/runtime/src/scr_crypto.h @@ -114,6 +114,23 @@ void scr_crypto_hkdf_async(ScrStr *digest, ScrBytes *ikm, ScrBytes *salt, ScrBytes *info, double keylen, ScrClosure *cb, ScrCryptoBytesFn fn); void scr_crypto_scrypt_async(ScrBytes *password, ScrBytes *salt, double keylen, ScrDyn *options, ScrClosure *cb, ScrCryptoBytesFn fn); +/* util.promisify over the callback forms: scr_crypto_promise_callback + * returns a callback closure (+1) that owns the promise, and the settle + * adapters fulfill it with the value as a Buffer or view (_bytes), a + * checked-dynamic Buffer, view or ArrayBuffer, a checked-dynamic value + * (_dyn), or a number, or reject it with the callback's error. After the + * callback form returns, scr_crypto_promise_reject_thrown moves a pending + * argument error into the promise as its rejection. */ +typedef struct ScrPromise ScrPromise; +ScrClosure *scr_crypto_promise_callback(ScrPromise *promise); +void scr_crypto_promise_reject_thrown(ScrPromise *promise); +void scr_crypto_promise_settle_bytes(ScrClosure *cb, ScrError *error, ScrBytes *value); +void scr_crypto_promise_settle_buffer_dyn(ScrClosure *cb, ScrError *error, ScrBytes *value); +void scr_crypto_promise_settle_view_dyn(ScrClosure *cb, ScrError *error, ScrBytes *value); +void scr_crypto_promise_settle_array_buffer(ScrClosure *cb, ScrError *error, ScrBytes *value); +void scr_crypto_promise_settle_dyn(ScrClosure *cb, ScrError *error, ScrBytes *value); +void scr_crypto_promise_settle_number(ScrClosure *cb, double value); +void scr_crypto_promise_settle_number_dyn(ScrClosure *cb, double value); /* The digest primitives beyond MD5/SHA-1/SHA-2 (scr_hash.c). Each final * reads a copy of its context. */ diff --git a/packages/runtime/src/scr_crypto_async.c b/packages/runtime/src/scr_crypto_async.c index bae5cf811..02aca7323 100644 --- a/packages/runtime/src/scr_crypto_async.c +++ b/packages/runtime/src/scr_crypto_async.c @@ -230,3 +230,83 @@ void scr_crypto_generate_key_async(ScrDyn *type, ScrDyn *options, ScrClosure *cb } scr_crypto_defer_dyn(key, NULL, cb, fn); } + +/* util.promisify over the callback forms above. The callback is a closure + * that owns the pending promise in caps[0], and each adapter below settles + * that promise where the callback would run: an error rejects it, and the + * value fulfills it in the representation the promise's type uses. */ +static ScrPromise *scr_crypto_promise_of(ScrClosure *cb) { + ScrPromise *p; + memcpy(&p, &cb->caps[0]->slot, sizeof p); + return p; +} + +ScrClosure *scr_crypto_promise_callback(ScrPromise *promise) { + ScrClosure *cb = scr_closure_new(NULL, 1); + cb->caps[0] = scr_box_new_obj(scr_promise_retain_v, scr_promise_release_v, NULL); + scr_box_set_ref(cb->caps[0], scr_promise_retain(promise)); + return cb; +} + +/* An argument error thrown before the operation started rejects the + * promise, as the throw inside Node's promisify wrapper does. */ +void scr_crypto_promise_reject_thrown(ScrPromise *promise) { + if (scr_exc_pending()) scr_promise_reject_pending(promise); +} + +static bool scr_crypto_promise_rejected(ScrPromise *p, ScrError *error) { + if (!error) return false; + scr_throw_obj(scr_error_retain(error), &scr_error_retain_v, &scr_error_release_v, + scr_error_trace_arg()); + scr_promise_reject_pending(p); + return true; +} + +static void scr_crypto_promise_fulfill_dyn(ScrPromise *p, ScrDyn *value /* moves */) { + scr_promise_fulfill_ref(p, value, scr_dyn_retain_v, scr_dyn_release_v, NULL); +} + +void scr_crypto_promise_settle_bytes(ScrClosure *cb, ScrError *error, ScrBytes *value) { + ScrPromise *p = scr_crypto_promise_of(cb); + if (scr_crypto_promise_rejected(p, error)) return; + scr_promise_fulfill_ref(p, value, scr_bytes_retain_v, scr_bytes_release_v, NULL); +} + +void scr_crypto_promise_settle_buffer_dyn(ScrClosure *cb, ScrError *error, ScrBytes *value) { + ScrPromise *p = scr_crypto_promise_of(cb); + if (scr_crypto_promise_rejected(p, error)) return; + ScrDyn *boxed = scr_dyn_new_buffer(value); + scr_bytes_release(value); + scr_crypto_promise_fulfill_dyn(p, boxed); +} + +void scr_crypto_promise_settle_view_dyn(ScrClosure *cb, ScrError *error, ScrBytes *value) { + ScrPromise *p = scr_crypto_promise_of(cb); + if (scr_crypto_promise_rejected(p, error)) return; + ScrDyn *boxed = scr_dyn_new_bytes(value); + scr_bytes_release(value); + scr_crypto_promise_fulfill_dyn(p, boxed); +} + +void scr_crypto_promise_settle_array_buffer(ScrClosure *cb, ScrError *error, ScrBytes *value) { + ScrPromise *p = scr_crypto_promise_of(cb); + if (scr_crypto_promise_rejected(p, error)) return; + ScrDyn *buffer = scr_array_buffer_from_bytes(value); + scr_bytes_release(value); + scr_crypto_promise_fulfill_dyn(p, buffer); +} + +/* generateKey and the checked-dynamic randomFill pass a ScrDyn value. */ +void scr_crypto_promise_settle_dyn(ScrClosure *cb, ScrError *error, ScrBytes *value) { + ScrPromise *p = scr_crypto_promise_of(cb); + if (scr_crypto_promise_rejected(p, error)) return; + scr_crypto_promise_fulfill_dyn(p, (ScrDyn *)value); +} + +void scr_crypto_promise_settle_number(ScrClosure *cb, double value) { + scr_promise_fulfill_f64(scr_crypto_promise_of(cb), value); +} + +void scr_crypto_promise_settle_number_dyn(ScrClosure *cb, double value) { + scr_crypto_promise_fulfill_dyn(scr_crypto_promise_of(cb), scr_dyn_new_num(value)); +} diff --git a/packages/runtime/src/scr_dgram.c b/packages/runtime/src/scr_dgram.c index 13650a35d..b02c41c03 100644 --- a/packages/runtime/src/scr_dgram.c +++ b/packages/runtime/src/scr_dgram.c @@ -1636,6 +1636,66 @@ void scr_dns_lookup_service(const ScrDyn *address, const ScrDyn *port, const Scr scr_dns_call_later(callback, args, 3, false); } +/* util.promisify(dns.lookup) and util.promisify(dns.lookupService): the + * callback forms with a callback that settles the returned promise. An + * error rejects it; otherwise it fulfills with { address, family } (the + * address array with options.all) or { hostname, service }, the objects + * Node's custom promisified forms build. An argument error rejects the + * promise instead of throwing. */ +static ScrDyn *scr_dns_promise_settle(ScrClosure *clo, ScrDyn *const *args, size_t argc, + const char *first, const char *second) { + ScrPromise *p; + memcpy(&p, &clo->caps[0]->slot, sizeof p); + if (argc >= 1 && !scr_dyn_is_nullish(args[0])) { + scr_dyn_throw(scr_dyn_retain(args[0])); + scr_promise_reject_pending(p); + return scr_dyn_undefined(); + } + ScrDyn *value; + if (argc == 2) { + value = scr_dyn_retain(args[1]); + } else { + value = scr_dyn_new_obj(); + scr_dyn_obj_set(value, first, strlen(first), argc >= 2 ? scr_dyn_retain(args[1]) : scr_dyn_undefined()); + scr_dyn_obj_set(value, second, strlen(second), argc >= 3 ? scr_dyn_retain(args[2]) : scr_dyn_undefined()); + } + scr_promise_fulfill_ref(p, value, scr_dyn_retain_v, scr_dyn_release_v, NULL); + return scr_dyn_undefined(); +} + +static ScrDyn *scr_dns_lookup_settle(ScrClosure *clo, ScrDyn *const *args, size_t argc) { + return scr_dns_promise_settle(clo, args, argc, "address", "family"); +} + +static ScrDyn *scr_dns_service_settle(ScrClosure *clo, ScrDyn *const *args, size_t argc) { + return scr_dns_promise_settle(clo, args, argc, "hostname", "service"); +} + +static ScrDyn *scr_dns_promise_callback(ScrPromise *p, ScrDynThunk thunk) { + ScrClosure *clo = scr_closure_new((void *)thunk, 1); + clo->caps[0] = scr_box_new_obj(scr_promise_retain_v, scr_promise_release_v, NULL); + scr_box_set_ref(clo->caps[0], scr_promise_retain(p)); + return scr_dyn_new_func(clo, thunk, 3, "(err,a,b)", "callback"); +} + +ScrPromise *scr_dns_lookup_promise(const ScrDyn *hostname, const ScrDyn *options) { + ScrPromise *p = scr_promise_new(); + ScrDyn *callback = scr_dns_promise_callback(p, scr_dns_lookup_settle); + scr_dns_lookup_dyn(hostname, options, callback, false); + scr_dyn_release(callback); + if (scr_exc_pending()) scr_promise_reject_pending(p); + return p; +} + +ScrPromise *scr_dns_lookup_service_promise(const ScrDyn *address, const ScrDyn *port) { + ScrPromise *p = scr_promise_new(); + ScrDyn *callback = scr_dns_promise_callback(p, scr_dns_service_settle); + scr_dns_lookup_service(address, port, callback, false); + scr_dyn_release(callback); + if (scr_exc_pending()) scr_promise_reject_pending(p); + return p; +} + /* dns.getServers(): the nameserver lines of /etc/resolv.conf, as c-ares * reads them ("[addr]:port" only for a port other than 53). +1. */ ScrDyn *scr_dns_get_servers(void) { diff --git a/packages/runtime/src/scr_dgram.h b/packages/runtime/src/scr_dgram.h index ccdfcbf77..6c8782da0 100644 --- a/packages/runtime/src/scr_dgram.h +++ b/packages/runtime/src/scr_dgram.h @@ -83,6 +83,11 @@ void scr_dns_lookup_dyn(const ScrDyn *hostname, const ScrDyn *options, const Scr bool typed); void scr_dns_lookup_service(const ScrDyn *address, const ScrDyn *port, const ScrDyn *callback, bool typed); +/* util.promisify(dns.lookup) and util.promisify(dns.lookupService): a +1 + * promise of the checked-dynamic result; never throws. */ +typedef struct ScrPromise ScrPromise; +ScrPromise *scr_dns_lookup_promise(const ScrDyn *hostname, const ScrDyn *options); +ScrPromise *scr_dns_lookup_service_promise(const ScrDyn *address, const ScrDyn *port); ScrDyn *scr_dns_get_servers(void); /* +1 */ ScrStr *scr_dns_get_default_result_order(void); /* +1 */ void scr_dns_set_default_result_order(const ScrDyn *order); diff --git a/tests/corpus/5631-promisify-crypto.ts b/tests/corpus/5631-promisify-crypto.ts new file mode 100644 index 000000000..bd5aaf00c --- /dev/null +++ b/tests/corpus/5631-promisify-crypto.ts @@ -0,0 +1,118 @@ +// util.promisify over the crypto callback functions: the promise settles +// with the value the callback form receives, or rejects with its error, +// after the call returns. An argument error rejects the promise instead of +// throwing. Random values are checked by length and range only. +import * as crypto from "node:crypto"; +import { pbkdf2, randomBytes, scrypt } from "node:crypto"; +import { promisify } from "node:util"; + +const randomBytesAsync = promisify(randomBytes); +const pbkdf2Async = promisify(pbkdf2); +const scryptAsync = promisify(scrypt); +const hkdfAsync = promisify(crypto.hkdf); +const randomFillAsync = promisify(crypto.randomFill); +const randomIntAsync = promisify(crypto.randomInt); +const generateKeyAsync = promisify(crypto.generateKey); + +async function rejects(label: string, run: () => Promise): Promise { + try { + await run(); + console.log(label, "fulfilled"); + } catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(label, "rejected", err.name, err.code, err.message); + } +} + +async function main(): Promise { + let returned = false; + const pending = randomBytesAsync(16); + returned = true; + const bytes = await pending; + console.log( + "randomBytes", + returned, + bytes.length, + bytes.toString("hex").length, + ); + console.log("randomBytes 0", (await randomBytesAsync(0)).length); + + const derived = await pbkdf2Async("password", "salt", 1000, 32, "sha256"); + console.log("pbkdf2", derived.toString("hex")); + console.log( + "pbkdf2 bytes", + ( + await pbkdf2Async(Buffer.from("pw"), new Uint8Array([1, 2]), 1, 8, "sha1") + ).toString("hex"), + ); + + console.log( + "scrypt", + (await scryptAsync("password", "salt", 16)).toString("hex"), + ); + console.log( + "scrypt options", + (await scryptAsync("password", "salt", 16, { N: 1024 })).toString("hex"), + ); + + const key = await hkdfAsync("sha256", "key", "salt", "info", 16); + console.log( + "hkdf", + key instanceof ArrayBuffer, + Buffer.from(key).toString("hex"), + ); + + const buf = Buffer.alloc(8); + const filled = await randomFillAsync(buf); + console.log("randomFill", filled === buf, filled.length); + const view = new Uint32Array(4); + const tail = await randomFillAsync(view, 2); + console.log("randomFill offset", tail === view, view[0], view[1]); + const middle = new Uint8Array(6); + await randomFillAsync(middle, 1, 2); + console.log("randomFill size", middle[0], middle[3], middle[4], middle[5]); + + const n = await randomIntAsync(10); + console.log("randomInt", Number.isInteger(n), n >= 0 && n < 10); + const m = await randomIntAsync(5, 7); + console.log("randomInt range", m === 5 || m === 6); + + const secret = await generateKeyAsync("hmac", { length: 64 }); + console.log("generateKey", secret.type, secret.symmetricKeySize); + + await rejects("randomBytes size", async () => { + await randomBytesAsync(-1); + }); + await rejects("pbkdf2 digest", async () => { + await pbkdf2Async("pw", "salt", 1, 8, "no-such-digest"); + }); + await rejects("pbkdf2 iterations", async () => { + await pbkdf2Async("pw", "salt", 0, 8, "sha256"); + }); + await rejects("scrypt keylen", async () => { + await scryptAsync("pw", "salt", -1); + }); + await rejects("hkdf digest", async () => { + await hkdfAsync("nope", "k", "s", "i", 8); + }); + await rejects("randomFill offset", async () => { + await randomFillAsync(Buffer.alloc(4), 9); + }); + await rejects("randomInt range", async () => { + await randomIntAsync(3, 3); + }); + await rejects("generateKey length", async () => { + await generateKeyAsync("hmac", { length: 3 }); + }); + + const order: string[] = []; + const first = randomBytesAsync(4).then(() => order.push("randomBytes")); + const second = pbkdf2Async("a", "b", 1, 4, "sha256").then(() => + order.push("pbkdf2"), + ); + order.push("sync"); + await Promise.all([first, second]); + console.log("order", order[0]); +} + +main().catch((e) => console.log("unexpected", String(e))); diff --git a/tests/corpus/5632-promisify-dns.ts b/tests/corpus/5632-promisify-dns.ts new file mode 100644 index 000000000..2c0a1adbc --- /dev/null +++ b/tests/corpus/5632-promisify-dns.ts @@ -0,0 +1,57 @@ +// util.promisify over dns.lookup and dns.lookupService: lookup's promise +// settles with { address, family }, or the address array with options.all, +// and lookupService's with { hostname, service }, after the call returns. A +// failed lookup rejects with the callback's error, and an argument error +// rejects the promise instead of throwing. +import * as dns from "node:dns"; +import { lookup } from "node:dns"; +import { promisify } from "node:util"; + +const lookupAsync = promisify(lookup); +const lookupServiceAsync = promisify(dns.lookupService); + +async function rejects(label: string, run: () => Promise): Promise { + try { + await run(); + console.log(label, "fulfilled"); + } catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(label, "rejected", err.name, err.code, err.message); + } +} + +async function main(): Promise { + let returned = false; + const pending = lookupAsync("127.0.0.1"); + returned = true; + const one = await pending; + console.log("literal", returned, one.address, one.family); + const six = await lookupAsync("::1", 6); + console.log("family", six.address, six.family); + const all = await lookupAsync("::1", { all: true }); + console.log("all", all.length, all[0]!.address, all[0]!.family); + const local = await lookupAsync("localhost", { family: 4 }); + console.log("localhost", local.address, local.family); + const local4 = await lookupAsync("localhost", { family: 4, all: true }); + console.log("localhost all", JSON.stringify(local4)); + + await rejects("missing host", async () => { + await lookupAsync("no-such-host.invalid"); + }); + await rejects("bad family", async () => { + await lookupAsync("localhost", 5); + }); + await rejects("bad hostname", async () => { + await lookupAsync(42 as unknown as string); + }); + await rejects("bad address", async () => { + await lookupServiceAsync("not-an-address", 22); + }); + await rejects("bad port", async () => { + await lookupServiceAsync("127.0.0.1", 70000); + }); + const service = await lookupServiceAsync("127.0.0.1", 22); + console.log("service", typeof service.hostname, typeof service.service); +} + +main().catch((e) => console.log("unexpected", String(e))); diff --git a/tests/fixtures/node-types/promisify-crypto.ts b/tests/fixtures/node-types/promisify-crypto.ts new file mode 100644 index 000000000..f854b0278 --- /dev/null +++ b/tests/fixtures/node-types/promisify-crypto.ts @@ -0,0 +1,22 @@ +import * as crypto from "node:crypto"; +import { promisify } from "node:util"; + +const randomBytes = promisify(crypto.randomBytes); +const pbkdf2 = promisify(crypto.pbkdf2); +const scrypt = promisify(crypto.scrypt); +const hkdf = promisify(crypto.hkdf); +const randomInt = promisify(crypto.randomInt); +const generateKey = promisify(crypto.generateKey); + +console.log((await randomBytes(12)).length); +console.log((await pbkdf2("pw", "salt", 10, 16, "sha512")).toString("hex")); +console.log(((await scrypt("pw", "salt", 16)) as Buffer).toString("base64")); +console.log(Buffer.from(await hkdf("sha256", "key", "salt", "info", 12)).toString("hex")); +const n = (await randomInt(4)) as number; +console.log(n >= 0 && n < 4); +console.log((await generateKey("aes", { length: 128 })).symmetricKeySize); +try { + await pbkdf2("pw", "salt", 1, 8, "md-none"); +} catch (e) { + if (e instanceof Error) console.log(e.name, e.message); +} diff --git a/tests/fixtures/node-types/promisify-dns.ts b/tests/fixtures/node-types/promisify-dns.ts new file mode 100644 index 000000000..9e4fe9c19 --- /dev/null +++ b/tests/fixtures/node-types/promisify-dns.ts @@ -0,0 +1,18 @@ +import * as dns from "node:dns"; +import { promisify } from "node:util"; + +const lookup = promisify(dns.lookup); +const lookupService = promisify(dns.lookupService); + +const one = await lookup("127.0.0.1"); +console.log(one.address, one.family); +const all = await lookup("::1", { all: true }); +console.log(all.map((entry) => `${entry.address}/${entry.family}`).join(",")); +const service = await lookupService("127.0.0.1", 80); +console.log(typeof service.hostname, typeof service.service); +try { + await lookup("no-such-host.invalid"); +} catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(err.code, err.message); +} diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 2c80c39a2..d28b6e014 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1834,6 +1834,8 @@ "5566-fs-dirent-dyn-boundaries/main.mjs": 2607, "5585-record-results-inlined.ts": 2922, "5595-net-ref-unref.ts": 2593, + "5631-promisify-crypto.ts": 2200, + "5632-promisify-dns.ts": 1700, "5644-net-socket-addresses.ts": 2220, "5645-net-socket-callbacks.ts": 2442, "5646-net-server-connections.ts": 2389, @@ -4534,6 +4536,8 @@ "5566-fs-dirent-dyn-boundaries/main.mjs": 3333, "5585-record-results-inlined.ts": 3681, "5595-net-ref-unref.ts": 3036, + "5631-promisify-crypto.ts": 2600, + "5632-promisify-dns.ts": 2000, "5644-net-socket-addresses.ts": 2393, "5645-net-socket-callbacks.ts": 2060, "5646-net-server-connections.ts": 2755, diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index bbd6045e5..ccaee08f0 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -440,6 +440,42 @@ test("node-types: promisified zlib one-shots settle from the worker-pool codec", expect(comparableStderr(native.stderr)).toBe(node.stderr); }); +test("node-types: promisified crypto callback functions settle with the callback value", async () => { + const outDir = outDirFor("promisify-crypto"); + const entry = join(nodeTypesDir, "promisify-crypto.ts"); + const result = await compile(entry, { + outPath: join(outDir, "promisify-crypto"), + outDir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), + ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); +}); + +test("node-types: promisified dns lookups settle with the lookup objects", async () => { + const outDir = outDirFor("promisify-dns"); + const entry = join(nodeTypesDir, "promisify-dns.ts"); + const result = await compile(entry, { + outPath: join(outDir, "promisify-dns"), + outDir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), + ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); +}); + test("node-types: unsupported child stdin forms remain named fences", async () => { const dir = outDirFor("node-child-stdin-fences"); const entry = join(nodeTypesDir, "child-stdin-fences.ts"); From 27f78a981df2254b05a0bac956960bb7dab104f2 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 09:14:01 -0500 Subject: [PATCH 080/117] Read fields as undefined before their assignment A constructor that let other code read a field before assigning it (a base constructor calling an override, or the constructor calling its own method) read an empty slot, which crashed the executable for string fields. Node reads undefined. Fields assigned after construction can expose the instance now admit undefined. Allocation writes undefined into them. String, number, boolean, bigint and union fields read as runtime-optional values, and class, array, record and collection fields use the deferred-init reads, whose member access throws a TypeError. Classes whose construction cannot expose the instance before their assignments keep their layouts. --- .../frontend/lowering/construction-escapes.ts | 9 + .../src/frontend/lowering/lower-classes.ts | 208 +++++++++++++----- .../src/frontend/lowering/lower-exprs.ts | 94 ++++++++ .../compiler/src/frontend/lowering/lowerer.ts | 12 + .../test/class-early-field-reads.test.ts | 93 ++++++++ ...5943-fields-read-before-assignment.ts.json | 6 + ...4-js-fields-read-before-assignment.js.json | 6 + .../5943-fields-read-before-assignment.ts | 181 +++++++++++++++ .../5944-js-fields-read-before-assignment.js | 28 +++ tests/harness/corpus-costs.json | 12 +- 10 files changed, 587 insertions(+), 62 deletions(-) create mode 100644 packages/compiler/test/class-early-field-reads.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json create mode 100644 tests/corpus/5943-fields-read-before-assignment.ts create mode 100644 tests/corpus/5944-js-fields-read-before-assignment.js diff --git a/packages/compiler/src/frontend/lowering/construction-escapes.ts b/packages/compiler/src/frontend/lowering/construction-escapes.ts index 484920a1c..a1626f12d 100644 --- a/packages/compiler/src/frontend/lowering/construction-escapes.ts +++ b/packages/compiler/src/frontend/lowering/construction-escapes.ts @@ -124,6 +124,15 @@ export function constructionEscape(inputs: ConstructionInputs): ConstructionEsca continue; } if (ts.isExpressionStatement(stmt) && !exposes(stmt.expression, depth)) continue; + // A check that only reads assigned fields and throws or does nothing + // with the receiver (`if (this.size < 0) throw new RangeError()`) + // does not expose the instance; assignments in its branches are not + // definite and still count as exposures. + if ( + (ts.isIfStatement(stmt) || ts.isThrowStatement(stmt) || ts.isBlock(stmt)) && + !exposes(stmt, depth) + ) + continue; return false; } return true; diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 06739166c..7a98096b7 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -143,7 +143,7 @@ import { lowerObjectFactoryNew } from "./object-factory-new.js"; import { tryLowerExpression } from "./expressions/try-lower-expression.js"; import { lowerInstanceConstructorNew } from "./class-instance-constructor.js"; import { classPrototypeData } from "./class-prototypes.js"; -import { constructionEscape } from "./construction-escapes.js"; +import { constructionEscape, mentionsReceiver } from "./construction-escapes.js"; import { checkedClassConstruction, checkedClassConstructionPacked } from "./class-construction.js"; import { initializeRuntimeStatics, hasRuntimeStatics } from "./class-runtime-statics.js"; import { reflectedClassStaticMethodValue } from "./class-method-values.js"; @@ -468,6 +468,11 @@ export interface ClassInfo { * unassigned read throws the catchable TypeError instead of yielding * an undefined the declared type cannot hold (SEMANTICS.md). */ deferredInitFields?: Set; + /** Fields (inherited included) that code construction exposes the + * instance to can read before their assignment: the slot is the + * undefined-armed union, allocation writes undefined, and reads yield the + * union value, so an early read sees undefined as in Node. */ + earlyReadFields?: Set; /** True when construction may hand the instance to other code (a method * call, an argument, a callback, or a base constructor that does) — a * subclass's own fields can then be read before their assignment. */ @@ -3473,55 +3478,54 @@ export function collectClassShapeInner( const derived = decl.heritageClauses?.some((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword) ?? false; - // Generic instances and mixins share layouts across declarations, so - // they only report whether construction exposes the instance. - const escape: { escapes: boolean; assigned: Set | null } = - familyMode || mixin - ? { escapes: derived, assigned: null } - : constructionEscape({ - ctor, - fields: fieldOrder.flatMap((f) => - paramProps.some((pp) => pp.name === f.name) - ? [] - : [{ name: f.name, initializer: f.initializer }], - ), - paramProps: paramProps.map((pp) => pp.name), - derived, - baseEscapes: - base === null || - callableBase !== undefined || - factoryBaseExpression !== undefined || - base.constructionEscapes === true, - isField: (name) => - fields.has(name) && - !methods.has(`set:${name}`) && - !lowerer.findMethodOn(base, `set:${name}`), - privateMethodBody: (call) => { - const callee = call.expression; - if (!ts.isPropertyAccessExpression(callee)) return null; - const name = callee.name.text; - const declaration = decl.members.find( - (member): member is ts.MethodDeclaration => - ts.isMethodDeclaration(member) && - member.body !== undefined && - (ts.isIdentifier(member.name) || ts.isPrivateIdentifier(member.name)) && - member.name.text === name, - ); - if (!declaration?.body || declaration.asteriskToken) return null; - const modifiers = ts.getModifiers(declaration) ?? []; - if ( - modifiers.some( - (m) => - m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.AsyncKeyword, - ) + // A generic family is not emitted; its instances and each mixin + // application analyze their own construction with their actual base. + const escape: { escapes: boolean; assigned: Set | null } = familyMode + ? { escapes: derived, assigned: null } + : constructionEscape({ + ctor, + fields: fieldOrder.flatMap((f) => + paramProps.some((pp) => pp.name === f.name) + ? [] + : [{ name: f.name, initializer: f.initializer }], + ), + paramProps: paramProps.map((pp) => pp.name), + derived, + baseEscapes: + base === null || + callableBase !== undefined || + factoryBaseExpression !== undefined || + base.constructionEscapes === true, + isField: (name) => + fields.has(name) && + !methods.has(`set:${name}`) && + !lowerer.findMethodOn(base, `set:${name}`), + privateMethodBody: (call) => { + const callee = call.expression; + if (!ts.isPropertyAccessExpression(callee)) return null; + const name = callee.name.text; + const declaration = decl.members.find( + (member): member is ts.MethodDeclaration => + ts.isMethodDeclaration(member) && + member.body !== undefined && + (ts.isIdentifier(member.name) || ts.isPrivateIdentifier(member.name)) && + member.name.text === name, + ); + if (!declaration?.body || declaration.asteriskToken) return null; + const modifiers = ts.getModifiers(declaration) ?? []; + if ( + modifiers.some( + (m) => + m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.AsyncKeyword, ) - return null; - const isPrivate = - ts.isPrivateIdentifier(declaration.name) || - modifiers.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword); - return isPrivate ? declaration.body : null; - }, - }); + ) + return null; + const isPrivate = + ts.isPrivateIdentifier(declaration.name) || + modifiers.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword); + return isPrivate ? declaration.body : null; + }, + }); // The deferred definite-assignment check: a field on the unguarded // list passes only with an unconditional `this.x = ...` at the // constructor's TOP LEVEL — the same standard the JS-class path @@ -3577,18 +3581,30 @@ export function collectClassShapeInner( } } - if (escape.assigned && !inst) { + // Fields assigned after construction can expose the instance (a method + // call, a base constructor that calls an override) can be read while + // Node still holds undefined. Their slots admit undefined, allocation + // writes it, and reads yield it, as in Node. + const earlyReadFields = new Set(base?.earlyReadFields ?? []); + if (escape.assigned && escape.escapes) { for (const f of fieldOrder) { if (f.redeclared || escape.assigned.has(f.name) || deferredInitFields.has(f.name)) continue; - if (paramProps.some((pp) => pp.name === f.name)) continue; const declared = fields.get(f.name); - if (declared?.kind !== "object" || lowerer.classes.get(declared.className)?.def.runtime) + if (declared === undefined || !earlyReadable(lowerer, declared)) continue; + // A declared `T | undefined` field already starts undefined. + if (declared.kind === "union" && lowerer.armTag(declared.unionId, UNDEFINED_T) >= 0) continue; - const armed = lowerer.withUndefinedArm(declared); - if (armed === null || armed.kind !== "union") continue; + const armed = lowerer.runtimeOptionalType(declared); + if (armed.kind !== "union") continue; fields.set(f.name, armed); f.type = armed; - deferredInitFields.add(f.name); + // Primitive and union slots yield the undefined value itself. + // Reference slots keep the deferred-init reads: consumers that + // observe undefined (printing, equality, typeof, nullish defaults) + // see it, and member access on it throws a TypeError, as in Node. + if (declared.kind === "union" || PRIMITIVE_EARLY_READS.has(declared.kind)) + earlyReadFields.add(f.name); + else deferredInitFields.add(f.name); } } @@ -3693,6 +3709,43 @@ export function collectClassShapeInner( (name) => !hasAccessor(name) && !methods.has(name) && !lowerer.findMethodOn(base, name), ) : null; + // Constructor statements that run after the instance may have been + // exposed (a method call, `this` passed along, a base constructor + // that exposes it): a field they create can be read before its + // assignment, while Node holds undefined. + const exposedBefore = new Set(); + { + let exposed = false; + for (const stmt of ctor?.body?.statements ?? []) { + const expression = ts.isExpressionStatement(stmt) ? stmt.expression : null; + if ( + expression && + ts.isCallExpression(expression) && + expression.expression.kind === ts.SyntaxKind.SuperKeyword + ) { + if (base?.constructionEscapes === true || expression.arguments.some(mentionsReceiver)) + exposed = true; + continue; + } + const assigned = + expression && + ts.isBinaryExpression(expression) && + expression.operatorToken.kind === ts.SyntaxKind.EqualsToken && + ts.isPropertyAccessExpression(expression.left) && + expression.left.expression.kind === ts.SyntaxKind.ThisKeyword + ? expression + : null; + if (exposed || (assigned && mentionsReceiver(assigned.right))) exposedBefore.add(stmt); + const plainAssignment = + assigned !== null && + ts.isPropertyAccessExpression(assigned.left) && + !mentionsReceiver(assigned.right) && + !hasAccessor(assigned.left.name.text) && + !methods.has(assigned.left.name.text) && + !lowerer.findMethodOn(base, assigned.left.name.text); + if (!plainAssignment && mentionsReceiver(stmt)) exposed = true; + } + } if (ctor?.body) { for (const stmt of ctor.body.statements) { const lhs = @@ -3763,8 +3816,15 @@ export function collectClassShapeInner( type = inheritedJsFieldType(lowerer, decl, name, type); // super() can invoke a subclass setter or method before its // constructor assignments run. These slots start undefined. - if (base && lowerer.dynConvertible(type) && !sealedPrefix?.created.has(name)) - type = DYN; + const sealed = sealedPrefix?.created.has(name) === true; + if (base && lowerer.dynConvertible(type) && !sealed) type = DYN; + if (exposedBefore.has(stmt) && !sealed && earlyReadable(lowerer, type)) { + const armed = lowerer.runtimeOptionalType(type); + if (armed.kind === "union") { + type = armed; + earlyReadFields.add(name); + } + } fields.set(name, type); fieldOrder.push({ name, type, initializer: undefined }); continue; @@ -4025,6 +4085,7 @@ export function collectClassShapeInner( ? { classDecorators: { nodes: classDecoratorNodes } } : {}), ...(deferredInitFields.size > 0 ? { deferredInitFields } : {}), + ...(earlyReadFields.size > 0 ? { earlyReadFields } : {}), ...(escape.escapes ? { constructionEscapes: true as const } : {}), }; // GENERIC members get their declaring-class backlink now that the @@ -6199,6 +6260,33 @@ function overrideReturnAbi( return declared; } +/** Field kinds whose early reads yield the undefined value (earlyReadFields). */ +const PRIMITIVE_EARLY_READS: ReadonlySet = new Set([ + "f64", + "bool", + "string", + "bigint", +]); + +/** Field types whose slot can admit undefined for reads before the field's + * assignment. Date values are scalars, so their unassigned slot is memory + * safe; checked-dynamic slots already hold undefined. */ +function earlyReadable(lowerer: Lowerer, type: IrType): boolean { + if (isUnitType(type)) return false; + switch (type.kind) { + case "dyn": + case "void": + case "date": + case "generator": + case "caught": + return false; + case "object": + return lowerer.classes.get(type.className)?.def.runtime !== true; + default: + return true; + } +} + /** The nearest declaration of `name` at or above `info` — the method a * receiver of that static class runs when nothing below overrides it. */ export function findMethodOn( @@ -7628,7 +7716,11 @@ function paramPropInitStmts(lowerer: Lowerer, info: ClassInfo, thisLocal: IrLoca obj: { kind: "varRef", localId: thisLocal.id, type: thisType, loc }, className: info.def.name, field: pp.name, - value: { kind: "varRef", localId: local!.id, type: local!.type, loc }, + // An early-readable field's slot admits undefined (earlyReadFields). + value: lowerer.coerceToExpected( + { kind: "varRef", localId: local!.id, type: local!.type, loc }, + info.fields.get(pp.name) ?? local!.type, + ), loc, }); } diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index d2d990e16..8777cb960 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -3133,6 +3133,51 @@ export function lowerTernary( * the same union (unnarrowed use), to a SUB-union (partial narrowing — * unrepresentable without a re-tag), or to nothing (`never` in an * exhaustive default) leaves the expression union-typed. */ +/** Uses that read an early-read field's value as Node does when it is + * undefined: printing, templates, operators, tests, member access, calls of + * program functions (whose parameters the optional-value analysis widens), + * and stores into bindings, fields and returns. Other uses, such as library + * arguments, extract the declared type with a check. */ +function observesEarlyRead(node: ts.Node): boolean { + let child = node; + let parent = node.parent; + while (parent && ts.isParenthesizedExpression(parent)) { + child = parent; + parent = parent.parent; + } + if (!parent) return false; + if ( + ts.isTemplateSpan(parent) || + ts.isBinaryExpression(parent) || + ts.isPrefixUnaryExpression(parent) || + ts.isPostfixUnaryExpression(parent) || + ts.isTypeOfExpression(parent) || + ts.isConditionalExpression(parent) || + ts.isIfStatement(parent) || + ts.isWhileStatement(parent) || + ts.isReturnStatement(parent) || + ts.isVariableDeclaration(parent) || + ts.isPropertyAssignment(parent) || + ts.isArrayLiteralExpression(parent) || + (ts.isPropertyAccessExpression(parent) && parent.expression === child) || + (ts.isElementAccessExpression(parent) && parent.expression === child) + ) + return true; + if (ts.isCallExpression(parent) && parent.arguments.includes(child as ts.Expression)) { + const callee = parent.expression; + if ( + ts.isPropertyAccessExpression(callee) && + ts.isIdentifier(callee.expression) && + callee.expression.text === "console" + ) + return true; + return ( + !ts.isPropertyAccessExpression(callee) || callee.expression.kind === ts.SyntaxKind.ThisKeyword + ); + } + return false; +} + export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrExpr { if ( (expr.type.kind === "union" || expr.type.kind === "dyn") && @@ -3343,6 +3388,25 @@ export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrEx if (expr.type.kind !== "union") return expr; if (ts.isPropertyAccessExpression(node) && isOptionalProcessStreamProperty(lowerer, node)) return expr; + // A field read before its assignment holds undefined although its + // declared type omits it; the declared type is no narrowing proof. A flow + // narrowing past the declared type (`if (this.x !== null)`) extracts the + // narrowed arm with a check, since the slot may still hold undefined. + if ( + expr.kind === "fieldGet" && + lowerer.classes.get(expr.className)?.earlyReadFields?.has(expr.field) === true + ) { + const symbol = ts.isPropertyAccessExpression(node) + ? lowerer.checker.getSymbolAtLocation(node.name) + : undefined; + const declared = symbol ? lowerer.mapTypeOf(lowerer.checker.getTypeOfSymbol(symbol)) : null; + const narrowedArm = lowerer.mapTypeOf(lowerer.typeOf(node)); + if (narrowedArm === null || narrowedArm.kind === "union") return expr; + if (declared !== null && typeEquals(declared, narrowedArm) && observesEarlyRead(node)) + return expr; + const helper = lowerer.narrowedArmHelper(expr.type.unionId, narrowedArm, expr.loc); + return helper ? lowerer.checkedNarrowCall(helper, expr, narrowedArm, expr.loc) : expr; + } // Represented fields and index values can include undefined even when // checker inference or lib.d.ts declares strings (RegExp captures). @@ -15103,6 +15167,20 @@ export function fieldGetExpr( const helper = lowerer.deferredReadHelper(target.fieldType.unionId, inner, loc); if (helper) return { kind: "call", callee: helper, args: [read], type: inner, loc }; } + // An early-read field (ClassInfo.earlyReadFields) yields its undefined + // where the use reads it as Node does; elsewhere the declared type is + // extracted with a check. + if ( + target.fieldType.kind === "union" && + lowerer.classes.get(target.className)?.earlyReadFields?.has(target.field) === true && + !observesEarlyRead(blame) + ) { + const declared = lowerer.mapTypeOf(lowerer.typeOf(blame)); + if (declared && declared.kind !== "union") { + const helper = lowerer.narrowedArmHelper(target.fieldType.unionId, declared, loc); + if (helper) return lowerer.checkedNarrowCall(helper, read, declared, loc); + } + } return read; } return { @@ -15643,6 +15721,22 @@ function lowerFieldCompoundValue( if (op === "+" && read.type.kind === "string") { appended = lowerer.ensureString(rhs, rhsNode ?? access); value = { kind: "strConcat", left: read, right: appended, type: STRING, loc }; + } else if ( + op === "+" && + read.type.kind === "union" && + lowerer.stripUndefinedArm(read.type).kind === "string" && + target.container === "class" && + lowerer.classes.get(target.className)?.earlyReadFields?.has(target.field) === true + ) { + // A string field read before its assignment holds undefined, which + // concatenates as "undefined". + value = { + kind: "strConcat", + left: lowerer.ensureString(read, access), + right: lowerer.ensureString(rhs, rhsNode ?? access), + type: STRING, + loc, + }; } else if (numericRead.type.kind === "f64" && numericRhs.type.kind === "f64") { value = { kind: "bin", op, left: numericRead, right: numericRhs, type: F64, loc }; } else if (bigintValue) { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 087b4e628..eeba5c8fb 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -3933,6 +3933,18 @@ export class Lowerer { if (!s) return null; return s.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(s) : s; }; + // Fields that can be read before their assignment hold undefined then; + // their reads are runtime-optional values like missing array reads. + for (const info of this.classes.values()) { + if (!info.earlyReadFields || !info.decl?.name) continue; + const classSymbol = symbolOf(info.decl.name); + if (!classSymbol) continue; + const instance = this.checker.getDeclaredTypeOfSymbol(classSymbol); + for (const name of info.earlyReadFields) { + const property = this.checker.getPropertyOfType(instance, name); + if (property) optionalSymbols.add(property); + } + } const signatureOf = (node: ts.Identifier): FnSig | null => { const symbol = symbolOf(node); if (!symbol) return null; diff --git a/packages/compiler/test/class-early-field-reads.test.ts b/packages/compiler/test/class-early-field-reads.test.ts new file mode 100644 index 000000000..c602a2f42 --- /dev/null +++ b/packages/compiler/test/class-early-field-reads.test.ts @@ -0,0 +1,93 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule, validateModule } from "../src/index.js"; +import type { IrModule } from "../src/ir/ir.js"; + +async function lower(source: string, file = "main.ts"): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-early-field-reads-")); + try { + const entry = join(dir, file), + output = join(dir, "main.ir.json"); + await writeFile(entry, source); + const result = await compile(entry, { outDir: dir, outPath: output, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((item) => `${item.code}: ${item.message}`).join("\n")); + const module = deserializeModule(await readFile(output, "utf8")); + expect(validateModule(module)).toEqual([]); + return module; + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +/** Field name → IR kind for a class. */ +function fields(module: IrModule, name: string): string { + const cls = module.classes.find((candidate) => candidate.name === name); + expect(cls, name).toBeDefined(); + return cls!.fields + .filter((field) => !field.name.startsWith("%")) + .map((field) => `${field.name}:${field.type.kind}`) + .join(" "); +} + +test("fields assigned after construction can call an override admit undefined", async () => { + const module = await lower(` +abstract class Base { + constructor() { + this.describe(); + } + abstract describe(): void; +} +class Panel extends Base { + label: string; + width: number; + count = 0; + constructor() { + super(); + this.label = "panel"; + this.width = 2; + } + describe(): void { + console.log(this.label, this.width, this.count); + } +} +class Plain { + label: string; + width: number; + constructor() { + this.label = "plain"; + this.width = 1; + this.describe(); + } + describe(): void { + console.log(this.label, this.width); + } +} +new Panel(); +new Plain(); +`); + expect(fields(module, "Panel")).toBe("label:union width:union count:union"); + expect(fields(module, "Plain")).toBe("label:string width:f64"); +}); + +test("JavaScript fields created after the constructor calls a method admit undefined", async () => { + const module = await lower( + ` +class Widget { + constructor() { + this.ready = true; + this.render(); + this.title = "widget"; + } + render() { + console.log(this.ready, this.title); + } +} +new Widget(); +`, + "main.js", + ); + expect(fields(module, "Widget")).toBe("ready:bool title:union"); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json new file mode 100644 index 000000000..d2dcdcc24 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5943-fields-read-before-assignment.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json new file mode 100644 index 000000000..e9800b71d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5944-js-fields-read-before-assignment.js" + ], + "diags": [] +} diff --git a/tests/corpus/5943-fields-read-before-assignment.ts b/tests/corpus/5943-fields-read-before-assignment.ts new file mode 100644 index 000000000..922b3c34d --- /dev/null +++ b/tests/corpus/5943-fields-read-before-assignment.ts @@ -0,0 +1,181 @@ +// @transform-types +// Fields that a base constructor (or the constructor itself) can read +// through an override or a method call before they are assigned hold +// undefined then, as in Node, for every field kind. After construction +// the fields read and update normally. +class Point { + x: number; + constructor(x: number) { + this.x = x; + } +} +function show(label: string, value: number): string { + return `${label}=${value}`; +} +abstract class Widget { + log: string[] = []; + constructor() { + this.describe("base"); + } + abstract describe(when: string): void; +} +class Panel extends Widget { + label: string; + width: number; + visible: boolean; + origin: Point; + items: number[]; + options: { depth: number }; + key: string | number; + index: Map; + tags: Set; + count = 5; + constructor(label: string, readonly id: string) { + super(); + this.label = label; + this.width = 10; + this.visible = true; + this.origin = new Point(1); + this.items = [1, 2]; + this.options = { depth: 2 }; + this.key = 7; + this.index = new Map([["a", 1]]); + this.tags = new Set(["t"]); + this.describe("ctor"); + } + describe(when: string): void { + console.log(when, this.label, this.width, this.visible, this.origin, this.items, this.options, this.key, this.count, this.id); + console.log(when, `${this.label}:${this.width}`, this.width + 1, this.count * 2, this.label === undefined, typeof this.items, this.origin?.x, this.options?.depth ?? -1, this.index?.size, this.tags?.has("t")); + console.log(when, show(this.label, this.width), String(this.key), [this.label].length); + try { + console.log(this.label.length, this.items.length); + } catch (error) { + console.log(when, (error as Error).message); + } + } + grow(): number { + this.count++; + this.width += 5; + this.label += "!"; + this.items.push(this.width); + return this.count + this.width + this.items.length; + } +} +const panel = new Panel("main", "p1"); +console.log(panel.grow(), panel.label, panel.items, panel.count, panel.width); + +class Plain { + total: number; + name: string; + constructor() { + this.total = 1; + this.name = "plain"; + this.bump(); + } + bump(): void { + this.total++; + } +} +const plain = new Plain(); +console.log(plain.total, plain.name); + +class Toucher { + constructor() { + this.touch(); + } + touch(): void {} +} +class Counter extends Toucher { + count = 0; + label: string; + items: string[]; + constructor() { + super(); + this.label = "c"; + this.items = []; + } + override touch(): void { + this.count++; + this.label += "x"; + console.log(this.count, this.label, Number.isNaN(this.count)); + try { + this.items.push("a"); + } catch (error) { + console.log(error instanceof TypeError); + } + } +} +const c = new Counter(); +c.touch(); +console.log(c.count, c.label, c.items); + +class Shower { + constructor() { + this.show(); + } + show(): void {} +} +class Box extends Shower { + label: string; + value: T; + constructor(value: T) { + super(); + this.label = "box"; + this.value = value; + } + override show(): void { + console.log("show", this.label, this.value); + } +} +new Box(3).show(); +new Box("s").show(); + +type Ctor = new (...args: any[]) => T; +class Viewer { + constructor() { + this.show(); + } + show(): void {} +} +function Labeled>(Parent: B) { + return class extends Parent { + label = "mixed"; + override show(): void { + console.log("show", this.label); + } + }; +} +const L = Labeled(Viewer); +new L().show(); + +interface Crash { loc: number; message: string } +class Setupper { + constructor() { + this.setup(); + } + setup(): void {} +} +class Host extends Setupper { + crash: Crash | null; + name: string | null; + constructor(c: Crash | null) { + super(); + this.crash = c; + this.name = "host"; + } + override setup(): void { + console.log("setup", this.crash, this.name); + if (this.crash !== null) { + try { + console.log(this.crash.loc); + } catch (error) { + console.log(error instanceof TypeError); + } + } + } + report(): string { + if (this.crash) return `${this.crash.message} at ${this.crash.loc}`; + return this.name === null ? "none" : this.name.toUpperCase(); + } +} +console.log(new Host({ loc: 3, message: "boom" }).report(), new Host(null).report()); diff --git a/tests/corpus/5944-js-fields-read-before-assignment.js b/tests/corpus/5944-js-fields-read-before-assignment.js new file mode 100644 index 000000000..e313a12b0 --- /dev/null +++ b/tests/corpus/5944-js-fields-read-before-assignment.js @@ -0,0 +1,28 @@ +// JavaScript class fields that the constructor creates after it calls a +// method, or after a base constructor that does, hold undefined until +// they are assigned, as in Node. +class Widget { + constructor(name) { + this.render(); + this.name = name; + this.size = 3; + this.title = "widget"; + this.parts = ["a"]; + this.meta = { id: 1 }; + } + render() { + console.log("render", this.name, this.title, this.size, this.parts, this.meta, this.size + 1, `${this.name}!`); + } +} +class Big extends Widget { + constructor() { + super("big"); + this.extra = 2; + } + render() { + super.render(); + console.log("big", this.extra); + } +} +new Widget("w").render(); +new Big().render(); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 2c80c39a2..a3f845cf8 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1869,6 +1869,8 @@ "5842-qs-parse-null-prototype.ts": 1774, "5843-qs-parse-null-prototype-js.mjs": 1559, "5844-date-unknown-values.ts": 3969, + "5846-events-esm-default-max.ts": 2633, + "5847-events-cjs-default-max.cjs": 2823, "5857-regexp-unicode-sets.ts": 3350, "5858-disposable-stack.ts": 3050, "5859-disposable-stack-js.js": 3100, @@ -1899,6 +1901,8 @@ "5923-matchall-groups-js.js": 3970, "5939-js-let-object-reassigned-wider.js": 1945, "5942-local-class-observed-methods.ts": 5063, + "5943-fields-read-before-assignment.ts": 6856, + "5944-js-fields-read-before-assignment.js": 4247, "5950-tuple-predicate-methods.ts": 5990, "5951-result-never-widening.ts": 4710, "5955-any-promise-methods.js": 3940, @@ -1913,8 +1917,6 @@ "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, - "5846-events-esm-default-max.ts": 2633, - "5847-events-cjs-default-max.cjs": 2823, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4569,6 +4571,8 @@ "5842-qs-parse-null-prototype.ts": 7077, "5843-qs-parse-null-prototype-js.mjs": 5395, "5844-date-unknown-values.ts": 4543, + "5846-events-esm-default-max.ts": 3102, + "5847-events-cjs-default-max.cjs": 3039, "5857-regexp-unicode-sets.ts": 3900, "5858-disposable-stack.ts": 3750, "5859-disposable-stack-js.js": 3600, @@ -4599,6 +4603,8 @@ "5923-matchall-groups-js.js": 6650, "5939-js-let-object-reassigned-wider.js": 4436, "5942-local-class-observed-methods.ts": 6212, + "5943-fields-read-before-assignment.ts": 72293, + "5944-js-fields-read-before-assignment.js": 40310, "5950-tuple-predicate-methods.ts": 7790, "5951-result-never-widening.ts": 6120, "5955-any-promise-methods.js": 5120, @@ -4613,8 +4619,6 @@ "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, - "5846-events-esm-default-max.ts": 3102, - "5847-events-cjs-default-max.cjs": 3039, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 33c9d917960928d1f55b7ce39d4bee0dd23ceda7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 09:17:29 -0500 Subject: [PATCH 081/117] Widen nested record fields with the records that hold them A record held in another record's field (`state.parsed`) and passed to a function that stores a possibly missing array element in it kept its declared layout, so the store threw where Node stores undefined. The field read opened the record flow class of the function's parameter. Such a field read now gets a field slot in the record flow classes. Field slots join the same field of every member of the owner's class, take the values literals and assignments store in the field, and widen only when the owner's class can take the new layout too. Every member of the owner's class then holds the widened record, so writes and identity are kept. An owner that is spread, destructured or passed to Object.values or Object.entries keeps the declared layout. --- .../compiler/src/frontend/lowering/lowerer.ts | 63 ++++-- .../lowering/runtime-optional-records.test.ts | 18 ++ .../lowering/runtime-optional-records.ts | 180 +++++++++++++++++- ...ested-record-field-optional-writes.ts.json | 6 + ...946-nested-record-field-optional-writes.ts | 43 +++++ tests/harness/corpus-costs.json | 10 +- 6 files changed, 295 insertions(+), 25 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5946-nested-record-field-optional-writes.ts.json create mode 100644 tests/corpus/5946-nested-record-field-optional-writes.ts diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 087b4e628..1977ec3a6 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -5851,25 +5851,61 @@ export class Lowerer { addClassFields(recordFlows.bindingClass(symbol), fields); for (const [symbol, fields] of returnFields) addClassFields(recordFlows.returnClass(symbol), fields); + // A record field that flows into other slots (`fill(args, state.parsed)`) + // widens with its owner's class: every member takes the field's widened + // layout, so the field and the slots it reaches share one record. + const nestedFields = new Map>(); + for (let changed = true; changed;) { + changed = false; + for (const { owner, name, classId } of recordFlows.fields()) { + if (nestedFields.get(owner)?.has(name)) continue; + if (!(classFields.has(classId) || nestedFields.has(classId))) continue; + if (!recordFlows.closed(classId)) continue; + const byName = nestedFields.get(owner) ?? new Map(); + byName.set(name, classId); + nestedFields.set(owner, byName); + changed = true; + } + } const settledFields = ( id: number | null, own: ReadonlySet | undefined, ): ReadonlySet | undefined => id === null ? own - : classFields.has(id) && recordFlows.closed(id) - ? classFields.get(id) + : (classFields.has(id) || nestedFields.has(id)) && recordFlows.closed(id) + ? (classFields.get(id) ?? new Set()) : undefined; - const widenRecordFields = (type: IrType, fields: ReadonlySet): IrType => { + const widenRecordFields = ( + type: IrType, + fields: ReadonlySet, + id: number | null = null, + seen: ReadonlySet = new Set(), + ): IrType => { let promoted = type; + const fieldOf = (name: string) => + promoted.kind === "record" + ? this.shapes.get(promoted.shapeId)?.fields.find((f) => f.name === name) + : undefined; for (const field of fields) { - const source = - promoted.kind === "record" - ? this.shapes.get(promoted.shapeId)?.fields.find((f) => f.name === field) - : undefined; + const source = fieldOf(field); if (source) promoted = this.runtimeOptionalRecordField(promoted, field, addUndefined(source.type)); } + if (id === null || seen.has(id)) return promoted; + const nested = nestedFields.get(id); + if (!nested) return promoted; + for (const [field, inner] of nested) { + const source = fieldOf(field); + if (source?.type.kind !== "record") continue; + const widened = widenRecordFields( + source.type, + classFields.get(inner) ?? new Set(), + inner, + new Set([...seen, id]), + ); + promoted = this.runtimeOptionalRecordField(promoted, field, widened); + } return promoted; }; for (const [symbol, id] of recordFlows.bindings()) @@ -5884,9 +5920,10 @@ export class Lowerer { for (const [bound, { target, index }] of recordParameterSlots) { const shape = signatureBySymbol.get(target)?.params[index]; if (!shape || shape.type.kind !== "record") continue; - const fields = settledFields(recordFlows.bindingClass(bound), optionalFields.get(bound)); + const id = recordFlows.bindingClass(bound); + const fields = settledFields(id, optionalFields.get(bound)); if (!fields) continue; - const promoted = widenRecordFields(shape.type, fields); + const promoted = widenRecordFields(shape.type, fields, id); if (typeEquals(promoted, shape.type)) continue; shape.type = promoted; this.runtimeOptionalBindingTypes.set(bound, promoted); @@ -5895,7 +5932,7 @@ export class Lowerer { const id = recordFlows.returnClass(symbol); const fields = id === null ? undefined : settledFields(id, undefined); if (fields && sig.returnType.kind === "record") { - const next = widenRecordFields(sig.returnType, fields); + const next = widenRecordFields(sig.returnType, fields, id); sig.returnType = next; if (sig.top) sig.top.returnType = next; if (sig.method) sig.method.ret = next; @@ -5981,7 +6018,8 @@ export class Lowerer { if (global) global.type = promoted; } } - const fields = settledFields(recordFlows.bindingClass(symbol), optionalFields.get(symbol)); + const flowClass = recordFlows.bindingClass(symbol); + const fields = settledFields(flowClass, optionalFields.get(symbol)); if (!dynamicObjectEntryRows.has(symbol) && !optionalSymbols.has(symbol) && !fields) return; const current = this.mapTypeOf(this.typeOf(node.name)); if (!current) return; @@ -5998,7 +6036,8 @@ export class Lowerer { }; } } - if (fields && promoted.kind === "record") promoted = widenRecordFields(promoted, fields); + if (fields && promoted.kind === "record") + promoted = widenRecordFields(promoted, fields, flowClass); if (!typeEquals(promoted, current)) { this.runtimeOptionalBindingTypes.set(symbol, promoted); const global = ts.isIdentifier(node.name) diff --git a/packages/compiler/src/frontend/lowering/runtime-optional-records.test.ts b/packages/compiler/src/frontend/lowering/runtime-optional-records.test.ts index 2ca59739d..f95694624 100644 --- a/packages/compiler/src/frontend/lowering/runtime-optional-records.test.ts +++ b/packages/compiler/src/frontend/lowering/runtime-optional-records.test.ts @@ -53,6 +53,8 @@ function classes(source: string): { : null, declarationOf: (symbol) => declarations.get(symbol), recordShape: (node) => { + // Field slots: a binding's field read where a record is expected. + if (ts.isPropertyAccessExpression(node)) return "R"; const declaration = node.parent; if (!declaration) return null; if (ts.isParameter(declaration)) return annotated(declaration.type); @@ -183,3 +185,19 @@ test("assignments join their target and a foreign value opens it", () => { expect(flows.closed("target")).toBe(true); expect(flows.closed("foreign")).toBe(false); }); + +test("a binding's record field joins the slots it reaches and widens with its owner", () => { + const flows = classes(` + function fill(into: R): void { into.v = 1; } + const state = { parsed: { v: 0 } }; + fill(state.parsed); + function mark(m: R): void { m.v = 2; } + const spread = { parsed: { v: 0 } }; + mark(spread.parsed); + console.log({ ...spread }); + `); + expect(flows.closed("into")).toBe(true); + expect(flows.closed("state")).toBe(true); + // A spread copies the field out of its owner, so the record keeps its layout. + expect(flows.closed("m")).toBe(false); +}); diff --git a/packages/compiler/src/frontend/lowering/runtime-optional-records.ts b/packages/compiler/src/frontend/lowering/runtime-optional-records.ts index 0ecdd62b3..334f94d4f 100644 --- a/packages/compiler/src/frontend/lowering/runtime-optional-records.ts +++ b/packages/compiler/src/frontend/lowering/runtime-optional-records.ts @@ -85,6 +85,20 @@ export class RecordFlowClasses { /** Names written as shorthand properties (`{ p }`): the checker resolves * those to the property, so a binding of that name stays open. */ private readonly shorthandNames = new Set(); + /** Record fields of tracked bindings that flow between slots + * (`fill(args, state.parsed)`), by owner symbol and field name. A field + * slot widens only with its owner, whose layout holds it. */ + private readonly fieldSlots = new Map>(); + /** The owner binding slot of each field slot. */ + private readonly fieldOwners = new Map(); + /** Object literals entering each slot; their property values enter the + * class's field slots. */ + private readonly literalSources: { slot: number; literal: ts.ObjectLiteralExpression }[] = []; + /** Slots whose field values are copied out whole (a spread, a + * destructuring, `Object.values`), so a nested record would convert. */ + private readonly copiedOut = new Set(); + /** Counts merges and openings, so field joins run until stable. */ + private changes = 0; constructor( private readonly files: readonly ts.SourceFile[], @@ -94,6 +108,7 @@ export class RecordFlowClasses { this.collectFunctions(); this.collectSlots(); this.connect(); + this.connectFields(); } /** The class id of a binding or parameter slot, or null when the symbol @@ -160,9 +175,27 @@ export class RecordFlowClasses { shape = own; } this.shapeChecked.set(root, uniform); + // A field slot takes a widened layout only with its owner's class. + for (const [slot, owner] of this.fieldOwners) { + if (!uniform) break; + if (this.find(slot) === root && !this.closed(owner)) uniform = false; + } + this.shapeChecked.set(root, uniform); return uniform; } + /** Every field slot: its owner's class, the field name and its class. */ + fields(): { owner: number; name: string; classId: number }[] { + const out: { owner: number; name: string; classId: number }[] = []; + for (const byName of this.fieldSlots.values()) { + for (const [name, slot] of byName) { + const owner = this.fieldOwners.get(slot)!; + out.push({ owner: this.find(owner), name, classId: this.find(slot) }); + } + } + return out; + } + private newSlot(node: ts.Node, isReturn = false): number { const id = this.parent.length; this.parent.push(id); @@ -189,10 +222,109 @@ export class RecordFlowClasses { if (ra === rb) return; this.parent[rb] = ra; this.open[ra] = this.open[ra]! || this.open[rb]!; + this.changes++; } private markOpen(slot: number): void { - this.open[this.find(slot)] = true; + const root = this.find(slot); + if (!this.open[root]) this.changes++; + this.open[root] = true; + } + + /** The slot of a tracked binding's record field, created on first use. */ + private fieldSlot(owner: ts.Symbol, name: string, node: ts.Node): number | undefined { + const ownerSlot = this.bindingSlots.get(owner); + if (ownerSlot === undefined) return undefined; + let byName = this.fieldSlots.get(owner); + if (!byName) { + byName = new Map(); + this.fieldSlots.set(owner, byName); + } + let slot = byName.get(name); + if (slot === undefined) { + slot = this.newSlot(node); + byName.set(name, slot); + this.fieldOwners.set(slot, ownerSlot); + this.changes++; + } + return slot; + } + + /** `binding.name` where the binding is a tracked slot. */ + private fieldAccess(node: ts.Node): { owner: ts.Symbol; name: string } | null { + if (!ts.isPropertyAccessExpression(node) || !ts.isIdentifier(node.expression)) return null; + if (!ts.isIdentifier(node.name)) return null; + const owner = this.host.symbolOf(node.expression); + return owner && this.bindingSlots.has(owner) ? { owner, name: node.name.text } : null; + } + + /** Joins each field slot with the same field of every member of its + * owner's class, gives it the values that literals and assignments store + * in the field, and opens it with its owner, until no class changes. */ + private connectFields(): void { + const visitedUses = new Set(); + const visitedLiterals = new Set(); + for (let before = -1; before !== this.changes;) { + before = this.changes; + // Grouped once per pass; joins made during a pass show in the next. + const members = new Map(); + for (const [symbol, slot] of this.bindingSlots) addTo(members, this.find(slot), symbol); + const literals = new Map(); + this.literalSources.forEach(({ slot }, i) => addTo(literals, this.find(slot), i)); + const copied = new Set([...this.copiedOut].map((slot) => this.find(slot))); + for (const [symbol, byName] of [...this.fieldSlots]) { + const root = this.find(this.bindingSlots.get(symbol)!); + for (const [name, field] of [...byName]) { + for (const member of members.get(root) ?? []) { + const peer = this.fieldSlot(member, name, this.slotNodes[field]!)!; + this.union(field, peer); + const key = `${this.bindingSlots.get(member)}:${name}`; + if (visitedUses.has(key)) continue; + visitedUses.add(key); + for (const reference of this.referencesOf(member)) this.fieldUse(reference, name, peer); + } + for (const i of literals.get(root) ?? []) { + const key = `${i}:${name}`; + if (visitedLiterals.has(key)) continue; + visitedLiterals.add(key); + for (const property of this.literalSources[i]!.literal.properties) { + if (ts.isSpreadAssignment(property)) { + this.markOpen(field); + continue; + } + const propertyName = property.name; + if ( + !propertyName || + !(ts.isIdentifier(propertyName) || ts.isStringLiteral(propertyName)) || + propertyName.text !== name + ) + continue; + if (ts.isPropertyAssignment(property)) this.source(property.initializer, field); + else if (ts.isShorthandPropertyAssignment(property)) + this.source(property.name as ts.Identifier, field); + else this.markOpen(field); + } + } + if (this.open[this.find(root)] || copied.has(root)) this.markOpen(field); + } + } + } + } + + /** Checks one reference to a field slot's owner: a read of the field + * (`owner.name`, `owner["name"]`) must be a member use, and a computed + * key can reach the field too. */ + private fieldUse(reference: ts.Identifier, name: string, field: number): void { + const access = reference.parent; + if (!access || (access as { expression?: ts.Node }).expression !== reference) return; + if (ts.isPropertyAccessExpression(access)) { + if (access.name.text === name && !this.use(access, field)) this.markOpen(field); + return; + } + if (!ts.isElementAccessExpression(access)) return; + const key = peel(access.argumentExpression); + if (!ts.isStringLiteral(key) && !ts.isNoSubstitutionTemplateLiteral(key)) this.markOpen(field); + else if (key.text === name && !this.use(access, field)) this.markOpen(field); } private index(): void { @@ -473,7 +605,15 @@ export class RecordFlowClasses { * when the value can be an object some other storage already holds. */ private source(node: ts.Expression, slot: number): void { const e = peel(node); - if (ts.isObjectLiteralExpression(e)) return; + if (ts.isObjectLiteralExpression(e)) { + this.literalSources.push({ slot, literal: e }); + return; + } + const access = this.fieldAccess(e); + if (access) { + this.union(slot, this.fieldSlot(access.owner, access.name, e)!); + return; + } if (ts.isIdentifier(e)) { const symbol = this.host.symbolOf(e); const other = symbol ? this.bindingSlots.get(symbol) : undefined; @@ -519,7 +659,7 @@ export class RecordFlowClasses { /** True when this reference to a member only reads or writes its fields, * passes the record to another member (a flow `source` joins), or * inspects it without keeping or converting it. */ - private use(reference: ts.Identifier, slot: number): boolean { + private use(reference: ts.Expression, slot: number): boolean { let value: ts.Node = reference; for (;;) { const user = value.parent; @@ -536,7 +676,10 @@ export class RecordFlowClasses { } if (ts.isPropertyAccessExpression(user) && user.expression === value) return true; if (ts.isElementAccessExpression(user) && user.expression === value) return true; - if (ts.isSpreadAssignment(user)) return true; + if (ts.isSpreadAssignment(user)) { + this.copiedOut.add(slot); + return true; + } if (ts.isTemplateSpan(user) || ts.isTypeOfExpression(user)) return true; if (ts.isExpressionStatement(user)) return true; if (ts.isPrefixUnaryExpression(user) && user.operator === ts.SyntaxKind.ExclamationToken) @@ -588,7 +731,8 @@ export class RecordFlowClasses { op === ts.SyntaxKind.AmpersandAmpersandEqualsToken; // A record assigned to a member joins it when the member's own // reference is visited, below. - if (assigns && user.right === value) return this.isMember(user.left); + if (assigns && user.right === value) + return this.isMember(user.left) || this.isFieldMember(user.left); if (assigns && user.left === value && value === reference) { this.source(user.right, slot); return true; @@ -597,7 +741,10 @@ export class RecordFlowClasses { return false; } if (ts.isVariableDeclaration(user) && user.initializer === value) { - if (ts.isObjectBindingPattern(user.name)) return true; + if (ts.isObjectBindingPattern(user.name)) { + this.copiedOut.add(slot); + return true; + } return this.isMember(user.name); } if (ts.isReturnStatement(user)) { @@ -629,11 +776,13 @@ export class RecordFlowClasses { } if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.expression)) { const methods = READING_CALLS.get(callee.expression.text); - return ( + const reads = !!methods && methods.has(callee.name.text) && - this.host.isGlobal(callee.expression, callee.expression.text) - ); + this.host.isGlobal(callee.expression, callee.expression.text); + if (reads && (callee.name.text === "values" || callee.name.text === "entries")) + this.copiedOut.add(slot); + return reads; } return false; } @@ -646,6 +795,19 @@ export class RecordFlowClasses { const symbol = this.host.symbolOf(node); return !!symbol && this.bindingSlots.has(symbol); } + + /** A tracked binding's field as an assignment target: the stored record + * joins the field slot when the field's uses are visited. */ + private isFieldMember(node: ts.Node): boolean { + const access = this.fieldAccess(node); + return !!access && this.fieldSlot(access.owner, access.name, node) !== undefined; + } +} + +function addTo(map: Map, key: number, value: T): void { + const list = map.get(key); + if (list) list.push(value); + else map.set(key, [value]); } /** The return expressions of a function body, excluding nested functions. */ diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5946-nested-record-field-optional-writes.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5946-nested-record-field-optional-writes.ts.json new file mode 100644 index 000000000..df296d33f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5946-nested-record-field-optional-writes.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5946-nested-record-field-optional-writes.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5946-nested-record-field-optional-writes.ts b/tests/corpus/5946-nested-record-field-optional-writes.ts new file mode 100644 index 000000000..ff1b2d25a --- /dev/null +++ b/tests/corpus/5946-nested-record-field-optional-writes.ts @@ -0,0 +1,43 @@ +// A record held in another record's field, passed to a function that stores +// a possibly missing array element in it, keeps the write and its identity, +// as in Node; the outer record's layout holds the widened field. +type Parsed = { command: string; rest: string[] }; +type Holder = { parsed: Parsed; label: string }; + +function fill(args: string[], into: Parsed): Parsed { + into.command = args[0]; + into.rest = args.slice(1); + return into; +} + +const state = { parsed: { command: "", rest: [] as string[] } }; +fill(["deep", "x"], state.parsed); +console.log(state.parsed.command, state.parsed.rest); +const alias = state.parsed; +fill([], state.parsed); +console.log(state.parsed.command, alias.command, alias === state.parsed, typeof alias.command); +console.log(state, JSON.stringify(state)); + +state.parsed = { command: "fresh", rest: [] }; +fill(["again"], state.parsed); +console.log(state.parsed.command, alias.command); + +function run(holder: Holder, args: string[]): string { + fill(args, holder.parsed); + return `${holder.label}:${holder.parsed.command ?? "none"}`; +} +console.log(run({ parsed: { command: "", rest: [] }, label: "a" }, ["go"])); +console.log(run({ parsed: { command: "", rest: [] }, label: "b" }, [])); + +function makeHolder(label: string): Holder { + return { parsed: { command: "init", rest: [] }, label }; +} +const made = makeHolder("made"); +fill([], made.parsed); +console.log(made.parsed.command === undefined, made.label); +fill(["set"], made.parsed); +console.log(made.parsed.command.toUpperCase()); + +const empty: Parsed = { command: "x", rest: [] }; +fill([], empty); +console.log(empty.command, empty.rest.length); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 2c80c39a2..da4cd097f 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1869,6 +1869,8 @@ "5842-qs-parse-null-prototype.ts": 1774, "5843-qs-parse-null-prototype-js.mjs": 1559, "5844-date-unknown-values.ts": 3969, + "5846-events-esm-default-max.ts": 2633, + "5847-events-cjs-default-max.cjs": 2823, "5857-regexp-unicode-sets.ts": 3350, "5858-disposable-stack.ts": 3050, "5859-disposable-stack-js.js": 3100, @@ -1899,6 +1901,7 @@ "5923-matchall-groups-js.js": 3970, "5939-js-let-object-reassigned-wider.js": 1945, "5942-local-class-observed-methods.ts": 5063, + "5946-nested-record-field-optional-writes.ts": 6045, "5950-tuple-predicate-methods.ts": 5990, "5951-result-never-widening.ts": 4710, "5955-any-promise-methods.js": 3940, @@ -1913,8 +1916,6 @@ "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, - "5846-events-esm-default-max.ts": 2633, - "5847-events-cjs-default-max.cjs": 2823, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4569,6 +4570,8 @@ "5842-qs-parse-null-prototype.ts": 7077, "5843-qs-parse-null-prototype-js.mjs": 5395, "5844-date-unknown-values.ts": 4543, + "5846-events-esm-default-max.ts": 3102, + "5847-events-cjs-default-max.cjs": 3039, "5857-regexp-unicode-sets.ts": 3900, "5858-disposable-stack.ts": 3750, "5859-disposable-stack-js.js": 3600, @@ -4599,6 +4602,7 @@ "5923-matchall-groups-js.js": 6650, "5939-js-let-object-reassigned-wider.js": 4436, "5942-local-class-observed-methods.ts": 6212, + "5946-nested-record-field-optional-writes.ts": 68117, "5950-tuple-predicate-methods.ts": 7790, "5951-result-never-widening.ts": 6120, "5955-any-promise-methods.js": 5120, @@ -4613,8 +4617,6 @@ "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, - "5846-events-esm-default-max.ts": 3102, - "5847-events-cjs-default-max.cjs": 3039, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From 6c4e4c39b41989d5d8bb90a9f42b6ea3852322f0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 09:23:31 -0500 Subject: [PATCH 082/117] Keep object-literal computed keys out of the method replacement census An object literal with a computed key that does not fold to a constant, such as `{ [key]: 1 }`, entered the method replacement census as a write with an unknown key and no receiver. That marked every class method name in the program as replaceable, so method calls went through the checked property lookup. A computed key in an object literal defines a property of the new object, which is not a class instance, so the census now skips it. Literals passed to Object.assign or Object.defineProperties are still judged with their receiver. Closes #962 Co-authored-by: Quim T. <26749475+espetro@users.noreply.github.com> --- .../lowering/class-method-mutations.ts | 7 +++- .../test/class-method-mutations.test.ts | 27 +++++++++++++ ...literal-computed-keys-keep-methods.ts.json | 6 +++ ...ject-literal-computed-keys-keep-methods.ts | 39 +++++++++++++++++++ tests/harness/corpus-costs.json | 10 +++-- 5 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts.json create mode 100644 tests/corpus/5938-object-literal-computed-keys-keep-methods.ts diff --git a/packages/compiler/src/frontend/lowering/class-method-mutations.ts b/packages/compiler/src/frontend/lowering/class-method-mutations.ts index 8e7b1f152..75abeaf57 100644 --- a/packages/compiler/src/frontend/lowering/class-method-mutations.ts +++ b/packages/compiler/src/frontend/lowering/class-method-mutations.ts @@ -288,7 +288,12 @@ export function collectClassMethodMutations( ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) && - ts.isComputedPropertyName(node.name) + ts.isComputedPropertyName(node.name) && + // A computed key in an object literal defines a property of the new + // object, which is not a class instance. Literals passed to + // Object.assign or Object.defineProperties are judged with their + // receiver below. + !ts.isObjectLiteralExpression(node.parent) ) { markKey(node.name.expression, node); } diff --git a/packages/compiler/test/class-method-mutations.test.ts b/packages/compiler/test/class-method-mutations.test.ts index 50c8a2ae2..2258bd54a 100644 --- a/packages/compiler/test/class-method-mutations.test.ts +++ b/packages/compiler/test/class-method-mutations.test.ts @@ -87,3 +87,30 @@ test("an asserted string key keeps checked dispatch", async () => { ); expect(await callersOf(source, "%dyn.class.properties")).not.toEqual([]); }); + +const tally = ` +class Tally { + n = 0; + add(): void { this.n++; } +} +function entry(target: object, key: string, value: number): TYPE { + return LITERAL; +} +const tally = new Tally(); +tally.add(); +console.log(tally.n, Object.keys(entry(tally, String(tally.n), 2))); +`; + +test("a computed key in an object literal leaves method calls direct", async () => { + const source = tally + .replace("TYPE", "Record") + .replace("LITERAL", "{ [key]: value }"); + expect(await callersOf(source, "%dyn.class.properties")).toEqual([]); +}); + +test("a computed key in an Object.assign source keeps checked dispatch", async () => { + const source = tally + .replace("TYPE", "object") + .replace("LITERAL", "Object.assign(target, { [key]: value })"); + expect(await callersOf(source, "%dyn.class.properties")).not.toEqual([]); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts.json new file mode 100644 index 000000000..356382374 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts b/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts new file mode 100644 index 000000000..bd324210a --- /dev/null +++ b/tests/corpus/5938-object-literal-computed-keys-keep-methods.ts @@ -0,0 +1,39 @@ +// An object literal with a computed key that is only known at runtime +// defines a property of that new object. Class methods, including methods +// of generic classes, keep their calls. +class Ctx { + v: number; + constructor() { + this.v = 0; + } + json(o: T): string { + return JSON.stringify(o); + } + status(n: number): Ctx { + this.v = n; + return this; + } +} + +class Counter { + count = 0; + bump(): number { + return ++this.count; + } +} + +function headers(names: string[]): Record { + const out: Record = {}; + for (const name of names) Object.assign(out, { [name.toLowerCase()]: name.length }); + return out; +} + +const prefix = process.argv.length > 99 ? "never" : "x-"; +const key = `${prefix}id`; +const literal: Record = { [key]: 1, [`${key}-2`]: 2 }; +const ctx = new Ctx<{ ok: boolean }>(); +const counter = new Counter(); +counter.bump(); +console.log(literal, headers(["Accept", "Host"])); +console.log(typeof ctx.json, typeof ctx.status, ctx.status(200).json({ ok: true }), ctx.v); +console.log(counter.bump(), counter.count); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 2c80c39a2..ef8e840e2 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1869,6 +1869,8 @@ "5842-qs-parse-null-prototype.ts": 1774, "5843-qs-parse-null-prototype-js.mjs": 1559, "5844-date-unknown-values.ts": 3969, + "5846-events-esm-default-max.ts": 2633, + "5847-events-cjs-default-max.cjs": 2823, "5857-regexp-unicode-sets.ts": 3350, "5858-disposable-stack.ts": 3050, "5859-disposable-stack-js.js": 3100, @@ -1897,6 +1899,7 @@ "5915-dyn-error-string-conversions.ts": 3200, "5922-matchall-groups-callbacks.ts": 3650, "5923-matchall-groups-js.js": 3970, + "5938-object-literal-computed-keys-keep-methods.ts": 3195, "5939-js-let-object-reassigned-wider.js": 1945, "5942-local-class-observed-methods.ts": 5063, "5950-tuple-predicate-methods.ts": 5990, @@ -1913,8 +1916,6 @@ "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, - "5846-events-esm-default-max.ts": 2633, - "5847-events-cjs-default-max.cjs": 2823, "600-closures-basic.ts": 2349, "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, @@ -4569,6 +4570,8 @@ "5842-qs-parse-null-prototype.ts": 7077, "5843-qs-parse-null-prototype-js.mjs": 5395, "5844-date-unknown-values.ts": 4543, + "5846-events-esm-default-max.ts": 3102, + "5847-events-cjs-default-max.cjs": 3039, "5857-regexp-unicode-sets.ts": 3900, "5858-disposable-stack.ts": 3750, "5859-disposable-stack-js.js": 3600, @@ -4597,6 +4600,7 @@ "5915-dyn-error-string-conversions.ts": 4247, "5922-matchall-groups-callbacks.ts": 5960, "5923-matchall-groups-js.js": 6650, + "5938-object-literal-computed-keys-keep-methods.ts": 7194, "5939-js-let-object-reassigned-wider.js": 4436, "5942-local-class-observed-methods.ts": 6212, "5950-tuple-predicate-methods.ts": 7790, @@ -4613,8 +4617,6 @@ "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, - "5846-events-esm-default-max.ts": 3102, - "5847-events-cjs-default-max.cjs": 3039, "600-closures-basic.ts": 2534, "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, From e12db2974f7bf59bb6f8d43d2157d6f7117cd265 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 17 Oct 2026 12:33:51 -0700 Subject: [PATCH 083/117] Verify checker-proven narrowings at run time unionNarrow, downcast and caughtNarrow extracted a payload as the arm, class or caught kind TypeScript's narrowing proved, with no runtime check. A wrong proof read the payload as another type. Each extraction now verifies its proof once: the union tag (for a two-arm union, that the value does not hold the other arm, which LLVM folds under either dominating test), the target's vtable preorder intervals (shared with instanceof), or the caught kind or class (shared with caughtTest). A mismatch calls scr_trap with an internal-error message from a cold block. A correct program never reaches it: narrowings the frontend cannot prove already lower to checked extraction, which throws the catchable TypeError, and analyses treat these expressions as non-throwing, so a failing guard aborts instead of unwinding. The guards found a stale narrowing the stability analysis missed: a binding initialized or assigned from a narrowed read whose narrowing a callback invalidated inherits that narrowing (`const held: Expr = current`). main segfaults on that program where Node throws a TypeError. NarrowingStability now treats such bindings like captured mutable ones, so their narrowed reads use checked extraction. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/backend/llvm/emitter.ts | 10 +- .../compiler/src/backend/llvm/expr-calls.ts | 33 ++- .../compiler/src/backend/llvm/expr-dynamic.ts | 77 ++----- .../src/backend/llvm/narrow-guards.ts | 191 ++++++++++++++++++ .../lowering/expressions/evaluation-safety.ts | 7 +- .../src/frontend/lowering/lower-exprs.ts | 16 +- .../src/frontend/lowering/lower-stmts.ts | 2 +- .../frontend/lowering/narrowing-stability.ts | 78 ++++++- packages/compiler/src/ir/ir.ts | 39 ++-- packages/compiler/src/ir/validate.ts | 2 +- .../test/narrow-guard-emission.test.ts | 119 +++++++++++ .../corpus/5770-guarded-union-narrows.ts.json | 6 + .../corpus/5771-guarded-downcasts.ts.json | 6 + .../corpus/5772-guarded-catch-narrows.ts.json | 6 + .../5773-stale-narrowing-inherited.ts.json | 6 + tests/corpus/5770-guarded-union-narrows.ts | 88 ++++++++ tests/corpus/5771-guarded-downcasts.ts | 81 ++++++++ tests/corpus/5772-guarded-catch-narrows.ts | 63 ++++++ .../corpus/5773-stale-narrowing-inherited.ts | 74 +++++++ 19 files changed, 790 insertions(+), 114 deletions(-) create mode 100644 packages/compiler/src/backend/llvm/narrow-guards.ts create mode 100644 packages/compiler/test/narrow-guard-emission.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5770-guarded-union-narrows.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5771-guarded-downcasts.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5772-guarded-catch-narrows.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5773-stale-narrowing-inherited.ts.json create mode 100644 tests/corpus/5770-guarded-union-narrows.ts create mode 100644 tests/corpus/5771-guarded-downcasts.ts create mode 100644 tests/corpus/5772-guarded-catch-narrows.ts create mode 100644 tests/corpus/5773-stale-narrowing-inherited.ts diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 2cccda19c..44213e2d2 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -398,6 +398,7 @@ import { } from "./shapes.js"; import type { ExprOf, LibCallExpr, LlStreamTypedRefAdapter, LlValue } from "./expr-context.js"; import { INLINE_LITERAL_BYTES, literalEqualityDefinition } from "./string-literal-equality.js"; +import { emitDowncastGuard, emitUnionNarrowGuard } from "./narrow-guards.js"; export { LlvmUnsupportedError } from "./unsupported.js"; @@ -10356,11 +10357,16 @@ export class LlEmitter { if (canStackUnion(e, this.boxedUnionsById)) return emitStackUnion(this, e).value; if (e.kind === "unionNarrow") { const union = this.emitUnionProjection(e.value); + emitUnionNarrowGuard(this, union.name, e.unionId, e.tag); return { name: this.unionPeek(union.name, e.unionId), type: e.type }; } if ((e.kind === "downcast" || e.kind === "upcast") && e.value.type.kind === "object") { - // Prefix layouts: a class cast reads the operand's own pointer. - return { name: this.emitReadReceiver(e.value).name, type: e.type }; + // Prefix layouts: a class cast reads the operand's own pointer; a + // downcast verifies its target class (narrow-guards.ts). + const receiver = this.emitReadReceiver(e.value); + if (e.kind === "downcast" && e.type.kind === "object") + emitDowncastGuard(this, receiver.name, e.value.type.className, e.type.className); + return { name: receiver.name, type: e.type }; } // A nullable-pointer field has no box to borrow. Projections use // emitUnionProjection; other borrowers get an owned heap box. diff --git a/packages/compiler/src/backend/llvm/expr-calls.ts b/packages/compiler/src/backend/llvm/expr-calls.ts index 059af307b..b1d810a3f 100644 --- a/packages/compiler/src/backend/llvm/expr-calls.ts +++ b/packages/compiler/src/backend/llvm/expr-calls.ts @@ -32,7 +32,6 @@ import { mangleVtStruct, } from "../mangle.js"; import { - classMembershipIntervals, classEnvironmentIndex, classStructSym, vtEntriesFor, @@ -52,6 +51,7 @@ import { inputSuffixWrites, } from "./borrowed-inputs.js"; import type { Writes } from "./reference-writes.js"; +import { emitClassMembership, emitDowncastGuard } from "./narrow-guards.js"; export function emitCallExpr( host: LlvmEmitterContext, @@ -1129,8 +1129,11 @@ export function emitCallExpr( // Prefix layout: both directions are reinterprets of the SAME // pointer — no RC traffic, ownership transfers from the operand // temp to the result temp (struck so the one +1 releases exactly - // once, under the RESULT type's release). + // once, under the RESULT type's release). A downcast verifies the + // class tsc's narrowing proved (narrow-guards.ts). const v = host.emitExpr(e.value); + if (e.kind === "downcast" && e.type.kind === "object" && v.type.kind === "object") + emitDowncastGuard(host, v.name, v.type.className, e.type.className); if (isRefCounted(v.type)) host.moveTemp(v); return host.own({ name: v.name, type: e.type }); } @@ -1142,24 +1145,14 @@ export function emitCallExpr( // The test only reads the vtable word: a borrowable operand needs no // retain/release pair around it. const v = emitBorrowedInputs(host, [e.value])[0]!; - const target = host.classMetaOf(e.className); - const pre = host.loadVtPre(v.name, e.value.type.className); - let result: string | undefined; - for (const interval of classMembershipIntervals(host.classMeta, target.def.name)) { - const ge = B.tmp(), - le = B.tmp(), - test = B.tmp(); - B.line(`${ge} = icmp uge ${host.sizeType} ${pre}, ${interval.pre}`); - B.line(`${le} = icmp ule ${host.sizeType} ${pre}, ${interval.post}`); - B.line(`${test} = and i1 ${ge}, ${le} ; instanceof ${e.className}`); - if (result === undefined) result = test; - else { - const combined = B.tmp(); - B.line(`${combined} = or i1 ${result}, ${test}`); - result = combined; - } - } - return { name: result!, type: e.type }; + const result = emitClassMembership( + host, + v.name, + e.value.type.className, + e.className, + `instanceof ${e.className}`, + ); + return { name: result, type: e.type }; } case "virtualCall": { // Dispatch through the receiver's vtable: the slot lives on the diff --git a/packages/compiler/src/backend/llvm/expr-dynamic.ts b/packages/compiler/src/backend/llvm/expr-dynamic.ts index 9a8ef28fb..76df9795d 100644 --- a/packages/compiler/src/backend/llvm/expr-dynamic.ts +++ b/packages/compiler/src/backend/llvm/expr-dynamic.ts @@ -1,4 +1,9 @@ import { classMembershipIntervals } from "./classes.js"; +import { + emitCaughtInstanceof, + emitCaughtNarrowGuard, + emitUnionNarrowGuard, +} from "./narrow-guards.js"; import { borrowableInputs, emitBorrowedInput, emitBorrowedInputs } from "./borrowed-inputs.js"; import { preservesDynTest } from "./checked-value-lifetimes.js"; import { typedRefConstructor } from "./shapes.js"; @@ -295,13 +300,14 @@ export function emitDynamicExpr( return host.own({ name: host.unionNewOwned(e.unionId, e.tag, v), type: e.type }); } case "unionNarrow": { - // Tag-UNCHECKED payload extraction: the frontend emits this only - // where tsc's control-flow narrowing proved the tag. Ref payloads - // come out +1. The receiver is consumed before any later expression. + // Payload extraction where tsc's control-flow narrowing proved the + // tag; the guard verifies it (narrow-guards.ts). Ref payloads come + // out +1. The receiver is consumed before any later expression. const u = host.emitUnionProjection(e.value); const arm = e.type; if (isUnitType(arm)) throw new InternalCompilerError(`llvm emitter bug: unionNarrow to unit arm ${arm.kind}`); + emitUnionNarrowGuard(host, u.name, e.unionId, e.tag); const v = host.unionExtract(u.name, e.unionId, arm); return host.own({ name: v, type: arm }); } @@ -974,56 +980,7 @@ export function emitDynamicExpr( // borrowed. SCR_EXC_STR = 3, SCR_EXC_F64 = 1, SCR_EXC_BOOL = 2. const c = host.emitReadReceiver(e.value); if (e.test === "instanceof") { - const target = host.classMetaOf(e.className!); - if (!target.hierarchy) { - // Standalone class payloads have no vtable word. Their retain - // adapter identifies the exact native layout in the snapshot. - const adapterSlot = B.tmp(); - const adapter = B.tmp(); - B.line(`${adapterSlot} = getelementptr inbounds %ScrCaught, ptr ${c.name}, i64 0, i32 5`); - B.line(`${adapter} = load ptr, ptr ${adapterSlot}`); - let result: string | undefined; - const intervals = classMembershipIntervals(host.classMeta, target.def.name); - for (const candidate of host.classMeta.values()) { - if ( - candidate.hierarchy || - !intervals.some((range) => range.pre <= candidate.pre && candidate.pre <= range.post) - ) - continue; - const rc = vAdapters(host.shapeHost, { kind: "object", className: candidate.def.name }); - const matches = B.tmp(); - B.line(`${matches} = icmp eq ptr ${adapter}, ${rc.retain}`); - if (result === undefined) result = matches; - else { - const joined = B.tmp(); - B.line(`${joined} = or i1 ${result}, ${matches}`); - result = joined; - } - } - if (result === undefined) - throw new InternalCompilerError("empty standalone class membership"); - if (e.negated !== true) return { name: result, type: e.type }; - const negated = B.tmp(); - B.line(`${negated} = xor i1 ${result}, true`); - return { name: negated, type: e.type }; - } - host.declare( - `declare zeroext i1 @scr_caught_instanceof(ptr, ${host.sizeType}, ${host.sizeType})`, - ); - let t: string | undefined; - for (const interval of classMembershipIntervals(host.classMeta, target.def.name)) { - const test = B.tmp(); - B.line( - `${test} = call zeroext i1 @scr_caught_instanceof(ptr ${c.name}, ${host.sizeType} ${interval.pre}, ${host.sizeType} ${interval.post})`, - ); - if (t === undefined) t = test; - else { - const combined = B.tmp(); - B.line(`${combined} = or i1 ${t}, ${test}`); - t = combined; - } - } - if (t === undefined) throw new InternalCompilerError("empty class membership"); + const t = emitCaughtInstanceof(host, c.name, e.className!); if (e.negated !== true) return { name: t, type: e.type }; const n = B.tmp(); B.line(`${n} = xor i1 ${t}, true`); @@ -1097,10 +1054,18 @@ export function emitDynamicExpr( return out; } case "caughtNarrow": { - // Checker-trusted extraction (the matching caughtTest was proven - // by tsc's narrowing): scalars read the snapshot's slots, - // refcounted payloads come out retained (+1). Box borrowed. + // Extraction where tsc's narrowing proved the matching caughtTest; + // the guard verifies it (narrow-guards.ts). Scalars read the + // snapshot's slots, refcounted payloads come out retained (+1). Box + // borrowed. const c = host.emitReadReceiver(e.value); + if ( + e.type.kind === "f64" || + e.type.kind === "bool" || + e.type.kind === "string" || + e.type.kind === "object" + ) + emitCaughtNarrowGuard(host, c.name, e.type); if (e.type.kind === "f64") { const p = B.tmp(); const v = B.tmp(); diff --git a/packages/compiler/src/backend/llvm/narrow-guards.ts b/packages/compiler/src/backend/llvm/narrow-guards.ts new file mode 100644 index 000000000..883045b95 --- /dev/null +++ b/packages/compiler/src/backend/llvm/narrow-guards.ts @@ -0,0 +1,191 @@ +/* Runtime guards for checker-proven narrowings. + * + * `unionNarrow`, `downcast` and `caughtNarrow` extract a payload whose arm, + * class or kind TypeScript's control-flow narrowing proved. Emitted code + * verifies that proof once at the narrowing site: the tag, class interval or + * caught kind is compared and a mismatch stops the program through the + * runtime trap funnel instead of reading the payload as the wrong type. A + * correct program never takes the failing branch: the frontend lowers every + * narrowing it cannot prove through checked extraction, which throws the + * catchable TypeError. A failing guard is therefore a compiler bug, so it + * aborts rather than unwinding through code that assumed the extraction + * could not throw. The guards are cheap: one load and compare per site, + * which LLVM folds where an identical test already dominates. */ +import { InternalCompilerError } from "../../errors.js"; +import { classMembershipIntervals } from "./classes.js"; +import type { LlvmEmitterContext } from "./expr-context.js"; +import { vAdapters } from "./shapes.js"; + +export const NARROW_GUARD_MESSAGES = { + union: "scriptc: internal error: a narrowed union value holds a different arm\n", + downcast: "scriptc: internal error: a downcast object is not an instance of its target class\n", + caught: "scriptc: internal error: a narrowed catch binding holds a different value\n", +} as const; + +/** Continues in a fresh block where `ok` holds; otherwise traps with the + * message for `kind`. */ +export function emitNarrowGuard( + host: LlvmEmitterContext, + ok: string, + kind: keyof typeof NARROW_GUARD_MESSAGES, +): void { + const B = host.B; + host.declare(`declare i1 @llvm.expect.i1(i1, i1)`); + host.declare(`declare void @scr_trap(ptr)`); + const expected = B.tmp(); + B.line(`${expected} = call i1 @llvm.expect.i1(i1 ${ok}, i1 true)`); + const pass = B.newLabel("narrow.ok"); + const fail = B.newLabel("narrow.bad"); + B.condBr(expected, pass, fail); + B.startBlock(fail); + B.line(`call void @scr_trap(ptr ${host.cstr(NARROW_GUARD_MESSAGES[kind])})`); + B.terminate("unreachable"); + B.startBlock(pass); +} + +/** Verifies that the union value `unionName` holds arm `tag`. A two-arm + * union holds it exactly when it does not hold the other arm; testing the + * other arm lets LLVM fold the guard under a dominating `!== other` test as + * well as under `=== tag` (a tag outside the arms is not a union value). */ +export function emitUnionNarrowGuard( + host: LlvmEmitterContext, + unionName: string, + unionId: string, + tag: number, +): void { + const ok = host.B.tmp(); + const actual = host.unionTag(unionName, unionId); + if (host.unionsById.get(unionId)?.arms.length === 2) + host.B.line(`${ok} = icmp ne i32 ${actual}, ${1 - tag}`); + else host.B.line(`${ok} = icmp eq i32 ${actual}, ${tag}`); + emitNarrowGuard(host, ok, "union"); +} + +/** The i1 `instanceof` test of the borrowed object `objName`, statically a + * `staticClassName`, against `targetClassName`'s preorder intervals. */ +export function emitClassMembership( + host: LlvmEmitterContext, + objName: string, + staticClassName: string, + targetClassName: string, + comment: string, +): string { + const B = host.B; + const target = host.classMetaOf(targetClassName); + const pre = host.loadVtPre(objName, staticClassName); + let result: string | undefined; + for (const interval of classMembershipIntervals(host.classMeta, target.def.name)) { + const ge = B.tmp(), + le = B.tmp(), + test = B.tmp(); + B.line(`${ge} = icmp uge ${host.sizeType} ${pre}, ${interval.pre}`); + B.line(`${le} = icmp ule ${host.sizeType} ${pre}, ${interval.post}`); + B.line(`${test} = and i1 ${ge}, ${le} ; ${comment}`); + if (result === undefined) result = test; + else { + const combined = B.tmp(); + B.line(`${combined} = or i1 ${result}, ${test}`); + result = combined; + } + } + return result!; +} + +/** Verifies that the borrowed object `objName` is a `targetClassName`. */ +export function emitDowncastGuard( + host: LlvmEmitterContext, + objName: string, + staticClassName: string, + targetClassName: string, +): void { + const ok = emitClassMembership( + host, + objName, + staticClassName, + targetClassName, + `downcast ${targetClassName}`, + ); + emitNarrowGuard(host, ok, "downcast"); +} + +/** The i1 `e instanceof C` test of the borrowed catch snapshot `caught`. + * Hierarchy classes compare the OBJ payload's vtable preorder; standalone + * class payloads have no vtable word, so their retain adapter identifies + * the exact native layout. */ +export function emitCaughtInstanceof( + host: LlvmEmitterContext, + caught: string, + className: string, +): string { + const B = host.B; + const target = host.classMetaOf(className); + const intervals = classMembershipIntervals(host.classMeta, target.def.name); + if (!target.hierarchy) { + const adapterSlot = B.tmp(); + const adapter = B.tmp(); + B.line(`${adapterSlot} = getelementptr inbounds %ScrCaught, ptr ${caught}, i64 0, i32 5`); + B.line(`${adapter} = load ptr, ptr ${adapterSlot}`); + let result: string | undefined; + for (const candidate of host.classMeta.values()) { + if ( + candidate.hierarchy || + !intervals.some((range) => range.pre <= candidate.pre && candidate.pre <= range.post) + ) + continue; + const rc = vAdapters(host.shapeHost, { kind: "object", className: candidate.def.name }); + const matches = B.tmp(); + B.line(`${matches} = icmp eq ptr ${adapter}, ${rc.retain}`); + if (result === undefined) result = matches; + else { + const joined = B.tmp(); + B.line(`${joined} = or i1 ${result}, ${matches}`); + result = joined; + } + } + if (result === undefined) throw new InternalCompilerError("empty standalone class membership"); + return result; + } + host.declare( + `declare zeroext i1 @scr_caught_instanceof(ptr, ${host.sizeType}, ${host.sizeType})`, + ); + let result: string | undefined; + for (const interval of intervals) { + const test = B.tmp(); + B.line( + `${test} = call zeroext i1 @scr_caught_instanceof(ptr ${caught}, ${host.sizeType} ${interval.pre}, ${host.sizeType} ${interval.post})`, + ); + if (result === undefined) result = test; + else { + const combined = B.tmp(); + B.line(`${combined} = or i1 ${result}, ${test}`); + result = combined; + } + } + if (result === undefined) throw new InternalCompilerError("empty class membership"); + return result; +} + +/** SCR_EXC_F64 = 1, SCR_EXC_BOOL = 2, SCR_EXC_STR = 3 (scr_exception.h). */ +export const CAUGHT_SCALAR_KINDS = { f64: 1, bool: 2, string: 3 } as const; + +/** Verifies that the borrowed catch snapshot `caught` holds a value of the + * narrowed type: a scalar's kind tag, or an object's class. */ +export function emitCaughtNarrowGuard( + host: LlvmEmitterContext, + caught: string, + type: { kind: "f64" | "bool" | "string" } | { kind: "object"; className: string }, +): void { + const B = host.B; + let ok: string; + if (type.kind === "object") { + ok = emitCaughtInstanceof(host, caught, type.className); + } else { + const kp = B.tmp(); + const k = B.tmp(); + ok = B.tmp(); + B.line(`${kp} = getelementptr inbounds %ScrCaught, ptr ${caught}, i64 0, i32 1`); + B.line(`${k} = load i32, ptr ${kp}`); + B.line(`${ok} = icmp eq i32 ${k}, ${CAUGHT_SCALAR_KINDS[type.kind]}`); + } + emitNarrowGuard(host, ok, "caught"); +} diff --git a/packages/compiler/src/frontend/lowering/expressions/evaluation-safety.ts b/packages/compiler/src/frontend/lowering/expressions/evaluation-safety.ts index 791df1340..0c4da61be 100644 --- a/packages/compiler/src/frontend/lowering/expressions/evaluation-safety.ts +++ b/packages/compiler/src/frontend/lowering/expressions/evaluation-safety.ts @@ -6,9 +6,10 @@ import type { IrExpr } from "../../../ir/ir.js"; export function isSafeToRepeat(expr: IrExpr): boolean { if (expr.kind === "varRef") return true; if (expr.kind === "recordGet" || expr.kind === "fieldGet") return isSafeToRepeat(expr.obj); - // The trust-the-checker narrowing bridges over a pure read: extraction - // and downcast are reads too (the +1 on ref payloads is RC bookkeeping, - // not an observable effect — each emission owns its own copy). + // The narrowing bridges over a pure read: extraction and downcast are + // reads too (their guards only compare, and the +1 on ref payloads is RC + // bookkeeping, not an observable effect — each emission owns its own + // copy). if (expr.kind === "unionNarrow" || expr.kind === "downcast") return isSafeToRepeat(expr.value); return false; } diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 0fb81e2da..18c034221 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -3128,9 +3128,9 @@ export function lowerTernary( * union-typed reference at use sites (`if (r.kind === "ok") { ...r... }` * types `r` as the ok-arm inside the branch); the IR value is still the * tagged union, so the read is bridged with a `unionNarrow` extracting - * the arm's payload. The extraction is tag-UNCHECKED at runtime — - * soundness rests entirely on tsc having proven the tag (the project's - * trust-the-checker thesis; see docs/ir.md). A checker type that maps to + * the arm's payload. The extraction relies on tsc having proven the tag; + * backends verify it once and trap on a mismatch, so a wrong proof stops + * the program instead of reading another arm. A checker type that maps to * the same union (unnarrowed use), to a SUB-union (partial narrowing — * unrepresentable without a re-tag), or to nothing (`never` in an * exhaustive default) leaves the expression union-typed. */ @@ -3320,8 +3320,8 @@ export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrEx } // instanceof narrowing for classes: tsc types this USE as a subclass of // the IR value's class (only a dynamic instanceof test narrows a class - // type), so the read bridges with an unchecked static downcast — the - // same trust-the-checker contract as the union bridge below. + // type), so the read bridges with a static downcast that backends verify + // at run time, like the union bridge below. if (expr.type.kind === "object") { const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node)); if (narrowed?.kind === "union") { @@ -3972,7 +3972,7 @@ function runtimeOptionalAssertionErases( * (`w = 5; if (w !== null)`), the comparison is statically decided and * folds to a bool literal — that drops only a side-effect-free read * (flow narrowing applies to references, never to calls), and soundness - * is the same trust-the-checker bet unionNarrow already makes. Null when + * rests on the same narrowing proof unionNarrow relies on. Null when * neither side is a unit literal (not a unit comparison). */ export function lowerUnitComparison( lowerer: Lowerer, @@ -11904,8 +11904,8 @@ function lowerCjsExportTableThisMember( /** A read of a catch binding — the caught analog of maybeNarrow. Where * tsc's control-flow narrowing has proven a supported test (`instanceof` * over a hierarchy class, `typeof` over a primitive), the read bridges - * with a kind-unchecked `caughtNarrow` extraction (trust-the-checker, - * exactly like unionNarrow). Every OTHER read is the narrowness fence: + * with a `caughtNarrow` extraction whose kind backends verify at run time, + * exactly like unionNarrow. Every OTHER read is the narrowness fence: * the binding's payload is a typed exception snapshot, not a dyn, so * un-narrowed uses have nothing sound to lower to. */ export function caughtRead( diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 2cc51e789..e21409aee 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -5405,7 +5405,7 @@ function lowerBranchSwitch( * cell, deliberately narrower than dyn: the supported uses are the * narrowing tests (`e instanceof C` over hierarchy classes, `typeof e * === "string"/"number"/"boolean"`), reads under a proven narrow - * (caughtRead bridges them with caughtNarrow, trust-the-checker like + * (caughtRead bridges them with caughtNarrow, verified at run time like * unionNarrow), and rethrow (`throw e`). Unsupported raw uses and * assignments are fenced (SC1063 and friends); destructuring patterns * are SC1062. Captures retain the snapshot beyond the catch scope. diff --git a/packages/compiler/src/frontend/lowering/narrowing-stability.ts b/packages/compiler/src/frontend/lowering/narrowing-stability.ts index 4ae8eec67..5bd563d9d 100644 --- a/packages/compiler/src/frontend/lowering/narrowing-stability.ts +++ b/packages/compiler/src/frontend/lowering/narrowing-stability.ts @@ -11,9 +11,10 @@ import type { Lowerer } from "./lowerer.js"; * after assignments and tests, and keeps that narrowing across calls: a * callback, method or getter that clears or replaces the property (or a * closure that reassigns the binding) leaves the reference typed by its old - * value. Lowering bridges a narrowed union read with an UNCHECKED payload - * extraction and folds `?.`, truthiness and `typeof` by the narrowed type, - * so such a read would interpret the wrong arm. This analysis decides when + * value. Lowering bridges a narrowed union read with a payload extraction + * that traps on the wrong arm and folds `?.`, truthiness and `typeof` by the + * narrowed type, so such a read would abort or fold to the old value instead + * of throwing the catchable TypeError. This analysis decides when * the narrowing is provably current: * * - every property in the reference is construction-only (no store to its @@ -30,6 +31,10 @@ import type { Lowerer } from "./lowerer.js"; * A loop around the use that starts inside that span contributes its * whole body, since its back edge reaches the use again. * + * A binding initialized or assigned from a read whose narrowing may be + * stale inherits that narrowing (`const held: Expr = current` keeps the arm + * `current` was typed with), so its narrowed reads are never trusted. + * * TypeScript never carries a property narrowing into a nested function, * and every narrowing (an assignment, test, predicate or assertion of the * reference) is an occurrence of the reference, so a narrowed use always @@ -42,6 +47,7 @@ export class NarrowingStability { private readonly verdicts = new Map(); private readonly effects = new Map(); private readonly capturedMutable = new Map(); + private readonly staleBindings = new Map(); private readonly identifierWrites = new Map>(); private readonly widened = new Map(); private readonly plainContainers = new Map(); @@ -90,7 +96,7 @@ export class NarrowingStability { } if (ts.isIdentifier(node)) { const symbol = this.bindingOf(node); - if (!symbol || !this.isCapturedMutable(symbol)) return false; + if (!symbol || !this.mayHoldStaleNarrowing(symbol)) return false; return !this.trusted(node); } return false; @@ -113,7 +119,8 @@ export class NarrowingStability { declared = this.declaredPropertyType(node); } else { const symbol = this.bindingOf(node); - declared = symbol && this.isCapturedMutable(symbol) ? checker.getTypeOfSymbol(symbol) : null; + declared = + symbol && this.mayHoldStaleNarrowing(symbol) ? checker.getTypeOfSymbol(symbol) : null; } if (declared === null) return null; const narrowedTs = checker.getTypeAtLocation(node); @@ -245,6 +252,10 @@ export class NarrowingStability { ) return false; } + if (ts.isIdentifier(chain.root)) { + const root = this.bindingOf(chain.root); + if (root !== null && this.inheritsStaleNarrowing(root)) return false; + } const rootStable = chain.root.kind === ts.SyntaxKind.ThisKeyword || (ts.isIdentifier(chain.root) && !this.rootCapturedMutable(chain.root)); @@ -346,6 +357,63 @@ export class NarrowingStability { return !program.wildcard && !program.mutable.has(name) && !program.accessors.has(name); } + /** A binding whose narrowed reads may observe a narrowing that no longer + * holds: another function assigns it, or it inherits a stale narrowing. */ + private mayHoldStaleNarrowing(symbol: ts.Symbol): boolean { + return this.isCapturedMutable(symbol) || this.inheritsStaleNarrowing(symbol); + } + + /** The binding is initialized or assigned from a narrowed read that may be + * stale, so TypeScript's narrowing of the binding may be stale too. */ + private inheritsStaleNarrowing(symbol: ts.Symbol): boolean { + const cached = this.staleBindings.get(symbol); + if (cached !== undefined) return cached; + // A cycle of bindings assigned from each other contributes nothing. + this.staleBindings.set(symbol, false); + let result = false; + try { + const decl = this.lowerer.checker.valueDeclarationOf(symbol); + if (decl !== undefined && ts.isVariableDeclaration(decl)) { + if (decl.initializer !== undefined && this.mayBeStale(decl.initializer)) result = true; + else { + for (const write of this.writesIn(decl.getSourceFile()).get(symbol.name) ?? []) { + const assignment = write.parent; + if ( + ts.isBinaryExpression(assignment) && + assignment.left === write && + assignment.operatorToken.kind === ts.SyntaxKind.EqualsToken && + this.lowerer.resolveValueSymbol(write) === symbol && + this.mayBeStale(assignment.right) + ) { + result = true; + break; + } + } + } + } + } finally { + this.staleBindings.set(symbol, result); + } + return result; + } + + /** A reference TypeScript narrows below its declared type where the + * narrowing may no longer hold. */ + private mayBeStale(expression: ts.Expression): boolean { + let e = expression; + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (!ts.isIdentifier(e) && !ts.isPropertyAccessExpression(e)) return false; + const checker = this.lowerer.checker; + let declared: ts.Type | null; + if (ts.isPropertyAccessExpression(e)) declared = this.declaredPropertyType(e); + else { + const symbol = this.bindingOf(e); + declared = symbol === null ? null : checker.getTypeOfSymbol(symbol); + } + if (declared === null || checker.getTypeAtLocation(e) === declared) return false; + return !this.trusted(e); + } + /** A `let`/`var`/parameter binding assigned from a function other than * the one that declares it: any call may change it. */ private isCapturedMutable(symbol: ts.Symbol): boolean { diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 9591c684a..80ec0e972 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -344,8 +344,8 @@ export type IrType = * Runtime representation is a refcounted snapshot box (ScrCaught) holding * the taken exception: a kind tag plus the payload. Even NARROWER than * dyn: the only expressions a caught value may appear in are `caughtTest` - * (kind/instanceof tests), `caughtNarrow` (checker-trusted extraction - * under a proven test), and the `rethrow` statement — the frontend + * (kind/instanceof tests), `caughtNarrow` (extraction under a proven + * test, verified at run time), and the `rethrow` statement — the frontend * rejects every other use with the narrowing hint. */ | { kind: "caught" } | { kind: "promise"; inner: IrType } // heap, refcounted, settled-once @@ -2953,11 +2953,12 @@ export type IrExpr = * fulfillment payload (scr_await_void) and rejections flow untyped. * Ownership of the operand transfers to the result, like upcast. */ | { kind: "promiseVoidWiden"; value: IrExpr; type: IrType; loc: SrcLoc } - /** Checker-trusted narrowing of a base-class value to a subclass (`type` - * is the subclass). The frontend emits this only where tsc's control-flow - * narrowing has already proven the dynamic class (an `instanceof` guard) - * — the same trust-the-checker contract as unionNarrow: no runtime check, - * a pointer reinterpret with ownership transferring like upcast. */ + /** Narrowing of a base-class value to a subclass (`type` is the + * subclass). The frontend emits this only where tsc's control-flow + * narrowing has already proven the dynamic class (an `instanceof` guard), + * like unionNarrow. Backends verify the class once and trap on a mismatch + * a correct program never reaches, then reinterpret the pointer with + * ownership transferring like upcast. */ | { kind: "downcast"; value: IrExpr; type: IrType; loc: SrcLoc } /** `x instanceof C` where x's static class and C are both in extends- * hierarchies: an O(1) preorder-interval check against the vtable the @@ -3386,12 +3387,13 @@ export type IrExpr = type: IrType; loc: SrcLoc; } - /** Checker-trusted extraction of a catch binding's payload as `type` — - * the caught analog of unionNarrow: the frontend emits this only where - * tsc's control-flow narrowing has already proven the matching test - * (`e instanceof C` / `typeof e === "string"`), so the read is - * kind-UNCHECKED at runtime. `type` is f64, bool, string, or a - * class object; refcounted results come out retained (+1). */ + /** Extraction of a catch binding's payload as `type` — the caught + * analog of unionNarrow: the frontend emits this only where tsc's + * control-flow narrowing has already proven the matching test + * (`e instanceof C` / `typeof e === "string"`). Backends verify the kind + * or class once and trap on a mismatch a correct program never reaches. + * `type` is f64, bool, string, or a class object; refcounted results come + * out retained (+1). */ | { kind: "caughtNarrow"; value: IrExpr; type: IrType; loc: SrcLoc } /** CHECKED extraction of a catch binding's payload as a hierarchy-class * instance — the caught analog of dynCheck, emitted for `e as C` casts @@ -3417,11 +3419,12 @@ export type IrExpr = * varRef (borrowed); `type` is dyn; the result is a fresh tree (+1), * never aliasing the payload. Never throws. */ | { kind: "caughtToDyn"; value: IrExpr; type: IrType; loc: SrcLoc } - /** Union payload extraction, tag-UNCHECKED: `value` is union-typed, - * `type` is arms[tag], and the backend reads the payload assuming the tag - * — SOUNDNESS RESTS ON tsc's control-flow narrowing (the frontend emits - * this only where the checker has already narrowed the expression to that - * arm; see docs/ir.md). Refcounted payloads come out retained (+1). */ + /** Union payload extraction: `value` is union-typed and `type` is + * arms[tag]. The frontend emits this only where tsc's control-flow + * narrowing has already narrowed the expression to that arm; backends + * verify the tag once and trap on a mismatch a correct program never + * reaches, so a wrong proof cannot read the payload as another arm. + * Refcounted payloads come out retained (+1). */ | { kind: "unionNarrow"; unionId: string; tag: number; value: IrExpr; type: IrType; loc: SrcLoc } /** Discriminant read `r.kind` on a union receiver: every arm is a * record/class possessing field `field` with the SAME primitive IR type diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index f7d30a1bb..d7211e756 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -2907,7 +2907,7 @@ function validateFunction( case "downcast": { // A pointer reinterpret is sound exactly between hierarchy // relatives: upcast widens a STRICT descendant to an ancestor, - // downcast (checker-trusted) narrows an ancestor to a STRICT + // downcast (verified at run time) narrows an ancestor to a STRICT // descendant. Upcast additionally widens CLASS VALUES // (classval:D → classval:C): the same pointer, type-only — legal // exactly when D strictly descends from C AND the two completed diff --git a/packages/compiler/test/narrow-guard-emission.test.ts b/packages/compiler/test/narrow-guard-emission.test.ts new file mode 100644 index 000000000..251809345 --- /dev/null +++ b/packages/compiler/test/narrow-guard-emission.test.ts @@ -0,0 +1,119 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile } from "../src/index.js"; + +async function emitLlvm(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-narrow-guards-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ll"); + await writeFile(entry, source); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "llvm" }); + expect(result.ok, JSON.stringify(result.diagnostics)).toBe(true); + return await readFile(outPath, "utf8"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +/** The trap call guarding narrowings of `kind`, after its message constant. */ +function guardCount(llvm: string, message: string): number { + const constant = [...llvm.matchAll(/^(@[\w.]+) = [^\n]*c"([^"]*)"/gm)].find(([, , text]) => + text!.startsWith(message), + ); + if (constant === undefined) return 0; + return llvm.split(`call void @scr_trap(ptr ${constant[1]})`).length - 1; +} + +test("typeof narrowing verifies the union tag before reading the payload", async () => { + const llvm = await emitLlvm(` +function width(v: string | number): number { + if (typeof v === "string") return v.length; + return v; +} +console.log(width("abc") + width(4)); +`); + expect(guardCount(llvm, "scriptc: internal error: a narrowed union value")).toBeGreaterThan(0); +}); + +/** The tag compares that feed narrowing guards, as `eq K` / `ne K`. */ +function guardCompares(llvm: string): string[] { + const compares: string[] = []; + for (const fn of llvm.split("\ndefine ")) { + for (const [, expected, ok] of fn.matchAll( + /(%[\w.]+) = call i1 @llvm\.expect\.i1\(i1 (%[\w.]+), i1 true\)/g, + )) { + if (!fn.includes(`br i1 ${expected}, label %narrow.ok`)) continue; + const def = new RegExp(`^\\s*${ok} = icmp (eq|ne) i32 %[\\w.]+, (\\d+)$`, "m").exec(fn); + if (def) compares.push(`${def[1]} ${def[2]}`); + } + } + return compares; +} + +test("two-arm union guards test the other arm; wider unions test the arm", async () => { + const two = await emitLlvm(` +function width(v: string | number): number { + if (typeof v === "string") return v.length; + return v; +} +console.log(width("abc") + width(4)); +`); + const twoCompares = guardCompares(two); + expect(twoCompares.length).toBeGreaterThan(0); + expect(twoCompares.every((c) => c.startsWith("ne "))).toBe(true); + const three = await emitLlvm(` +function width(v: string | number | boolean): number { + if (typeof v === "string") return v.length; + if (typeof v === "number") return v; + return v ? 1 : 0; +} +console.log(width("abc") + width(4) + width(true)); +`); + const threeCompares = guardCompares(three); + expect(threeCompares.length).toBeGreaterThan(0); + expect(threeCompares.every((c) => c.startsWith("eq "))).toBe(true); +}); + +test("instanceof narrowing verifies the downcast class interval", async () => { + const llvm = await emitLlvm(` +class Base { id = 1; } +class Child extends Base { values = [2, 4]; } +function count(value: Base): number { + if (value instanceof Child) return value.values.length; + return value.id; +} +console.log(count(new Child()), count(new Base())); +`); + expect(guardCount(llvm, "scriptc: internal error: a downcast object")).toBeGreaterThan(0); +}); + +test("catch-binding narrowing verifies the caught kind and class", async () => { + const llvm = await emitLlvm(` +class Failure extends Error { code = 7; } +function run(which: number): string { + try { + if (which === 0) throw "text"; + throw new Failure("bad"); + } catch (e) { + if (typeof e === "string") return e; + if (e instanceof Failure) return String(e.code); + return "other"; + } +} +console.log(run(0), run(1)); +`); + expect(guardCount(llvm, "scriptc: internal error: a narrowed catch binding")).toBeGreaterThan(1); +}); + +test("programs without narrowings carry no guards", async () => { + const llvm = await emitLlvm(` +let total = 0; +for (let i = 0; i < 10; i++) total += i; +console.log(total); +`); + expect(llvm).not.toContain("scriptc: internal error: a narrowed"); + expect(llvm).not.toContain("scriptc: internal error: a downcast"); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5770-guarded-union-narrows.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5770-guarded-union-narrows.ts.json new file mode 100644 index 000000000..18a2666e2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5770-guarded-union-narrows.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5770-guarded-union-narrows.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5771-guarded-downcasts.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5771-guarded-downcasts.ts.json new file mode 100644 index 000000000..c2570951b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5771-guarded-downcasts.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5771-guarded-downcasts.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5772-guarded-catch-narrows.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5772-guarded-catch-narrows.ts.json new file mode 100644 index 000000000..6de65b731 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5772-guarded-catch-narrows.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5772-guarded-catch-narrows.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5773-stale-narrowing-inherited.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5773-stale-narrowing-inherited.ts.json new file mode 100644 index 000000000..7a82f68e4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5773-stale-narrowing-inherited.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5773-stale-narrowing-inherited.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5770-guarded-union-narrows.ts b/tests/corpus/5770-guarded-union-narrows.ts new file mode 100644 index 000000000..2673fb048 --- /dev/null +++ b/tests/corpus/5770-guarded-union-narrows.ts @@ -0,0 +1,88 @@ +// Union narrowings that TypeScript proves are verified at run time: every +// narrowing below reads its payload through a tag guard. Correct programs +// never trip it, so output matches Node across typeof, nullable, tagged, +// switch, early-return, loop and closure narrowings, including payloads +// borrowed for field reads and owned ones stored into arrays. +type Shape = + | { kind: "circle"; r: number } + | { kind: "rect"; w: number; h: number } + | { kind: "label"; text: string }; + +class Node2 { + value: number; + next: Node2 | null; + constructor(value: number, next: Node2 | null) { + this.value = value; + this.next = next; + } +} + +function describe(v: string | number | boolean): string { + if (typeof v === "string") return `string:${v.length}:${v.toUpperCase()}`; + if (typeof v === "number") return `number:${(v * 2).toFixed(1)}`; + return `boolean:${v ? "yes" : "no"}`; +} + +function area(s: Shape): number { + switch (s.kind) { + case "circle": + return Math.round(Math.PI * s.r * s.r); + case "rect": + return s.w * s.h; + case "label": + return s.text.length; + } +} + +function sumList(head: Node2 | null): number { + let total = 0; + let cur = head; + while (cur !== null) { + total += cur.value; + cur = cur.next; + } + return total; +} + +function firstWord(text: string | undefined): string { + if (text === undefined) return ""; + const words = text.split(" "); + return words[0] ?? ""; +} + +function pickNames(items: (string | number)[]): string[] { + const names: string[] = []; + for (const item of items) { + if (typeof item !== "string") continue; + names.push(item); + } + return names; +} + +function makeFormatter(prefix: string | null): (n: number) => string { + const p = prefix ?? "#"; + return (n) => `${p}${n}`; +} + +const values: (string | number | boolean)[] = ["abc", 4.25, true, "", 0, false]; +for (const v of values) console.log(describe(v)); + +const shapes: Shape[] = [ + { kind: "circle", r: 2 }, + { kind: "rect", w: 3, h: 5 }, + { kind: "label", text: "hello" }, +]; +let totalArea = 0; +for (let round = 0; round < 1000; round++) for (const s of shapes) totalArea += area(s); +console.log("area", totalArea); + +let list: Node2 | null = null; +for (let i = 1; i <= 100; i++) list = new Node2(i, list); +console.log("list", sumList(list), sumList(null)); + +console.log(firstWord("guarded narrows"), firstWord(undefined), firstWord("")); +console.log(pickNames(["a", 1, "b", 2, "c"]).join(",")); +const fmt = makeFormatter(null); +const fmt2 = makeFormatter("n="); +console.log(fmt(1), fmt2(2)); + diff --git a/tests/corpus/5771-guarded-downcasts.ts b/tests/corpus/5771-guarded-downcasts.ts new file mode 100644 index 000000000..a85b2e08f --- /dev/null +++ b/tests/corpus/5771-guarded-downcasts.ts @@ -0,0 +1,81 @@ +// instanceof narrowing downcasts objects to subclasses; the downcast is +// verified against the target's preorder intervals at run time. Covers +// multi-level hierarchies, abstract bases, generic classes, and receivers +// borrowed for field reads as well as owned values passed on. +abstract class Animal { + name: string; + constructor(name: string) { + this.name = name; + } + abstract sound(): string; +} +class Dog extends Animal { + tricks = ["sit", "roll"]; + sound(): string { + return "woof"; + } +} +class Puppy extends Dog { + age = 1; + sound(): string { + return "yip"; + } +} +class Cat extends Animal { + lives = 9; + sound(): string { + return "meow"; + } +} + +class Box { + value: T; + constructor(value: T) { + this.value = value; + } +} +class LabeledBox extends Box { + label: string; + constructor(value: T, label: string) { + super(value); + this.label = label; + } +} + +function describe(a: Animal): string { + if (a instanceof Puppy) return `${a.name} puppy age ${a.age} ${a.tricks.length} tricks`; + if (a instanceof Dog) return `${a.name} dog ${a.tricks.join("+")}`; + if (a instanceof Cat) return `${a.name} cat ${a.lives} lives`; + return `${a.name} unknown`; +} + +function keepDogs(all: Animal[]): Dog[] { + const dogs: Dog[] = []; + for (const a of all) if (a instanceof Dog) dogs.push(a); + return dogs; +} + +function labelOf(b: Box): string { + return b instanceof LabeledBox ? `${b.label}=${b.value}` : `box=${b.value}`; +} + +function labelOfText(b: Box): string { + return b instanceof LabeledBox ? `${b.label}:${b.value}` : `text:${b.value}`; +} + +const zoo: Animal[] = [new Dog("rex"), new Cat("tom"), new Puppy("bit"), new Cat("kit")]; +for (const a of zoo) console.log(describe(a), a.sound()); +console.log( + "dogs", + keepDogs(zoo) + .map((d) => d.name) + .join(","), +); + +let tricks = 0; +for (let round = 0; round < 2000; round++) + for (const a of zoo) if (a instanceof Dog) tricks += a.tricks.length; +console.log("tricks", tricks); + +console.log(labelOf(new Box(1)), labelOf(new LabeledBox(2, "two"))); +console.log(labelOfText(new Box("a")), labelOfText(new LabeledBox("b", "bee"))); diff --git a/tests/corpus/5772-guarded-catch-narrows.ts b/tests/corpus/5772-guarded-catch-narrows.ts new file mode 100644 index 000000000..a29bda9a0 --- /dev/null +++ b/tests/corpus/5772-guarded-catch-narrows.ts @@ -0,0 +1,63 @@ +// Catch bindings narrowed by typeof or instanceof extract their payload +// through a kind or class guard. Covers string, number and boolean throws, +// Error subclass hierarchies, and a thrown standalone class. +class AppError extends Error { + code: number; + constructor(message: string, code: number) { + super(message); + this.name = "AppError"; + this.code = code; + } +} +class NotFound extends AppError { + path: string; + constructor(path: string) { + super(`missing ${path}`, 404); + this.name = "NotFound"; + this.path = path; + } +} +class Signal { + reason: string; + constructor(reason: string) { + this.reason = reason; + } +} + +function fail(which: number): void { + if (which === 0) throw "text"; + if (which === 1) throw 7.5; + if (which === 2) throw false; + if (which === 3) throw new NotFound("/etc/x"); + if (which === 4) throw new AppError("bad", 500); + if (which === 5) throw new RangeError("range"); + if (which === 6) throw new Signal("stop"); +} + +function classify(which: number): string { + try { + fail(which); + return "ok"; + } catch (e) { + if (typeof e === "string") return `string ${e.length} ${e}`; + if (typeof e === "number") return `number ${e * 2}`; + if (typeof e === "boolean") return `boolean ${!e}`; + if (e instanceof NotFound) return `notfound ${e.path} ${e.code}`; + if (e instanceof AppError) return `app ${e.code} ${e.message}`; + if (e instanceof Error) return `error ${e.name}: ${e.message}`; + if (e instanceof Signal) return `signal ${e.reason}`; + return "unknown"; + } +} + +for (let which = 0; which <= 7; which++) console.log(which, classify(which)); + +let codes = 0; +for (let i = 0; i < 500; i++) { + try { + fail(3 + (i % 2)); + } catch (e) { + if (e instanceof AppError) codes += e.code; + } +} +console.log("codes", codes); diff --git a/tests/corpus/5773-stale-narrowing-inherited.ts b/tests/corpus/5773-stale-narrowing-inherited.ts new file mode 100644 index 000000000..a63ed4614 --- /dev/null +++ b/tests/corpus/5773-stale-narrowing-inherited.ts @@ -0,0 +1,74 @@ +// A binding initialized or assigned from a stale narrowed read inherits the +// stale narrowing: after reset() stores a Lit, TypeScript still types +// `current` as Neg, and `const held: Expr = current` narrows `held` to Neg +// too. Reads of such bindings observe the value stored now, as Node does: +// members every arm has read the current arm, and an arm-only member of +// the wrong arm throws the catchable TypeError instead of reading another +// record's slot. +type Lit = { kind: "lit"; value: number }; +type Neg = { kind: "neg"; operand: Expr }; +type Expr = Lit | Neg; + +function show(e: Expr): string { + return e.kind === "lit" ? String(e.value) : `-${show(e.operand)}`; +} + +function fromInitializer(replace: boolean): string { + let current: Expr | null = null; + const reset = (): void => { + current = { kind: "lit", value: 7 }; + }; + current = { kind: "neg", operand: { kind: "lit", value: 1 } }; + if (replace) reset(); + if (current === null) return "null"; + const held: Expr = current; + const kind = held.kind; + try { + return `${kind} ${show(held.operand)}`; + } catch (e) { + return `${kind} caught ${(e as Error).name}`; + } +} + +function fromAssignment(replace: boolean): string { + let current: Expr | null = null; + const reset = (): void => { + current = { kind: "lit", value: 8 }; + }; + current = { kind: "neg", operand: { kind: "lit", value: 2 } }; + if (replace) reset(); + let held: Expr = { kind: "lit", value: 0 }; + if (current === null) return show(held); + held = current; + try { + return `${held.kind} ${show(held.operand)}`; + } catch (e) { + return `${held.kind} caught ${(e as Error).name}`; + } +} + +class Holder { + expr: Expr | null = null; + replace(): void { + this.expr = { kind: "lit", value: 9 }; + } +} + +function fromProperty(replace: boolean): string { + const h = new Holder(); + h.expr = { kind: "neg", operand: { kind: "lit", value: 3 } }; + if (replace) h.replace(); + if (h.expr === null) return "null"; + const held: Expr = h.expr; + try { + return `${held.kind} ${show(held.operand)}`; + } catch (e) { + return `${held.kind} caught ${(e as Error).name}`; + } +} + +for (const replace of [false, true]) { + console.log("initializer:", fromInitializer(replace)); + console.log("assignment:", fromAssignment(replace)); + console.log("property:", fromProperty(replace)); +} From 23e445f3a0d964aff5c05f933ec7eb471812ae42 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 07:31:37 -0700 Subject: [PATCH 084/117] Say that a lying type predicate can fail a narrowing guard A narrowing guard fails on a compiler bug, and also on a program whose hand-written type predicate or assertion function (`x is T`, `asserts x is T`) lied about a value's type: TypeScript trusts those claims without checking them. The trap messages no longer call the failure an internal error: scriptc: a narrowed value does not have the type its narrowing proved (a type predicate or assertion may be wrong) with matching wording for downcasts and catch bindings. The guard header and the IR comments say the same. A native test pins that a lying predicate and a lying assertion function print their earlier output and then abort with the message, where they used to crash. Co-Authored-By: Claude Opus 5.5 --- .../src/backend/llvm/narrow-guards.ts | 24 ++++--- packages/compiler/src/ir/ir.ts | 13 ++-- .../test/narrow-guard-emission.test.ts | 9 ++- .../compiler/test/narrow-guard-traps.test.ts | 72 +++++++++++++++++++ 4 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 packages/compiler/test/narrow-guard-traps.test.ts diff --git a/packages/compiler/src/backend/llvm/narrow-guards.ts b/packages/compiler/src/backend/llvm/narrow-guards.ts index 883045b95..910af6f79 100644 --- a/packages/compiler/src/backend/llvm/narrow-guards.ts +++ b/packages/compiler/src/backend/llvm/narrow-guards.ts @@ -4,22 +4,26 @@ * class or kind TypeScript's control-flow narrowing proved. Emitted code * verifies that proof once at the narrowing site: the tag, class interval or * caught kind is compared and a mismatch stops the program through the - * runtime trap funnel instead of reading the payload as the wrong type. A - * correct program never takes the failing branch: the frontend lowers every - * narrowing it cannot prove through checked extraction, which throws the - * catchable TypeError. A failing guard is therefore a compiler bug, so it - * aborts rather than unwinding through code that assumed the extraction - * could not throw. The guards are cheap: one load and compare per site, - * which LLVM folds where an identical test already dominates. */ + * runtime trap funnel instead of reading the payload as the wrong type. The + * frontend lowers every narrowing it knows it cannot prove through checked + * extraction, which throws the catchable TypeError, so a failing guard means + * either a compiler bug or a program whose hand-written type predicate or + * assertion function (`x is T`, `asserts x is T`) lied about a value's type: + * TypeScript trusts those claims without checking them. The guard aborts + * rather than unwinding through code that assumed the extraction could not + * throw. The guards are cheap: one load and compare per site, which LLVM + * folds where an identical test already dominates. */ import { InternalCompilerError } from "../../errors.js"; import { classMembershipIntervals } from "./classes.js"; import type { LlvmEmitterContext } from "./expr-context.js"; import { vAdapters } from "./shapes.js"; +const NARROW_GUARD_HINT = " (a type predicate or assertion may be wrong)\n"; + export const NARROW_GUARD_MESSAGES = { - union: "scriptc: internal error: a narrowed union value holds a different arm\n", - downcast: "scriptc: internal error: a downcast object is not an instance of its target class\n", - caught: "scriptc: internal error: a narrowed catch binding holds a different value\n", + union: `scriptc: a narrowed value does not have the type its narrowing proved${NARROW_GUARD_HINT}`, + downcast: `scriptc: a narrowed object is not an instance of the class its narrowing proved${NARROW_GUARD_HINT}`, + caught: `scriptc: a narrowed catch binding does not have the type its narrowing proved${NARROW_GUARD_HINT}`, } as const; /** Continues in a fresh block where `ok` holds; otherwise traps with the diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 80ec0e972..04c320b8f 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -2957,8 +2957,8 @@ export type IrExpr = * subclass). The frontend emits this only where tsc's control-flow * narrowing has already proven the dynamic class (an `instanceof` guard), * like unionNarrow. Backends verify the class once and trap on a mismatch - * a correct program never reaches, then reinterpret the pointer with - * ownership transferring like upcast. */ + * (a compiler bug or a lying type predicate or assertion function), then + * reinterpret the pointer with ownership transferring like upcast. */ | { kind: "downcast"; value: IrExpr; type: IrType; loc: SrcLoc } /** `x instanceof C` where x's static class and C are both in extends- * hierarchies: an O(1) preorder-interval check against the vtable the @@ -3391,8 +3391,8 @@ export type IrExpr = * analog of unionNarrow: the frontend emits this only where tsc's * control-flow narrowing has already proven the matching test * (`e instanceof C` / `typeof e === "string"`). Backends verify the kind - * or class once and trap on a mismatch a correct program never reaches. - * `type` is f64, bool, string, or a class object; refcounted results come + * or class once and trap on a mismatch (a compiler bug or a lying type + * predicate or assertion function). `type` is f64, bool, string, or a class object; refcounted results come * out retained (+1). */ | { kind: "caughtNarrow"; value: IrExpr; type: IrType; loc: SrcLoc } /** CHECKED extraction of a catch binding's payload as a hierarchy-class @@ -3422,8 +3422,9 @@ export type IrExpr = /** Union payload extraction: `value` is union-typed and `type` is * arms[tag]. The frontend emits this only where tsc's control-flow * narrowing has already narrowed the expression to that arm; backends - * verify the tag once and trap on a mismatch a correct program never - * reaches, so a wrong proof cannot read the payload as another arm. + * verify the tag once and trap on a mismatch (a compiler bug or a lying + * type predicate or assertion function), so a wrong proof cannot read the + * payload as another arm. * Refcounted payloads come out retained (+1). */ | { kind: "unionNarrow"; unionId: string; tag: number; value: IrExpr; type: IrType; loc: SrcLoc } /** Discriminant read `r.kind` on a union receiver: every arm is a diff --git a/packages/compiler/test/narrow-guard-emission.test.ts b/packages/compiler/test/narrow-guard-emission.test.ts index 251809345..026762cae 100644 --- a/packages/compiler/test/narrow-guard-emission.test.ts +++ b/packages/compiler/test/narrow-guard-emission.test.ts @@ -35,7 +35,7 @@ function width(v: string | number): number { } console.log(width("abc") + width(4)); `); - expect(guardCount(llvm, "scriptc: internal error: a narrowed union value")).toBeGreaterThan(0); + expect(guardCount(llvm, "scriptc: a narrowed value does not")).toBeGreaterThan(0); }); /** The tag compares that feed narrowing guards, as `eq K` / `ne K`. */ @@ -87,7 +87,7 @@ function count(value: Base): number { } console.log(count(new Child()), count(new Base())); `); - expect(guardCount(llvm, "scriptc: internal error: a downcast object")).toBeGreaterThan(0); + expect(guardCount(llvm, "scriptc: a narrowed object is not")).toBeGreaterThan(0); }); test("catch-binding narrowing verifies the caught kind and class", async () => { @@ -105,7 +105,7 @@ function run(which: number): string { } console.log(run(0), run(1)); `); - expect(guardCount(llvm, "scriptc: internal error: a narrowed catch binding")).toBeGreaterThan(1); + expect(guardCount(llvm, "scriptc: a narrowed catch binding")).toBeGreaterThan(1); }); test("programs without narrowings carry no guards", async () => { @@ -114,6 +114,5 @@ let total = 0; for (let i = 0; i < 10; i++) total += i; console.log(total); `); - expect(llvm).not.toContain("scriptc: internal error: a narrowed"); - expect(llvm).not.toContain("scriptc: internal error: a downcast"); + expect(llvm).not.toContain("scriptc: a narrowed"); }); diff --git a/packages/compiler/test/narrow-guard-traps.test.ts b/packages/compiler/test/narrow-guard-traps.test.ts new file mode 100644 index 000000000..be89ad341 --- /dev/null +++ b/packages/compiler/test/narrow-guard-traps.test.ts @@ -0,0 +1,72 @@ +/* A hand-written type predicate or assertion function is a claim TypeScript + * does not check. When it lies, the narrowing guard stops the program with + * its trap message instead of reading the payload as the claimed type (which + * crashed before the guards existed). Node throws or reads `undefined` + * there, so these programs intentionally diverge and are not corpus cases. */ +import { spawnSync } from "node:child_process"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile } from "../src/index.js"; + +const UNION_TRAP = + "scriptc: a narrowed value does not have the type its narrowing proved " + + "(a type predicate or assertion may be wrong)\n"; + +async function run(source: string): Promise> { + const dir = mkdtempSync(join(tmpdir(), "scriptc-narrow-traps-")); + try { + const entry = join(dir, "main.ts"); + writeFileSync(entry, source); + const built = await compile(entry, { + outDir: dir, + outPath: join(dir, "program"), + sanitize: process.env["SCRIPTC_SAN"] === "1", + }); + if (!built.ok) throw new Error(built.diagnostics.map((d) => d.message).join("\n")); + return spawnSync(built.binaryPath, [], { timeout: 30_000 }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +} + +test.skipIf(process.platform === "win32")( + "a lying type predicate stops at the narrowing guard", + async () => { + const result = await run(` +function isText(x: string | number): x is string { + return x !== ""; +} +function shout(v: string | number): string { + if (isText(v)) return v.toUpperCase(); + return "other"; +} +const inputs: (string | number)[] = ["a", 42]; +for (const v of inputs) console.log(shout(v)); +`); + expect(result.error).toBeUndefined(); + expect(result.signal).toBe("SIGABRT"); + expect(result.stdout.toString()).toBe("A\n"); + expect(result.stderr.toString()).toBe(UNION_TRAP); + }, +); + +test.skipIf(process.platform === "win32")( + "a lying assertion function stops at the narrowing guard", + async () => { + const result = await run(` +function assertText(x: string | number): asserts x is string {} +function width(v: string | number): number { + assertText(v); + return v.length; +} +const inputs: (string | number)[] = ["abc", 7]; +for (const v of inputs) console.log(width(v)); +`); + expect(result.error).toBeUndefined(); + expect(result.signal).toBe("SIGABRT"); + expect(result.stdout.toString()).toBe("3\n"); + expect(result.stderr.toString()).toBe(UNION_TRAP); + }, +); From b4ef932b722010ebf6f55044fd173a8524922d49 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 09:52:17 -0500 Subject: [PATCH 085/117] Support zlib stream classes as const aliases and instanceof targets `const C = zlib.Gzip` stopped at SC2020, and `instanceof zlib.Gzip` (any zlib class) stopped at SC1090. A const binding of a zlib class is now a compile-time alias with no runtime slot: `new C()`, `typeof C`, `C.name` and `C === zlib.Gzip` lower at the use. `instanceof` against a zlib class asks the runtime for the stream's mode when the operand is a Transform, tests for a Transform first when it is typed as one of Transform's bases, and answers false for other static types, as in Node. Other uses of an alias as a value report SC1090 at the use. --- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../frontend/lowering/builtins/compression.ts | 150 +++++++++++++++++- .../src/frontend/lowering/lower-classes.ts | 6 +- .../src/frontend/lowering/lower-exprs.ts | 42 ++++- .../src/frontend/lowering/lower-modules.ts | 2 + .../src/frontend/lowering/lower-stmts.ts | 2 + .../compiler/src/frontend/lowering/lowerer.ts | 5 + .../compiler/src/ir/builtin-signatures.ts | 3 + .../corpus/5975-zlib-class-values.ts.json | 6 + .../zlib-class-alias-escape.ts.json | 6 + packages/runtime/src/scr_zlib.h | 3 + packages/runtime/src/scr_zlib_stream.c | 5 + tests/corpus/5975-zlib-class-values.ts | 52 ++++++ tests/diagnostics/zlib-class-alias-escape.ts | 11 ++ .../zlib-class-alias-escape.ts.txt | 13 ++ tests/harness/corpus-costs.json | 2 + 16 files changed, 303 insertions(+), 6 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5975-zlib-class-values.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/zlib-class-alias-escape.ts.json create mode 100644 tests/corpus/5975-zlib-class-values.ts create mode 100644 tests/diagnostics/zlib-class-alias-escape.ts create mode 100644 tests/harness/__snapshots__/zlib-class-alias-escape.ts.txt diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index f69c96e6e..02bf37192 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -848,6 +848,7 @@ export const LIB_FN_SYMS: Record = { "fetch.abortAny": "scr_fetch_abort_any", "fetch.webIs": "scr_fetch_web_is", "fetch.streamIs": "scr_fetch_stream_is", + "zlib.streamIs": "scr_zlib_stream_is", "fetch.streamNew": "scr_fetch_stream_new", "fetch.streamFrom": "scr_fetch_stream_from", "fetch.readerRead": "scr_fetch_reader_read", diff --git a/packages/compiler/src/frontend/lowering/builtins/compression.ts b/packages/compiler/src/frontend/lowering/builtins/compression.ts index 9c47711c1..c9553c2f9 100644 --- a/packages/compiler/src/frontend/lowering/builtins/compression.ts +++ b/packages/compiler/src/frontend/lowering/builtins/compression.ts @@ -1,11 +1,12 @@ import { lowerBuiltinByteInput, errorFirstBytesCallback } from "./arguments.js"; -import { dynUndefinedExpr, numLit } from "../../../ir/build.js"; +import { dynUndefinedExpr, numLit, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; import { isNodeTypesPath } from "../../dts-paths.js"; import { + BOOL, BYTES_U8, DYN, F64, @@ -39,7 +40,8 @@ const ZLIB_CALLBACK_FNS: Readonly> = { unzip: "zlib.unzipCb", }; -const ZLIB_STREAM_T: IrType = { kind: "object", className: "%Transform" }; +const ZLIB_STREAM_CLASS = "%Transform"; +const ZLIB_STREAM_T: IrType = { kind: "object", className: ZLIB_STREAM_CLASS }; /** A zlib data argument, lowered once: Buffer/Uint8Array bytes, a string * (UTF-8 encoded here), or a checked-dynamic value (the JS lane's untyped @@ -130,6 +132,8 @@ export function zlibStreamModeOf( symbol: ts.Symbol | null | undefined, ): number | null { if (!symbol) return null; + const aliasMode = zlibClassAliasModeOf(lowerer, symbol, 0); + if (aliasMode !== undefined) return aliasMode; const target = symbol.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(symbol) : symbol; const mode = ZLIB_STREAM_MODES.get(target.name); @@ -494,3 +498,145 @@ export function lowerZlibModuleCall( } throw new InternalCompilerError(`unhandled lowered zlib member ${bi.member}`); } + +/** The zlib stream class an expression names (`zlib.Gzip`, an imported + * `Gzip`, a `const C = zlib.Gzip` alias), as its node_zlib_mode, or null. */ +export function zlibClassModeOfExpr(lowerer: Lowerer, expr: ts.Expression): number | null { + let e = expr; + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (ts.isIdentifier(e)) return zlibStreamModeOf(lowerer, lowerer.checker.getSymbolAtLocation(e)); + if (ts.isPropertyAccessExpression(e) && !e.questionDotToken) { + return zlibStreamModeOf(lowerer, lowerer.checker.getSymbolAtLocation(e.name)); + } + return null; +} + +/** The class name of a zlib stream mode (Node's constructor name). */ +export function zlibClassName(mode: number): string { + for (const [name, m] of ZLIB_STREAM_MODES) if (m === mode) return name; + return "Zlib"; +} + +/** The mode of a `const C = zlib.Gzip` binding (or an alias of such a + * binding), null when the symbol is a const binding of something else, + * undefined when it is not a const binding. Resolved from the declaration, + * so uses lowered before the declaration statement see the same answer. */ +function zlibClassAliasModeOf( + lowerer: Lowerer, + symbol: ts.Symbol, + depth: number, +): number | null | undefined { + const cached = lowerer.zlibClassAliases.get(symbol); + if (cached !== undefined) return cached; + if ((symbol.flags & ts.SymbolFlags.BlockScopedVariable) === 0) return undefined; + const decl = lowerer.checker.valueDeclarationOf(symbol); + if (decl === undefined || !ts.isVariableDeclaration(decl) || !ts.isIdentifier(decl.name)) { + return undefined; + } + // const only: a var or let binding could be reassigned + const list = decl.parent; + if (!ts.isVariableDeclarationList(list) || (list.flags & ts.NodeFlags.Const) === 0) { + return undefined; + } + let init = decl.initializer; + while (init !== undefined && ts.isParenthesizedExpression(init)) init = init.expression; + if (init === undefined || depth > 16) return null; + let mode: number | null = null; + if (ts.isIdentifier(init)) { + const next = lowerer.checker.getSymbolAtLocation(init); + if (next !== undefined) { + const nested = zlibClassAliasModeOf(lowerer, next, depth + 1); + mode = nested === undefined ? zlibStreamModeOf(lowerer, next) : nested; + } + } else if (ts.isPropertyAccessExpression(init) && !init.questionDotToken) { + mode = zlibStreamModeOf(lowerer, lowerer.checker.getSymbolAtLocation(init.name)); + } + if (mode !== null) lowerer.zlibClassAliases.set(symbol, mode); + return mode; +} + +/** True for `const C = zlib.Gzip` (or an alias of an alias): a + * compile-time zlib class alias that owns no runtime slot, so the + * statement lowering skips it. */ +export function registerZlibClassAlias( + lowerer: Lowerer, + nameNode: ts.Node, + init: ts.Expression | undefined, +): boolean { + if (!ts.isIdentifier(nameNode) || init === undefined) return false; + const symbol = lowerer.checker.getSymbolAtLocation(nameNode); + return symbol !== undefined && zlibClassAliasOf(lowerer, symbol) !== null; +} + +/** The mode of a `const C = zlib.Gzip` alias symbol, or null. */ +export function zlibClassAliasOf(lowerer: Lowerer, symbol: ts.Symbol): number | null { + return zlibClassAliasModeOf(lowerer, symbol, 0) ?? null; +} + +/** `value instanceof zlib.Gzip` (any spelling of the class, aliases + * included). zlib streams are runtime Transforms: a Transform operand asks + * the runtime for the stream's mode, and an operand typed as one of + * Transform's bases (Duplex, Readable, EventEmitter) is first tested for a + * Transform. Any other static type answers false after the operand + * evaluates. */ +export function lowerZlibInstanceOf( + lowerer: Lowerer, + expr: ts.BinaryExpression, + mode: number, + loc: SrcLoc, +): IrExpr { + const value = lowerer.lowerExpr(expr.left); + const type = value.type; + const holdsStream = (className: string): boolean => + className === ZLIB_STREAM_CLASS || lowerer.isSubclassOf(ZLIB_STREAM_CLASS, className); + const arms = type.kind === "union" ? lowerer.unions.get(type.unionId)?.arms : undefined; + if ( + type.kind === "dyn" || + arms?.some((arm) => arm.kind === "object" && holdsStream(arm.className)) + ) { + lowerer.unsupported( + "SC1090", + expr, + `'instanceof zlib.${zlibClassName(mode)}' on an untyped or union value (give the operand a stream type first)`, + ); + } + if (type.kind === "object" && holdsStream(type.className)) { + const isMode = (stream: IrExpr): IrExpr => ({ + kind: "libCall", + fn: "zlib.streamIs", + args: [stream, numLit(mode, loc)], + type: BOOL, + loc, + }); + if (type.className === ZLIB_STREAM_CLASS) return isMode(value); + const local = lowerer.declareHiddenLocal("%zlibTest", type); + const ref = varRef(local.id, type, loc); + return { + kind: "seqExpr", + stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], + result: { + kind: "logical", + op: "&&", + left: { + kind: "instanceOf", + value: ref, + className: ZLIB_STREAM_CLASS, + type: BOOL, + loc, + }, + right: isMode({ kind: "downcast", value: ref, type: ZLIB_STREAM_T, loc }), + type: BOOL, + loc, + }, + type: BOOL, + loc, + }; + } + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: value, loc }], + result: { kind: "boolLit", value: false, type: BOOL, loc }, + type: BOOL, + loc, + }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 7a98096b7..b9bfc7e99 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -10,7 +10,7 @@ import { InternalCompilerError } from "../../errors.js"; * hierarchy registration. */ import { fsStreamClassOf, lowerFsStreamNew } from "./builtins/fs-streams.js"; import * as ts from "../ts7/adapter.js"; -import { lowerZlibStreamNew, zlibStreamModeOf } from "./builtins/compression.js"; +import { lowerZlibStreamNew, zlibClassName, zlibStreamModeOf } from "./builtins/compression.js"; import type { FnCtx, Lowerer } from "./lowerer.js"; import { BOOL, @@ -8664,7 +8664,7 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { // `new zlib.Gzip(options?)` — the zlib stream classes. const zlibModeNs = zlibStreamModeOf(lowerer, resolved); if (zlibModeNs !== null) { - const what = `new zlib.${expr.expression.name.text}`; + const what = `new zlib.${zlibClassName(zlibModeNs)}`; return lowerZlibStreamNew(lowerer, expr.arguments ?? [], zlibModeNs, what, expr, loc); } // `new N.C(...)` / `new a.Point(...)` — construction through a @@ -8922,7 +8922,7 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { if (streamInfo) return lowerStreamNew(lowerer, expr, streamInfo); const zlibMode = zlibStreamModeOf(lowerer, symbol); if (zlibMode !== null) { - const what = `new zlib.${symbol!.name}`; + const what = `new zlib.${zlibClassName(zlibMode)}`; return lowerZlibStreamNew(lowerer, expr.arguments ?? [], zlibMode, what, expr, loc); } // `new URL(input)`: the WHATWG URL class (stdlib/@types provenance — diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index c8874fe34..33d602228 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -31,7 +31,14 @@ import { literalUnionArm } from "../union-discriminants.js"; * (FieldTarget). */ import { isFsStreamMember, lowerFsStreamProperty } from "./builtins/fs-streams.js"; import * as ts from "../ts7/adapter.js"; -import { isZlibStreamMember, lowerZlibStreamBytesWritten } from "./builtins/compression.js"; +import { + isZlibStreamMember, + lowerZlibInstanceOf, + lowerZlibStreamBytesWritten, + zlibClassAliasOf, + zlibClassModeOfExpr, + zlibClassName, +} from "./builtins/compression.js"; import { constituentTypes } from "../ts7/checker.js"; import { dirname } from "node:path"; import * as posix from "node:path/posix"; @@ -608,6 +615,10 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { if (isNodeModuleValue(lowerer, expr.expression)) { return { kind: "strLit", value: "object", type: STRING, loc }; } + // `typeof zlib.Gzip`, `typeof C` over a zlib class alias. + if (zlibClassModeOfExpr(lowerer, expr.expression) !== null) { + return { kind: "strLit", value: "function", type: STRING, loc }; + } if (ts.isPropertyAccessExpression(expr.expression)) { const member = expr.expression; const prototype = member.expression; @@ -864,6 +875,15 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { `a builtin function alias as an escaping value (call '${expr.text}' directly)`, ); } + // `const C = zlib.Gzip` owns no runtime slot: construction, + // instanceof, typeof and .name lower at their use sites. + if (sym && zlibClassAliasOf(lowerer, sym) !== null) { + lowerer.unsupported( + "SC1090", + expr, + `a zlib class alias as an escaping value (use '${expr.text}' with new, instanceof, typeof or .name)`, + ); + } } // Union-typed bindings read through tsc's control-flow narrowing: // when the checker types this USE as a single arm, maybeNarrow @@ -1799,6 +1819,11 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { const table = lowerInternTableProperty(lowerer, expr); if (table) return table; } + // `zlib.Gzip.name`, `C.name` over a zlib class alias. + if (expr.name.text === "name" && !expr.questionDotToken) { + const mode = zlibClassModeOfExpr(lowerer, expr.expression); + if (mode !== null) return { kind: "strLit", value: zlibClassName(mode), type: STRING, loc }; + } // Expando statics may still be absent even when JS inference sees // the eventual assignment's scalar type. Preserve the checked value. const staticField = lowerStaticFieldRead(lowerer, expr); @@ -10017,6 +10042,19 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr lowerUnionTypeofTest(lowerer, expr, loc); if (test) return test; } + // `C === zlib.Gzip` between two zlib class references: the classes + // are compile-time values, so the answer folds. + if ( + op === ts.SyntaxKind.EqualsEqualsEqualsToken || + op === ts.SyntaxKind.ExclamationEqualsEqualsToken + ) { + const leftClass = zlibClassModeOfExpr(lowerer, expr.left); + const rightClass = leftClass === null ? null : zlibClassModeOfExpr(lowerer, expr.right); + if (leftClass !== null && rightClass !== null) { + const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken; + return { kind: "boolLit", value: (leftClass === rightClass) !== negated, type: BOOL, loc }; + } + } const strictEquality = op === ts.SyntaxKind.EqualsEqualsEqualsToken || @@ -12062,6 +12100,8 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc // h2 compat 'connect' narrowing (lower-server.ts): a union tag test. const sockTest = lowerSocketInstanceOf(lowerer, expr, loc); if (sockTest !== null) return sockTest; + const zlibMode = zlibClassModeOfExpr(lowerer, expr.right); + if (zlibMode !== null) return lowerZlibInstanceOf(lowerer, expr, zlibMode, loc); if (lowerer.isStdlibGlobal(expr.right, "Set") || lowerer.isStdlibGlobal(expr.right, "Map")) { const collection = lowerer.isStdlibGlobal(expr.right, "Map") ? "map" : "set"; diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index 81ded6a58..c5802b07e 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -80,6 +80,7 @@ import { createRequireProgramModuleDecl, } from "./builtins/module-bindings.js"; import { isPromisifyCall, registerBuiltinCallableAlias } from "./builtins/callable-aliases.js"; +import { registerZlibClassAlias } from "./builtins/compression.js"; import { stripTypeCasts } from "./builtins/arguments.js"; import { bindingContextualGenericFnNodeOf, @@ -1700,6 +1701,7 @@ export function collectGlobals( // resolution and value reads reuse the source's interned closure. if (isConst && registerOverloadedCallableAlias(lowerer, decl)) continue; if (isConst && registerBuiltinCallableAlias(lowerer, decl.name, decl.initializer)) continue; + if (registerZlibClassAlias(lowerer, decl.name, decl.initializer)) continue; // `const f = (x) => ...` at file scope of an npm-static JS file // whose params are implicit-any: the implicit-monomorphization // twin of the generic binding above — no global exists; calls and diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 2cc51e789..5d742ee46 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -147,6 +147,7 @@ import { } from "./builtins/module-bindings.js"; import { lowerNodeModuleCall } from "./builtins/module-resolution.js"; import { registerBuiltinCallableAlias } from "./builtins/callable-aliases.js"; +import { registerZlibClassAlias } from "./builtins/compression.js"; import { lowerEnumDeclaration } from "./lower-enums.js"; import { abstractPropertyDeclOf, @@ -4263,6 +4264,7 @@ export function lowerVarDecl( // reads reuse its interned closure identity. if (!isLet && registerOverloadedCallableAlias(lowerer, decl)) return null; if (!isLet && registerBuiltinCallableAlias(lowerer, decl.name, decl.initializer)) return null; + if (registerZlibClassAlias(lowerer, decl.name, decl.initializer)) return null; // `const knownBy = (cmd) => ...` — an IMPLICIT-ANY function-value // binding in npm-static JS (function-scope bindings register here, in diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index b4520d3be..2b5ae2e92 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1802,6 +1802,11 @@ export class Lowerer { * typeParamBindings — the checker has no `T` to substitute, so the * binding rides the node-type accessor instead of mapType. */ implicitParamTypes: Map | null = null; + /** Immutable bindings that name a zlib stream class (`const C = + * zlib.Gzip`), keyed by the binding's symbol: the class's + * node_zlib_mode. No runtime slot exists: new, typeof, .name and === + * resolve at compile time, and instanceof checks the stream's mode. */ + readonly zlibClassAliases = new Map(); /** Whether some net.Socket in this program may get an encoding: a * setEncoding call whose receiver is a socket or an untyped value. * Computed once on first use (null until then). */ diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index ca2749591..b34bcefdd 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2771,6 +2771,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * receivers are borrowed. */ "zlib.streamNew": { argTypes: [F64, DYN], result: VOID }, "zlib.streamBytesWritten": { argTypes: [null], result: F64 }, + /** `stream instanceof zlib.Gzip`: the borrowed stream and the class's + * node_zlib_mode; true when the stream is a zlib stream of that mode. */ + "zlib.streamIs": { argTypes: [null, F64], result: BOOL }, "zlib.streamFlush": { argTypes: [null, DYN], result: VOID }, "zlib.streamFlushCb": { argTypes: [null, DYN, null], result: VOID }, "zlib.streamParams": { argTypes: [null, DYN, DYN], result: VOID }, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5975-zlib-class-values.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5975-zlib-class-values.ts.json new file mode 100644 index 000000000..561bd1e92 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5975-zlib-class-values.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5975-zlib-class-values.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/zlib-class-alias-escape.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/zlib-class-alias-escape.ts.json new file mode 100644 index 000000000..cab5c0ba0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/zlib-class-alias-escape.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/zlib-class-alias-escape.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_zlib.h b/packages/runtime/src/scr_zlib.h index 3ac07d844..124e157ab 100644 --- a/packages/runtime/src/scr_zlib.h +++ b/packages/runtime/src/scr_zlib.h @@ -90,6 +90,9 @@ ScrPromise *scr_zlib_codec_promise_dyn(ScrDyn *data, double mode, ScrDyn *opts); * with Node's ladder. The callbacks MOVE in and may be NULL. */ ScrStream *scr_zlib_stream_new(double mode, ScrDyn *opts); double scr_zlib_stream_bytes_written(ScrStream *s); +/* `s instanceof zlib.Gzip` (and the other classes): true when s is a zlib + * stream built with that mode. s is borrowed. */ +bool scr_zlib_stream_is(ScrStream *s, double mode); void scr_zlib_stream_flush(ScrStream *s, ScrDyn *kind, ScrClosure *cb); void scr_zlib_stream_params(ScrStream *s, ScrDyn *level, ScrDyn *strategy, ScrClosure *cb); void scr_zlib_stream_close(ScrStream *s, ScrClosure *cb); diff --git a/packages/runtime/src/scr_zlib_stream.c b/packages/runtime/src/scr_zlib_stream.c index 55dcd6302..14d8747e8 100644 --- a/packages/runtime/src/scr_zlib_stream.c +++ b/packages/runtime/src/scr_zlib_stream.c @@ -496,6 +496,11 @@ static ScrZlibStream *scr_zs_from_stream(ScrStream *s) { return zs; } +bool scr_zlib_stream_is(ScrStream *s, double mode) { + const ScrZlibStream *zs = scr_stream_native(s, &scr_zs_release_v); + return zs != NULL && zs->mode == (int)mode; +} + double scr_zlib_stream_bytes_written(ScrStream *s) { ScrZlibStream *zs = scr_zs_from_stream(s); return zs ? zs->bytes_written : 0; diff --git a/tests/corpus/5975-zlib-class-values.ts b/tests/corpus/5975-zlib-class-values.ts new file mode 100644 index 000000000..f46d7d5d4 --- /dev/null +++ b/tests/corpus/5975-zlib-class-values.ts @@ -0,0 +1,52 @@ +// The zlib stream classes as values: const aliases construct, instanceof +// tests each class against stream, EventEmitter and plain operands, and +// typeof, .name and === answer as in Node. +import * as zlib from "node:zlib"; +import { Gunzip, Unzip } from "node:zlib"; +import { Readable, Transform } from "node:stream"; +import { EventEmitter } from "node:events"; + +function makeLate() { + return new Late(); +} + +const Gz = zlib.Gzip; +const Gun = Gunzip; +const Again = Gz; +const Late = zlib.Inflate; + +const gz = new Gz(); +console.log("new alias", gz instanceof zlib.Gzip, gz instanceof Gz, gz instanceof Again); +console.log("other classes", gz instanceof Gun, gz instanceof Gunzip, gz instanceof zlib.Deflate); +console.log("factory", zlib.createGzip() instanceof Gz, zlib.createGunzip() instanceof Gz); +console.log("hoisted use", makeLate() instanceof zlib.Inflate, makeLate() instanceof Gun); + +const asTransform: Transform = new zlib.DeflateRaw(); +console.log("transform-typed", asTransform instanceof zlib.DeflateRaw, asTransform instanceof Gz); +const plain = new Transform({ + transform(chunk, _encoding, callback) { + callback(null, chunk); + }, +}); +console.log("plain transform", plain instanceof Gz, plain instanceof Transform); +const readable = new Readable({ read() {} }); +console.log("readable", readable instanceof zlib.Unzip); + +const emitter: EventEmitter = zlib.createDeflate(); +console.log("emitter-typed", emitter instanceof zlib.Deflate, emitter instanceof zlib.Inflate); +const bare = new EventEmitter(); +console.log("bare emitter", bare instanceof zlib.Deflate); +const record = { kind: "gzip" }; +console.log("object", record instanceof Gz); + +console.log("typeof", typeof Gz, typeof zlib.Inflate, typeof Unzip); +console.log("name", Gz.name, Again.name, Gun.name, zlib.DeflateRaw.name, Unzip.name); +console.log("identity", Gz === zlib.Gzip, Again === Gz, Gz === Gun, Gz !== zlib.Gunzip); + +const chunks: Buffer[] = []; +const roundTrip = new Again(); +roundTrip.on("data", (chunk: Buffer) => chunks.push(chunk)); +roundTrip.on("end", () => { + console.log("round trip", zlib.gunzipSync(Buffer.concat(chunks)).toString()); +}); +roundTrip.end("class values"); diff --git a/tests/diagnostics/zlib-class-alias-escape.ts b/tests/diagnostics/zlib-class-alias-escape.ts new file mode 100644 index 000000000..8c8e17452 --- /dev/null +++ b/tests/diagnostics/zlib-class-alias-escape.ts @@ -0,0 +1,11 @@ +// A zlib class alias owns no runtime value: construction, instanceof, +// typeof and .name compile, other uses report at the use. instanceof on +// an untyped operand reports as well. +import * as zlib from "node:zlib"; + +const Gz = zlib.Gzip; +const classes = [Gz]; +console.log(classes.length); + +const parsed: unknown = JSON.parse("{}"); +console.log(parsed instanceof Gz); diff --git a/tests/harness/__snapshots__/zlib-class-alias-escape.ts.txt b/tests/harness/__snapshots__/zlib-class-alias-escape.ts.txt new file mode 100644 index 000000000..ea9d76089 --- /dev/null +++ b/tests/harness/__snapshots__/zlib-class-alias-escape.ts.txt @@ -0,0 +1,13 @@ +zlib-class-alias-escape.ts:7:18 - error SC1090: a zlib class alias as an escaping value (use 'Gz' with new, instanceof, typeof or .name) is not supported yet + + 6 | const Gz = zlib.Gzip; + 7 | const classes = [Gz]; + | ^~ + 8 | console.log(classes.length); + +zlib-class-alias-escape.ts:11:13 - error SC1090: 'instanceof zlib.Gzip' on an untyped or union value (give the operand a stream type first) is not supported yet + + 10 | const parsed: unknown = JSON.parse("{}"); + 11 | console.log(parsed instanceof Gz); + | ^~~~~~~~~~~~~~~~~~~~ + 12 | \ No newline at end of file diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 4acd0928d..d5f63bfbc 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1916,6 +1916,7 @@ "5971-buffer-chunks-to-string.ts": 2700, "5972-net-set-encoding-listeners.ts": 2550, "5974-typeof-module-exports.cjs": 2000, + "5975-zlib-class-values.ts": 2800, "5990-worker-uncloneable.mjs": 3283, "5991-worker-async-dispose.mjs": 5699, "5992-worker-thread-name-lifetime.mjs": 2687, @@ -4620,6 +4621,7 @@ "5971-buffer-chunks-to-string.ts": 3100, "5972-net-set-encoding-listeners.ts": 3000, "5974-typeof-module-exports.cjs": 2500, + "5975-zlib-class-values.ts": 4200, "5990-worker-uncloneable.mjs": 22432, "5991-worker-async-dispose.mjs": 25768, "5992-worker-thread-name-lifetime.mjs": 28932, From acc920ab85a5beba405be2fd0368b8ca5e06b9fb Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 09:57:26 -0500 Subject: [PATCH 086/117] Add the TestContext filePath, attempt, passed, workerId and tags values node:test changes, matching Node 24.22: - t.filePath is the entry file's path, as Node's entryFile, fixed when the program is compiled. - t.attempt is 0, since a test runs once. - t.passed is false while the body runs and the test's outcome once the body ends, so afterEach and t.after hooks see it, as Node's pass() and fail() set it before them. - t.workerId is Number(process.env.NODE_TEST_WORKER_ID) || undefined. - t.tags is [], since the tags option has no lowering. - A test's t.before, t.after, t.beforeEach and t.afterEach hooks are released when the test ends. Hooks whose closures capture the test's context no longer keep it alive in a cycle, which the SCRIPTC_SAN=1 audit reported as live closures at exit. The ctx-members fixture compares the reporter output with Node, plain and with SCRIPTC_SAN=1. --- .../limitations/builtin-apis/test-runner.mdx | 1 + .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 34 ++++---- .../generated/node-v24-backlog.json | 79 ++++++++++------- .../generated/node-v24-internal.json | 45 +++++++--- internal/compatibility/static-support.json | 1 + .../ambient/scriptc-node-fallback.d.ts | 5 ++ .../compiler/src/backend/llvm/lib-test.ts | 4 + .../src/frontend/lowering/lower-test.ts | 86 ++++++++++++++++++- .../compiler/src/ir/builtin-signatures.ts | 4 + packages/runtime/src/scr_test.c | 21 +++++ packages/runtime/src/scr_test.h | 3 + tests/fixtures/node-test/cases/ctx-members.ts | 33 +++++++ 13 files changed, 254 insertions(+), 64 deletions(-) create mode 100644 tests/fixtures/node-test/cases/ctx-members.ts diff --git a/docs/content/limitations/builtin-apis/test-runner.mdx b/docs/content/limitations/builtin-apis/test-runner.mdx index 7a50901db..76d3a5c16 100644 --- a/docs/content/limitations/builtin-apis/test-runner.mdx +++ b/docs/content/limitations/builtin-apis/test-runner.mdx @@ -1,2 +1,3 @@ - **Concurrent tests:** with `{ concurrency }` above 1, subtests run on their own fibers, and results are reported in declaration order, as in Node. Concurrent bodies resume in Node's order around `beforeEach` hooks and nested suites. Other runner steps, such as `afterEach` and `after` hooks, take no microtask turns between bodies, so code that observes the interleaving of concurrent bodies across those steps can see a different order than Node. - **Snapshots:** `t.assert.snapshot` and `t.assert.fileSnapshot` compile, with Node's default serializer, `JSON.stringify(value, null, 2)`, or an `options.serializers` array literal. A compiled test reads the snapshot file Node writes beside the entry file, `.snapshot`, at the entry file's path when the program was compiled. Running the binary with Node's flag `--test-update-snapshots` as its first argument writes the snapshot files instead; as in Node, the flag is kept out of `process.argv` and appears in `process.execArgv`. Snapshot files are read in the form Node writes them, `` exports[`key`] = `value`; `` statements. The `snapshot.setDefaultSnapshotSerializers` and `snapshot.setResolveSnapshotPath` module functions throw `SC2020`. +- **TestContext values:** `t.filePath` is the entry file's path when the program was compiled. `t.attempt` is `0`, since a test runs once. `t.passed` is `false` while the body runs and the test's outcome in its `afterEach` and `t.after` hooks. `t.workerId` is `Number(process.env.NODE_TEST_WORKER_ID) || undefined`, as in Node. `t.tags` is `[]`, since the `tags` test option throws `SC2020`; the array is not frozen as Node's is. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index f2bb89f6e..35cbcc65e 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "be8d5b094695385e34ea", + "artifactVersion": "622f48ed5c836aec4644", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 3c0350dc3..d84bdfdfa 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -689,9 +689,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 53, + "partial": 58, "refused": 0, - "not-implemented": 64, + "not-implemented": 59, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -66447,9 +66447,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66516,9 +66516,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66562,9 +66562,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66585,9 +66585,9 @@ "inherited": false }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66608,9 +66608,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 24821377e..96a3b9475 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1144, - "verify-gap": 2185, + "audit-partial": 1149, + "verify-gap": 2180, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -67742,12 +67742,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.context.filePath", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -67823,12 +67826,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.passed", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -67873,12 +67879,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.attempt", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -67898,12 +67907,15 @@ "priority": "low", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.tags", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -67923,12 +67935,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.workerId", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 3587ae2cb..54ec0d652 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -746,9 +746,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 53, + "partial": 58, "refused": 0, - "not-implemented": 64, + "not-implemented": 59, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -90972,6 +90972,7 @@ "tests/corpus/5813-mock-timers-module.ts", "tests/corpus/5814-mock-timers-date.ts", "tests/fixtures/node-test/cases/ctx-hooks.ts", + "tests/fixtures/node-test/cases/ctx-members.ts", "tests/fixtures/node-test/cases/ctx-plan.ts", "tests/fixtures/node-test/cases/mock-fn.ts", "tests/fixtures/node-test/cases/mock-method.ts", @@ -93684,8 +93685,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.context.filePath", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -93761,8 +93766,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.passed", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "ancestor" }, @@ -93807,8 +93816,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.attempt", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "ancestor" }, @@ -93830,8 +93843,12 @@ "inherited": false }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.tags", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "ancestor" }, @@ -93853,8 +93870,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.workerId", + "tests": [ + "tests/fixtures/node-test/cases/ctx-members.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "ancestor" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index fded9de97..b374403b5 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -356,6 +356,7 @@ { "chapter": "url", "signatures": ["`port` Type: {string}"], "status": "partial", "evidence": ["tests/corpus/2946-url-port-hash.ts"] }, { "chapter": "url", "signatures": ["Legacy `urlObject`", "`urlObject.auth`", "`urlObject.hash`", "`urlObject.host`", "`urlObject.hostname`", "`urlObject.href`", "`urlObject.path`", "`urlObject.pathname`", "`urlObject.port`", "`urlObject.protocol`", "`urlObject.query`", "`urlObject.search`", "`urlObject.slashes`"], "status": "partial", "evidence": ["tests/corpus/5221-url-parse-shapes.ts", "tests/corpus/5222-url-parse-hosts.ts", "tests/corpus/5223-url-parse-query.ts", "tests/corpus/5224-url-format-objects.ts", "tests/fixtures/node-types/url-legacy.ts"] }, { "chapter": "test", "parent": "`context.assert`", "symbols": ["context.assert.snapshot", "context.assert.fileSnapshot"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/snapshot.ts", "tests/harness/node-test.test.ts"] }, + { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.filePath", "passed", "attempt", "tags", "workerId"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/ctx-members.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.diagnostic", "context.name"], "status": "partial", "evidence": ["tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.fn"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.method", "mock.reset", "mock.restoreAll"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-method.ts", "tests/corpus/5810-mock-method-records.ts", "tests/corpus/5811-mock-tracker-restore.ts", "tests/harness/node-test.test.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 69093a600..242850e92 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3325,6 +3325,11 @@ declare module "node:test" { interface TestContext { readonly name: string; readonly fullName: string; + readonly filePath: string | undefined; + readonly attempt: number; + readonly passed: boolean; + readonly workerId: number | undefined; + readonly tags: readonly string[]; readonly assert: TestContextAssert; readonly mock: MockTracker; test(name: string, fn?: TestFn): Promise; diff --git a/packages/compiler/src/backend/llvm/lib-test.ts b/packages/compiler/src/backend/llvm/lib-test.ts index d0d9a9bfc..37e642d88 100644 --- a/packages/compiler/src/backend/llvm/lib-test.ts +++ b/packages/compiler/src/backend/llvm/lib-test.ts @@ -45,6 +45,10 @@ export function emitTestLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlVal return finishRuntimeCall(host, e, "scr_test_ctx_name", a); case "test.ctxFullName": return finishRuntimeCall(host, e, "scr_test_ctx_full_name", a); + case "test.ctxPassed": + return finishRuntimeCall(host, e, "scr_test_ctx_passed", a); + case "test.workerId": + return finishRuntimeCall(host, e, "scr_test_worker_id", a); case "test.ctxHook": host.moveTemp(args[2]!); return finishRuntimeCall(host, e, "scr_test_ctx_hook", a); diff --git a/packages/compiler/src/frontend/lowering/lower-test.ts b/packages/compiler/src/frontend/lowering/lower-test.ts index d18aec305..84be23b67 100644 --- a/packages/compiler/src/frontend/lowering/lower-test.ts +++ b/packages/compiler/src/frontend/lowering/lower-test.ts @@ -66,7 +66,7 @@ function lowerMockTrackerMember( const TEST_FN_HINT = "test bodies take () or (t: TestContext) and return void or Promise"; const TESTCTX_SURFACE_HINT = - "t.test, t.skip, t.todo, t.diagnostic, t.plan, t.before, t.after, t.beforeEach, t.afterEach, t.name, t.fullName, and t.assert.* are the supported TestContext members"; + "t.test, t.skip, t.todo, t.diagnostic, t.plan, t.before, t.after, t.beforeEach, t.afterEach, t.name, t.fullName, t.filePath, t.attempt, t.passed, t.workerId, t.tags, and t.assert.* are the supported TestContext members"; /** Registration calls return Node's Promise, but the promise only * resolves through the runner — consuming it outside `await t.test(...)` @@ -962,6 +962,78 @@ export function lowerTestMethodCall( ); } +/** t.filePath (the entry file, as Node's entryFile), t.attempt (0: tests + * run once), t.passed, t.workerId (Number(NODE_TEST_WORKER_ID) || + * undefined) and t.tags ([]: the tags option has no lowering), each + * coerced to the member's declared type. */ +function lowerTestCtxValue( + lowerer: Lowerer, + expr: ts.PropertyAccessExpression, + member: "filePath" | "attempt" | "passed" | "workerId" | "tags", +): IrExpr { + const loc = locOf(expr); + const receiver = lowerer.lowerExpr(expr.expression); + const declared = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (!declared) { + lowerer.noLowering(`TestContext.${member} of this type`, expr, TESTCTX_SURFACE_HINT); + } + const after = (value: IrExpr): IrExpr => ({ + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: receiver, loc }], + result: lowerer.coerceToExpected(value, declared), + type: declared, + loc, + }); + switch (member) { + case "filePath": + return after(strLit(lowerer.entry.fileName, loc)); + case "attempt": + return after(numLit(0, loc)); + case "tags": + return after({ kind: "arrayLit", elems: [], type: declared, loc }); + case "passed": + return lowerer.coerceToExpected( + { kind: "libCall", fn: "test.ctxPassed", args: [receiver], type: BOOL, loc }, + declared, + ); + case "workerId": { + const id = lowerer.declareHiddenLocal("%workerId", F64); + const missing = lowerer.wrappedUndefined(declared, loc); + if (!missing) + lowerer.noLowering("TestContext.workerId of this type", expr, TESTCTX_SURFACE_HINT); + return { + kind: "seqExpr", + stmts: [ + { kind: "exprStmt", expr: receiver, loc }, + { + kind: "varDecl", + localId: id.id, + init: { kind: "libCall", fn: "test.workerId", args: [], type: F64, loc }, + loc, + }, + ], + result: { + kind: "ternary", + cond: { + kind: "bin", + op: "!==", + left: varRef(id.id, F64, loc), + right: numLit(0, loc), + type: BOOL, + loc, + }, + then: lowerer.coerceToExpected(varRef(id.id, F64, loc), declared), + else_: missing, + type: declared, + loc, + }, + type: declared, + loc, + }; + } + } +} + /** `t.name` as a VALUE — one entry in lower-exprs' property chain. Null * for other receivers/members (the chain keeps trying); unlowered * TestContext members fence member-qualified. */ @@ -985,7 +1057,17 @@ export function lowerTestCtxProperty( loc, }; } - if (expr.name.text === "assert") return null; // claimed by the call path + const member = expr.name.text; + if ( + member === "filePath" || + member === "attempt" || + member === "passed" || + member === "workerId" || + member === "tags" + ) { + return lowerTestCtxValue(lowerer, expr, member); + } + if (member === "assert") return null; // claimed by the call path lowerer.noLowering( `TestContext.${expr.name.text}`, expr, diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index ca2749591..feee17027 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1454,6 +1454,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "test.ctxDiagnostic": { argTypes: [TESTCTX_T, STRING], result: VOID }, "test.ctxName": { argTypes: [TESTCTX_T], result: STRING }, "test.ctxFullName": { argTypes: [TESTCTX_T], result: STRING }, + // t.passed, and t.workerId's Number(NODE_TEST_WORKER_ID) with 0 for + // undefined. + "test.ctxPassed": { argTypes: [TESTCTX_T], result: BOOL }, + "test.workerId": { argTypes: [], result: F64 }, // t.before/t.after/t.beforeEach/t.afterEach (which: 0 before, 1 after, // 2 beforeEach, 3 afterEach); a throwing t.before is captured on the test. "test.ctxHook": { argTypes: [TESTCTX_T, F64, null, F64], result: VOID }, diff --git a/packages/runtime/src/scr_test.c b/packages/runtime/src/scr_test.c index 9e6da5939..f40827e42 100644 --- a/packages/runtime/src/scr_test.c +++ b/packages/runtime/src/scr_test.c @@ -122,6 +122,7 @@ struct ScrTestCtx { ScrPromise *done; /* owned; settles when a concurrent subtest finishes */ ScrPromise *slot; /* owned; the parent waiting for its next subtest to finish */ struct ScrMockTimers *mock_timers; /* t.mock.timers, made on first use; freed at exit */ + bool passed; /* t.passed: set when the body passes, as Node's pass() does */ }; static SCR_TL ScrTestCtx *scr_test_root = NULL; @@ -586,6 +587,7 @@ static void scr_test_run_node(ScrTestCtx *t) { if (t->mode == SCR_TEST_SKIP) { t->dur_ms = scr_now_ms() - start; t->state = SCR_TS_SKIPPED; + t->passed = true; scr_test_report_result(t); return; } @@ -664,6 +666,8 @@ static void scr_test_run_node(ScrTestCtx *t) { t->err = scr_exc_take(); failed = true; } + /* Node's pass()/fail(): afterEach hooks already see the outcome. */ + t->passed = !failed; scr_test_run_each_hooks(t, SCR_HOOK_AFTER_EACH, false); if (scr_exc_pending()) { if (!failed && !t->err) { @@ -686,6 +690,10 @@ static void scr_test_run_node(ScrTestCtx *t) { /* Then t.mock is reset: its mocks are restored and its timers reset. */ scr_test_mocks_restore(&t->mocks, true); scr_mt_reset(t->mock_timers); + /* Its t.before/t.after/t.beforeEach/t.afterEach hooks have all run, and + * nothing runs them again: dropping them releases closures that capture + * the context, which would otherwise keep it alive in a cycle. */ + for (int k = 0; k < 4; k++) scr_test_hooks_free(&t->hooks[k]); scr_test_parent_set(prev_parent); t->dur_ms = scr_now_ms() - start; if (t->mode == SCR_TEST_SKIP) { @@ -2160,6 +2168,19 @@ ScrStr *scr_test_ctx_name(ScrTestCtx *t) { /* t.fullName: the names from the outermost suite or test down to this one, * joined with " > ". */ +bool scr_test_ctx_passed(ScrTestCtx *t) { return t->passed; } + +/* t.workerId: Number(process.env.NODE_TEST_WORKER_ID) || undefined, with 0 + * standing for undefined. */ +double scr_test_worker_id(void) { + const char *env = getenv("NODE_TEST_WORKER_ID"); + if (!env) return 0; + ScrStr *s = scr_str_new(env, strlen(env)); + double n = scr_string_to_number(s); + scr_str_release(s); + return isnan(n) ? 0 : n; +} + ScrStr *scr_test_ctx_full_name(ScrTestCtx *t) { const ScrTestCtx *chain[64]; int n = 0; diff --git a/packages/runtime/src/scr_test.h b/packages/runtime/src/scr_test.h index b1078cccd..26f8928f3 100644 --- a/packages/runtime/src/scr_test.h +++ b/packages/runtime/src/scr_test.h @@ -46,6 +46,9 @@ void scr_test_ctx_hook(ScrTestCtx *t, double which, ScrClosure *cb, double flags void scr_test_ctx_plan(ScrTestCtx *t, double count); void scr_test_ctx_count(ScrTestCtx *t); ScrStr *scr_test_ctx_full_name(ScrTestCtx *t); +/* t.passed, and t.workerId as a number with 0 for undefined. */ +bool scr_test_ctx_passed(ScrTestCtx *t); +double scr_test_worker_id(void); ScrStr *scr_test_ctx_name(ScrTestCtx *t); /* +1 */ /* Mock trackers: the module's `mock` and each test's t.mock. track keeps * the closure that restores one mock; restore_all calls them in creation diff --git a/tests/fixtures/node-test/cases/ctx-members.ts b/tests/fixtures/node-test/cases/ctx-members.ts new file mode 100644 index 000000000..b9df422b3 --- /dev/null +++ b/tests/fixtures/node-test/cases/ctx-members.ts @@ -0,0 +1,33 @@ +// @exit: 1 +// TestContext members read as values: t.filePath (the entry file), +// t.attempt (0), t.passed (false while the body runs, the outcome in the +// test's t.after hooks), t.workerId (undefined outside a worker) and +// t.tags ([] without the tags option). +import { describe, it, test } from "node:test"; +import * as assert from "node:assert"; + +const seen: string[] = []; + +describe("passed", () => { + it("passes", (t) => { + t.after(() => { + seen.push(`after passes: ${t.passed}`); + }); + seen.push(`body: ${t.passed}`); + }); + it("fails", (t) => { + t.after(() => { + seen.push(`after fails: ${t.passed}`); + }); + throw new Error("expected failure"); + }); +}); + +test("members", (t) => { + const file = t.filePath ?? ""; + assert.strictEqual(file.endsWith("tests/fixtures/node-test/cases/ctx-members.ts"), true); + assert.strictEqual(t.attempt, 0); + assert.strictEqual(t.workerId === undefined, true); + assert.strictEqual(t.tags.length, 0); + assert.deepStrictEqual(seen, ["body: false", "after passes: true", "after fails: false"]); +}); From 8e6986c561803a89fcee41e34fdcc00dd0899a7d Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:17:51 -0700 Subject: [PATCH 087/117] Add the zero-cost gate scripts/zero-cost-gate.mjs compiles a fixed good-code set (the runtime benchmark workloads, the self-hosted compiler, and the TypeScript corpus) with a baseline and a candidate checkout. It requires byte-identical IR, LLVM and release executables, and names the first differing IR function, LLVM function or executable symbol when something changes. Programs that match the change's pattern signature (--allow) may differ. It also checks compile time (paired builds, bootstrap interval), binary size, optional per-function cachegrind instruction counts, and the two-tier I3 symbol rule: no executable gains dynamic-tier runtime symbols, and fully typed benchmark workloads define none. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 6 + scripts/zero-cost-compare.mjs | 475 ++++++++++++++++++++ scripts/zero-cost-gate.mjs | 647 +++++++++++++++++++++++++++ tests/harness/zero-cost-gate.test.ts | 145 ++++++ 4 files changed, 1273 insertions(+) create mode 100644 scripts/zero-cost-compare.mjs create mode 100644 scripts/zero-cost-gate.mjs create mode 100644 tests/harness/zero-cost-gate.test.ts diff --git a/AGENTS.md b/AGENTS.md index 4d66cb42f..16f90d68e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,6 +48,12 @@ Corpus programs are differential tests against Node: every program runs under No Before opening a PR that adds or changes corpus, diagnostic, or frontend fixtures, run `pnpm test:ts7 --baselines-only`. This fast completeness check uses the same fixture discovery as the parity suite; it does not type-check or replace behavioral parity. Generate missing preflight/order baselines, review their diagnostics and module order, and run the affected `order-parity.test.ts` batches before pushing. Keep existing baseline entries unchanged unless the corresponding behavior intentionally changes. The full `pnpm test:ts7` command also checks completeness before starting its sweep. +A change that must not cost good code anything, such as a compatibility fix that replaces a refusal, proves it with the zero-cost gate. The gate compiles the benchmark workloads, the self-hosted compiler, and the TypeScript corpus with two built checkouts. It requires byte-identical IR, LLVM, and release executables, and compile time within tolerance. `--allow=` names the change's pattern signature: programs whose sources match may differ, and the PR lists them. Any other difference fails the gate, which names the first differing function. `--quick` checks only the benchmarks; `--cachegrind` adds per-function instruction counts for executables that differ. Run it in a Sandbox with both checkouts prepared: + +```bash +node scripts/zero-cost-gate.mjs --baseline=/vercel/sandbox/prev --candidate=. --allow='\barguments\b' +``` + Test location follows scope: - Co-locate white-box unit tests with implementation files under diff --git a/scripts/zero-cost-compare.mjs b/scripts/zero-cost-compare.mjs new file mode 100644 index 000000000..5367c2957 --- /dev/null +++ b/scripts/zero-cost-compare.mjs @@ -0,0 +1,475 @@ +/* Comparison logic for scripts/zero-cost-gate.mjs, kept free of process + * orchestration so tests/harness/zero-cost-gate.test.ts can pin it. + * + * Artifacts are compared as bytes first. Only when they differ are they split + * into named units (IR functions, LLVM functions, executable symbols) to name + * the first unit that differs. The self-hosted compiler's IR and LLVM exceed + * V8's maximum string length, so splitting works on Buffers and hashes each + * unit instead of decoding the artifact. */ +import { createHash } from "node:crypto"; + +const hash = (bytes) => createHash("sha1").update(bytes).digest("hex"); + +/** Named units of an artifact: `order` lists unit keys in artifact order, + * `hashes` maps each key to a content hash, and `module` holds the + * module-level remainder (IR header, LLVM globals and declarations) as a list + * of comparable pieces with their labels. Repeated names get `#n` suffixes. */ +function unitsBuilder() { + const order = []; + const hashes = new Map(); + const seen = new Map(); + return { + order, + hashes, + module: [], + add(name, bytes) { + const count = seen.get(name) ?? 0; + seen.set(name, count + 1); + const key = count === 0 ? name : `${name}#${count + 1}`; + order.push(key); + hashes.set(key, hash(bytes)); + }, + }; +} + +/* ── IR (compact or readable JSON) ─────────────────────────────────────── */ + +function skipString(bytes, index) { + for (index++; index < bytes.length; index++) { + if (bytes[index] === 0x5c) index++; + else if (bytes[index] === 0x22) return index + 1; + } + return bytes.length; +} + +/** Byte ranges of the root object's `"functions"` array elements, or null. */ +export function irFunctionSpans(bytes) { + const key = Buffer.from('"functions"'); + let depth = 0; + for (let index = 0; index < bytes.length;) { + const byte = bytes[index]; + if (byte === 0x22) { + const end = skipString(bytes, index); + if (depth === 1 && end - index === key.length && bytes.subarray(index, end).equals(key)) { + let next = end; + while (next < bytes.length && bytes[next] !== 0x3a) next++; + next++; + while (next < bytes.length && bytes[next] !== 0x5b && bytes[next] <= 0x20) next++; + if (bytes[next] === 0x5b) return elementSpans(bytes, next); + } + index = end; + continue; + } + if (byte === 0x7b || byte === 0x5b) depth++; + else if (byte === 0x7d || byte === 0x5d) depth--; + index++; + } + return null; +} + +function elementSpans(bytes, open) { + const spans = []; + let depth = 0; + let start = -1; + for (let index = open + 1; index < bytes.length;) { + const byte = bytes[index]; + if (byte === 0x22) { + if (start < 0) start = index; + index = skipString(bytes, index); + continue; + } + if (byte === 0x7b || byte === 0x5b) { + if (start < 0) start = index; + depth++; + } else if (byte === 0x7d || byte === 0x5d) { + if (depth === 0) { + if (start >= 0) spans.push([start, trimEnd(bytes, index)]); + return { open, close: index, spans }; + } + depth--; + } else if (byte === 0x2c && depth === 0) { + spans.push([start, trimEnd(bytes, index)]); + start = -1; + } else if (start < 0 && byte > 0x20) start = index; + index++; + } + return null; +} + +function trimEnd(bytes, end) { + while (end > 0 && bytes[end - 1] <= 0x20) end--; + return end; +} + +/** The `name` of one serialized IR function. Functions serialize `name` + * first; anything else is parsed (a single function is small). */ +function irFunctionName(bytes, [start, end]) { + const head = bytes.toString("utf8", start, Math.min(end, start + 4096)); + const match = /^\{\s*"name"\s*:\s*("(?:[^"\\]|\\.)*")/.exec(head); + if (match) return JSON.parse(match[1]); + const fn = JSON.parse(bytes.toString("utf8", start, end)); + return typeof fn?.name === "string" ? fn.name : ""; +} + +/** IR units: one per function, plus the module header split by top-level + * key (and, for arrays, by element) so header differences are named too. */ +export function irUnits(bytes) { + const units = unitsBuilder(); + const located = irFunctionSpans(bytes); + let header; + if (located === null) header = JSON.parse(bytes.toString("utf8")); + else { + for (const span of located.spans) + units.add(irFunctionName(bytes, span), bytes.subarray(span[0], span[1])); + header = JSON.parse( + bytes.toString("utf8", 0, located.open + 1) + bytes.toString("utf8", located.close), + ); + } + for (const [key, value] of Object.entries(header)) { + if (key === "functions" && located !== null) continue; + if (Array.isArray(value)) + value.forEach((item, index) => { + const name = item && typeof item === "object" && "name" in item ? `:${item.name}` : ""; + units.module.push({ label: `${key}[${index}${name}]`, text: JSON.stringify(item) }); + }); + else units.module.push({ label: key, text: JSON.stringify(value) }); + } + return units; +} + +/* ── LLVM text ─────────────────────────────────────────────────────────── */ + +const DEFINE_NAME = /@("(?:[^"\\]|\\.)*"|[-\w$.]+)\s*\(/; + +/** LLVM units: one per `define … { … }` body; every other line is + * module-level text compared line by line. */ +export function llvmUnits(bytes) { + const units = unitsBuilder(); + let fnStart = -1; + let fnName = ""; + let lineNumber = 0; + for (let start = 0; start < bytes.length;) { + let end = bytes.indexOf(10, start); + if (end < 0) end = bytes.length; + lineNumber++; + if (fnStart >= 0) { + if (end - start === 1 && bytes[start] === 0x7d) { + units.add(fnName, bytes.subarray(fnStart, end)); + fnStart = -1; + } + } else if (bytes[start] === 0x64 && bytes.toString("latin1", start, start + 7) === "define ") { + const line = bytes.toString("utf8", start, end); + fnName = DEFINE_NAME.exec(line)?.[1] ?? ``; + fnStart = start; + if (line.endsWith("}")) { + units.add(fnName, bytes.subarray(fnStart, end)); + fnStart = -1; + } + } else if (end > start) { + units.module.push({ label: `line ${lineNumber}`, text: bytes.toString("utf8", start, end) }); + } + start = end + 1; + } + return units; +} + +/* ── unit comparison ───────────────────────────────────────────────────── */ + +const clip = (text, width = 160) => (text.length > width ? `${text.slice(0, width)}…` : text); + +/** Compare two unit sets. `first` names the first difference in baseline + * order: a changed or removed function, then an added one, then the first + * differing module-level piece. */ +export function compareUnits(baseline, candidate) { + const changed = []; + const removed = []; + for (const key of baseline.order) { + const other = candidate.hashes.get(key); + if (other === undefined) removed.push(key); + else if (other !== baseline.hashes.get(key)) changed.push(key); + } + const added = candidate.order.filter((key) => !baseline.hashes.has(key)); + let module = null; + const count = Math.max(baseline.module.length, candidate.module.length); + for (let index = 0; index < count && module === null; index++) { + const a = baseline.module[index]; + const b = candidate.module[index]; + if (a?.text !== b?.text) + module = { + label: (a ?? b).label, + baseline: a === undefined ? null : clip(a.text), + candidate: b === undefined ? null : clip(b.text), + }; + } + const firstFunction = baseline.order.find( + (key) => !candidate.hashes.has(key) || candidate.hashes.get(key) !== baseline.hashes.get(key), + ); + let first = null; + if (firstFunction !== undefined) + first = `${changed.includes(firstFunction) ? "changed" : "removed"} ${firstFunction}`; + else if (added.length > 0) first = `added ${added[0]}`; + else if (module !== null) first = `module ${module.label}`; + else if (baseline.order.join("\n") !== candidate.order.join("\n")) first = "function order"; + return { + identical: first === null, + first, + changed, + added, + removed, + module, + functions: { baseline: baseline.order.length, candidate: candidate.order.length }, + }; +} + +/** Byte-compare an artifact and, when it differs, name what changed. */ +export function compareArtifact(kind, baseline, candidate) { + if (baseline.equals(candidate)) return { identical: true }; + const split = kind === "ir" ? irUnits : llvmUnits; + const result = compareUnits(split(baseline), split(candidate)); + // Equal units with unequal bytes means formatting outside the units. + return { ...result, identical: false, first: result.first ?? "bytes outside named units" }; +} + +/* ── executables ───────────────────────────────────────────────────────── */ + +/** Defined symbols from `nm -S` output (GNU/LLVM nm, address size type + * name) or `nm` output without sizes (Apple, address type name). */ +export function parseNm(text) { + const symbols = []; + for (const line of text.split("\n")) { + const fields = line.trim().split(/\s+/); + if (fields.length === 4 && /^[0-9a-f]+$/i.test(fields[1])) + symbols.push({ + address: BigInt(`0x${fields[0]}`), + size: BigInt(`0x${fields[1]}`), + type: fields[2], + name: fields[3], + }); + else if (fields.length === 3 && /^[0-9a-f]+$/i.test(fields[0])) + symbols.push({ + address: BigInt(`0x${fields[0]}`), + size: null, + type: fields[1], + name: fields[2], + }); + } + return symbols; +} + +/** The virtual address of file offset `offset` in an ELF64 little-endian + * executable, from its PT_LOAD program headers, or null. */ +export function elfOffsetToAddress(bytes, offset) { + if (bytes.length < 64 || bytes.readUInt32BE(0) !== 0x7f454c46 || bytes[4] !== 2) return null; + const phoff = Number(bytes.readBigUInt64LE(0x20)); + const phentsize = bytes.readUInt16LE(0x36); + const phnum = bytes.readUInt16LE(0x38); + for (let index = 0; index < phnum; index++) { + const at = phoff + index * phentsize; + if (bytes.readUInt32LE(at) !== 1) continue; + const fileOffset = bytes.readBigUInt64LE(at + 8); + const address = bytes.readBigUInt64LE(at + 16); + const fileSize = bytes.readBigUInt64LE(at + 32); + const target = BigInt(offset); + if (target >= fileOffset && target < fileOffset + fileSize) + return address + (target - fileOffset); + } + return null; +} + +/** Name what differs between two executables: symbols added, removed or + * resized, then the symbol holding the first differing byte. */ +export function compareExecutables(baseline, candidate, baselineNm, candidateNm) { + if (baseline.equals(candidate)) return { identical: true }; + const before = new Map(parseNm(baselineNm).map((s) => [s.name, s])); + const after = new Map(parseNm(candidateNm).map((s) => [s.name, s])); + const removed = [...before.keys()].filter((name) => !after.has(name)); + const added = [...after.keys()].filter((name) => !before.has(name)); + const resized = [...before.values()] + .filter((s) => after.has(s.name) && s.size !== null && after.get(s.name).size !== s.size) + .map((s) => ({ + name: s.name, + baseline: Number(s.size), + candidate: Number(after.get(s.name).size), + })); + let offset = 0; + const limit = Math.min(baseline.length, candidate.length); + while (offset < limit && baseline[offset] === candidate[offset]) offset++; + const address = elfOffsetToAddress(baseline, offset); + let holder = null; + if (address !== null) + for (const s of before.values()) + if (s.size !== null && address >= s.address && address < s.address + s.size) holder = s.name; + const first = + resized[0] !== undefined + ? `resized ${resized[0].name}` + : removed[0] !== undefined + ? `removed ${removed[0]}` + : added[0] !== undefined + ? `added ${added[0]}` + : holder !== null + ? `bytes in ${holder}` + : `byte offset ${offset}`; + return { identical: false, first, offset, holder, added, removed, resized }; +} + +/* ── dynamic-tier symbols (two-tier design, invariant I3) ────────────────── */ + +/** Runtime symbol prefixes that belong to the dynamic tier: code a fully + * typed program has no reason to reach. A typed program's release binary + * must define none of them. Extend this list as dynamic-tier units land + * (S3/S4 add their scr_js_* families) and as legacy ScrDyn families move. + * The ScrDyn prefixes are the object-model entry points the two-tier audit + * (results/design-two-tier/DESIGN.md §3.2-3.3) lists as dynamic-only. */ +export const DYNAMIC_TIER_PREFIXES = [ + // Dynamic-tier runtime units (scr_js_value, scr_js_object, ...), from S3. + "scr_js_", + // ScrDyn property bags: reads, writes, lookup and key indexing. + "scr_dyn_obj_", + "scr_dyn_find_", + "scr_dyn_index_", + "scr_dyn_key_", + "sc_dyn_key_", + // Descriptors, own-property reflection, prototypes and proxies. + "scr_dyn_property_", + "scr_dyn_define_", + "scr_dyn_descriptor_", + "scr_dyn_own_", + "scr_dyn_get_own_", + "scr_dyn_prototype", + "scr_dyn_proxy_", + // Dynamic calls and the dynamic receiver read. + "scr_dyn_call", + "scr_dyn_apply", + "scr_dyn_invoke", + "scr_dyn_construct", + "scr_dyn_function_apply", + "scr_dyn_fn_get", + "scr_dyn_this_get", + // Dynamic operators and coercions. + "scr_dyn_add_", + "scr_dyn_arithmetic", + "scr_dyn_to_numeric", + "scr_dyn_number_coerce", + "scr_dyn_string_coerce", +]; + +/** Symbols under those prefixes that typed binaries reach today through a + * leak the two-tier design schedules for removal (S1). Remove an entry when + * its leak closes. */ +export const DYNAMIC_TIER_EXEMPT = new Map([ + // §3.3 L10: scr_dyn_release's dispose switch, linked whenever any dyn + // value can be released. + ["scr_dyn_obj_drop_keys", "L10"], +]); + +/** The dynamic-tier symbols among `names`, sorted. */ +export function dynamicTierSymbols(names) { + return [...new Set(names)] + .filter( + (name) => + DYNAMIC_TIER_PREFIXES.some((prefix) => name.startsWith(prefix)) && + !DYNAMIC_TIER_EXEMPT.has(name), + ) + .sort(); +} + +/* ── cachegrind ────────────────────────────────────────────────────────── */ + +/** Background threads whose instruction counts depend on scheduling: the + * allocator's prefault thread. */ +export const CACHEGRIND_EXCLUDED = new Set(["scr_sa_pf_main", "scr_sa_prefault"]); + +/** Per-function instruction counts (Ir) from a cachegrind output file, + * restricted to `keep` (the executable's own defined symbols). Dynamic + * linker and libc/pthread functions are outside `keep`; their counts vary + * run to run with lazy binding and thread wakeups. */ +export function cachegrindCounts(text, keep) { + const counts = new Map(); + let events = null; + let current = null; + for (const line of text.split("\n")) { + if (line.startsWith("events:")) events = line.slice(7).trim().split(/\s+/); + else if (line.startsWith("fn=")) { + const name = line.slice(3).trim(); + current = keep.has(name) && !CACHEGRIND_EXCLUDED.has(name) ? name : null; + } else if (line.startsWith("fl=") || line.startsWith("fi=") || line.startsWith("fe=")) continue; + else if (current !== null && /^\d/.test(line)) { + const fields = line.trim().split(/\s+/); + const column = events === null ? 0 : Math.max(0, events.indexOf("Ir")); + const ir = Number(fields[column + 1] ?? 0); + counts.set(current, (counts.get(current) ?? 0) + ir); + } + } + return counts; +} + +/** Per-function instruction-count deltas, largest absolute first. */ +export function compareCounts(baseline, candidate) { + const names = new Set([...baseline.keys(), ...candidate.keys()]); + const deltas = []; + let totalBaseline = 0; + let totalCandidate = 0; + for (const name of names) { + const a = baseline.get(name) ?? 0; + const b = candidate.get(name) ?? 0; + totalBaseline += a; + totalCandidate += b; + if (a !== b) deltas.push({ name, baseline: a, candidate: b, delta: b - a }); + } + deltas.sort((x, y) => Math.abs(y.delta) - Math.abs(x.delta) || (x.name < y.name ? -1 : 1)); + return { + identical: deltas.length === 0, + total: { baseline: totalBaseline, candidate: totalCandidate }, + deltas, + }; +} + +/* ── verdicts ──────────────────────────────────────────────────────────── */ + +/** One program's verdict from its build results and artifact comparisons. + * `allowed` marks programs that match the change's pattern signature. */ +export function programVerdict({ baseline, candidate, artifacts, allowed }) { + if (!baseline.ok || !candidate.ok) { + if (!baseline.ok && !candidate.ok && baseline.error === candidate.error) + return { verdict: "both-fail", fails: false }; + return { verdict: "build-error", fails: true }; + } + const differing = Object.entries(artifacts).filter(([, r]) => !r.identical); + if (differing.length === 0) return { verdict: "identical", fails: false }; + return allowed ? { verdict: "allowed", fails: false } : { verdict: "differs", fails: true }; +} + +export function median(values) { + const sorted = [...values].sort((a, b) => a - b); + const middle = sorted.length >> 1; + return sorted.length % 2 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2; +} + +export function geomean(values) { + return values.length === 0 + ? 1 + : Math.exp(values.reduce((sum, value) => sum + Math.log(value), 0) / values.length); +} + +/** Compile-time ratio (candidate / baseline) for a set of programs. Each + * row holds paired samples: one baseline and one candidate build that ran + * side by side, so both saw the same machine load. The estimate is the + * geometric mean of each program's median pair ratio, with a 95% bootstrap + * interval over the pairs. Builds on a shared VM vary by 10-20% run to run, + * so the gate judges the interval, not the point estimate. */ +export function timeRatio(rows, resamples = 2000) { + let state = 0x5eed; + const random = () => { + state = (Math.imul(state, 1664525) + 1013904223) >>> 0; + return state / 4294967296; + }; + const pick = (xs) => + Array.from({ length: xs.length }, () => xs[Math.floor(random() * xs.length)]); + const estimate = (draw) => geomean(rows.map((r) => median(draw(r.ratios)))); + const ratios = Array.from({ length: resamples }, () => estimate(pick)).sort((a, b) => a - b); + return { + ratio: estimate((xs) => xs), + low: ratios[Math.floor(resamples * 0.025)], + high: ratios[Math.floor(resamples * 0.975)], + }; +} diff --git a/scripts/zero-cost-gate.mjs b/scripts/zero-cost-gate.mjs new file mode 100644 index 000000000..f5fea63b9 --- /dev/null +++ b/scripts/zero-cost-gate.mjs @@ -0,0 +1,647 @@ +/* Zero-cost gate: prove that a compiler change leaves good code untouched. + * + * Compiles a fixed good-code set with a baseline and a candidate checkout and + * compares IR, LLVM and release executables byte for byte, plus compile time + * and binary size, and optionally per-function cachegrind instruction counts. + * Both checkouts compile the same program files (from --programs, default the + * baseline), so program paths embedded in artifacts match; checkout paths and + * timestamps do not reach the artifacts. Builds bypass the native cache. + * + * The good-code set: the runtime benchmark workloads (and benchmarks/builds + * applications), the self-hosted compiler (IR and LLVM), and the TypeScript + * corpus programs. A program whose sources match --allow (the change's + * pattern signature) may differ; any other difference fails the gate. */ +import assert from "node:assert/strict"; +import { spawn, spawnSync } from "node:child_process"; +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + statSync, + writeFileSync, +} from "node:fs"; +import { availableParallelism } from "node:os"; +import { dirname, join, relative, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { parseArgs } from "node:util"; +import { + cachegrindCounts, + compareArtifact, + compareCounts, + compareExecutables, + dynamicTierSymbols, + median, + parseNm, + programVerdict, + timeRatio, +} from "./zero-cost-compare.mjs"; + +const repoRoot = fileURLToPath(new URL("..", import.meta.url)); +const { values } = parseArgs({ + options: { + baseline: { type: "string" }, + candidate: { type: "string", default: repoRoot }, + programs: { type: "string", default: "baseline" }, + set: { type: "string", default: "bench,self,corpus" }, + quick: { type: "boolean", default: false }, + corpus: { type: "string", default: "ts" }, + shard: { type: "string" }, + only: { type: "string" }, + allow: { type: "string" }, + "timing-runs": { type: "string" }, + "self-timing-runs": { type: "string", default: "0" }, + "max-time-growth": { type: "string", default: "2" }, + "max-size-growth": { type: "string", default: "0" }, + cachegrind: { type: "boolean", default: false }, + jobs: { type: "string", default: String(Math.max(1, availableParallelism())) }, + json: { type: "string" }, + keep: { type: "boolean", default: false }, + help: { type: "boolean", default: false }, + }, +}); +if (values.help || values.baseline === undefined) { + console.log(`Usage: node scripts/zero-cost-gate.mjs --baseline= [--candidate=] + [--programs=baseline|candidate|] [--set=bench,self,corpus] [--quick] + [--corpus=ts|all] [--shard=i/n] [--only=] [--allow=] + [--timing-runs=N] [--self-timing-runs=N] [--max-time-growth=2] + [--max-size-growth=0] + [--cachegrind] [--jobs=N] [--json=] [--keep] + +Each checkout must be built (packages/cli/dist/bootstrap.js and this host's +runtime pack). Both compile the same program files, taken from --programs +(default: the baseline checkout). + +--set picks the good-code set: bench (benchmarks/runtime workloads and the +benchmarks/builds applications), self (packages/compiler/src/native/cli.ts, +LLVM only), corpus (tests/corpus TypeScript programs; --corpus=all adds +JavaScript entries). --quick is --set=bench --timing-runs=0, for CI. +--shard=i/n keeps every n-th corpus program; --only filters program ids. + +--allow= is the change's pattern signature: programs whose source +files match it may differ (reported as "allowed"). Any other difference in +IR, LLVM or the release executable fails the gate. + +--timing-runs=N (default 5) times N paired --emit=llvm builds per bench +program, baseline and candidate side by side. The self-hosted compiler's +comparison build is its first pair; --self-timing-runs adds more. The gate +fails when the 95% bootstrap interval of the bench geomean ratio, or of the +self-hosted ratio, lies entirely above --max-time-growth percent; an interval +that straddles it is reported as inconclusive. +--max-size-growth bounds executable growth (percent) of allowed programs. + +Dynamic-tier symbols (two-tier invariant I3): no executable may gain +symbols under DYNAMIC_TIER_PREFIXES (scripts/zero-cost-compare.mjs) unless +it matches --allow, and fully typed bench workloads (all but +DYNAMIC_WORKLOADS in this script) may define none. + +--cachegrind (Linux, valgrind on PATH) runs differing bench executables under +cachegrind and compares instruction counts per function of the executable's +own symbols, excluding the allocator's prefault thread. + +Exit status: 0 when the gate passes, 1 when it fails.`); + process.exit(values.help ? 0 : 2); +} + +const trees = { baseline: resolve(values.baseline), candidate: resolve(values.candidate) }; +for (const [label, root] of Object.entries(trees)) + assert.ok( + existsSync(join(root, "packages/cli/dist/bootstrap.js")), + `${label} checkout ${root} has no built CLI (packages/cli/dist/bootstrap.js)`, + ); +const programsRoot = + values.programs === "baseline" || values.programs === "candidate" + ? trees[values.programs] + : resolve(values.programs); +const sets = new Set((values.quick ? "bench" : values.set).split(",")); +for (const set of sets) assert.ok(["bench", "self", "corpus"].includes(set), `unknown set ${set}`); +const timingRuns = Number(values["timing-runs"] ?? (values.quick ? 0 : 5)); +const selfTimingRuns = Number(values["self-timing-runs"]); +const maxTimeGrowth = Number(values["max-time-growth"]) / 100; +const maxSizeGrowth = Number(values["max-size-growth"]) / 100; +const jobs = Number(values.jobs); +assert.ok(Number.isInteger(timingRuns) && timingRuns >= 0, "--timing-runs must be >= 0"); +assert.ok(Number.isInteger(jobs) && jobs >= 1, "--jobs must be >= 1"); +assert.ok(["ts", "all"].includes(values.corpus), "--corpus must be ts or all"); +const only = values.only ? new RegExp(values.only) : null; +const allow = values.allow ? new RegExp(values.allow, "m") : null; +if (values.cachegrind) + assert.equal( + spawnSync("valgrind", ["--version"]).status, + 0, + "--cachegrind needs valgrind on PATH", + ); + +const work = mkdtempSync("/tmp/scriptc-zero-cost-"); + +/* ── the good-code set ─────────────────────────────────────────────────── */ + +/** Every file a program reads: the entry and its relative imports. */ +function programInputs(entry) { + const files = new Set(); + const pending = [entry]; + while (pending.length > 0) { + const file = pending.pop(); + if (files.has(file)) continue; + files.add(file); + const text = readFileSync(file, "utf8"); + for (const match of text.matchAll( + /(?:from|import|require)\s*\(?\s*["'](\.{1,2}\/[^"']+)["']/g, + )) { + const base = resolve(dirname(file), match[1]); + const stem = base.replace(/\.(m|c)?js$/, ""); + const found = [ + base, + `${stem}.ts`, + `${stem}.mts`, + `${stem}.cts`, + `${base}.ts`, + join(base, "index.ts"), + ].find((candidate) => existsSync(candidate) && statSync(candidate).isFile()); + if (found !== undefined) pending.push(found); + } + } + return [...files]; +} + +function goodCodeSet() { + const programs = []; + if (sets.has("bench")) { + const suite = join(programsRoot, "benchmarks/runtime"); + const manifest = JSON.parse(readFileSync(join(suite, "workloads.json"), "utf8")); + const seen = new Set(); + for (const w of manifest.workloads) { + const entry = join(suite, w.entry); + if (seen.has(entry)) continue; + seen.add(entry); + programs.push({ id: `bench/${w.name}`, entry, kind: "exe", workload: w }); + } + } + if (sets.has("self")) + programs.push({ + id: "self/cli", + entry: join(programsRoot, "packages/compiler/src/native/cli.ts"), + kind: "source", + }); + if (sets.has("corpus")) { + const corpus = join(programsRoot, "tests/corpus"); + const exts = values.corpus === "all" ? ["ts", "js", "mjs", "cjs"] : ["ts"]; + const entries = []; + for (const name of readdirSync(corpus).sort()) { + const path = join(corpus, name); + if (statSync(path).isDirectory()) { + const main = exts.map((ext) => join(path, `main.${ext}`)).find((p) => existsSync(p)); + if (main !== undefined) entries.push(main); + } else if (exts.some((ext) => name.endsWith(`.${ext}`))) entries.push(path); + } + let selected = entries; + if (values.shard) { + const [index, count] = values.shard.split("/").map(Number); + assert.ok(index >= 1 && index <= count, "--shard must be i/n with 1 <= i <= n"); + selected = entries.filter((_, k) => k % count === index - 1); + } + for (const entry of selected) { + const head = readFileSync(entry, "utf8").split("\n", 2); + const speed = head.some((line) => /^\/\/ @optimization:\s*speed\s*$/.test(line)); + programs.push({ + id: `corpus/${relative(corpus, entry)}`, + entry, + kind: "exe", + optimization: speed ? "speed" : "release", + }); + } + } + return programs.filter((p) => only === null || only.test(p.id)); +} + +/* ── builds ────────────────────────────────────────────────────────────── */ + +function exec(command, args, options = {}) { + return new Promise((resolvePromise) => { + const started = process.hrtime.bigint(); + const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"], ...options }); + let stdout = ""; + let stderr = ""; + child.stdout.setEncoding("utf8").on("data", (c) => (stdout += c)); + child.stderr.setEncoding("utf8").on("data", (c) => (stderr += c)); + child.on("close", (status, signal) => + resolvePromise({ + status, + signal, + stdout, + stderr, + ms: Number(process.hrtime.bigint() - started) / 1e6, + }), + ); + }); +} + +function buildEnv() { + const env = { ...process.env, SCRIPTC_NO_CACHE: "1" }; + delete env.SCRIPTC_TIMING; + delete env.SCRIPTC_CACHE_DIR; + return env; +} + +function compile(tree, args) { + return exec( + process.execPath, + ["--max-old-space-size=8192", join(tree, "packages/cli/dist/bootstrap.js"), "build", ...args], + { cwd: programsRoot, env: buildEnv() }, + ); +} + +/** Build one program with one checkout. Executable programs build once, + * keeping the LLVM and IR beside the release executable. The self-hosted + * compiler emits LLVM only: each of its frontend runs takes minutes, and its + * LLVM names the first differing function as well as its IR would. */ +async function buildProgram(program, label) { + const dir = join(work, label, program.id.replace(/[^\w.-]+/g, "_")); + mkdirSync(dir, { recursive: true }); + const tree = trees[label]; + const failure = (result) => ({ + ok: false, + error: (result.stderr || result.stdout || `exit ${result.status ?? result.signal}`) + .replaceAll(dir, "") + .trim() + .slice(0, 4000), + }); + if (program.kind === "source") { + const llvm = join(dir, "program.ll"); + const result = await compile(tree, [program.entry, "--emit=llvm", "-o", llvm]); + if (result.status !== 0) return failure(result); + return { ok: true, dir, llvm, ms: result.ms }; + } + const exe = join(dir, "program"); + const result = await compile(tree, [ + program.entry, + `--optimization=${program.optimization ?? "release"}`, + "--keep-llvm", + "--emit-ir", + "-o", + exe, + ]); + if (result.status !== 0) return failure(result); + const files = readdirSync(dir); + const pick = (suffix) => { + const name = files.find((f) => f.endsWith(suffix)); + return name === undefined ? null : join(dir, name); + }; + return { ok: true, dir, exe, ir: pick(".ir.json"), llvm: pick(".ll"), ms: result.ms }; +} + +const nmCache = new Map(); +function nm(binary) { + if (nmCache.has(binary)) return nmCache.get(binary); + const result = spawnSync("nm", process.platform === "darwin" ? [binary] : ["-S", binary], { + encoding: "utf8", + maxBuffer: 256 * 1024 * 1024, + }); + const text = result.status === 0 ? result.stdout : ""; + nmCache.set(binary, text); + return text; +} + +/** Names of the functions an executable defines. */ +const definedFunctions = (binary) => + parseNm(nm(binary)) + .filter((s) => /^[tTwW]$/.test(s.type)) + .map((s) => s.name); + +/* Bench workloads whose release binaries link dynamic-tier symbols on + * b14377864 (DYNAMIC_TIER_PREFIXES in zero-cost-compare.mjs): JSON.parse + * trees, worker messages, regex exec metadata (two-tier §3.3 L5), and a + * shared scr_dyn_call/scr_dyn_define_property core not yet traced to its + * typed root. Every other bench workload is fully typed and must link none. + * Remove a workload here when a leak fix makes its binary clean. */ +const DYNAMIC_WORKLOADS = new Set([ + "bench/json-records", + "bench/cli-config", + "bench/http-api", + "bench/validate-errors", + "bench/regex-logs", + "bench/atomics-contended", + "bench/intern-table", + "bench/typed-array-scan-workers", + "bench/log-summary", + "bench/inventory-report", +]); + +/** The I3 symbol check. Every executable may not gain dynamic-tier symbols + * over the baseline (unless the program matches --allow); a fully typed + * bench workload may contain none at all. */ +function dynamicTierCheck(program, baseline, candidate, artifacts, allowed) { + if (!baseline.exe || !artifacts.exe) return null; + const typed = program.id.startsWith("bench/") && !DYNAMIC_WORKLOADS.has(program.id); + if (artifacts.exe.identical && !typed) return null; + const after = dynamicTierSymbols(definedFunctions(candidate.exe)); + const before = artifacts.exe.identical + ? after + : dynamicTierSymbols(definedFunctions(baseline.exe)); + const added = after.filter((name) => !before.includes(name)); + const failures = []; + if (typed && after.length > 0) + failures.push( + `fully typed program links dynamic-tier symbols: ${after.slice(0, 5).join(", ")}`, + ); + if (added.length > 0 && !allowed) + failures.push(`gained dynamic-tier symbols: ${added.slice(0, 5).join(", ")}`); + return { typed, count: after.length, added, failures }; +} + +function compareBuilds(baseline, candidate) { + const artifacts = {}; + for (const kind of ["ir", "llvm"]) { + if (!(kind in baseline)) continue; + if (baseline[kind] === null || candidate[kind] === null) { + artifacts[kind] = { identical: false, first: `missing ${kind} artifact` }; + continue; + } + artifacts[kind] = compareArtifact( + kind, + readFileSync(baseline[kind]), + readFileSync(candidate[kind]), + ); + } + if (baseline.exe) { + const a = readFileSync(baseline.exe); + const b = readFileSync(candidate.exe); + artifacts.exe = a.equals(b) + ? { identical: true } + : compareExecutables(a, b, nm(baseline.exe), nm(candidate.exe)); + artifacts.exe.bytes = { baseline: a.length, candidate: b.length }; + } + return artifacts; +} + +/** Run tasks with at most `jobs` at a time; heavy tasks run alone. */ +async function pool(tasks) { + const results = new Array(tasks.length); + let next = 0; + let running = 0; + let heavy = false; + await new Promise((done) => { + const pump = () => { + if (next === tasks.length && running === 0) return done(); + while (next < tasks.length && running < jobs && !heavy) { + const task = tasks[next]; + if (task.heavy && running > 0) break; + const index = next++; + running++; + if (task.heavy) heavy = true; + task.run().then((value) => { + results[index] = value; + running--; + if (task.heavy) heavy = false; + pump(); + }); + } + }; + pump(); + }); + return results; +} + +/* ── cachegrind ────────────────────────────────────────────────────────── */ + +async function instructionCounts(binary, args, out) { + const result = await exec("valgrind", [ + "--tool=cachegrind", + "--cache-sim=no", + `--cachegrind-out-file=${out}`, + binary, + ...args, + ]); + if (result.status !== 0) return null; + return cachegrindCounts(readFileSync(out, "utf8"), new Set(definedFunctions(binary))); +} + +/* ── main ──────────────────────────────────────────────────────────────── */ + +function revision(root) { + const r = spawnSync("git", ["-C", root, "rev-parse", "--short", "HEAD"], { encoding: "utf8" }); + if (r.status !== 0) return null; + const dirty = spawnSync("git", ["-C", root, "status", "--porcelain", "--untracked-files=no"], { + encoding: "utf8", + }); + return r.stdout.trim() + (dirty.stdout.trim() ? "+dirty" : ""); +} + +const fmtMs = (ms) => `${(ms / 1000).toFixed(2)}s`; +const pct = (ratio) => `${ratio >= 1 ? "+" : ""}${((ratio - 1) * 100).toFixed(2)}%`; + +const programs = goodCodeSet(); +assert.ok(programs.length > 0, "the selected good-code set is empty"); +const report = { + schema: 1, + date: new Date().toISOString(), + host: { platform: process.platform, arch: process.arch, node: process.version }, + trees: Object.fromEntries( + Object.entries(trees).map(([label, root]) => [label, { root, revision: revision(root) }]), + ), + programsRoot, + allow: values.allow ?? null, + programs: [], + timing: null, + failures: [], +}; +console.log( + `zero-cost gate: ${programs.length} programs (${[...sets].join(", ")}), ` + + `baseline ${trees.baseline}, candidate ${trees.candidate}, programs from ${programsRoot}`, +); + +let failed = false; +const started = Date.now(); +await pool( + programs.map((program) => ({ + heavy: program.kind === "source", + run: async () => { + const [baseline, candidate] = await Promise.all([ + buildProgram(program, "baseline"), + buildProgram(program, "candidate"), + ]); + const allowed = + allow !== null && + programInputs(program.entry).some((f) => allow.test(readFileSync(f, "utf8"))); + const artifacts = baseline.ok && candidate.ok ? compareBuilds(baseline, candidate) : {}; + const { verdict, fails } = programVerdict({ baseline, candidate, artifacts, allowed }); + const entry = { + id: program.id, + verdict, + allowed, + buildMs: { baseline: baseline.ms ?? null, candidate: candidate.ms ?? null }, + artifacts, + }; + if (!baseline.ok) entry.baselineError = baseline.error; + if (!candidate.ok) entry.candidateError = candidate.error; + const size = artifacts.exe?.bytes; + if (verdict === "allowed" && size && size.candidate > size.baseline * (1 + maxSizeGrowth)) { + entry.sizeFailure = true; + report.failures.push( + `${program.id}: executable grew ${size.baseline} -> ${size.candidate} bytes`, + ); + } + if (fails) report.failures.push(`${program.id}: ${verdict}`); + const symbols = + baseline.ok && candidate.ok + ? dynamicTierCheck(program, baseline, candidate, artifacts, allowed) + : null; + if (symbols !== null) entry.dynamicTier = symbols; + for (const failure of symbols?.failures ?? []) + report.failures.push(`${program.id}: ${failure}`); + if (fails || entry.sizeFailure || symbols?.failures.length) failed = true; + if (values.cachegrind && program.workload && artifacts.exe && !artifacts.exe.identical) { + const w = program.workload; + if (w.kind === "server" || w.args.includes("{input}")) + entry.cachegrind = { skipped: "needs a server client or generated input" }; + else { + const counts = await Promise.all([ + instructionCounts(baseline.exe, w.args, join(baseline.dir, "cg.out")), + instructionCounts(candidate.exe, w.args, join(candidate.dir, "cg.out")), + ]); + entry.cachegrind = counts.includes(null) + ? { skipped: "valgrind run failed" } + : (({ deltas, ...rest }) => ({ ...rest, deltas: deltas.slice(0, 20) }))( + compareCounts(counts[0], counts[1]), + ); + } + } + printProgram(entry); + report.programs.push(entry); + nmCache.delete(baseline.exe); + nmCache.delete(candidate.exe); + if (!values.keep) { + if (baseline.dir) rmSync(baseline.dir, { recursive: true, force: true }); + if (candidate.dir) rmSync(candidate.dir, { recursive: true, force: true }); + } + }, + })), +); + +function printProgram(entry) { + const label = { + identical: "identical", + allowed: "allowed ", + differs: "DIFFERS ", + "build-error": "ERROR ", + "both-fail": "both-fail", + }[entry.verdict]; + const notes = []; + for (const [kind, result] of Object.entries(entry.artifacts)) + if (!result.identical) { + const counts = result.changed + ? ` (${result.changed.length} changed, ${result.added.length} added, ${result.removed.length} removed)` + : ""; + notes.push(`${kind}: ${result.first}${counts}`); + } + const size = entry.artifacts.exe?.bytes; + if (size && size.baseline !== size.candidate) + notes.push( + `size ${size.baseline} -> ${size.candidate} B (${pct(size.candidate / size.baseline)})`, + ); + if (entry.cachegrind?.total) { + const { total, deltas } = entry.cachegrind; + notes.push( + `Ir ${total.baseline} -> ${total.candidate} (${pct(total.candidate / Math.max(1, total.baseline))})` + + (deltas[0] + ? `, largest ${deltas[0].name} ${deltas[0].delta > 0 ? "+" : ""}${deltas[0].delta}` + : ""), + ); + } else if (entry.cachegrind?.skipped) + notes.push(`cachegrind skipped: ${entry.cachegrind.skipped}`); + for (const failure of entry.dynamicTier?.failures ?? []) notes.push(`SYMBOLS: ${failure}`); + if (entry.baselineError) notes.push(`baseline: ${entry.baselineError.split("\n")[0]}`); + if (entry.candidateError) notes.push(`candidate: ${entry.candidateError.split("\n")[0]}`); + console.log(`${label} ${entry.id}${notes.length ? ` ${notes.join("; ")}` : ""}`); +} + +/* Compile time: paired --emit=llvm builds, the baseline and the candidate + * side by side, one program at a time. Identical LLVM means everything after + * emission (LLVM optimization, linking) costs the same, so the timed part is + * the compiler's own work. The self-hosted compiler takes minutes per build; + * its main comparison build is its first pair. */ +if (timingRuns > 0) { + const rows = []; + const pair = async (program) => { + const [baseline, candidate] = await Promise.all( + ["baseline", "candidate"].map((label) => + compile(trees[label], [ + program.entry, + "--emit=llvm", + "-o", + join(work, `timing-${label}.ll`), + ]), + ), + ); + return baseline.status === 0 && candidate.status === 0 ? [baseline.ms, candidate.ms] : null; + }; + for (const program of programs) { + if (program.id.startsWith("corpus/")) continue; + const row = { id: program.id, baselineMs: [], candidateMs: [], ratios: [] }; + const add = (sample) => { + if (sample === null) return; + row.baselineMs.push(Math.round(sample[0])); + row.candidateMs.push(Math.round(sample[1])); + row.ratios.push(sample[1] / sample[0]); + }; + const runs = program.kind === "source" ? selfTimingRuns : timingRuns; + if (program.kind === "source") { + const built = report.programs.find((p) => p.id === program.id)?.buildMs; + if (built?.baseline && built?.candidate) add([built.baseline, built.candidate]); + } + for (let run = 0; run < runs; run++) add(await pair(program)); + if (row.ratios.length === 0) continue; + rows.push(row); + console.log( + `time ${program.id} ${fmtMs(median(row.baselineMs))} -> ${fmtMs(median(row.candidateMs))} ` + + `(${pct(median(row.ratios))}, ${row.ratios.length} pairs)`, + ); + } + report.timing = { runs: timingRuns, maxGrowth: maxTimeGrowth, rows, groups: {} }; + const groups = { + bench: rows.filter((r) => r.id.startsWith("bench/")), + self: rows.filter((r) => r.id === "self/cli"), + }; + for (const [name, group] of Object.entries(groups)) { + if (group.length === 0) continue; + const result = timeRatio(group); + report.timing.groups[name] = result; + const verdict = + result.low > 1 + maxTimeGrowth + ? "SLOWER" + : result.high > 1 + maxTimeGrowth + ? "inconclusive (rerun with more runs)" + : "within tolerance"; + console.log( + `time ${name} ${group.length > 1 ? "geomean " : ""}${pct(result.ratio)} ` + + `[95% CI ${pct(result.low)}, ${pct(result.high)}]: ${verdict}`, + ); + if (result.low > 1 + maxTimeGrowth) { + failed = true; + report.failures.push( + `${name} compile time grew ${pct(result.ratio)} (CI low ${pct(result.low)})`, + ); + } + } +} + +const counts = {}; +for (const p of report.programs) counts[p.verdict] = (counts[p.verdict] ?? 0) + 1; +report.counts = counts; +report.verdict = failed ? "fail" : "pass"; +report.elapsedMs = Date.now() - started; +if (values.json) { + mkdirSync(dirname(resolve(values.json)), { recursive: true }); + writeFileSync(values.json, JSON.stringify(report, null, 2) + "\n"); +} +if (!values.keep) rmSync(work, { recursive: true, force: true }); +else console.log(`artifacts kept in ${work}`); +console.log( + `zero-cost gate: ${failed ? "FAIL" : "PASS"} — ${Object.entries(counts) + .map(([k, v]) => `${v} ${k}`) + .join(", ")} in ${fmtMs(report.elapsedMs)}`, +); +for (const failure of report.failures) console.log(` ${failure}`); +process.exit(failed ? 1 : 0); diff --git a/tests/harness/zero-cost-gate.test.ts b/tests/harness/zero-cost-gate.test.ts new file mode 100644 index 000000000..c75a115c8 --- /dev/null +++ b/tests/harness/zero-cost-gate.test.ts @@ -0,0 +1,145 @@ +import { expect, test } from "vitest"; +import { + cachegrindCounts, + compareArtifact, + compareCounts, + compareExecutables, + dynamicTierSymbols, + programVerdict, +} from "../../scripts/zero-cost-compare.mjs"; + +const ir = (functions: object[], globals: object[]) => + Buffer.from(JSON.stringify({ irVersion: 16, functions, globals, sourceFile: "/p/main.ts" })); + +const llvm = (body: string, extra = "") => + Buffer.from( + [ + "; Generated by scriptc (LLVM backend) from /p/main.ts. Do not edit.", + '@.str = private constant [3 x i8] c"hi\\00"', + "define internal i64 @add(i64 %a, i64 %b) {", + ` ${body}`, + "}", + 'define void @"main.$1"() { ret void }', + extra, + "declare void @scr_print(ptr)", + "", + ].join("\n"), + ); + +test("the zero-cost gate names the first differing IR and LLVM unit", () => { + const f = { name: "f", params: [], body: [{ kind: "return" }] }; + const g = { name: "g", params: [], body: [] }; + const base = ir([f, g, f], [{ name: "a", type: "i64" }]); + expect(compareArtifact("ir", base, Buffer.from(base))).toEqual({ identical: true }); + + const changed = compareArtifact( + "ir", + base, + ir([f, { ...g, params: [1] }, f], [{ name: "a", type: "i64" }]), + ); + expect(changed).toMatchObject({ + identical: false, + first: "changed g", + changed: ["g"], + added: [], + module: null, + }); + + const header = compareArtifact("ir", base, ir([f, g, f], [{ name: "a", type: "f64" }])); + expect(header).toMatchObject({ first: "module globals[0:a]", changed: [] }); + // Repeated names are matched by occurrence, so an insertion shows as added. + expect(compareArtifact("ir", base, ir([f, g, f, f], [{ name: "a", type: "i64" }]))).toMatchObject( + { + first: "added f#3", + }, + ); + + const ll = llvm("%r = add i64 %a, %b\n ret i64 %r"); + expect(compareArtifact("llvm", ll, Buffer.from(ll))).toEqual({ identical: true }); + expect(compareArtifact("llvm", ll, llvm("%r = sub i64 %a, %b\n ret i64 %r"))).toMatchObject({ + first: "changed add", + changed: ["add"], + functions: { baseline: 2, candidate: 2 }, + }); + expect( + compareArtifact( + "llvm", + ll, + llvm("%r = add i64 %a, %b\n ret i64 %r", "define void @new() { ret void }"), + ), + ).toMatchObject({ first: "added new", added: ["new"] }); + const global = compareArtifact("llvm", ll, Buffer.from(ll.toString().replace("hi", "ho"))); + expect(global).toMatchObject({ first: "module line 2", changed: [] }); + expect(global.module.candidate).toContain("ho"); +}); + +test("the zero-cost gate compares executables and instruction counts per function", () => { + const nm = + "0000000000001000 0000000000000010 T main\n0000000000001010 0000000000000020 t scr_add\n"; + const resized = compareExecutables( + Buffer.from("abcd"), + Buffer.from("abXd"), + nm, + nm.replace("0000000000000020 t", "0000000000000030 t"), + ); + expect(resized).toMatchObject({ identical: false, first: "resized scr_add", offset: 2 }); + + const output = (main: number, prefault: number, loader: number) => + [ + "events: Ir", + "fl=???", + "fn=main", + `0 ${main}`, + "fn=scr_sa_prefault", + `0 ${prefault}`, + "fn=_dl_lookup_symbol_x", + `0 ${loader}`, + "fn=scr_add", + "0 7", + "0 3", + ].join("\n"); + const own = new Set(["main", "scr_add", "scr_sa_prefault"]); + const base = cachegrindCounts(output(100, 50, 9000), own); + expect([...base]).toEqual([ + ["main", 100], + ["scr_add", 10], + ]); + expect(compareCounts(base, cachegrindCounts(output(100, 75, 9300), own)).identical).toBe(true); + expect(compareCounts(base, cachegrindCounts(output(104, 50, 9000), own))).toMatchObject({ + identical: false, + total: { baseline: 110, candidate: 114 }, + deltas: [{ name: "main", delta: 4 }], + }); +}); + +test("the zero-cost gate recognizes dynamic-tier runtime symbols", () => { + expect( + dynamicTierSymbols([ + "main", + "scr_dyn_release", + "scr_dyn_obj_drop_keys", + "scr_dyn_this_push_dyn", + "scr_js_load_ic", + "scr_dyn_obj_read", + "scr_dyn_obj_read", + ]), + ).toEqual(["scr_dyn_obj_read", "scr_js_load_ic"]); +}); + +test("the zero-cost gate fails differing programs unless they match the signature", () => { + const ok = { ok: true }; + const same = { ir: { identical: true }, exe: { identical: true } }; + const differs = { ir: { identical: true }, exe: { identical: false } }; + const verdict = ( + artifacts: object, + allowed = false, + baseline: object = ok, + candidate: object = ok, + ) => programVerdict({ baseline, candidate, artifacts, allowed }); + expect(verdict(same)).toEqual({ verdict: "identical", fails: false }); + expect(verdict(differs)).toEqual({ verdict: "differs", fails: true }); + expect(verdict(differs, true)).toEqual({ verdict: "allowed", fails: false }); + const failed = { ok: false, error: "SC1090" }; + expect(verdict({}, false, failed, failed)).toEqual({ verdict: "both-fail", fails: false }); + expect(verdict({}, true, ok, failed)).toEqual({ verdict: "build-error", fails: true }); +}); From 675388805ce59a3174a322091a61686c16cb3129 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 10:18:12 -0500 Subject: [PATCH 088/117] Read named groups through optional chains and keep their null prototype `m?.groups?.year` compiles on exec and match results, including a null match, where the read was refused before. The matchAll row callbacks also cover findIndex and findLastIndex. Reshaping an index-signature record into another index-signature type keeps the source's null prototype, since the two are one object in JavaScript. A match's groups read through `m?.groups`, or assigned to a declared type such as `{ [k: string]: string } | undefined`, now prints "[Object: null prototype]" as in Node, where it printed a plain object. --- .../builtin-apis/regular-expressions.mdx | 2 +- .../lowering/containers/indexed-objects.ts | 94 ++++++++++--------- .../src/frontend/lowering/lower-exprs.ts | 7 +- .../src/frontend/lowering/surfaces.ts | 4 +- .../5907-regex-groups-match-rows.ts.json | 6 ++ tests/corpus/5907-regex-groups-match-rows.ts | 33 +++++++ tests/harness/__snapshots__/regex.ts.txt | 2 +- tests/harness/corpus-costs.json | 2 + 8 files changed, 102 insertions(+), 48 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5907-regex-groups-match-rows.ts.json create mode 100644 tests/corpus/5907-regex-groups-match-rows.ts diff --git a/docs/content/limitations/builtin-apis/regular-expressions.mdx b/docs/content/limitations/builtin-apis/regular-expressions.mdx index a765bbe3c..d4287396d 100644 --- a/docs/content/limitations/builtin-apis/regular-expressions.mdx +++ b/docs/content/limitations/builtin-apis/regular-expressions.mdx @@ -1 +1 @@ -- **Regular expressions:** Native checked storage preserves identity, `source`, `flags`, flag properties, and stateful `test`, and the flag getters (`global`, `unicodeSets`, and the rest) compile on statically typed regexes. Static `exec`, global `match`, and numeric `lastIndex` access use the native matcher. Runtime constructors accept checked strings and native regex copies; `replace` and `replaceAll` accept native regex values with string templates or callbacks, including captures, named groups, and UTF-16 offsets. Non-numeric `lastIndex`, detached methods, and `exec` through an untyped receiver are unsupported. The `v` (unicode sets) flag supports class set operations (`--`, `&&`), nested classes, `\q{...}` string literals, and properties of strings such as `\p{RGI_Emoji}`. `new RegExp` with an invalid pattern throws a `SyntaxError` whose message comes from the native engine and can differ from Node's. The `d` (match indices) flag is unsupported: regex literals and `new RegExp` calls with a literal flag string containing it fail to compile with SC1120, and `new RegExp` with a computed flag string containing it throws an error naming the flag. +- **Regular expressions:** Native checked storage preserves identity, `source`, `flags`, flag properties, and stateful `test`, and the flag getters (`global`, `unicodeSets`, and the rest) compile on statically typed regexes. Static `exec`, global `match`, and numeric `lastIndex` access use the native matcher. Runtime constructors accept checked strings and native regex copies; `replace` and `replaceAll` accept native regex values with string templates or callbacks, including captures, named groups, and UTF-16 offsets. Named groups (`groups`) read on matches of a statically known regex: from `exec` and `match`, through optional chains (`m?.groups?.name`), in a `for...of` over `matchAll`, and on the element parameter of an array-method callback over `matchAll` rows. The groups object has a null prototype, as in Node. Non-numeric `lastIndex`, detached methods, and `exec` through an untyped receiver are unsupported. The `v` (unicode sets) flag supports class set operations (`--`, `&&`), nested classes, `\q{...}` string literals, and properties of strings such as `\p{RGI_Emoji}`. `new RegExp` with an invalid pattern throws a `SyntaxError` whose message comes from the native engine and can differ from Node's. The `d` (match indices) flag is unsupported: regex literals and `new RegExp` calls with a literal flag string containing it fail to compile with SC1120, and `new RegExp` with a computed flag string containing it throws an error naming the flag. diff --git a/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts b/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts index e917ee75f..cca4bd51b 100644 --- a/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts +++ b/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts @@ -1,3 +1,4 @@ +import { nullProtoRecordShape, recordNullProtoTest } from "../null-prototype.js"; import { countedFor, numLit, varRef } from "../../../ir/build.js"; import { objectEnumerationReceiver } from "../object-enumeration-receiver.js"; import { InternalCompilerError } from "../../../errors.js"; @@ -852,50 +853,57 @@ export function lowerRecordOvfCaptureHelper( lift === "dyn" ? { kind: "dynFrom", value: v, type: DYN, loc } : lowerer.applyWidthLift(lift, v, tIv, loc); - const body: IrStmt[] = [ - { - kind: "varDecl", - localId: "out.0", - init: { - kind: "recordLit", - fields: inits.map((d) => ({ - name: d.name, - value: - d.kind === "direct" - ? lowerer.presenceKeepingCopy( - sRef, - fromId, - d.name, - lowerer.applyWidthLift( - d.lift, - { - kind: "recordGet", - obj: sRef, - shapeId: fromId, - field: d.name, - type: d.src, - loc, - }, - to.fields.find((f) => f.name === d.name)!.type, - loc, - ), + const fresh: IrExpr & { kind: "recordLit" } = { + kind: "recordLit", + fields: inits.map((d) => ({ + name: d.name, + value: + d.kind === "direct" + ? lowerer.presenceKeepingCopy( + sRef, + fromId, + d.name, + lowerer.applyWidthLift( + d.lift, + { + kind: "recordGet", + obj: sRef, + shapeId: fromId, + field: d.name, + type: d.src, loc, - ) - : ({ - // No source property of this name: the field starts - // absent (an overflow write below can supply it). - kind: "fieldAbsent", - unionId: d.unionId, - type: to.fields.find((f) => f.name === d.name)!.type, - loc, - } satisfies IrExpr), - })), - type: toT, - loc, - }, - loc, - }, - ]; + }, + to.fields.find((f) => f.name === d.name)!.type, + loc, + ), + loc, + ) + : ({ + // No source property of this name: the field starts + // absent (an overflow write below can supply it). + kind: "fieldAbsent", + unionId: d.unionId, + type: to.fields.find((f) => f.name === d.name)!.type, + loc, + } satisfies IrExpr), + })), + type: toT, + loc, + }; + // The source and its reshape are one object in JavaScript, so a + // null-prototype source (a match's groups, Object.groupBy) keeps it. + const init: IrExpr = + nullProtoRecordShape(lowerer, fromT) && nullProtoRecordShape(lowerer, toT) + ? { + kind: "ternary", + cond: recordNullProtoTest(sRef, fromId, loc), + then: { ...fresh, nullProto: true }, + else_: fresh, + type: toT, + loc, + } + : fresh; + const body: IrStmt[] = [{ kind: "varDecl", localId: "out.0", init, loc }]; const fieldStmts = new Map(); // Source declared fields in declaration order, skipping unset // optionals (stance 37) and the direct-initialized (consumed) names. diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 142b00c7e..9f12be3e0 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -13726,6 +13726,8 @@ const MATCH_ROW_CALLBACK_METHODS = new Set([ "filter", "find", "findLast", + "findIndex", + "findLastIndex", "some", "every", "flatMap", @@ -13839,7 +13841,10 @@ function matchAllRegexOf(lowerer: Lowerer, e: ts.Expression): ts.Expression | nu * receiver isn't a match slice or the regex isn't traceable — the * caller's member fence (with the groups hint) names the gap. */ function lowerMatchGroupsRead(lowerer: Lowerer, expr: ts.PropertyAccessExpression): IrExpr | null { - if (expr.name.text !== "groups" || expr.questionDotToken !== undefined) return null; + if (expr.name.text !== "groups") return null; + // `m?.groups` re-dispatches through the optional-chain machinery, which + // narrows the receiver to its match arm first. + if (expr.questionDotToken !== undefined && !lowerer.chainHandled.has(expr)) return null; const loc = locOf(expr); const strArr = arrayOf(STRING); const recvT = lowerer.mapTypeOf(lowerer.typeOf(expr.expression)); diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 1cd12f9c6..d394c1960 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -3046,8 +3046,8 @@ export function stdlibMemberFence(lowerer: Lowerer, access: ts.PropertyAccessExp hint = "'.groups' lowers when the match's regex is STATICALLY known — a regex literal, or a " + "const initialized with one (the group-name table is built at compile time) — and the " + - "read is not an optional-chain step: narrow the match instead (if (m) { m.groups } or " + - "m!.groups)"; + "match comes from exec, match, a for-of over matchAll, or the element parameter of an " + + "array-method callback over matchAll rows"; } else if (recvIr?.kind === "array" && member === "flat") { hint = "flat has no lowering (flatMap does) — flatten into an accumulator instead: " + diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5907-regex-groups-match-rows.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5907-regex-groups-match-rows.ts.json new file mode 100644 index 000000000..ec7d62945 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5907-regex-groups-match-rows.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5907-regex-groups-match-rows.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5907-regex-groups-match-rows.ts b/tests/corpus/5907-regex-groups-match-rows.ts new file mode 100644 index 000000000..22334bad6 --- /dev/null +++ b/tests/corpus/5907-regex-groups-match-rows.ts @@ -0,0 +1,33 @@ +// Named groups on matchAll rows (array-method callbacks over spread rows, +// duplicate names), through optional chains on exec and match results +// (including null matches), and the groups object's null prototype through +// inspection, declared types and unions. Node.js prints the same. +const text = "a1 b22 c333"; +const re = /(?[a-z])(?\d+)/g; +const rows = [...text.matchAll(re)]; +console.log(rows.map((m) => `${m.groups!.word}=${m.groups!.num}`).join(" ")); +rows.forEach((m) => console.log("each", m.groups?.word, m[0])); +console.log(rows.filter((m) => m.groups!.num.length > 1).length, rows.find((m) => m.groups!.word === "c")?.[0]); +console.log([..."x9y8".matchAll(/(?[a-z])|(?\d)/g)].map((m) => `${m.groups!.l ?? "-"}${m.groups!.d ?? "-"}`).join(",")); +console.log(rows.some((m) => m.groups!.word === "b"), rows.every(function (m) { return m.groups!.num !== ""; })); +for (const s of ["2024-05", "nope", "07/1999"]) { + const m = /(?\d{4})-(?\d{2})|(?\d{2})\/(?\d{4})/.exec(s); + console.log(s, m?.groups?.year, m?.groups?.month ?? "none", m?.groups); +} +const mm = "id=42".match(/id=(?\d+)/); +console.log(mm?.groups?.id, "nothing".match(/(?z)/)?.groups?.z); +const none = /(?q)/.exec("abc"); +console.log(none?.groups, none?.groups?.q === undefined); +const parts = /(?\d)-(?\w)/.exec("1-a")!; +const g = parts.groups!; +console.log(parts.groups, JSON.stringify(g), Object.keys(g), Object.getPrototypeOf(g) === null); +try { console.log(String(g)); } catch (e) { console.log((e as Error).name, (e as Error).message); } +const { y, z } = parts.groups!; +console.log(y, z); +const one = /(?\d)/.exec("1"); +console.log(one?.groups); +const maybeGroups = one?.groups; +console.log(maybeGroups); +console.log(one!.groups); +const declared: { [k: string]: string } | undefined = one!.groups; +console.log(declared); diff --git a/tests/harness/__snapshots__/regex.ts.txt b/tests/harness/__snapshots__/regex.ts.txt index 22bdbef90..899633aed 100644 --- a/tests/harness/__snapshots__/regex.ts.txt +++ b/tests/harness/__snapshots__/regex.ts.txt @@ -21,4 +21,4 @@ regex.ts:9:22 - error SC2020: 'RegExpExecArray.groups' is part of the standard l | ^~~~~~~~ 10 | } - hint: '.groups' lowers when the match's regex is STATICALLY known — a regex literal, or a const initialized with one (the group-name table is built at compile time) — and the read is not an optional-chain step: narrow the match instead (if (m) { m.groups } or m!.groups) \ No newline at end of file + hint: '.groups' lowers when the match's regex is STATICALLY known — a regex literal, or a const initialized with one (the group-name table is built at compile time) — and the match comes from exec, match, a for-of over matchAll, or the element parameter of an array-method callback over matchAll rows \ No newline at end of file diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 954f0857d..4702d3676 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1894,6 +1894,7 @@ "5904-async-generator-completion.ts": 2950, "5905-array-from-async-generator.ts": 2750, "5906-array-from-async-generator-js.js": 2950, + "5907-regex-groups-match-rows.ts": 3150, "5910-set-prototype-of-primitive-object-kinds.ts": 2719, "5911-dyn-class-to-primitive.ts": 2850, "5912-dyn-class-conversion-methods.ts": 3251, @@ -4602,6 +4603,7 @@ "5904-async-generator-completion.ts": 3800, "5905-array-from-async-generator.ts": 3500, "5906-array-from-async-generator-js.js": 3750, + "5907-regex-groups-match-rows.ts": 3750, "5910-set-prototype-of-primitive-object-kinds.ts": 5033, "5911-dyn-class-to-primitive.ts": 4732, "5912-dyn-class-conversion-methods.ts": 4424, From 4d417da7b89f196aa7ddf4d63b332fffe7206f09 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 10:22:24 -0500 Subject: [PATCH 089/117] Select the discriminated member for asserted object literals An object literal asserted to a discriminated union keeps its own record layout, and that layout can equal another member's layout: in `{ kind: "return", value, loc } as Stmt`, a non-null `value` gives the fields of a `throw` member. The value was wrapped as that member, so a switch on `kind` read it with the `return` member's layout. The compiled program aborted with an invalid union tag or read past the record; the native compiler crashed this way while lowering three.js. The literal's discriminant now selects the member through type assertions too, as it already did through parentheses and `satisfies`. --- .../compiler/src/frontend/lowering/lowerer.ts | 11 ++++- .../6021-asserted-literal-union-arm.ts.json | 6 +++ .../corpus/6021-asserted-literal-union-arm.ts | 42 +++++++++++++++++++ tests/harness/corpus-costs.json | 2 + 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6021-asserted-literal-union-arm.ts.json create mode 100644 tests/corpus/6021-asserted-literal-union-arm.ts diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index fe998af36..6ae4fa4aa 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -8581,9 +8581,18 @@ export class Lowerer { // initial contextual layout was chosen. Its known discriminator still // selects the destination arm; validate that payload before wrapping. // Work with the already lowered value so property effects run once. + // A type assertion keeps the literal's own record layout, which can + // equal another arm's layout (`{ kind: "return", value, loc } as Stmt` + // when a `throw` arm has the same fields), so assertions are looked + // through as well. if (expr.type.kind === "record" && expected.kind === "union") { let literal = node; - while (ts.isParenthesizedExpression(literal) || ts.isSatisfiesExpression(literal)) + while ( + ts.isParenthesizedExpression(literal) || + ts.isSatisfiesExpression(literal) || + ts.isAsExpression(literal) || + ts.isTypeAssertion(literal) + ) literal = literal.expression; const def = this.unions.get(expected.unionId); if (def?.discriminant && ts.isObjectLiteralExpression(literal)) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6021-asserted-literal-union-arm.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6021-asserted-literal-union-arm.ts.json new file mode 100644 index 000000000..e3b27d23c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6021-asserted-literal-union-arm.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6021-asserted-literal-union-arm.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6021-asserted-literal-union-arm.ts b/tests/corpus/6021-asserted-literal-union-arm.ts new file mode 100644 index 000000000..cbe8b74f7 --- /dev/null +++ b/tests/corpus/6021-asserted-literal-union-arm.ts @@ -0,0 +1,42 @@ +// Object literals asserted to a discriminated union whose own fields match +// another member's fields: the discriminant selects the member. +interface Loc { + start: number; +} +type Expr = { kind: "num"; value: number; loc: Loc } | { kind: "str"; text: string; loc: Loc }; +type Stmt = + | { kind: "return"; value: Expr | null; awaited?: true; loc: Loc } + | { kind: "throw"; value: Expr; loc: Loc } + | { kind: "if"; cond: Expr; then: Stmt[]; loc: Loc }; + +function show(stmt: Stmt): string { + switch (stmt.kind) { + case "return": + return `return${stmt.awaited ? " awaited" : ""} ${stmt.value === null ? "-" : stmt.value.kind}`; + case "throw": + return `throw ${stmt.value.kind}`; + case "if": + return `if ${stmt.cond.kind} { ${stmt.then.map(show).join("; ")} }`; + } +} + +function guarded(value: Expr, loc: Loc): Stmt { + return { kind: "if", cond: value, then: [{ kind: "return", value, loc } as Stmt], loc }; +} + +function branches(reflect: boolean, value: Expr, loc: Loc): Stmt[] { + return [ + ...(reflect + ? [{ kind: "return", value, loc } as Stmt] + : [{ kind: "throw", value, loc } as Stmt, { kind: "return", value: null, loc } as Stmt]), + ]; +} + +const loc: Loc = { start: 0 }; +const num: Expr = { kind: "num", value: 1, loc }; +const str: Expr = { kind: "str", text: "x", loc }; +console.log(show(guarded(num, loc))); +console.log(branches(true, str, loc).map(show).join(" | ")); +console.log(branches(false, num, loc).map(show).join(" | ")); +const listed: Stmt[] = [{ kind: "return", value: str, loc } as Stmt, { kind: "throw", value: num, loc }]; +console.log(listed.map(show).join(" | "), listed.map((stmt) => stmt.kind).join(",")); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 954f0857d..9bb030c07 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1927,6 +1927,7 @@ "601-closures-loops.ts": 1788, "602-closures-identity-recursion.ts": 2372, "6020-class-extends-function-constructor.js": 4300, + "6021-asserted-literal-union-arm.ts": 3400, "603-closures-rc-stress.ts": 1832, "604-closures-for-of.ts": 2639, "605-closures-forward-capture-tdz.ts": 3277, @@ -4635,6 +4636,7 @@ "601-closures-loops.ts": 2297, "602-closures-identity-recursion.ts": 2427, "6020-class-extends-function-constructor.js": 7500, + "6021-asserted-literal-union-arm.ts": 7200, "603-closures-rc-stress.ts": 2589, "604-closures-for-of.ts": 3514, "605-closures-forward-capture-tdz.ts": 4638, From 3c264cf0d9984e382631e92dcb8e30955522689a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 10:26:31 -0500 Subject: [PATCH 090/117] Renumber the local-class corpus program to 5945 The program shared the number 5942 with 5942-callback-specialization-throws.ts. Its cost entries and order-parity baseline move with it. --- .../tests/corpus/5942-local-class-observed-methods.ts.json | 6 ------ .../tests/corpus/5945-local-class-observed-methods.ts.json | 6 ++++++ ...rved-methods.ts => 5945-local-class-observed-methods.ts} | 0 tests/harness/corpus-costs.json | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5945-local-class-observed-methods.ts.json rename tests/corpus/{5942-local-class-observed-methods.ts => 5945-local-class-observed-methods.ts} (100%) diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json deleted file mode 100644 index 89502dd27..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5942-local-class-observed-methods.ts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/corpus/5942-local-class-observed-methods.ts" - ], - "diags": [] -} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5945-local-class-observed-methods.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5945-local-class-observed-methods.ts.json new file mode 100644 index 000000000..f1de4d608 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5945-local-class-observed-methods.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5945-local-class-observed-methods.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5942-local-class-observed-methods.ts b/tests/corpus/5945-local-class-observed-methods.ts similarity index 100% rename from tests/corpus/5942-local-class-observed-methods.ts rename to tests/corpus/5945-local-class-observed-methods.ts diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 954f0857d..b4f0b3fd8 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1904,9 +1904,9 @@ "5923-matchall-groups-js.js": 3970, "5938-object-literal-computed-keys-keep-methods.ts": 3195, "5939-js-let-object-reassigned-wider.js": 1945, - "5942-local-class-observed-methods.ts": 5063, "5943-fields-read-before-assignment.ts": 6856, "5944-js-fields-read-before-assignment.js": 4247, + "5945-local-class-observed-methods.ts": 5063, "5946-nested-record-field-optional-writes.ts": 6045, "5950-tuple-predicate-methods.ts": 5990, "5951-result-never-widening.ts": 4710, @@ -4612,9 +4612,9 @@ "5923-matchall-groups-js.js": 6650, "5938-object-literal-computed-keys-keep-methods.ts": 7194, "5939-js-let-object-reassigned-wider.js": 4436, - "5942-local-class-observed-methods.ts": 6212, "5943-fields-read-before-assignment.ts": 72293, "5944-js-fields-read-before-assignment.js": 40310, + "5945-local-class-observed-methods.ts": 6212, "5946-nested-record-field-optional-writes.ts": 68117, "5950-tuple-predicate-methods.ts": 7790, "5951-result-never-widening.ts": 6120, From c73f36390627c7a94c3eaace80d6ca9764ad8b19 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 10:31:11 -0500 Subject: [PATCH 091/117] Pass the SuiteContext and hook contexts node:test changes, matching Node 24.22: - A describe or suite body may take its SuiteContext, with name, fullName, filePath, attempt, passed and diagnostic. Its passed is false until the suite has finished, after its after hooks. - before and after hooks may take the suite's context, and beforeEach and afterEach hooks the test's. A test's t.before, t.after, t.beforeEach and t.afterEach hooks may take the test's context. - SuiteContext maps to the runner node that TestContext maps to, so the TestContext members that SuiteContext shares lower the same way. The suite-context fixture compares the reporter output and the order of the bodies and hooks with Node, plain and with SCRIPTC_SAN=1. --- .../limitations/builtin-apis/test-runner.mdx | 1 + .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 40 ++++---- .../generated/node-v24-backlog.json | 94 +++++++++++-------- .../generated/node-v24-internal.json | 53 ++++++++--- internal/compatibility/static-support.json | 1 + .../ambient/scriptc-node-fallback.d.ts | 15 ++- .../src/frontend/lowering/lower-test.ts | 25 +++-- packages/compiler/src/frontend/type-mapper.ts | 10 +- .../compiler/src/ir/builtin-signatures.ts | 6 +- packages/runtime/src/scr_test.c | 27 ++++-- .../fixtures/node-test/cases/suite-context.ts | 57 +++++++++++ 12 files changed, 232 insertions(+), 99 deletions(-) create mode 100644 tests/fixtures/node-test/cases/suite-context.ts diff --git a/docs/content/limitations/builtin-apis/test-runner.mdx b/docs/content/limitations/builtin-apis/test-runner.mdx index 76d3a5c16..e1baac963 100644 --- a/docs/content/limitations/builtin-apis/test-runner.mdx +++ b/docs/content/limitations/builtin-apis/test-runner.mdx @@ -1,3 +1,4 @@ - **Concurrent tests:** with `{ concurrency }` above 1, subtests run on their own fibers, and results are reported in declaration order, as in Node. Concurrent bodies resume in Node's order around `beforeEach` hooks and nested suites. Other runner steps, such as `afterEach` and `after` hooks, take no microtask turns between bodies, so code that observes the interleaving of concurrent bodies across those steps can see a different order than Node. - **Snapshots:** `t.assert.snapshot` and `t.assert.fileSnapshot` compile, with Node's default serializer, `JSON.stringify(value, null, 2)`, or an `options.serializers` array literal. A compiled test reads the snapshot file Node writes beside the entry file, `.snapshot`, at the entry file's path when the program was compiled. Running the binary with Node's flag `--test-update-snapshots` as its first argument writes the snapshot files instead; as in Node, the flag is kept out of `process.argv` and appears in `process.execArgv`. Snapshot files are read in the form Node writes them, `` exports[`key`] = `value`; `` statements. The `snapshot.setDefaultSnapshotSerializers` and `snapshot.setResolveSnapshotPath` module functions throw `SC2020`. - **TestContext values:** `t.filePath` is the entry file's path when the program was compiled. `t.attempt` is `0`, since a test runs once. `t.passed` is `false` while the body runs and the test's outcome in its `afterEach` and `t.after` hooks. `t.workerId` is `Number(process.env.NODE_TEST_WORKER_ID) || undefined`, as in Node. `t.tags` is `[]`, since the `tags` test option throws `SC2020`; the array is not frozen as Node's is. +- **Suite and hook contexts:** a `describe` body may take its `SuiteContext`, which has `name`, `fullName`, `filePath`, `attempt`, `passed` and `diagnostic`. Hooks may take their context, as in Node: the suite's for `before` and `after`, the test's for `beforeEach`, `afterEach`, `t.before` and `t.after`. The `SuiteContext` `signal` and `log` members, and hook `done` callbacks, throw `SC2020`. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 35cbcc65e..a64169933 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "622f48ed5c836aec4644", + "artifactVersion": "a610bdd1ae56e1c4cd38", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index d84bdfdfa..d4b6839e7 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -689,9 +689,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 58, + "partial": 64, "refused": 0, - "not-implemented": 59, + "not-implemented": 53, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -66677,9 +66677,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66723,9 +66723,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66746,9 +66746,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66769,9 +66769,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66815,9 +66815,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -66838,9 +66838,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 3a8eca639..f36c865cf 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1149, - "verify-gap": 2180, + "audit-partial": 1155, + "verify-gap": 2174, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -68013,12 +68013,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.context.diagnostic", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -68063,12 +68066,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.context.filePath", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -68088,12 +68094,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.context.fullName", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -68113,12 +68122,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.context.name", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -68163,12 +68175,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.passed", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] } } }, @@ -68188,12 +68203,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:test", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:test.attempt", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 327e41a49..514282a0a 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -746,9 +746,9 @@ "apiEntries": 117, "static": { "supported": 0, - "partial": 58, + "partial": 64, "refused": 0, - "not-implemented": 59, + "not-implemented": 53, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -90980,6 +90980,7 @@ "tests/fixtures/node-test/cases/mock-timers.ts", "tests/fixtures/node-test/cases/only-nested.ts", "tests/fixtures/node-test/cases/snapshot.ts", + "tests/fixtures/node-test/cases/suite-context.ts", "tests/fixtures/node-test/cases/suite-variants.ts", "tests/fixtures/node-test/cases/todo-suites.ts", "tests/harness/node-test.test.ts" @@ -93943,8 +93944,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.context.diagnostic", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -93989,8 +93994,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.context.filePath", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -94012,8 +94021,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.context.fullName", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -94035,8 +94048,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.context.name", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "exact" }, @@ -94081,8 +94098,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.passed", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "ancestor" }, @@ -94104,8 +94125,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:test" + "status": "partial", + "evidence": "compiler-feature:test.attempt", + "tests": [ + "tests/fixtures/node-test/cases/suite-context.ts", + "tests/harness/node-test.test.ts" + ] }, "anchorSource": "ancestor" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index c87bb257a..45a946925 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -357,6 +357,7 @@ { "chapter": "url", "signatures": ["Legacy `urlObject`", "`urlObject.auth`", "`urlObject.hash`", "`urlObject.host`", "`urlObject.hostname`", "`urlObject.href`", "`urlObject.path`", "`urlObject.pathname`", "`urlObject.port`", "`urlObject.protocol`", "`urlObject.query`", "`urlObject.search`", "`urlObject.slashes`"], "status": "partial", "evidence": ["tests/corpus/5221-url-parse-shapes.ts", "tests/corpus/5222-url-parse-hosts.ts", "tests/corpus/5223-url-parse-query.ts", "tests/corpus/5224-url-format-objects.ts", "tests/fixtures/node-types/url-legacy.ts"] }, { "chapter": "test", "parent": "`context.assert`", "symbols": ["context.assert.snapshot", "context.assert.fileSnapshot"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/snapshot.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.filePath", "passed", "attempt", "tags", "workerId"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/ctx-members.ts", "tests/harness/node-test.test.ts"] }, + { "chapter": "test", "parent": "Class: `SuiteContext`", "symbols": ["context.name", "context.fullName", "context.filePath", "context.diagnostic", "passed", "attempt"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/suite-context.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.diagnostic", "context.name"], "status": "partial", "evidence": ["tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.fn"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.method", "mock.reset", "mock.restoreAll"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-method.ts", "tests/corpus/5810-mock-method-records.ts", "tests/corpus/5811-mock-tracker-restore.ts", "tests/harness/node-test.test.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 06938ad18..d72ca2dcd 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3375,8 +3375,18 @@ declare module "node:util/types" { * suites typecheck but fence at their use sites (no lowering). */ declare module "node:test" { type TestFn = (t: TestContext) => void | Promise; - type SuiteFn = () => void; - type HookFn = () => void | Promise; + type SuiteFn = (s: SuiteContext) => void; + type HookFn = (c: TestContext | SuiteContext) => void | Promise; + /* The describe/suite callback's context, and the before/after hook + * context of a suite. */ + interface SuiteContext { + readonly name: string; + readonly fullName: string; + readonly filePath: string | undefined; + readonly attempt: number; + readonly passed: boolean; + diagnostic(message: string): void; + } interface TestOptions { skip?: boolean | string; todo?: boolean | string; @@ -3537,6 +3547,7 @@ declare module "node:test" { run, snapshot, TestContext, + SuiteContext, TestOptions, Mock, MockFunctionContext, diff --git a/packages/compiler/src/frontend/lowering/lower-test.ts b/packages/compiler/src/frontend/lowering/lower-test.ts index 84be23b67..b9d4e8df1 100644 --- a/packages/compiler/src/frontend/lowering/lower-test.ts +++ b/packages/compiler/src/frontend/lowering/lower-test.ts @@ -409,11 +409,16 @@ function lowerSuite( } if (methodMode === 1 || methodMode === 2) opts.mode = methodMode; const cb = lowerer.lowerExpr(fnNode); - if (cb.type.kind !== "func" || cb.type.params.length !== 0) { + // The body may take the SuiteContext (flag 2, as test bodies take theirs). + if ( + cb.type.kind !== "func" || + cb.type.params.length > 1 || + (cb.type.params.length === 1 && cb.type.params[0]!.kind !== "testCtx") + ) { lowerer.noLowering( - `${what} whose body is not a zero-parameter function`, + `${what} whose body is not a function of the SuiteContext`, fnNode, - "suite bodies take no parameters (they run at registration)", + "suite bodies take no parameters or the SuiteContext (they run at registration)", ); } if (cb.type.ret.kind !== "void" && !isUnitType(cb.type.ret)) { @@ -427,7 +432,10 @@ function lowerSuite( const mode = numLit(opts.mode, loc); const msg = opts.msg ?? strLit("", loc); // describe.only and { only: true } mark the suite (flag 4, as for tests). - const flags = numLit(optionFlags(opts) | (methodMode === 3 ? 4 : 0), loc); + const flags = numLit( + optionFlags(opts) | (methodMode === 3 ? 4 : 0) | (cb.type.params.length === 1 ? 2 : 0), + loc, + ); return withOptionValues( { kind: "libCall", @@ -456,10 +464,12 @@ function lowerHook( lowerer.noLowering( `${what} with ${args.length} arguments`, expr, - "the supported form is one zero-parameter function (hook options have no lowering)", + "the supported form is one function (hook options have no lowering)", ); } - const { cb, flags } = lowerBodyArg(lowerer, args[0]!, what, false); + // A hook may take its context: the suite's for before/after, the test's + // for beforeEach/afterEach. + const { cb, flags } = lowerBodyArg(lowerer, args[0]!, what, true); return { kind: "libCall", fn: "test.hook", @@ -919,7 +929,8 @@ export function lowerTestMethodCall( ); } const receiver = lowerer.lowerExpr(access.expression); - const { cb, flags } = lowerBodyArg(lowerer, args[0]!, what, false); + // The hook may take the test's context. + const { cb, flags } = lowerBodyArg(lowerer, args[0]!, what, true); return { kind: "libCall", fn: "test.ctxHook", diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 36cf9a7fb..5ecfc60ae 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -2952,11 +2952,13 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { return { kind: "dgramSocket" }; } // node:test's TestContext — the test-body parameter (`test('x', (t) => - // ...)`). @types/node's `class TestContext` and the fallback - // declarations' interface both live inside `declare module "node:test"` - // (isDeclaredInAmbientModule answers for both spellings). + // ...)`) — and SuiteContext, the describe-body and suite-hook parameter: + // both are the runner's node for the test or suite. @types/node's + // classes and the fallback declarations' interfaces all live inside + // `declare module "node:test"` (isDeclaredInAmbientModule answers for + // both spellings). if ( - psym?.name === "TestContext" && + (psym?.name === "TestContext" || psym?.name === "SuiteContext") && checker .declarationsOf(psym) .some( diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index db5e2c619..780918333 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1436,10 +1436,8 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ argTypes: [STRING, F64, STRING, F64, STRING, F64, F64, F64], result: VOID, }, - "test.suite": { - argTypes: [STRING, F64, STRING, { kind: "func", params: [], ret: VOID }, STRING, F64, F64], - result: VOID, - }, + // The suite body takes no parameters or its SuiteContext (flag 2). + "test.suite": { argTypes: [STRING, F64, STRING, null, STRING, F64, F64], result: VOID }, "test.hook": { argTypes: [F64, null, F64], result: VOID }, "test.sub": { argTypes: [TESTCTX_T, STRING, F64, STRING, null, F64, STRING, F64, F64, F64], diff --git a/packages/runtime/src/scr_test.c b/packages/runtime/src/scr_test.c index f40827e42..cb2c81971 100644 --- a/packages/runtime/src/scr_test.c +++ b/packages/runtime/src/scr_test.c @@ -406,9 +406,12 @@ static void scr_test_mocks_restore(ScrTestHooks *mocks, bool forget) { /* Run `which` hooks up (beforeEach: outermost suite first) or down * (afterEach: innermost first) the ancestor chain. A hook throw fails the * test with the hook's error (Node cancels harder — SEMANTICS.md). */ -static void scr_test_run_hooks_of(ScrTestCtx *owner, int which) { +/* `ctx` is the context a hook that takes one receives: the suite or test + * for its own before/after hooks, the test for the beforeEach/afterEach + * chain. */ +static void scr_test_run_hooks_of(ScrTestCtx *owner, int which, ScrTestCtx *ctx) { for (size_t i = 0; i < owner->hooks[which].n && !scr_exc_pending(); i++) { - scr_test_call(owner->hooks[which].v[i].cb, owner->hooks[which].v[i].flags, NULL, NULL); + scr_test_call(owner->hooks[which].v[i].cb, owner->hooks[which].v[i].flags, ctx, NULL); } } @@ -422,9 +425,9 @@ static bool scr_test_run_each_hooks(ScrTestCtx *t, int which, bool outermost_fir if (p->hooks[which].n > 0) any = true; } if (outermost_first) { - for (int i = n - 1; i >= 0; i--) scr_test_run_hooks_of(chain[i], which); + for (int i = n - 1; i >= 0; i--) scr_test_run_hooks_of(chain[i], which, t); } else { - for (int i = 0; i < n; i++) scr_test_run_hooks_of(chain[i], which); + for (int i = 0; i < n; i++) scr_test_run_hooks_of(chain[i], which, t); } return any; } @@ -595,7 +598,7 @@ static void scr_test_run_node(ScrTestCtx *t) { /* The body already ran at registration (children collected). A hook * throw fails the SUITE with that error — before-failures skip the * children (Node cancels them; SEMANTICS.md numbers the difference). */ - scr_test_run_hooks_of(t, SCR_HOOK_BEFORE); + scr_test_run_hooks_of(t, SCR_HOOK_BEFORE, t); if (scr_exc_pending()) { t->err = scr_exc_take(); } else { @@ -606,7 +609,7 @@ static void scr_test_run_node(ScrTestCtx *t) { } else { scr_test_run_children(t); } - scr_test_run_hooks_of(t, SCR_HOOK_AFTER); + scr_test_run_hooks_of(t, SCR_HOOK_AFTER, t); if (scr_exc_pending()) t->err = scr_exc_take(); } t->dur_ms = scr_now_ms() - start; @@ -619,6 +622,8 @@ static void scr_test_run_node(ScrTestCtx *t) { : scr_test_subtree_failed(t) ? SCR_TS_CHILDFAIL : SCR_TS_PASS; } + /* Node's suite pass() comes after its after hooks. */ + t->passed = t->state == SCR_TS_PASS || t->state == SCR_TS_TODO_PASS; scr_test_report_result(t); return; } @@ -678,7 +683,7 @@ static void scr_test_run_node(ScrTestCtx *t) { } } /* t.after hooks run once the test and its afterEach chain finish. */ - scr_test_run_hooks_of(t, SCR_HOOK_AFTER); + scr_test_run_hooks_of(t, SCR_HOOK_AFTER, t); if (scr_exc_pending()) { if (!failed && !t->err) { t->err = scr_exc_take(); @@ -1519,7 +1524,11 @@ void scr_test_suite(ScrStr *name /*borrowed*/, double mode, ScrStr *msg /*borrow if (cb && (int)mode != SCR_TEST_SKIP) { ScrTestCtx *prev = scr_test_parent_get(); scr_test_parent_set(t); - ((void (*)(ScrClosure *))cb->fn)(cb); + /* flag 2: the body takes its SuiteContext (+1, as test bodies do). */ + if ((int)flags & SCR_TEST_F_CTX) + ((void (*)(ScrClosure *, ScrTestCtx *))cb->fn)(cb, scr_testctx_retain(t)); + else + ((void (*)(ScrClosure *))cb->fn)(cb); scr_test_parent_set(prev); } scr_closure_release(cb); @@ -1597,7 +1606,7 @@ void scr_test_ctx_todo(ScrTestCtx *t, ScrStr *msg /*borrowed*/) { * each descendant subtest, and after runs once the test finishes. */ void scr_test_ctx_hook(ScrTestCtx *t, double which, ScrClosure *cb /*moves*/, double flags) { if ((int)which == SCR_HOOK_BEFORE) { - scr_test_call(cb, (int)flags, NULL, NULL); + scr_test_call(cb, (int)flags, t, NULL); scr_closure_release(cb); if (scr_exc_pending() && !t->before_err) t->before_err = scr_exc_take(); else if (scr_exc_pending()) scr_exc_clear(); diff --git a/tests/fixtures/node-test/cases/suite-context.ts b/tests/fixtures/node-test/cases/suite-context.ts new file mode 100644 index 000000000..5a13136ff --- /dev/null +++ b/tests/fixtures/node-test/cases/suite-context.ts @@ -0,0 +1,57 @@ +// The SuiteContext a describe body receives (name, fullName, filePath, +// attempt, passed, diagnostic), and the context hooks receive: before and +// after get the suite's, beforeEach and afterEach the test's, and a test's +// t.before and t.after hooks the test's. +import { after, afterEach, before, beforeEach, describe, it, test } from "node:test"; +import * as assert from "node:assert"; + +const seen: string[] = []; +let outerPassed = (): boolean => false; + +describe("outer", (s) => { + const file = (s.filePath ?? "").endsWith("tests/fixtures/node-test/cases/suite-context.ts"); + seen.push(`body: ${s.name} | ${s.fullName} | ${s.passed} | ${s.attempt} | ${file}`); + s.diagnostic("suite diagnostic"); + outerPassed = () => s.passed; + before((c) => { + seen.push(`before: ${c.name}`); + }); + after((c) => { + seen.push(`after: ${c.name} ${c.passed}`); + }); + beforeEach((c) => { + seen.push(`beforeEach: ${c.name}`); + }); + afterEach((c) => { + seen.push(`afterEach: ${c.name} ${c.passed}`); + }); + describe("inner", (s2) => { + seen.push(`inner: ${s2.fullName}`); + it("x", () => {}); + }); + it("y", (t) => { + t.before((c) => { + seen.push(`t.before: ${c.name}`); + }); + t.after((c) => { + seen.push(`t.after: ${c.name} ${c.passed}`); + }); + }); +}); + +test("report", () => { + seen.push(`outer afterwards: ${outerPassed()}`); + assert.deepStrictEqual(seen, [ + "body: outer | outer | false | 0 | true", + "inner: outer > inner", + "before: outer", + "beforeEach: x", + "afterEach: x true", + "beforeEach: y", + "t.before: y", + "afterEach: y true", + "t.after: y true", + "after: outer false", + "outer afterwards: true", + ]); +}); From dcdca2b8107994107418afb8ce641010ce5b7807 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:32:40 -0700 Subject: [PATCH 092/117] Read and write records through a binding that may hold a missing record Under noUncheckedIndexedAccess, `let e = map[k]; if (e === undefined) { e = {}; map[k] = e } e[c] = v` failed with SC9001 "recordKeySet receiver: expected record, got union". A runtime-optional binding read with a computed key reaches the record read and write lowerings as its `record | undefined` storage. Those lowerings now hold the receiver, the key and, for writes, the value in temporaries and throw Node's TypeError for an undefined receiver ("Cannot read properties of undefined (reading 'k')", "Cannot set properties of undefined (setting 'k')") after evaluating them in Node's order. Every other receiver builds the same IR as before. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-exprs.ts | 229 ++++++++++++++++-- .../main.ts.json | 6 + .../main.ts | 70 ++++++ .../tsconfig.json | 6 + 4 files changed, 295 insertions(+), 16 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6101-record-get-or-create-unchecked/main.ts.json create mode 100644 tests/corpus/6101-record-get-or-create-unchecked/main.ts create mode 100644 tests/corpus/6101-record-get-or-create-unchecked/tsconfig.json diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index f0538bb71..5f5bc3ff3 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -16,6 +16,7 @@ import { STATS_TYPE_TESTS } from "./builtins/filesystem.js"; import { threadsImportOf } from "../threads-import.js"; import { experimentalImportOf, lifetimeRegionMemberOf } from "../experimental-import.js"; import { lowerInternTableProperty } from "./intern-tables.js"; +import { concatStrings } from "./containers/dynamic-receivers.js"; import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../ir/build.js"; import { InternalCompilerError } from "../../errors.js"; import { SYMBOL_T } from "../../ir/ir.js"; @@ -7077,6 +7078,194 @@ export function lowerRecordKeyRead( // The receiver lowers FIRST (both branches below read it, and JS // evaluates the receiver before the key). const obj = lowerer.lowerExpr(expr.expression); + const optional = optionalRecordReceiver(lowerer, obj); + if (optional) { + // A runtime-optional binding read with a computed key reaches here as + // its `record | undefined` storage. JavaScript evaluates the receiver, + // then the key, and only then throws for an undefined receiver, naming + // the key. Hold both in temporaries so that order and message survive. + const receiver = lowerer.declareHiddenLocal("%optionalRecord", obj.type); + const stmts: IrStmt[] = [{ kind: "varDecl", localId: receiver.id, init: obj, loc }]; + let keyRef: IrExpr | null = + litKey !== null ? { kind: "strLit", value: litKey, type: STRING, loc } : null; + const read = lowerRecordKeyReadFrom( + lowerer, + expr, + shapeId, + shape, + includeUndefined, + litKey, + optionalRecordPresent(optional, receiver, loc), + (key) => { + if (keyRef !== null) return key; + const held = lowerer.declareHiddenLocal("%optionalRecordKey", STRING); + stmts.push({ kind: "varDecl", localId: held.id, init: key, loc }); + keyRef = varRef(held.id, STRING, loc); + return keyRef; + }, + ); + if (keyRef === null) { + lowerer.unsupported( + "SC1090", + keyNode, + "this computed key through a binding that may hold a missing record (narrow the binding or the key first)", + ); + } + return { + kind: "seqExpr", + stmts, + result: optionalRecordGuard(optional, receiver, keyRef, "reading", read, loc), + type: read.type, + loc, + }; + } + return lowerRecordKeyReadFrom(lowerer, expr, shapeId, shape, includeUndefined, litKey, obj, null); +} + +/** The `record | undefined` storage of a runtime-optional binding whose + * only value arm is a record (the get-or-create local after its presence + * guard). Null for every other receiver. */ +function optionalRecordReceiver( + lowerer: Lowerer, + obj: IrExpr, +): { unionId: string; undefinedTag: number; presentTag: number; record: IrType } | null { + if (obj.type.kind !== "union") return null; + const def = lowerer.unions.get(obj.type.unionId); + if (!def || def.arms.length !== 2) return null; + const undefinedTag = lowerer.armTag(obj.type.unionId, UNDEFINED_T); + if (undefinedTag < 0) return null; + const presentTag = undefinedTag === 0 ? 1 : 0; + const record = def.arms[presentTag]!; + if (record.kind !== "record" || lowerer.shapes.get(record.shapeId)?.tuple) return null; + return { unionId: obj.type.unionId, undefinedTag, presentTag, record }; +} + +function optionalRecordPresent( + optional: NonNullable>, + receiver: IrLocal, + loc: SrcLoc, +): IrExpr { + return { + kind: "unionNarrow", + unionId: optional.unionId, + tag: optional.presentTag, + value: varRef(receiver.id, receiver.type, loc), + type: optional.record, + loc, + }; +} + +/** Node's TypeError for a keyed access on undefined ("Cannot read + * properties of undefined (reading 'k')", or "Cannot set ... (setting + * 'k')" for a write), naming the already-evaluated property key. */ +function optionalRecordThrow( + key: IrExpr, + verb: "reading" | "setting", + type: IrType, + loc: SrcLoc, +): IrExpr { + const message = concatStrings( + [ + strLit( + `Cannot ${verb === "reading" ? "read" : "set"} properties of undefined (${verb} '`, + loc, + ), + key, + strLit("')", loc), + ], + loc, + ); + return { + kind: "libCall", + fn: "error.nodeThrow", + args: [numLit(1, loc), strLit("", loc), message], + type, + loc, + }; +} + +function optionalRecordIsUndefined( + optional: NonNullable>, + receiver: IrLocal, + loc: SrcLoc, +): IrExpr { + return { + kind: "unionIsTag", + unionId: optional.unionId, + tag: optional.undefinedTag, + negated: false, + value: varRef(receiver.id, receiver.type, loc), + type: BOOL, + loc, + }; +} + +/** `present` when the held receiver is a record, otherwise the TypeError. */ +function optionalRecordGuard( + optional: NonNullable>, + receiver: IrLocal, + key: IrExpr, + verb: "reading" | "setting", + present: IrExpr, + loc: SrcLoc, +): IrExpr { + return { + kind: "ternary", + cond: optionalRecordIsUndefined(optional, receiver, loc), + then: optionalRecordThrow(key, verb, present.type, loc), + else_: present, + type: present.type, + loc, + }; +} + +/** A keyed write whose receiver may be the `record | undefined` storage of + * a runtime-optional binding: JavaScript evaluates the receiver, the key + * and the value, then throws for an undefined receiver. Other receivers + * build the write directly. */ +function optionalRecordWrite( + lowerer: Lowerer, + obj: IrExpr, + key: IrExpr, + value: IrExpr, + loc: SrcLoc, + build: (receiver: IrExpr, key: IrExpr, value: IrExpr) => IrStmt, +): IrStmt { + const optional = optionalRecordReceiver(lowerer, obj); + if (!optional) return build(obj, key, value); + const receiver = lowerer.declareHiddenLocal("%optionalRecord", obj.type); + const body: IrStmt[] = [{ kind: "varDecl", localId: receiver.id, init: obj, loc }]; + const hold = (e: IrExpr, name: string): IrExpr => { + if (e.kind === "strLit" || e.kind === "numLit") return e; + const held = lowerer.declareHiddenLocal(name, e.type); + body.push({ kind: "varDecl", localId: held.id, init: e, loc }); + return varRef(held.id, e.type, loc); + }; + const heldKey = hold(key, "%optionalRecordKey"); + const heldValue = hold(value, "%optionalRecordValue"); + body.push({ + kind: "if", + cond: optionalRecordIsUndefined(optional, receiver, loc), + then: [{ kind: "exprStmt", expr: optionalRecordThrow(heldKey, "setting", VOID, loc), loc }], + else_: null, + loc, + }); + body.push(build(optionalRecordPresent(optional, receiver, loc), heldKey, heldValue)); + return { kind: "block", body, loc }; +} + +function lowerRecordKeyReadFrom( + lowerer: Lowerer, + expr: ts.ElementAccessExpression, + shapeId: string, + shape: IrRecordShape, + includeUndefined: boolean, + litKey: string | null, + obj: IrExpr, + holdKey: ((key: IrExpr) => IrExpr) | null, +): IrExpr { + const loc = locOf(expr); + const keyNode = expr.argumentExpression; // A record-mapped CHECKER type over a VALUE living in the checked-dynamic tree (a JS // file-scope object-literal global): the checked-dynamic keyed read — // dynKeyGet against the runtime keys (a missing key answers the checked-dynamic tree @@ -7177,6 +7366,7 @@ export function lowerRecordKeyRead( if (key.type.kind !== "string") { lowerer.unsupported("SC1090", keyNode, "indexing records with non-string or non-number keys"); } + if (holdKey) key = holdKey(key); if (shape.fields.length === 0 && shape.indexValue === undefined) { const result = dynUndefinedExpr(loc); return { @@ -8161,14 +8351,21 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression): if (field) { const obj = lowerer.lowerExpr(target.expression); const value = lowerer.lowerExprExpecting(expr.right, field.type); - return { - kind: "recordSet", + return optionalRecordWrite( + lowerer, obj, - shapeId: receiverIr.shapeId, - field: litKey, + strLit(litKey, locOf(target.argumentExpression)), value, - loc: locOf(expr), - }; + locOf(expr), + (receiver, _key, held) => ({ + kind: "recordSet", + obj: receiver, + shapeId: receiverIr.shapeId, + field: litKey, + value: held, + loc: locOf(expr), + }), + ); } } if (!shape.indexValue) { @@ -8211,14 +8408,14 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression): const value = lowerer.coerceInto(expr.right, lowerer.lowerExpr(expr.right), common); if (!typeEquals(value.type, common)) lowerer.badType(expr.right, lowerer.typeOf(expr.right)); - return { + return optionalRecordWrite(lowerer, obj, key, value, locOf(expr), (receiver, k, v) => ({ kind: "recordKeySet", - obj, + obj: receiver, shapeId: receiverIr.shapeId, - key, - value, + key: k, + value: v, loc: locOf(expr), - }; + })); } // A LITERAL key naming no declared field is a pure overflow insert // — no collision to validate. Runtime keys must be able to collide @@ -8264,15 +8461,15 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression): shape.indexValue, expr.right, ); - return { + return optionalRecordWrite(lowerer, obj, key, value, locOf(expr), (receiver, k, v) => ({ kind: "recordKeySet", - obj, + obj: receiver, shapeId: receiverIr.shapeId, - key, - value, + key: k, + value: v, ...(overflowOnly ? { overflowOnly: true as const } : {}), loc: locOf(expr), - }; + })); } } // Keyed write `d[k] = v` on a CHECKED-DYNAMIC receiver (a JS `any` diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6101-record-get-or-create-unchecked/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6101-record-get-or-create-unchecked/main.ts.json new file mode 100644 index 000000000..dcb5b192f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6101-record-get-or-create-unchecked/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6101-record-get-or-create-unchecked/main.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6101-record-get-or-create-unchecked/main.ts b/tests/corpus/6101-record-get-or-create-unchecked/main.ts new file mode 100644 index 000000000..a2b4ef705 --- /dev/null +++ b/tests/corpus/6101-record-get-or-create-unchecked/main.ts @@ -0,0 +1,70 @@ +// Get-or-create over nested index-signature records under +// noUncheckedIndexedAccess: after the presence guard the binding is still +// stored with its undefined arm, and reads, writes and absence probes with +// computed keys go through it (an internal compiler error before). +type ExportMap = Record>; + +function build(rows: { k: string; c: string; v: string }[]): ExportMap { + const map: ExportMap = {}; + for (const r of rows) { + let entry = map[r.k]; + if (entry === undefined) { + entry = {}; + map[r.k] = entry; + } + entry[r.c] = r.v; + } + return map; +} +console.log( + JSON.stringify( + build([ + { k: "a", c: "x", v: "1" }, + { k: "a", c: "y", v: "2" }, + { k: "b", c: "x", v: "3" }, + ]), + ), +); + +function touch(map: ExportMap, k: string): string { + let e = map[k]; + if (e === undefined) { + e = { [k]: "init" }; + map[k] = e; + } + const before = e[k] ?? "none"; + e[k] = e[k] + "!"; + return before + (k in e ? "+" : "-"); +} +const m: ExportMap = {}; +console.log(touch(m, "a"), touch(m, "a"), touch(m, "b"), JSON.stringify(m)); + +function tally(counts: Record>, group: string, item: string): void { + let row = counts[group]; + if (!row) { + row = {}; + counts[group] = row; + } + row[item] = (row[item] ?? 0) + 1; +} +const counts: Record> = {}; +for (const [g, i] of [ + ["fruit", "apple"], + ["fruit", "pear"], + ["veg", "kale"], + ["fruit", "apple"], +]) { + tally(counts, g!, i!); +} +console.log(JSON.stringify(counts)); + +// Module scope. +const top: ExportMap = {}; +const key = process.argv.length > 99 ? "unused" : "k"; +let slot = top[key]; +if (slot === undefined) { + slot = {}; + top[key] = slot; +} +slot[key] = "v"; +console.log(JSON.stringify(top), slot[key], slot["other"] ?? "missing"); diff --git a/tests/corpus/6101-record-get-or-create-unchecked/tsconfig.json b/tests/corpus/6101-record-get-or-create-unchecked/tsconfig.json new file mode 100644 index 000000000..f2e1c10cd --- /dev/null +++ b/tests/corpus/6101-record-get-or-create-unchecked/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "strict": true, + "noUncheckedIndexedAccess": true + } +} From ce87ba722dc84fa3be14c8bfb0a615f0d52261c3 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:32:46 -0700 Subject: [PATCH 093/117] Read missing record keys as undefined before every absence guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `let e = map[k]; if (e === undefined) { e = {}; map[k] = e } e[c] = v` on a `Record>` compiled, then aborted with "record has no key (typed slot…)" where Node prints the result. Without noUncheckedIndexedAccess a keyed record read keeps its typed trap unless the next statement tests the binding for absence, and only `if (!e)` counted. Comparisons with the missing value now count too (`=== undefined`, `== null`, `!== void 0`, `typeof e === "undefined"` and their mirrored forms) for index-signature record reads whose checker type lacks undefined. Module-scope declarations get the same treatment: their pre-registered global takes the undefined arm before any body reads it, and the initializer lowers as the absence probe. Array reads, annotated bindings and noUncheckedIndexedAccess programs compile as before. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-stmts.ts | 141 ++++++++++++++---- .../compiler/src/frontend/lowering/lowerer.ts | 30 ++++ .../corpus/6100-record-get-or-create.ts.json | 6 + tests/corpus/6100-record-get-or-create.ts | 119 +++++++++++++++ 4 files changed, 269 insertions(+), 27 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6100-record-get-or-create.ts.json create mode 100644 tests/corpus/6100-record-get-or-create.ts diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index ad4fd5312..7eb86d6d9 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -4334,16 +4334,21 @@ export function lowerVarDecl( if (wrapped) return { kind: "assign", localId: g.id, value: wrapped, loc: locOf(decl) }; return null; } - const raw = lowerVariableInitializer( - lowerer, - decl.initializer, - g.type.kind === "dyn" && - (isNativeBuiltinValueInitializer(lowerer, decl.initializer) || - ts.isArrayLiteralExpression(decl.initializer) || - ts.isObjectLiteralExpression(decl.initializer)) - ? DYN - : undefined, - ); + const guardedRead = isGuardedRecordRead(lowerer, decl) + ? lowerAbsenceProbe(lowerer, decl.initializer) + : null; + const raw = + guardedRead ?? + lowerVariableInitializer( + lowerer, + decl.initializer, + g.type.kind === "dyn" && + (isNativeBuiltinValueInitializer(lowerer, decl.initializer) || + ts.isArrayLiteralExpression(decl.initializer) || + ts.isObjectLiteralExpression(decl.initializer)) + ? DYN + : undefined, + ); if ( isJsSourceFile(decl.getSourceFile()) && !decl.type && @@ -5139,29 +5144,111 @@ export function jsBindingHasOpenWrites(lowerer: Lowerer, decl: ts.VariableDeclar } function immediatelyGuardedAbsenceProbe(lowerer: Lowerer, decl: ts.VariableDeclaration): boolean { - if (decl.type || !ts.isIdentifier(decl.name) || !decl.initializer) return false; + const guard = immediateAbsenceGuard(lowerer, decl); + // `if (!x)`: the falsy test sees a missing value. + if (guard === "falsy") return true; + // `if (x === undefined)` and its spellings compare the binding with the + // missing value itself, so the read must be able to produce it. Only + // index-signature record reads take this form: array reads already + // carry their undefined arm, and their ordinary lowering keeps its + // bounds proofs. + return guard === "compare" && isIndexSignatureRecordRead(lowerer, decl); +} + +/** A file-scope or block-scope `let e = map[k]` over an index-signature + * record whose next statement guards `e` for absence (`if (e === + * undefined)`, `if (!e)`, ...): the get-or-create idiom. Its read keeps the + * missing key as undefined even without noUncheckedIndexedAccess. */ +export function isGuardedRecordRead(lowerer: Lowerer, decl: ts.VariableDeclaration): boolean { + return immediateAbsenceGuard(lowerer, decl) !== null && isIndexSignatureRecordRead(lowerer, decl); +} + +function isIndexSignatureRecordRead(lowerer: Lowerer, decl: ts.VariableDeclaration): boolean { + if (!decl.initializer) return false; + let init = decl.initializer; + while (ts.isParenthesizedExpression(init)) init = init.expression; + if (!ts.isElementAccessExpression(init)) return false; + // Under noUncheckedIndexedAccess the checker already spells the missing + // arm, and the ordinary read carries it. + const read = lowerer.typeOf(init); + if ( + (read.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0 || + (read.isUnionType() && + ts.constituentTypes(read).some((t) => (t.flags & ts.TypeFlags.Undefined) !== 0)) + ) + return false; + const receiver = lowerer.mapTypeOf(lowerer.typeOf(init.expression)); + const shape = receiver?.kind === "record" ? lowerer.shapes.get(receiver.shapeId) : undefined; + return !!shape && !shape.tuple && !!shape.indexValue && shape.indexValue.kind !== "dyn"; +} + +/** How the statement right after an unannotated declaration tests the + * declared binding for absence: `if (!x)` ("falsy"), or a comparison with + * the missing value — `x === undefined`, `x == null`, `x !== void 0`, + * `typeof x === "undefined"` and their mirrored and negated spellings + * ("compare"). Null for anything else. */ +function immediateAbsenceGuard( + lowerer: Lowerer, + decl: ts.VariableDeclaration, +): "falsy" | "compare" | null { + if (decl.type || !ts.isIdentifier(decl.name) || !decl.initializer) return null; const statement = decl.parent?.parent; - if (!statement || !ts.isVariableStatement(statement)) return false; + if (!statement || !ts.isVariableStatement(statement)) return null; const container = statement.parent; const statements = ts.isBlock(container) || ts.isSourceFile(container) ? container.statements : null; - if (!statements) return false; + if (!statements) return null; const index = statements.indexOf(statement); const next = index >= 0 ? statements[index + 1] : undefined; - if (!next || !ts.isIfStatement(next)) return false; - let condition = next.expression; - while (ts.isParenthesizedExpression(condition)) condition = condition.expression; - if ( - !ts.isPrefixUnaryExpression(condition) || - condition.operator !== ts.SyntaxKind.ExclamationToken - ) - return false; - let operand = condition.operand; - while (ts.isParenthesizedExpression(operand)) operand = operand.expression; - return ( - ts.isIdentifier(operand) && - lowerer.resolveValueSymbol(operand) === lowerer.resolveValueSymbol(decl.name) - ); + if (!next || !ts.isIfStatement(next)) return null; + const binding = lowerer.resolveValueSymbol(decl.name); + const peel = (node: ts.Expression): ts.Expression => { + while (ts.isParenthesizedExpression(node)) node = node.expression; + return node; + }; + const isBinding = (node: ts.Expression): boolean => { + const operand = peel(node); + return ts.isIdentifier(operand) && lowerer.resolveValueSymbol(operand) === binding; + }; + const condition = peel(next.expression); + if (ts.isPrefixUnaryExpression(condition)) + return condition.operator === ts.SyntaxKind.ExclamationToken && isBinding(condition.operand) + ? "falsy" + : null; + if (!ts.isBinaryExpression(condition)) return null; + const op = condition.operatorToken.kind; + const strict = + op === ts.SyntaxKind.EqualsEqualsEqualsToken || + op === ts.SyntaxKind.ExclamationEqualsEqualsToken; + const loose = + op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsToken; + if (!strict && !loose) return null; + const isUndefined = (node: ts.Expression): boolean => { + const operand = peel(node); + if (ts.isVoidExpression(operand)) return true; + return ( + ts.isIdentifier(operand) && + operand.text === "undefined" && + (lowerer.typeOf(operand).flags & ts.TypeFlags.Undefined) !== 0 + ); + }; + const isNull = (node: ts.Expression): boolean => peel(node).kind === ts.SyntaxKind.NullKeyword; + const missing = (node: ts.Expression): boolean => isUndefined(node) || (loose && isNull(node)); + const isTypeofBinding = (node: ts.Expression): boolean => { + const operand = peel(node); + return ts.isTypeOfExpression(operand) && isBinding(operand.expression); + }; + const isUndefinedTag = (node: ts.Expression): boolean => { + const operand = peel(node); + return ts.isStringLiteralLike(operand) && operand.text === "undefined"; + }; + const { left, right } = condition; + return (isBinding(left) && missing(right)) || + (missing(left) && isBinding(right)) || + (isTypeofBinding(left) && isUndefinedTag(right)) || + (isUndefinedTag(left) && isTypeofBinding(right)) + ? "compare" + : null; } function falsyExitRuntimeOptionalLocals(lowerer: Lowerer, stmt: ts.IfStatement): IrLocal[] { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 12deec7ad..aca306900 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -525,6 +525,7 @@ import { lowerForOf, lowerForStatement, matchGroupsPatternSource, + isGuardedRecordRead, } from "./lower-stmts.js"; import { type FieldTarget, @@ -3908,6 +3909,33 @@ export class Lowerer { } } + /** A file-scope get-or-create read (`let e = map[k]; if (e === + * undefined) ...` over an index-signature record) keeps a missing key as + * undefined (isGuardedRecordRead). Its pre-registered global takes the + * undefined arm before any body reads it; the declaration lowers its + * initializer as the matching absence probe. */ + analyzeGuardedRecordReadGlobals(parts: FileParts[]): void { + for (const { sf } of parts) { + for (const statement of sf.statements) { + if (!ts.isVariableStatement(statement)) continue; + for (const decl of statement.declarationList.declarations) { + if (!ts.isIdentifier(decl.name) || !isGuardedRecordRead(this, decl)) continue; + const global = this.globalOf(decl.name); + const symbol = this.resolveValueSymbol(decl.name); + if (!global || !symbol || global.tdz || this.runtimeOptionalBindingTypes.has(symbol)) + continue; + const widened = + global.type.kind === "union" + ? this.withUndefinedArmOf(global.type) + : this.withUndefinedArm(global.type); + if (!widened || typeEquals(widened, global.type)) continue; + global.type = widened; + this.runtimeOptionalBindingTypes.set(symbol, widened); + } + } + } + } + analyzeRuntimeOptionalArrayReads(parts: FileParts[]): void { const provenance = RuntimeOptionalProvenance.fromEnvironment(); // The site whose value the current promotion follows (debug only). @@ -6058,6 +6086,7 @@ export class Lowerer { this.collectProgram(parts); this.analyzeRuntimeOptionalArrayReads(parts); this.analyzeDateJsonResults(parts); + this.analyzeGuardedRecordReadGlobals(parts); // Decorated classes analyze AFTER the whole collection pass: a // decorator's return type may name a subclass declared below the // class, and reference lowering needs each class's rebindability @@ -6443,6 +6472,7 @@ export class Lowerer { this.collectProgram(parts); this.analyzeRuntimeOptionalArrayReads(parts); this.analyzeDateJsonResults(parts); + this.analyzeGuardedRecordReadGlobals(parts); // Decorated classes analyze post-collection here too: the %init seeds // lower the decoration calls, whose edges (decorator bodies, construct // thunks) reachable emit must see. diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6100-record-get-or-create.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6100-record-get-or-create.ts.json new file mode 100644 index 000000000..b7c18a8a4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6100-record-get-or-create.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6100-record-get-or-create.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6100-record-get-or-create.ts b/tests/corpus/6100-record-get-or-create.ts new file mode 100644 index 000000000..807cb303e --- /dev/null +++ b/tests/corpus/6100-record-get-or-create.ts @@ -0,0 +1,119 @@ +// Get-or-create over nested index-signature records without +// noUncheckedIndexedAccess: a missing key reads as undefined when the next +// statement tests the binding for absence, in every spelling of that test, +// at module scope and inside functions. A write with a computed key through +// a binding that may hold a missing element throws Node's TypeError after +// the key and the value evaluated. +type ExportMap = Record>; + +interface Target { + subpath: string; + condition: string; + target: string; +} + +function build(targets: Target[]): { exports: ExportMap; unmapped: string[] } { + const exports: ExportMap = {}; + const unmapped: string[] = []; + for (const t of targets) { + if (t.target === "") { + unmapped.push(t.subpath); + continue; + } + let entry = exports[t.subpath]; + if (entry === undefined) { + entry = {}; + exports[t.subpath] = entry; + } + entry[t.condition] = `./${t.target}`; + entry["types"] = `./${t.target}`; + } + return { exports: exports, unmapped: unmapped }; +} + +const result = build([ + { subpath: ".", condition: "import", target: "src/index.ts" }, + { subpath: ".", condition: "require", target: "src/index.ts" }, + { subpath: "./x", condition: "default", target: "" }, + { subpath: "./y", condition: "node", target: "src/y.ts" }, +]); +console.log(JSON.stringify(result.exports), result.unmapped.join(",")); + +function group(words: string[]): Record { + const byInitial: Record = {}; + for (const w of words) { + const k = w.slice(0, 1); + let list = byInitial[k]; + if (list == null) { + list = []; + byInitial[k] = list; + } + list.push(w); + } + return byInitial; +} +console.log(JSON.stringify(group(["apple", "avocado", "banana", "blueberry", "cherry"]))); + +function count(words: string[]): Record { + const counts: Record = {}; + for (const w of words) { + const n = counts[w]; + if (typeof n === "undefined") counts[w] = 1; + else counts[w] = n + 1; + } + return counts; +} +console.log(JSON.stringify(count(["a", "b", "a", "c", "a"]))); + +function lookup(table: Record, key: string): string { + const hit = table[key]; + if (hit !== undefined) return hit; + return `<${key} missing>`; +} +console.log(lookup({ a: "A" }, "a"), lookup({ a: "A" }, "b")); + +function rows(table: Record>, key: string, col: string): number { + const row = table[key]; + if (row != undefined) return row[col] ?? -1; + return -2; +} +console.log(rows({ r: { c: 3 } }, "r", "c"), rows({ r: { c: 3 } }, "r", "d"), rows({}, "x", "c")); + +// Module scope. +const nested: Record> = {}; +const key = process.argv.length > 99 ? "unused" : "k"; +let slot = nested[key]; +if (slot === undefined) { + slot = {}; + nested[key] = slot; +} +slot[key] = 1; +slot["fixed"] = 2; +console.log(JSON.stringify(nested)); + +const names: Record = { present: "yes" }; +const missing = names[key]; +if (!missing) console.log("falsy guard:", missing); +const present = names["present"]; +if (present === void 0) console.log("unreachable"); +else console.log("present:", present); + +// A write with a computed key through a binding that may hold a missing +// array element throws Node's TypeError naming the key, after evaluating +// the key and the value. +function probe(tables: Record[]): void { + const firstTable = tables[0]; + const lastTable = tables[5]; + const pick = (k: string): string => { + console.log("key", k); + return k; + }; + firstTable[pick("b")] = pick("second"); + console.log(JSON.stringify(firstTable)); + try { + lastTable[pick("c")] = pick("value"); + } catch (e) { + console.log((e as Error).name, (e as Error).message); + } +} +probe([{ a: "first" }]); From 95712ea5906d7eefafa973ec44ed2c783ef80ff6 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:32:52 -0700 Subject: [PATCH 094/117] Keep refused local classes out of speculative type queries Whole-program analyses that query types before reachability is known (the computed-key write census for JavaScript method dispatch, and the runtime-optional array analysis) can name a function-local class whose collection is refused. No statement owns that refusal there, so it escaped as an uncaught PoisonError from collectClassShapeInner and crashed the compiler (the ts-api-utils probe, @typescript-eslint/typescript-estree, and small TypeScript programs). These analyses now run under Lowerer.speculativeTypeQueries: a refused local class is unmappable for the query and its diagnostics are dropped, and the class's own declaration collects it again and reports them if the program reaches it. Collection and body lowering keep their poison handling. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-classes.ts | 2 +- .../compiler/src/frontend/lowering/lowerer.ts | 62 ++++++++++++++++--- .../6102-local-class-type-query.js.json | 6 ++ .../local-class-type-query-brand.ts.json | 6 ++ .../local-class-type-query.ts.json | 6 ++ tests/corpus/6102-local-class-type-query.js | 42 +++++++++++++ .../local-class-type-query-brand.ts | 14 +++++ tests/diagnostics/local-class-type-query.ts | 14 +++++ .../local-class-type-query-brand.ts.txt | 6 ++ .../local-class-type-query.ts.txt | 6 ++ 10 files changed, 156 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-brand.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query.ts.json create mode 100644 tests/corpus/6102-local-class-type-query.js create mode 100644 tests/diagnostics/local-class-type-query-brand.ts create mode 100644 tests/diagnostics/local-class-type-query.ts create mode 100644 tests/harness/__snapshots__/local-class-type-query-brand.ts.txt create mode 100644 tests/harness/__snapshots__/local-class-type-query.ts.txt diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 06739166c..bfb7e06b8 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -6385,7 +6385,7 @@ export function collectInheritedJsFieldWrites( * hierarchy identifies the original declarations through aliases as well. */ export function collectVirtualJsMethods(lowerer: Lowerer, files: readonly ts.SourceFile[]): void { const families: [ts.MethodDeclaration, ts.MethodDeclaration][] = []; - collectClassMethodMutations(lowerer, files); + lowerer.speculativeTypeQueries(() => collectClassMethodMutations(lowerer, files)); const visit = (node: ts.Node): void => { if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) { const accessors = node.members.filter( diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index aca306900..147a6232b 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -2825,7 +2825,8 @@ export class Lowerer { return null; } const className = this.classNamer(decl); - if (!this.collectingExprClasses.has(decl)) this.lowerClassExpressionInfo(decl); + if (!this.collectingExprClasses.has(decl) && !this.collectLocalClassForType(decl)) + return null; return { kind: "object", className }; }, mixinIntersectionInstance: (widened) => mixinIntersectionInstanceType(this, widened), @@ -6084,9 +6085,11 @@ export class Lowerer { for (const fp of parts) this.checker.prefetchSourceFile(fp.sf); } this.collectProgram(parts); - this.analyzeRuntimeOptionalArrayReads(parts); - this.analyzeDateJsonResults(parts); - this.analyzeGuardedRecordReadGlobals(parts); + this.speculativeTypeQueries(() => { + this.analyzeRuntimeOptionalArrayReads(parts); + this.analyzeDateJsonResults(parts); + this.analyzeGuardedRecordReadGlobals(parts); + }); // Decorated classes analyze AFTER the whole collection pass: a // decorator's return type may name a subclass declared below the // class, and reference lowering needs each class's rebindability @@ -6470,9 +6473,11 @@ export class Lowerer { collectionEdges.add(name); }; this.collectProgram(parts); - this.analyzeRuntimeOptionalArrayReads(parts); - this.analyzeDateJsonResults(parts); - this.analyzeGuardedRecordReadGlobals(parts); + this.speculativeTypeQueries(() => { + this.analyzeRuntimeOptionalArrayReads(parts); + this.analyzeDateJsonResults(parts); + this.analyzeGuardedRecordReadGlobals(parts); + }); // Decorated classes analyze post-collection here too: the %init seeds // lower the decoration calls, whose edges (decorator bodies, construct // thunks) reachable emit must see. @@ -9615,6 +9620,49 @@ export class Lowerer { return lowerClassExpressionInfo(this, expr); } + /** Depth of the whole-program analyses that query types across every + * file before reachability is known (speculativeTypeQueries). */ + private speculativeTypeQueryDepth = 0; + + /** Runs a whole-program analysis whose type queries are speculative: they + * visit every file, reached or not, and no statement or declaration owns + * a refusal they trigger (collectLocalClassForType). */ + speculativeTypeQueries(analysis: () => void): void { + this.speculativeTypeQueryDepth++; + try { + analysis(); + } finally { + this.speculativeTypeQueryDepth--; + } + } + + /** Collects a function-local class because a type query named its + * instance type. Collection and body lowering own a refusal of that + * class: the poison reaches the declaration or statement that asked, as + * before. A speculative whole-program analysis owns none, so there the + * class is unmappable for the query and its diagnostics are dropped; + * lowering the class's own declaration collects it again and reports + * them if the program reaches it. */ + collectLocalClassForType(decl: ts.ClassLikeDeclaration): boolean { + if (this.speculativeTypeQueryDepth === 0 || this.fnStack.length > 0) { + this.lowerClassExpressionInfo(decl); + return true; + } + const sink: ScrDiagnostic[] = []; + const previousSink = this.diagSink; + this.diagSink = sink; + try { + this.lowerClassExpressionInfo(decl); + } catch (e) { + if (e instanceof PoisonError) return false; + throw e; + } finally { + this.diagSink = previousSink; + } + for (const d of sink) this.pushDiag(d); + return true; + } + lowerClassExpression(expr: ts.ClassLikeDeclaration): IrExpr { return lowerClassExpression(this, expr); } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json new file mode 100644 index 000000000..86c6ba9e8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6102-local-class-type-query.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-brand.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-brand.ts.json new file mode 100644 index 000000000..e17ea3bf5 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-brand.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/local-class-type-query-brand.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query.ts.json new file mode 100644 index 000000000..3c89fba9f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/local-class-type-query.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6102-local-class-type-query.js b/tests/corpus/6102-local-class-type-query.js new file mode 100644 index 000000000..92fe35725 --- /dev/null +++ b/tests/corpus/6102-local-class-type-query.js @@ -0,0 +1,42 @@ +// A whole-program analysis that queries types before reachability is known +// (the computed-key write census here) can name a function-local class whose +// collection is refused. That query has no owner for the refusal: the class +// stays unmapped for it, and the refusal belongs to the class's own +// declaration, which this program never executes (it used to crash the +// compiler with an uncaught PoisonError). +function main(run) { + if (!run) return "skipped"; + const Project = class { + constructor() { + this.name = "p"; + } + close() { + if (this.missingFilesMap) { + this.missingFilesMap.clear(); + this.missingFilesMap = void 0; + } + } + add(k) { + (this.missingFilesMap || (this.missingFilesMap = new Map())).set(k, 1); + } + }; + const holder = { p: new Project() }; + const key = String(run); + holder.p[key] = "q"; + return holder.p.name; +} + +class Counter { + constructor() { + this.counts = {}; + } + bump(key) { + this.counts[key] = (this.counts[key] || 0) + 1; + return this.counts[key]; + } +} + +const counter = new Counter(); +const word = process.argv.length > 99 ? "unused" : "word"; +counter.bump(word); +console.log(main(0), counter.bump(word)); diff --git a/tests/diagnostics/local-class-type-query-brand.ts b/tests/diagnostics/local-class-type-query-brand.ts new file mode 100644 index 000000000..566304627 --- /dev/null +++ b/tests/diagnostics/local-class-type-query-brand.ts @@ -0,0 +1,14 @@ +// The same speculative element-type query, reaching a function-local class +// with a private brand through the function's returned array. +function make() { + class Box { + #v = 1; + read(): number { + return this.#v; + } + } + return [new Box()]; +} +const xs = make(); +const x = xs[0]; +console.log(x === undefined ? -1 : x.read()); diff --git a/tests/diagnostics/local-class-type-query.ts b/tests/diagnostics/local-class-type-query.ts new file mode 100644 index 000000000..217653ff2 --- /dev/null +++ b/tests/diagnostics/local-class-type-query.ts @@ -0,0 +1,14 @@ +// A whole-program analysis queries the element type of `items` before any +// body lowers. The function-local class it names is refused: the refusal is +// reported once, at the class (it used to crash the compiler with an uncaught +// PoisonError). +function make() { + class Box { + static count = 0; + v = 1; + } + return new Box(); +} +const items = [make()]; +const first = items[0]; +console.log(first ? first.v : 0); diff --git a/tests/harness/__snapshots__/local-class-type-query-brand.ts.txt b/tests/harness/__snapshots__/local-class-type-query-brand.ts.txt new file mode 100644 index 000000000..6db3418a8 --- /dev/null +++ b/tests/harness/__snapshots__/local-class-type-query-brand.ts.txt @@ -0,0 +1,6 @@ +local-class-type-query-brand.ts:4:3 - error SC1090: function-local classes with private brands are not supported yet + + 3 | function make() { + 4 | class Box { + | ^~~~~~~~~~~ + 5 | #v = 1; \ No newline at end of file diff --git a/tests/harness/__snapshots__/local-class-type-query.ts.txt b/tests/harness/__snapshots__/local-class-type-query.ts.txt new file mode 100644 index 000000000..87489fcd5 --- /dev/null +++ b/tests/harness/__snapshots__/local-class-type-query.ts.txt @@ -0,0 +1,6 @@ +local-class-type-query.ts:6:3 - error SC1090: function-local classes with statics, decorators, or generic members are not supported yet + + 5 | function make() { + 6 | class Box { + | ^~~~~~~~~~~ + 7 | static count = 0; \ No newline at end of file From 15096a47ed9ebdfda61983675dcdc4f623784dcb Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:32:58 -0700 Subject: [PATCH 095/117] Answer typeof on builtin import bindings by the export's kind `const { inspect } = require("util"); typeof inspect` printed "string", as did `import { inspect } from "node:util"` in an ES module and `typeof promises` from `fs`. JavaScript sources represent builtin values without their own lowering as identity tokens (strings), and typeof answered from that representation. typeof on a builtin import binding in a JavaScript source now answers "function" for exported functions and classes and "object" for exported objects; the binding read has no effects. TypeScript sources compile as before. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-exprs.ts | 24 +++++++++++++++++++ .../6103-typeof-builtin-bindings.cjs.json | 6 +++++ .../6104-typeof-builtin-bindings.mjs.json | 6 +++++ tests/corpus/6103-typeof-builtin-bindings.cjs | 15 ++++++++++++ tests/corpus/6104-typeof-builtin-bindings.mjs | 11 +++++++++ 5 files changed, 62 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6103-typeof-builtin-bindings.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6104-typeof-builtin-bindings.mjs.json create mode 100644 tests/corpus/6103-typeof-builtin-bindings.cjs create mode 100644 tests/corpus/6104-typeof-builtin-bindings.mjs diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 5f5bc3ff3..3062ff06b 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -678,6 +678,30 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { if (!sym) { return { kind: "strLit", value: "undefined", type: STRING, loc }; } + // `const { inspect } = require("util")` / `import { inspect } from + // "node:util"`: a binding of a builtin module's exported function, + // class or object. JavaScript sources represent such a value without + // its own lowering as an identity token (a string), so the operand's + // representation cannot answer. Node's answer follows the export's + // kind, and the binding read has no effects. + const imported = isJsSourceFile(tested.getSourceFile()) + ? lowerer.builtinImportOf(tested) + : null; + if ( + imported && + builtinModuleConstOf(lowerer, imported.module, imported.member) === undefined + ) { + const t = lowerer.typeOf(tested); + if ( + lowerer.checker.getCallSignatures(t).length > 0 || + lowerer.checker.getConstructSignatures(t).length > 0 + ) { + return { kind: "strLit", value: "function", type: STRING, loc }; + } + if ((t.flags & ts.TypeFlags.Object) !== 0) { + return { kind: "strLit", value: "object", type: STRING, loc }; + } + } if (lowerer.isStdlibSymbol(sym)) { const t = lowerer.typeOf(expr.expression); if ( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6103-typeof-builtin-bindings.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6103-typeof-builtin-bindings.cjs.json new file mode 100644 index 000000000..008914d85 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6103-typeof-builtin-bindings.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6103-typeof-builtin-bindings.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6104-typeof-builtin-bindings.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6104-typeof-builtin-bindings.mjs.json new file mode 100644 index 000000000..b6a8a48e2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6104-typeof-builtin-bindings.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6104-typeof-builtin-bindings.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/6103-typeof-builtin-bindings.cjs b/tests/corpus/6103-typeof-builtin-bindings.cjs new file mode 100644 index 000000000..ecef94dd3 --- /dev/null +++ b/tests/corpus/6103-typeof-builtin-bindings.cjs @@ -0,0 +1,15 @@ +// typeof on bindings destructured from Node builtin modules: Node answers by +// the export's kind ("function" for functions and classes, "object" for +// namespace objects), never by how the binding is represented. +const { inspect, format, promisify, deprecate, isDeepStrictEqual } = require("util"); +const { join, resolve } = require("path"); +const { readFileSync, promises } = require("fs"); +const { EventEmitter } = require("events"); +const { createHash } = require("crypto"); +const util = require("node:util"); +const { inspect: aliased } = util; +console.log(typeof inspect, typeof format, typeof promisify, typeof deprecate, typeof isDeepStrictEqual); +console.log(typeof join, typeof resolve, typeof readFileSync, typeof promises); +console.log(typeof EventEmitter, typeof createHash, typeof aliased, typeof util.inspect); +console.log(typeof inspect === "function" ? "callable" : "not callable"); +console.log(join("a", "b"), format("%s=%d", "x", 1), inspect({ a: [1, 2] })); diff --git a/tests/corpus/6104-typeof-builtin-bindings.mjs b/tests/corpus/6104-typeof-builtin-bindings.mjs new file mode 100644 index 000000000..dd2976775 --- /dev/null +++ b/tests/corpus/6104-typeof-builtin-bindings.mjs @@ -0,0 +1,11 @@ +// typeof on named, default-destructured and namespace-destructured builtin +// bindings in an ES module: Node answers by the export's kind. +import util, { inspect as namedInspect, format } from "node:util"; +import * as path from "node:path"; +import { createHash } from "node:crypto"; +import { promises } from "node:fs"; +const { inspect, promisify } = util; +const { join } = path; +console.log(typeof inspect, typeof promisify, typeof namedInspect, typeof format); +console.log(typeof join, typeof createHash, typeof util.inspect, typeof promises); +console.log(namedInspect("s"), format("%d", 2), join("x", "y")); From 5a6efaf01049ca33d8ab46604e7b1b279ca604ab Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:33:04 -0700 Subject: [PATCH 096/117] Bind top-level this in CommonJS modules to the module's exports object Top-level `this` in a CommonJS JavaScript file, also inside top-level arrow functions, read as undefined; Node binds it to the module's original exports object. It is now a per-module object created when the module starts: typeof, truthiness, identity and passing it along (the UMD wrapper `(function (root) { ... })(this)`, CoffeeScript's `.call(this)`) behave as in Node. Exports stay the static export table, so a property access through top-level `this` is a named refusal rather than a write no requirer would see. ES modules keep undefined. The UMD host test `typeof module !== "undefined" && module.exports` read `module.exports` through the module handle as undefined inside functions, so such modules took the non-CommonJS branch (this is what broke ipaddr.js). `module.exports` used only for its truthiness now answers true when every `module.exports =` in the file assigns an object or function. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-exprs.ts | 4 + .../src/frontend/lowering/lower-modules.ts | 11 ++ .../frontend/lowering/lower-node-module.ts | 134 +++++++++++++++++- .../compiler/src/frontend/lowering/lowerer.ts | 15 +- .../6105-cjs-top-level-this/main.js.json | 7 + .../corpus/6106-esm-top-level-this.mjs.json | 6 + tests/corpus/6105-cjs-top-level-this/lib.js | 11 ++ tests/corpus/6105-cjs-top-level-this/main.js | 12 ++ .../6105-cjs-top-level-this/package.json | 1 + tests/corpus/6106-esm-top-level-this.mjs | 4 + 10 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6105-cjs-top-level-this/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6106-esm-top-level-this.mjs.json create mode 100644 tests/corpus/6105-cjs-top-level-this/lib.js create mode 100644 tests/corpus/6105-cjs-top-level-this/main.js create mode 100644 tests/corpus/6105-cjs-top-level-this/package.json create mode 100644 tests/corpus/6106-esm-top-level-this.mjs diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 3062ff06b..6dc85f251 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -195,6 +195,7 @@ import { tryLowerExpression } from "./expressions/try-lower-expression.js"; import { fenceNodeModuleMutation, isNodeModuleValue, + lowerCjsTopLevelThis, lowerNodeModuleIdentifier, lowerNodeModuleProperty, lowerRequireCacheElement, @@ -1648,6 +1649,9 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { // constant. TypeScript keeps the fence (noImplicitThis makes it a // compile-time story there). if (isJsSourceFile(expr.getSourceFile())) { + // Module scope of a CommonJS file: `this` is module.exports. + const exportsThis = lowerCjsTopLevelThis(lowerer, expr); + if (exportsThis) return exportsThis; return { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }; } lowerer.unsupported("SC1080", expr); diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index d18c4f547..7ff595117 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -2656,6 +2656,17 @@ export function lowerFileInit( loc: loc0, }); } + // Top-level `this` of a CommonJS module: its object exists before the + // module's first statement (lowerCjsTopLevelThis). + const exportsThis = lowerer.cjsExportsThis.get(sf); + if (exportsThis) { + header.push({ + kind: "assign", + localId: exportsThis.id, + value: { kind: "dynObjLit", fields: [], type: DYN, loc: loc0 }, + loc: loc0, + }); + } for (const { stmt, dep } of orderedImportsOf(lowerer.program, sf)) { const npm = lowerer.npmInitActions.get(sf)?.get(stmt); if (npm !== undefined && npm.length > 0) { diff --git a/packages/compiler/src/frontend/lowering/lower-node-module.ts b/packages/compiler/src/frontend/lowering/lower-node-module.ts index ad3f86dee..c15749601 100644 --- a/packages/compiler/src/frontend/lowering/lower-node-module.ts +++ b/packages/compiler/src/frontend/lowering/lower-node-module.ts @@ -8,10 +8,11 @@ import * as win32 from "node:path/win32"; import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; import type { FileParts } from "./lower-modules.js"; -import { isNodeEsmFile, locOf } from "../program.js"; +import { isCjsJsFile, isNodeEsmFile, locOf } from "../program.js"; import { runtimePathForTarget } from "../runtime-resolve.js"; import { BOOL, + DYN, F64, type IrExpr, type IrStmt, @@ -224,6 +225,135 @@ function nodeModuleType(lowerer: Lowerer, node: ts.Expression): boolean { return rendered === "ScriptcModule" || rendered === "NodeModule" || rendered === "NodeJS.Module"; } +/** `module.exports` used only for its truthiness (the UMD test `typeof + * module !== "undefined" && module.exports`): the exports object starts as + * a fresh object, so it stays truthy unless the module replaces it with a + * value that can be falsy. True when every `module.exports = value` in the + * file assigns an object or function. */ +function moduleExportsAlwaysTruthy(lowerer: Lowerer, expr: ts.PropertyAccessExpression): boolean { + if (!truthinessOnly(expr)) return false; + const sf = expr.getSourceFile(); + if (isNodeEsmFile(sf, lowerer.program)) return false; + let truthy = true; + ts.walkPreorder(sf, (node) => { + if ( + !ts.isBinaryExpression(node) || + node.operatorToken.kind < ts.SyntaxKind.FirstAssignment || + node.operatorToken.kind > ts.SyntaxKind.LastAssignment + ) + return undefined; + let target = node.left; + while (ts.isParenthesizedExpression(target)) target = target.expression; + if ( + !ts.isPropertyAccessExpression(target) || + target.name.text !== "exports" || + !isCjsModuleGlobal(lowerer, target.expression) + ) + return undefined; + const type = lowerer.typeOf(node.right); + const objectLike = (t: ts.Type): boolean => + t.isUnionType() + ? ts.constituentTypes(t).every(objectLike) + : (t.flags & ts.TypeFlags.Object) !== 0 || (t.flags & ts.TypeFlags.NonPrimitive) !== 0; + if (node.operatorToken.kind !== ts.SyntaxKind.EqualsToken || !objectLike(type)) { + truthy = false; + return "stop"; + } + return undefined; + }); + return truthy; +} + +/** Whether only the truthiness of `node` can be observed: a condition, a + * `!` operand, or a `&&`/`||` operand of an expression that is itself used + * only for its truthiness. */ +function truthinessOnly(node: ts.Expression): boolean { + let child: ts.Node = node; + for (let parent = node.parent; ; child = parent, parent = parent.parent) { + if (ts.isParenthesizedExpression(parent)) continue; + if (ts.isPrefixUnaryExpression(parent)) + return parent.operator === ts.SyntaxKind.ExclamationToken; + if ( + ts.isBinaryExpression(parent) && + (parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || + parent.operatorToken.kind === ts.SyntaxKind.BarBarToken) + ) + continue; + if (ts.isIfStatement(parent) || ts.isWhileStatement(parent) || ts.isDoStatement(parent)) + return parent.expression === child; + if (ts.isForStatement(parent)) return parent.condition === child; + if (ts.isConditionalExpression(parent)) return parent.condition === child; + return false; + } +} + +/** `this` at the top level of a CommonJS module (directly, or inside + * arrow functions there): Node calls the module wrapper with `this` bound + * to the module's original exports object. */ +export function isCjsTopLevelThis(lowerer: Lowerer, node: ts.Node): boolean { + if (node.kind !== ts.SyntaxKind.ThisKeyword) return false; + for (let p: ts.Node | undefined = node.parent; p && !ts.isSourceFile(p); p = p.parent) { + if (ts.isArrowFunction(p)) continue; + if ( + ts.isFunctionLike(p) || + ts.isClassDeclaration(p) || + ts.isClassExpression(p) || + ts.isClassStaticBlockDeclaration(p) + ) + return false; + } + return isCjsJsFile(node.getSourceFile(), lowerer.program); +} + +export function usesCjsTopLevelThis(lowerer: Lowerer, sf: ts.SourceFile): boolean { + if (!isCjsJsFile(sf, lowerer.program)) return false; + let found = false; + ts.walkPreorder(sf, (node) => { + if ( + node !== sf && + !ts.isArrowFunction(node) && + (ts.isFunctionLike(node) || + ts.isClassDeclaration(node) || + ts.isClassExpression(node) || + ts.isClassStaticBlockDeclaration(node)) + ) + return "skip"; + if (node.kind === ts.SyntaxKind.ThisKeyword) { + found = true; + return "stop"; + } + return undefined; + }); + return found; +} + +/** The value of top-level `this` in a CommonJS module: the module's own + * object standing for its original exports, created when the module starts + * (lowerFileInit). Exports themselves are the static export table, so a + * property access through `this` would read or write an object no requirer + * sees; it keeps a named refusal instead. Typeof, truthiness, identity and + * passing the value along (the UMD wrapper `(function (root) { ... })(this)`) + * behave as in Node. */ +export function lowerCjsTopLevelThis(lowerer: Lowerer, expr: ts.Expression): IrExpr | null { + if (!isCjsTopLevelThis(lowerer, expr)) return null; + const global = lowerer.cjsExportsThis.get(expr.getSourceFile()); + if (!global) return null; + let receiver: ts.Node = expr; + while (ts.isParenthesizedExpression(receiver.parent)) receiver = receiver.parent; + const access = receiver.parent; + if ( + (ts.isPropertyAccessExpression(access) || ts.isElementAccessExpression(access)) && + access.expression === receiver + ) { + lowerer.unsupported( + "SC1090", + access, + "property access through top-level 'this' in a CommonJS module (it is module.exports; spell exports.)", + ); + } + return varRef(global.id, DYN, locOf(expr)); +} + function optionalModule( lowerer: Lowerer, node: ts.Expression, @@ -309,6 +439,8 @@ export function lowerNodeModuleProperty( if (!direct && !nodeModuleType(lowerer, expr.expression)) return null; if (expr.questionDotToken) return null; const member = expr.name.text; + if (member === "exports" && direct && moduleExportsAlwaysTruthy(lowerer, expr)) + return boolLit(true, locOf(expr)); if (member === "exports" || member === "require") return null; let moduleRef = direct ? cjsModuleRef(lowerer, expr.expression) diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 147a6232b..e4736fe2f 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -264,7 +264,7 @@ import { appendForkModules, appendWorkerModules, } from "./lower-modules.js"; -import { prepareCjsModuleGraph } from "./lower-node-module.js"; +import { prepareCjsModuleGraph, usesCjsTopLevelThis } from "./lower-node-module.js"; import { registerBuiltinEventTargetClasses } from "./lower-event-target.js"; import { type ClassInfo, @@ -1845,6 +1845,9 @@ export class Lowerer { * carry undefined at runtime. Identifier reads keep the union tag so * typeof and later boundaries observe the real value. */ readonly runtimeOptionalGlobals = new Set(); + /** Per CommonJS file using top-level `this`: the global holding the + * object that stands for its original exports (lowerCjsTopLevelThis). */ + readonly cjsExportsThis = new Map(); /** Bindings whose unchecked string arithmetic can produce either a number * (NaN for an absent read) or a string. Preserve that result union at bare * reads instead of applying the checker-bare string narrowing adapter. */ @@ -3656,6 +3659,16 @@ export class Lowerer { const id = `%g.${tag}%loaded`; this.moduleGuardOf.set(fp.sf, id); this.globalsList.push({ id, name: "%loaded", type: BOOL, mutable: true }); + if (usesCjsTopLevelThis(this, fp.sf)) { + const exportsThis: IrGlobal = { + id: `%g.${tag}%exportsThis`, + name: "%exportsThis", + type: DYN, + mutable: true, + }; + this.globalsList.push(exportsThis); + this.cjsExportsThis.set(fp.sf, exportsThis); + } } // A module is intrinsically async when an await/for-await occurs diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6105-cjs-top-level-this/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6105-cjs-top-level-this/main.js.json new file mode 100644 index 000000000..ef768b4ce --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6105-cjs-top-level-this/main.js.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6105-cjs-top-level-this/lib.js", + "/tests/corpus/6105-cjs-top-level-this/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6106-esm-top-level-this.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6106-esm-top-level-this.mjs.json new file mode 100644 index 000000000..ad427bd7f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6106-esm-top-level-this.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6106-esm-top-level-this.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/6105-cjs-top-level-this/lib.js b/tests/corpus/6105-cjs-top-level-this/lib.js new file mode 100644 index 000000000..7addc1840 --- /dev/null +++ b/tests/corpus/6105-cjs-top-level-this/lib.js @@ -0,0 +1,11 @@ +// A required CommonJS module sees its own exports object as `this`, and the +// UMD test for a CommonJS host takes the module.exports branch. +const kind = typeof this; +let host = "global"; +if (typeof module !== "undefined" && module.exports) host = "commonjs"; +(function (root) { + console.log("lib wrapper root:", typeof root, root ? "truthy" : "falsy"); +})(this); +exports.describe = function () { + return kind + " " + host; +}; diff --git a/tests/corpus/6105-cjs-top-level-this/main.js b/tests/corpus/6105-cjs-top-level-this/main.js new file mode 100644 index 000000000..1da910171 --- /dev/null +++ b/tests/corpus/6105-cjs-top-level-this/main.js @@ -0,0 +1,12 @@ +// Top-level `this` in a CommonJS module is module.exports (an object), also +// inside arrow functions at module scope. +const lib = require("./lib.js"); +const self = this; +const arrow = () => this; +console.log(typeof this, self === this, arrow() === this, this ? "truthy" : "falsy"); +console.log(lib.describe()); +(function () { + console.log("call(this):", typeof this); +}).call(this); +if ((typeof module !== "undefined" && module !== null) && module.exports) console.log("commonjs host"); +else console.log("browser host"); diff --git a/tests/corpus/6105-cjs-top-level-this/package.json b/tests/corpus/6105-cjs-top-level-this/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/corpus/6105-cjs-top-level-this/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/corpus/6106-esm-top-level-this.mjs b/tests/corpus/6106-esm-top-level-this.mjs new file mode 100644 index 000000000..6079ecc1e --- /dev/null +++ b/tests/corpus/6106-esm-top-level-this.mjs @@ -0,0 +1,4 @@ +// Top-level `this` in an ES module stays undefined, also inside arrow +// functions at module scope. +const arrow = () => this; +console.log(typeof this, this === undefined, typeof arrow()); From 835ee0a08de616e3a4318c5d01e0e8cc7fc8cd13 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 10:36:41 -0500 Subject: [PATCH 097/117] Drop the cost entries of a corpus program this PR doesn't add --- tests/harness/corpus-costs.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index b402f2e9d..bfe076caf 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1845,7 +1845,6 @@ "5951-result-never-widening.ts": 4710, "5952-record-missing-keys.ts": 6090, "5953-nan-coded-method-returns.ts": 4100, - "5954-generic-optional-returns.ts": 4740, "5955-any-promise-methods.js": 3940, "5956-erased-generic-members.ts": 6730, "5970-net-connect-host-name.ts": 2400, @@ -4479,7 +4478,6 @@ "5951-result-never-widening.ts": 6120, "5952-record-missing-keys.ts": 20400, "5953-nan-coded-method-returns.ts": 15600, - "5954-generic-optional-returns.ts": 4070, "5955-any-promise-methods.js": 5120, "5956-erased-generic-members.ts": 8750, "5970-net-connect-host-name.ts": 2800, From 4128e6f6f5feccdc738c0d70097c68a433aa2bb1 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:46:38 -0700 Subject: [PATCH 098/117] Count instructions for differing corpus executables in the zero-cost gate --cachegrind now also runs differing corpus executables (without arguments, accepting intentional non-zero exits), so emitter changes that only touch corpus programs get per-function instruction deltas. AGENTS.md mentions the dynamic-tier symbol rule. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 2 +- scripts/zero-cost-gate.mjs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 16f90d68e..b94c90067 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,7 +48,7 @@ Corpus programs are differential tests against Node: every program runs under No Before opening a PR that adds or changes corpus, diagnostic, or frontend fixtures, run `pnpm test:ts7 --baselines-only`. This fast completeness check uses the same fixture discovery as the parity suite; it does not type-check or replace behavioral parity. Generate missing preflight/order baselines, review their diagnostics and module order, and run the affected `order-parity.test.ts` batches before pushing. Keep existing baseline entries unchanged unless the corresponding behavior intentionally changes. The full `pnpm test:ts7` command also checks completeness before starting its sweep. -A change that must not cost good code anything, such as a compatibility fix that replaces a refusal, proves it with the zero-cost gate. The gate compiles the benchmark workloads, the self-hosted compiler, and the TypeScript corpus with two built checkouts. It requires byte-identical IR, LLVM, and release executables, and compile time within tolerance. `--allow=` names the change's pattern signature: programs whose sources match may differ, and the PR lists them. Any other difference fails the gate, which names the first differing function. `--quick` checks only the benchmarks; `--cachegrind` adds per-function instruction counts for executables that differ. Run it in a Sandbox with both checkouts prepared: +A change that must not cost good code anything, such as a compatibility fix that replaces a refusal, proves it with the zero-cost gate. The gate compiles the benchmark workloads, the self-hosted compiler, and the TypeScript corpus with two built checkouts. It requires byte-identical IR, LLVM, and release executables, and compile time within tolerance. `--allow=` names the change's pattern signature: programs whose sources match may differ, and the PR lists them. Any other difference fails the gate, which names the first differing function. The gate also enforces the two-tier runtime separation: no executable may gain symbols from `DYNAMIC_TIER_PREFIXES` in `scripts/zero-cost-compare.mjs`, and fully typed benchmarks may link none; extend that list as dynamic-tier units land. `--quick` checks only the benchmarks; `--cachegrind` adds per-function instruction counts for executables that differ. Run it in a Sandbox with both checkouts prepared: ```bash node scripts/zero-cost-gate.mjs --baseline=/vercel/sandbox/prev --candidate=. --allow='\barguments\b' diff --git a/scripts/zero-cost-gate.mjs b/scripts/zero-cost-gate.mjs index f5fea63b9..db98bf249 100644 --- a/scripts/zero-cost-gate.mjs +++ b/scripts/zero-cost-gate.mjs @@ -97,9 +97,10 @@ symbols under DYNAMIC_TIER_PREFIXES (scripts/zero-cost-compare.mjs) unless it matches --allow, and fully typed bench workloads (all but DYNAMIC_WORKLOADS in this script) may define none. ---cachegrind (Linux, valgrind on PATH) runs differing bench executables under -cachegrind and compares instruction counts per function of the executable's -own symbols, excluding the allocator's prefault thread. +--cachegrind (Linux, valgrind on PATH) runs differing executables under +cachegrind (bench workloads with their arguments, corpus programs without) +and compares instruction counts per function of the executable's own +symbols, excluding the allocator's prefault thread. Exit status: 0 when the gate passes, 1 when it fails.`); process.exit(values.help ? 0 : 2); @@ -414,7 +415,8 @@ async function instructionCounts(binary, args, out) { binary, ...args, ]); - if (result.status !== 0) return null; + // Corpus programs may exit non-zero on purpose (`// @exit: 1`). + if (result.signal !== null || !existsSync(out)) return null; return cachegrindCounts(readFileSync(out, "utf8"), new Set(definedFunctions(binary))); } @@ -492,8 +494,10 @@ await pool( for (const failure of symbols?.failures ?? []) report.failures.push(`${program.id}: ${failure}`); if (fails || entry.sizeFailure || symbols?.failures.length) failed = true; - if (values.cachegrind && program.workload && artifacts.exe && !artifacts.exe.identical) { - const w = program.workload; + if (values.cachegrind && artifacts.exe && !artifacts.exe.identical) { + // Bench workloads run with their benchmark arguments; corpus + // programs take none. + const w = program.workload ?? { args: [] }; if (w.kind === "server" || w.args.includes("{input}")) entry.cachegrind = { skipped: "needs a server client or generated input" }; else { From 1090c05dfe6be947af2e821f74e17ab16d872da9 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 08:57:56 -0700 Subject: [PATCH 099/117] Compile chalk 5 through the dynamic object model chalk's callable builder (a function whose prototype chain is set with Object.setPrototypeOf, with style getters from Object.defineProperties) already ran on the checked-dynamic model. What failed was the code around it. Each fix is general and sits on a path that used to end in a refusal or a runtime fence, or is confined to JavaScript files: - package.json "imports" inside a --npm-static package resolve to the shipped JS with the "node" condition hoisted, like the tsgo fs shadow; - JavaScript object literals that the file reshapes at run time (keyed writes with runtime keys, delete, Object.defineProperty/ies) map to the checked-dynamic type, with the literals nested in them; - a JavaScript class whose only member is a constructor that returns a value and never reads `this` answers that value from `new` (the return used to be discarded silently); - `const { env } = process` binds the data member in JavaScript; - `o && x` / `o || x` with an always-truthy object, array or function left operand; - Number.parseInt/parseFloat over checked-dynamic values apply ToString; - Function.prototype as a value is one compiler-emitted function; - calls of String.prototype-only names (bold, italics, ...) on untyped receivers call the receiver's own or inherited member; a string receiver throws the refusal at run time. Programs without these patterns compile to identical bytes: the runtime benchmark workloads, the self-hosted compiler (LLVM and executable) and the TypeScript corpus IR were compared against the baseline. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/builtins/numbers.ts | 18 +- .../src/frontend/lowering/builtins/process.ts | 35 ++ .../lowering/js-dynamic-objects.test.ts | 38 ++ .../frontend/lowering/js-dynamic-objects.ts | 312 +++++++++++++++++ .../src/frontend/lowering/lower-calls.ts | 57 ++- .../src/frontend/lowering/lower-classes.ts | 3 + .../src/frontend/lowering/lower-exprs.ts | 56 +++ .../src/frontend/lowering/lower-stmts.ts | 33 +- .../compiler/src/frontend/lowering/lowerer.ts | 3 + packages/compiler/src/frontend/npm-static.ts | 4 + .../compiler/src/frontend/resolve.test.ts | 54 +++ packages/compiler/src/frontend/resolve.ts | 12 + packages/compiler/src/frontend/type-mapper.ts | 14 + .../main.ts.json | 7 + .../tests/corpus/js-callable-builder.js.json | 6 + .../js-class-constructor-returns/main.ts.json | 7 + .../js-function-prototype-value.js.json | 6 + .../corpus/js-number-parse-dynamic.js.json | 6 + .../corpus/js-process-destructure.mjs.json | 6 + .../corpus/js-reshaped-object-literal.js.json | 6 + .../corpus/truthy-object-logical.ts.json | 6 + .../fixtures/npm/cases/chalk5/main.ts.json | 6 + .../js-builder-string-method-names/builder.js | 22 ++ .../js-builder-string-method-names/main.ts | 14 + tests/corpus/js-callable-builder.js | 110 ++++++ .../js-class-constructor-returns/factory.js | 35 ++ .../js-class-constructor-returns/main.ts | 11 + tests/corpus/js-function-prototype-value.js | 17 + tests/corpus/js-number-parse-dynamic.js | 8 + tests/corpus/js-process-destructure.mjs | 12 + tests/corpus/js-reshaped-object-literal.js | 42 +++ tests/corpus/truthy-object-logical.ts | 31 ++ tests/fixtures/npm/cases/chalk5/main.ts | 64 ++++ .../cases/chalk5/node_modules/chalk/license | 9 + .../chalk5/node_modules/chalk/package.json | 83 +++++ .../node_modules/chalk/source/index.d.ts | 325 ++++++++++++++++++ .../chalk5/node_modules/chalk/source/index.js | 225 ++++++++++++ .../node_modules/chalk/source/utilities.js | 33 ++ .../source/vendor/ansi-styles/index.d.ts | 236 +++++++++++++ .../chalk/source/vendor/ansi-styles/index.js | 223 ++++++++++++ .../source/vendor/supports-color/browser.d.ts | 1 + .../source/vendor/supports-color/browser.js | 34 ++ .../source/vendor/supports-color/index.d.ts | 55 +++ .../source/vendor/supports-color/index.js | 190 ++++++++++ tests/fixtures/npm/cases/chalk5/package.json | 1 + tests/harness/chalk.test.ts | 97 ++++++ 46 files changed, 2569 insertions(+), 4 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/js-dynamic-objects.test.ts create mode 100644 packages/compiler/src/frontend/lowering/js-dynamic-objects.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-builder-string-method-names/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-callable-builder.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-class-constructor-returns/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-function-prototype-value.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-number-parse-dynamic.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-process-destructure.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-reshaped-object-literal.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/truthy-object-logical.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json create mode 100644 tests/corpus/js-builder-string-method-names/builder.js create mode 100644 tests/corpus/js-builder-string-method-names/main.ts create mode 100644 tests/corpus/js-callable-builder.js create mode 100644 tests/corpus/js-class-constructor-returns/factory.js create mode 100644 tests/corpus/js-class-constructor-returns/main.ts create mode 100644 tests/corpus/js-function-prototype-value.js create mode 100644 tests/corpus/js-number-parse-dynamic.js create mode 100644 tests/corpus/js-process-destructure.mjs create mode 100644 tests/corpus/js-reshaped-object-literal.js create mode 100644 tests/corpus/truthy-object-logical.ts create mode 100644 tests/fixtures/npm/cases/chalk5/main.ts create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/license create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/package.json create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.js create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/utilities.js create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.js create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.js create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.js create mode 100644 tests/fixtures/npm/cases/chalk5/package.json create mode 100644 tests/harness/chalk.test.ts diff --git a/packages/compiler/src/frontend/lowering/builtins/numbers.ts b/packages/compiler/src/frontend/lowering/builtins/numbers.ts index 08d6cb349..4f86e6f74 100644 --- a/packages/compiler/src/frontend/lowering/builtins/numbers.ts +++ b/packages/compiler/src/frontend/lowering/builtins/numbers.ts @@ -2,7 +2,7 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer, own } from "../lowerer.js"; import { lowerCheckedPredicateValue } from "../lower-builtin-values.js"; import { locOf } from "../../program.js"; -import { BOOL, F64, type IrExpr, type IrLibFn } from "../../../ir/ir.js"; +import { BOOL, F64, STRING, type IrExpr, type IrLibFn } from "../../../ir/ir.js"; import { lowerBuiltinValuePreservingUndefined, lowerOptionalNumberPredicate } from "./arguments.js"; import { tryLowerExpression } from "../expressions/try-lower-expression.js"; import { lowerStaticNumberGlobal } from "../lower-calls.js"; @@ -88,6 +88,22 @@ export function lowerNumberStaticCall( const parsed = lowerStaticNumberGlobal(lowerer, member, call, call.arguments, loc); if (parsed !== null) return parsed; } + // A checked-dynamic argument (`Number.parseInt(env.FORCE_COLOR, 10)` + // over a JavaScript dictionary read): the parsers' own ToString, + // exactly the global parseFloat's dyn form. + if (probed?.type.kind === "dyn") { + const text: IrExpr = { + kind: "libCall", + fn: "dyn.toStringCoerce", + args: [probed], + type: STRING, + loc, + }; + if (member === "parseFloat") + return { kind: "libCall", fn: "num.parseFloat", args: [text], type: F64, loc }; + const radix = lowerer.lowerExprExpecting(call.arguments[1]!, F64); + return { kind: "libCall", fn: "num.parseInt", args: [text, radix], type: F64, loc }; + } const argText = probed !== null ? lowerer.fmt(probed.type) diff --git a/packages/compiler/src/frontend/lowering/builtins/process.ts b/packages/compiler/src/frontend/lowering/builtins/process.ts index 97bf1e963..94c2cdba7 100644 --- a/packages/compiler/src/frontend/lowering/builtins/process.ts +++ b/packages/compiler/src/frontend/lowering/builtins/process.ts @@ -233,6 +233,41 @@ export function lowerProcessStreamProperty( * read in source order). Method members referenced without a call are * rejected specifically. Null for non-process receivers (the chain keeps * trying other property lowerings). */ +/** The value of a DATA member of the process global taken off by + * destructuring (`const { env, argv } = process` in JavaScript, the + * supports-color opening): the same values the spelled `process.env` / + * `process.argv` reads produce, typed by the binding. Null for members + * this does not cover (methods keep the destructuring fence). */ +export function processDataMemberValue( + lowerer: Lowerer, + member: string, + binding: ts.Node, + loc: SrcLoc, +): IrExpr | null { + switch (member) { + case "env": { + const mapped = lowerer.mapTypeOf(lowerer.typeOf(binding)); + if (mapped?.kind !== "record") return null; + const helper = envSnapshotHelper(lowerer, mapped.shapeId, loc); + return helper === null ? null : { kind: "call", callee: helper, args: [], type: mapped, loc }; + } + case "argv": + return { kind: "libCall", fn: "process.argv", args: [], type: arrayOf(STRING), loc }; + case "platform": + return { kind: "libCall", fn: "process.platform", args: [], type: STRING, loc }; + case "arch": + return { kind: "libCall", fn: "process.arch", args: [], type: STRING, loc }; + case "pid": + return { kind: "libCall", fn: "process.pid", args: [], type: F64, loc }; + case "execPath": + return { kind: "libCall", fn: "process.execPath", args: [], type: STRING, loc }; + case "versions": + return { kind: "libCall", fn: "process.versions", args: [], type: DYN, loc }; + default: + return null; + } +} + export function lowerProcessProperty( lowerer: Lowerer, expr: ts.PropertyAccessExpression, diff --git a/packages/compiler/src/frontend/lowering/js-dynamic-objects.test.ts b/packages/compiler/src/frontend/lowering/js-dynamic-objects.test.ts new file mode 100644 index 000000000..23ebdfaa9 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/js-dynamic-objects.test.ts @@ -0,0 +1,38 @@ +import { afterAll, expect, test } from "vitest"; +import * as ts from "../ts7/adapter.js"; +import { closeSourceParser, parseSourceFile } from "../ts7/source-parser-node.js"; +import { isValueReturningConstructorClass } from "./js-dynamic-objects.js"; + +afterAll(closeSourceParser); + +function classify(source: string): boolean { + const file = parseSourceFile("classes.js", source, "js"); + let decl: ts.ClassDeclaration | undefined; + ts.walkPreorder(file, (node) => { + if (!decl && ts.isClassDeclaration(node)) decl = node; + }); + if (!decl) throw new Error("fixture has no class"); + return isValueReturningConstructorClass(decl); +} + +test("a constructor-only class returning a value is claimed", () => { + expect(classify(`class Chalk { constructor(options) { return chalkFactory(options); } }`)).toBe( + true, + ); + expect(classify(`class C { constructor(a) { if (a) return { a }; return [a]; } ; }`)).toBe(true); + expect(classify(`class C { constructor() { const f = () => 1; return { f }; } }`)).toBe(true); +}); + +test("classes that keep their instance layout are left alone", () => { + // No value return, or only nested functions return. + expect(classify(`class C { constructor() { return; } }`)).toBe(false); + expect(classify(`class C { constructor() { function f() { return 1; } f(); } }`)).toBe(false); + expect(classify(`class C { constructor() { const f = () => { return 1; }; f(); } }`)).toBe(false); + // Other members, heritage, or a constructor that observes `this`. + expect(classify(`class C { constructor() { return {}; } m() {} }`)).toBe(false); + expect(classify(`class C { x = 1; constructor() { return {}; } }`)).toBe(false); + expect(classify(`class C extends B { constructor() { super(); return {}; } }`)).toBe(false); + expect(classify(`class C { constructor() { this.a = 1; return {}; } }`)).toBe(false); + expect(classify(`class C { constructor() { const g = () => this; return { g }; } }`)).toBe(false); + expect(classify(`class C {}`)).toBe(false); +}); diff --git a/packages/compiler/src/frontend/lowering/js-dynamic-objects.ts b/packages/compiler/src/frontend/lowering/js-dynamic-objects.ts new file mode 100644 index 000000000..1d7ab6eee --- /dev/null +++ b/packages/compiler/src/frontend/lowering/js-dynamic-objects.ts @@ -0,0 +1,312 @@ +/* JavaScript declarations whose values only the checked-dynamic + * representation can hold faithfully. TypeScript infers a fixed object + * type for each of them, but the program changes the value's shape or + * identity at run time, so a static layout would answer stale members + * (or throw on a value that no longer fits): + * + * - a non-empty object literal bound to a variable that the same file + * grows or reshapes dynamically: a keyed write with a runtime key + * (`o[k] = v`), a `delete`, or `Object.defineProperty(o, ...)` / + * `Object.defineProperties(o, ...)` (ansi-styles' `assembleStyles`). + * The object literals nested in its property values belong to the same + * value graph and are marked with it; + * - a class whose only member is a constructor that returns a value and + * never reads `this` (chalk's `class Chalk { constructor(options) { + * return chalkFactory(options); } }`): `new C()` answers whatever the + * constructor returns, so its instance type has no fixed layout. + * + * The type mapper answers the checked-dynamic type for the instance and + * object-literal types these declarations own (TypeMapperCtx + * .jsDynamicDeclaration). The scan is syntactic, runs over JavaScript + * files only, and an empty answer leaves every mapping unchanged, so + * TypeScript programs and JavaScript that never uses these patterns + * compile exactly as before. */ +import * as ts from "../ts7/adapter.js"; +import { isJsSourceFile, locOf } from "../program.js"; +import { BOOL, DYN, type IrExpr, type IrStmt } from "../../ir/ir.js"; +import { dynUndefinedExpr, nodeThrowExpr } from "../../ir/build.js"; +import type { Lowerer } from "./lowerer.js"; +import type { ParamShape } from "./call-signatures.js"; +import { newFnCtx } from "./function-context.js"; + +const SCANNED_KINDS: ReadonlySet = new Set([ + ts.SyntaxKind.VariableDeclaration, + ts.SyntaxKind.ClassDeclaration, + ts.SyntaxKind.BinaryExpression, + ts.SyntaxKind.DeleteExpression, + ts.SyntaxKind.CallExpression, +]); + +function unparenthesized(node: ts.Expression): ts.Expression { + while (ts.isParenthesizedExpression(node)) node = node.expression; + return node; +} + +function isLiteralKey(node: ts.Expression): boolean { + const key = unparenthesized(node); + return ( + ts.isStringLiteral(key) || ts.isNumericLiteral(key) || ts.isNoSubstitutionTemplateLiteral(key) + ); +} + +function isAssignmentOperator(kind: ts.SyntaxKind): boolean { + return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment; +} + +/** `class C { constructor(...) { ...; return value; } }` with nothing else: + * no heritage, decorators or other members, a constructor body that + * returns a value at its own level and never mentions `this`/`super`. */ +export function isValueReturningConstructorClass(decl: ts.ClassDeclaration): boolean { + if (decl.heritageClauses !== undefined && decl.heritageClauses.length > 0) return false; + if (decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.Decorator)) return false; + let ctor: ts.ConstructorDeclaration | undefined; + for (const member of decl.members) { + if (ts.isSemicolonClassElement(member)) continue; + if (!ts.isConstructorDeclaration(member) || ctor !== undefined) return false; + ctor = member; + } + if (ctor?.body === undefined) return false; + let returnsValue = false; + let observesThis = false; + const visit = (node: ts.Node): void => { + if (observesThis) return; + if (node.kind === ts.SyntaxKind.ThisKeyword || node.kind === ts.SyntaxKind.SuperKeyword) { + observesThis = true; + return; + } + // Arrow functions share the constructor's `this`; other functions + // have their own `this` and their own returns. + if (ts.isFunctionLike(node) && !ts.isArrowFunction(node)) return; + if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) return; + if (ts.isReturnStatement(node) && node.expression !== undefined && !insideArrow(node, ctor!)) + returnsValue = true; + node.forEachChild(visit); + }; + ctor.body.forEachChild(visit); + for (const parameter of ctor.parameters) parameter.forEachChild(visit); + return returnsValue && !observesThis; +} + +function insideArrow(node: ts.Node, ctor: ts.ConstructorDeclaration): boolean { + for (let p = node.parent; p !== undefined && p !== ctor; p = p.parent) { + if (ts.isArrowFunction(p)) return true; + } + return false; +} + +function markNested(literal: ts.ObjectLiteralExpression, out: Set): void { + if (out.has(literal)) return; + out.add(literal); + for (const property of literal.properties) { + if (!ts.isPropertyAssignment(property)) continue; + const value = unparenthesized(property.initializer); + if (ts.isObjectLiteralExpression(value)) markNested(value, out); + } +} + +export function jsDynamicDeclarations( + files: readonly ts.SourceFile[], + checker: ts.TypeChecker, +): Set { + const out = new Set(); + for (const file of files) { + if (!isJsSourceFile(file) || file.isDeclarationFile) continue; + const literals = new Map(); + const reshaped = new Set(); + const receiver = (expression: ts.Expression | undefined): void => { + if (expression === undefined) return; + const target = unparenthesized(expression); + if (!ts.isIdentifier(target)) return; + const symbol = checker.getSymbolAtLocation(target); + if (symbol !== undefined) reshaped.add(symbol); + }; + ts.walkPreorder( + file, + (node) => { + if (ts.isVariableDeclaration(node)) { + if (!ts.isIdentifier(node.name) || node.initializer === undefined) return; + const init = unparenthesized(node.initializer); + // An empty literal's binding is already checked-dynamic + // (jsOpenObjectType), and its type describes no layout. + if (!ts.isObjectLiteralExpression(init) || init.properties.length === 0) return; + const symbol = checker.getSymbolAtLocation(node.name); + if (symbol !== undefined) literals.set(symbol, init); + return; + } + if (ts.isClassDeclaration(node)) { + if (isValueReturningConstructorClass(node)) out.add(node); + return; + } + if (ts.isBinaryExpression(node)) { + if (!isAssignmentOperator(node.operatorToken.kind)) return; + const left = unparenthesized(node.left); + if (ts.isElementAccessExpression(left) && !isLiteralKey(left.argumentExpression)) + receiver(left.expression); + return; + } + if (ts.isDeleteExpression(node)) { + const operand = unparenthesized(node.expression); + if (ts.isElementAccessExpression(operand) || ts.isPropertyAccessExpression(operand)) + receiver(operand.expression); + return; + } + if (ts.isCallExpression(node)) { + const callee = unparenthesized(node.expression); + if ( + ts.isPropertyAccessExpression(callee) && + ts.isIdentifier(callee.expression) && + callee.expression.text === "Object" && + (callee.name.text === "defineProperty" || callee.name.text === "defineProperties") + ) + receiver(node.arguments[0]); + } + }, + SCANNED_KINDS, + ); + for (const symbol of reshaped) { + const literal = literals.get(symbol); + if (literal !== undefined) markNested(literal, out); + } + } + return out; +} + +/** `new C(args)` for a value-returning constructor class (above): the + * constructor body runs as an ordinary JavaScript function whose result + * is the construction's value. A returned object or function is Node's + * answer; a fall-through or primitive return would answer the bare + * instance, which has no static home here, and throws the deferred + * refusal instead. Null when the callee is not such a class. */ +export function lowerValueReturningConstructorNew( + lowerer: Lowerer, + expr: ts.NewExpression, +): IrExpr | null { + const isDynamic = lowerer.typeCtx.jsDynamicDeclaration; + if (isDynamic === undefined) return null; + const callee = unparenthesized(expr.expression); + if (!ts.isIdentifier(callee)) return null; + let symbol = lowerer.resolveValueSymbol(callee); + if (symbol !== null && (symbol.flags & ts.SymbolFlags.Alias) !== 0) + symbol = lowerer.checker.getAliasedSymbol(symbol); + const decl = symbol + ? lowerer.checker + .declarationsOf(symbol) + .find((node): node is ts.ClassDeclaration => ts.isClassDeclaration(node) && isDynamic(node)) + : undefined; + if (decl === undefined) return null; + const loc = locOf(expr); + const ctor = decl.members.find(ts.isConstructorDeclaration)!; + const simple = ctor.parameters.every( + (p) => ts.isIdentifier(p.name) && p.dotDotDotToken === undefined && p.initializer === undefined, + ); + if (!simple || !ts.isSourceFile(decl.parent)) { + lowerer.unsupported( + "SC1090", + expr, + "constructing a class whose constructor returns a value, with parameter defaults, rest or patterns, or declared inside a function", + ); + } + const args = expr.arguments ?? []; + if (args.some(ts.isSpreadElement)) { + lowerer.unsupported( + "SC1090", + expr, + "spread arguments when constructing a class whose constructor returns a value", + ); + } + const key = `ctorValue:${decl.getSourceFile().fileName}:${decl.getStart()}`; + let name = lowerer.valueHelpers.get(key); + if (name === undefined) { + name = `%ctorValue.${lowerer.valueHelpers.size}`; + lowerer.valueHelpers.set(key, name); + const savedClass = lowerer.currentClass; + lowerer.currentClass = null; + lowerer.fnStack.push(newFnCtx(false, null, null, DYN)); + try { + const shapes: ParamShape[] = ctor.parameters.map(() => ({ type: DYN, mode: "required" })); + const declared = lowerer.declareParams(ctor.parameters, shapes); + const body: IrStmt[] = [ + ...declared.prologue, + ...lowerer.lowerStmts(ctor.body!.statements), + { + kind: "runtimeFence", + code: "SC1090", + message: `constructors that return no object (the bare instance of '${decl.name?.text ?? "class"}' has no representation here) are not supported yet [SC1090 at ${decl.getSourceFile().fileName}:${ts.getLineAndCharacterOfPosition(decl.getSourceFile(), ctor.getStart()).line + 1}]`, + loc: locOf(ctor), + }, + ]; + lowerer.liftedFns.push({ + name, + params: declared.params, + returnType: DYN, + locals: lowerer.ctx.locals, + body, + loc: locOf(ctor), + }); + } finally { + lowerer.fnStack.pop(); + lowerer.currentClass = savedClass; + } + } + const lowered = ctor.parameters.map((_, i) => + args[i] !== undefined ? lowerer.lowerExprExpecting(args[i]!, DYN) : dynUndefinedExpr(loc), + ); + // Surplus arguments still evaluate, left to right, after the others. + const surplus: IrStmt[] = args + .slice(ctor.parameters.length) + .map((arg) => ({ kind: "exprStmt", expr: lowerer.lowerExpr(arg), loc: locOf(arg) })); + const result = lowerer.declareHiddenLocal("%constructed", DYN); + const value: IrExpr = { kind: "varRef", localId: result.id, type: DYN, loc }; + const sf = expr.getSourceFile(); + const line = ts.getLineAndCharacterOfPosition(sf, expr.getStart()).line + 1; + const objectLike: IrExpr = { + kind: "logical", + op: "||", + left: { kind: "dynTest", test: "function", value, type: BOOL, loc }, + right: { + kind: "logical", + op: "&&", + left: { kind: "dynTest", test: "object", value, type: BOOL, loc }, + right: { kind: "dynTest", test: "null", negated: true, value, type: BOOL, loc }, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }; + const args0: IrStmt[] = []; + const argLocals = lowered.map((arg) => { + const local = lowerer.declareHiddenLocal("%constructArg", DYN); + args0.push({ kind: "varDecl", localId: local.id, init: arg, loc }); + return { kind: "varRef", localId: local.id, type: DYN, loc } as IrExpr; + }); + return { + kind: "seqExpr", + stmts: [ + ...args0, + ...surplus, + { + kind: "varDecl", + localId: result.id, + init: { kind: "call", callee: name, args: argLocals, type: DYN, loc }, + loc, + }, + ], + result: { + kind: "ternary", + cond: objectLike, + then: value, + else_: nodeThrowExpr( + 0, + "SC1090", + `constructors that return no object are not supported yet [SC1090 at ${sf.fileName}:${line}]`, + DYN, + loc, + ), + type: DYN, + loc, + }, + type: DYN, + loc, + }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 56c639397..04034c2e0 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -3463,13 +3463,41 @@ function lowerDynReceiverMethodCall( // its name overlaps a primitive prototype (`colors.bold(...)`): the // source value was compiled from that object shape, while genuinely // untyped/any receivers retain the runtime-kind ambiguity and fence. - if (DYN_PROTO_METHOD_NAMES.has(access.name.text) && !ownCallable) return null; + // A name only String.prototype declares (`bold`, `italics`, `link`, + // ...) on a checker-untyped receiver: every other dyn kind answers its + // own or inherited member exactly like a non-prototype name (chalk's + // `chalk.red.bold(...)` reads a prototype getter of a function), so + // only a string receiver keeps the refusal, deferred to run time. + const stringOnlyName = + checkerUntyped && !ownCallable && DYN_STRING_PROTO_ONLY_NAMES.has(access.name.text); + if (DYN_PROTO_METHOD_NAMES.has(access.name.text) && !ownCallable && !stringOnlyName) return null; // Optional forms (`obj.cb?.()`, `obj?.cb()`) belong to the chain // machinery's short-circuit semantics — not modeled here yet. if (call.questionDotToken || access.questionDotToken) return null; const loc = locOf(call); const receiverLocal = lowerer.declareHiddenLocal("%dynCallReceiver", DYN); const receiver: IrExpr = { kind: "varRef", localId: receiverLocal.id, type: DYN, loc }; + // The string refusal throws in place of the member read (a seqExpr + // statement cannot leave the expression). + const stringRefusal = (read: IrExpr): IrExpr => { + if (!stringOnlyName) return read; + const sf = call.getSourceFile(); + const line = ts.getLineAndCharacterOfPosition(sf, call.getStart(sf)).line + 1; + return { + kind: "ternary", + cond: { kind: "dynTest", test: "string", value: receiver, type: BOOL, loc }, + then: nodeThrowExpr( + 0, + "SC1090", + `method calls like '${access.getText()}' on a string are not supported yet [SC1090 at ${sf.fileName}:${line}]`, + DYN, + loc, + ), + else_: read, + type: DYN, + loc, + }; + }; const member: IrExpr = { kind: "dynKeyGet", key: { kind: "strLit", value: access.name.text, type: STRING, loc: locOf(access) }, @@ -3481,7 +3509,7 @@ function lowerDynReceiverMethodCall( const callee = varRef(calleeLocal.id, DYN, loc); const stmts: IrStmt[] = [ { kind: "varDecl", localId: receiverLocal.id, init: recv, loc }, - { kind: "varDecl", localId: calleeLocal.id, init: member, loc }, + { kind: "varDecl", localId: calleeLocal.id, init: stringRefusal(member), loc }, ]; if (call.arguments.some(ts.isSpreadElement)) { const spread = lowerSpreadArgsCall(lowerer, call, callee, loc); @@ -3590,6 +3618,31 @@ const DYN_PROTO_METHOD_NAMES = new Set([ "toPrecision", ]); +/** The DYN_PROTO_METHOD_NAMES that only String.prototype declares among + * the dyn-representable kinds' prototypes. */ +const DYN_STRING_PROTO_ONLY_NAMES = new Set([ + "anchor", + "big", + "blink", + "bold", + "codePointAt", + "fixed", + "fontcolor", + "fontsize", + "isWellFormed", + "italics", + "link", + "localeCompare", + "normalize", + "small", + "strike", + "sub", + "sup", + "toLocaleLowerCase", + "toLocaleUpperCase", + "toWellFormed", +]); + /** The SHARED prototype names scr_dyn_invoke dispatches at runtime (the * subset of DYN_PROTO_METHOD_NAMES with a receiver-kind dispatch): the * runtime runs the real method for the receiver's kind, throws Node's diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 06739166c..b5d0e4ac8 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -1,3 +1,4 @@ +import { lowerValueReturningConstructorNew } from "./js-dynamic-objects.js"; import { dynUndefinedExpr, nodeThrowExpr, varRef } from "../../ir/build.js"; import { checkedIterableSpread } from "./checked-iterable-spread.js"; import { lowerReadlineUiNew } from "./builtins/readline.js"; @@ -8422,6 +8423,8 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { undefined, lowerer.checker.getSymbolAtLocation(expr.expression), ); + const valueReturning = lowerValueReturningConstructorNew(lowerer, expr); + if (valueReturning) return valueReturning; const instanceConstructor = lowerInstanceConstructorNew(lowerer, expr); if (instanceConstructor) return instanceConstructor; const objectFactory = lowerObjectFactoryNew(lowerer, expr); diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index d2d990e16..977062d45 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -4974,6 +4974,34 @@ export function lowerIntrinsicProperty( return { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc: locOf(expr) }; if (lowerer.stdlibGlobalMember(expr, "Object") === "prototype") return { kind: "libCall", fn: "dyn.objectPrototype", args: [], type: DYN, loc: locOf(expr) }; + // Function.prototype as a VALUE (a prototype-chain link: + // `Object.setPrototypeOf(F.prototype, Function.prototype)`): one + // anonymous function answering undefined, length 0 — a zero-capture + // closure of a compiler helper, so every read is the same function + // (closure identity) and shares its property table. Reads through it + // find the function members the checked runtime models for every + // function (apply, constructor, name, length). Member forms keep their + // own lowerings. + if (lowerer.stdlibGlobalMember(expr, "Function") === "prototype") { + const loc = locOf(expr); + const name = "%dyn.functionPrototype"; + if (!lowerer.liftedFns.some((fn) => fn.name === name)) + lowerer.liftedFns.push({ + name, + params: [], + locals: [], + returnType: DYN, + body: [{ kind: "return", value: dynUndefinedExpr(loc), loc }], + loc, + }); + return { + kind: "dynFrom", + value: { kind: "closure", fnName: name, captures: [], type: funcOf([], DYN), loc }, + fnName: "", + type: DYN, + loc, + }; + } if (lowerer.stdlibGlobalMember(expr, "Array") === "isArray") return lowerArrayIsArrayValue(lowerer, locOf(expr)); if (lowerer.stdlibGlobalMember(expr, "Array") === "from") @@ -11203,6 +11231,34 @@ function lowerLogicalPair(lowerer: Lowerer, expr: ts.BinaryExpression, left: IrE // same lift the union-operand path above takes, arriving here // with two plain arm values instead. const target = lowerer.mapTypeOf(lowerer.typeOf(expr)); + // An always-truthy left operand (a record, object, array or function + // value: every JS object is truthy): `o && x` evaluates `o` for its + // effects and answers `x`; `o || x` answers `o` and never evaluates + // `x`. supports-color's `stream && stream.isTTY` is the shape. Ahead + // of the union lift below exactly where that lift would store the + // object in a result union with no arm for it; a union holding the + // operand keeps the lift. + if ( + REF_TRUTHY_KINDS.has(kind) && + (target?.kind !== "union" || + (op === ts.SyntaxKind.AmpersandAmpersandToken && + lowerer.armTag(target.unionId, left.type) < 0)) + ) { + const and = op === ts.SyntaxKind.AmpersandAmpersandToken; + const answer = and ? right : left; + const answerT = target ?? answer.type; + if (answerT.kind !== "void") { + const value = lowerer.coerceInto(and ? expr.right : expr.left, answer, answerT); + if (!and) return value; + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: left, loc }], + result: value, + type: answerT, + loc, + }; + } + } if (target?.kind === "union") { lowerer.requireTruthyUnion(target.unionId, expr); return { diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index cffe4c661..9e3375e6d 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -10,6 +10,7 @@ import { InternalCompilerError } from "../../errors.js"; * flow (if/while/for/for-of/do, switch, try/catch, abrupt completions), * explicit resource management, and blocked-binding poisoning. */ import * as ts from "../ts7/adapter.js"; +import { processDataMemberValue } from "./builtins/process.js"; import { bindingSource } from "../binding-source.js"; import type { Lowerer } from "./lowerer.js"; import { @@ -3131,6 +3132,9 @@ function stdlibGlobalTokenDestructure( token: string; alias: string | null; g: IrGlobal | undefined; + /** A data member's value (`const { env } = process`), bound instead + * of a token. */ + value?: IrExpr; }[] = []; for (const el of decl.name.elements) { if (el.name === undefined) continue; @@ -3166,8 +3170,9 @@ function stdlibGlobalTokenDestructure( "destructuring with computed keys that do not fold to one property name", ); } - let token: string; + let token = ""; let alias: string | null = null; + let value: IrExpr | null = null; if (globalName === "globalThis") { // The member must BE a stdlib global (user script vars are // properties of `typeof globalThis` too — their values are real @@ -3187,6 +3192,13 @@ function stdlibGlobalTokenDestructure( token = `[builtin console.${propName}]`; } else if (TOKEN_OPAQUE_GLOBALS.has(globalName)) { token = `[builtin ${globalName}.${propName}]`; + } else if ( + globalName === "process" && + ts.isIdentifier(el.name) && + (value = processDataMemberValue(lowerer, propName, el.name, locOf(el))) !== null + ) { + // A data member reads its value once, exactly like the spelled + // `process.` read the destructuring performs. } else { lowerer.unsupported( "SC1031", @@ -3203,6 +3215,10 @@ function stdlibGlobalTokenDestructure( ); } const g = lowerer.globalsBySymbol.get(symbol); + if (value !== null) { + binds.push({ name: el.name, token, alias, g, value }); + continue; + } if (g !== undefined && g.type.kind !== "string" && g.type.kind !== "dyn") { lowerer.unsupported( "SC1031", @@ -3215,6 +3231,21 @@ function stdlibGlobalTokenDestructure( const out: IrStmt[] = []; for (const b of binds) { const loc = locOf(b.name); + if (b.value !== undefined) { + if (b.g !== undefined) { + out.push({ + kind: "assign", + localId: b.g.id, + value: lowerer.coerceInto(b.name, b.value, b.g.type), + ...(b.g.tdz ? { initializes: true as const } : {}), + loc, + }); + } else { + const local = lowerer.declareLocal(b.name, b.name.text, b.value.type, isLet); + out.push({ kind: "varDecl", localId: local.id, init: b.value, loc }); + } + continue; + } const token: IrExpr = { kind: "strLit", value: b.token, type: STRING, loc }; if (b.alias !== null) { const symbol = lowerer.checker.getSymbolAtLocation(b.name); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 087b4e628..4193be2bb 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1,3 +1,4 @@ +import { jsDynamicDeclarations } from "./js-dynamic-objects.js"; import { lifetimeRegionType, lowerLifetimeRegionCall, @@ -2860,6 +2861,8 @@ export class Lowerer { this.fileTag.set(sf, sf === entry ? "" : `%m${i}.`); }); if (this.moduleOrder.length === 0) this.fileTag.set(entry, ""); + const jsDynamic = jsDynamicDeclarations(this.moduleOrder, this.checker); + if (jsDynamic.size > 0) this.typeCtx.jsDynamicDeclaration = (decl) => jsDynamic.has(decl); this.registerBuiltinErrorClasses(); registerBuiltinEmitterClass(this); registerBuiltinStreamClasses(this); diff --git a/packages/compiler/src/frontend/npm-static.ts b/packages/compiler/src/frontend/npm-static.ts index 1f83a12d4..d2f4ea3e8 100644 --- a/packages/compiler/src/frontend/npm-static.ts +++ b/packages/compiler/src/frontend/npm-static.ts @@ -190,6 +190,10 @@ export function npmStaticTransformPkgJson(pkg: Record): void { for (const value of Object.values(obj)) transform(value); }; if (pkg["exports"] !== undefined) transform(pkg["exports"]); + // The "imports" field maps "#" specifiers with the same condition objects + // (chalk 5's `"#supports-color": { node, default }`), so Node's "node" + // target hoists there too. + if (pkg["imports"] !== undefined) transform(pkg["imports"]); } /** npmStaticTransformPkgJson over a package.json TEXT (the fs shadow's diff --git a/packages/compiler/src/frontend/resolve.test.ts b/packages/compiler/src/frontend/resolve.test.ts index 0d135b3c2..0dd09e73d 100644 --- a/packages/compiler/src/frontend/resolve.test.ts +++ b/packages/compiler/src/frontend/resolve.test.ts @@ -11,6 +11,7 @@ import { setProjectPathMappings, setProjectRealm, } from "./resolve.js"; +import { setNpmStaticPackages } from "./npm-static.js"; const fixturesRoot = join(import.meta.dirname, "../../../..", "tests/fixtures"); @@ -60,3 +61,56 @@ test("source-only workspace packages are project modules while JavaScript packag clearResolveCaches(); } }); + +test("package imports inside a --npm-static package answer the shipped JavaScript", async () => { + // chalk 5's shape: a declaration twin beside every runtime file, and a + // `{ node, default }` imports entry whose node target is what Node runs. + const dir = realpathSync(await mkdtemp(join(tmpdir(), "scriptc-resolve-imports-"))); + try { + const pkg = join(dir, "node_modules", "colors"); + const vendor = join(pkg, "source", "vendor"); + await mkdir(join(vendor, "styles"), { recursive: true }); + await mkdir(join(vendor, "detect"), { recursive: true }); + await Promise.all([ + writeFile( + join(pkg, "package.json"), + JSON.stringify({ + name: "colors", + version: "1.0.0", + type: "module", + exports: "./source/index.js", + imports: { + "#styles": "./source/vendor/styles/index.js", + "#detect": { + node: "./source/vendor/detect/index.js", + default: "./source/vendor/detect/browser.js", + }, + }, + }), + ), + writeFile(join(pkg, "source", "index.js"), 'import styles from "#styles";\n'), + writeFile(join(pkg, "source", "index.d.ts"), "export {};\n"), + writeFile(join(vendor, "styles", "index.js"), "export default {};\n"), + writeFile(join(vendor, "styles", "index.d.ts"), "export {};\n"), + writeFile(join(vendor, "detect", "index.js"), "export default 1;\n"), + writeFile(join(vendor, "detect", "index.d.ts"), "export {};\n"), + writeFile(join(vendor, "detect", "browser.js"), "export default 0;\n"), + writeFile(join(vendor, "detect", "browser.d.ts"), "export {};\n"), + ]); + const from = join(pkg, "source", "index.js"); + + clearResolveCaches(); + setNpmStaticPackages([]); + expect(resolveProjectModule(from, "#styles")).toBe(join(vendor, "styles", "index.d.ts")); + + clearResolveCaches(); + setNpmStaticPackages(["colors"]); + expect(resolveProjectModule(from, "#styles")).toBe(join(vendor, "styles", "index.js")); + expect(resolveProjectModule(from, "#detect")).toBe(join(vendor, "detect", "index.js")); + expect(resolveProjectModule(from, "#missing")).toBeNull(); + } finally { + setNpmStaticPackages([]); + clearResolveCaches(); + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/src/frontend/resolve.ts b/packages/compiler/src/frontend/resolve.ts index db440c199..463400475 100644 --- a/packages/compiler/src/frontend/resolve.ts +++ b/packages/compiler/src/frontend/resolve.ts @@ -617,6 +617,18 @@ export function resolveProjectImport(fromFile: string, specifier: string): strin // Node's validity rule: only the bare "#" is never resolvable ("#/..." // matches "#/*"-pattern keys on current Node). if (specifier === "#") return null; + // Inside an opted-in --npm-static package, an imports entry resolves + // the way the tsgo host's fs shadow does: the transformed document + // (the "node" condition hoisted), the runtime JS conditions, and the + // shipped JS rather than a declaration twin (see resolveRelativeModule). + if (npmStaticPackageOfPath(resolve(fromFile)) !== null) { + const transformed = JSON.parse(JSON.stringify(pkg)) as PkgJson & Record; + npmStaticTransformPkgJson(transformed); + const jsTarget = resolvePackageImports(transformed.imports, specifier, JS_ONLY_CONDITIONS); + if (jsTarget === null || !jsTarget.startsWith("./")) return null; + const jsPath = join(pkgDir, jsTarget); + return normalizeResolvedAnswer(loadAsJsFile(jsPath) ?? loadAsJsDirectory(jsPath)); + } target = resolvePackageImports(pkg.imports, specifier, EXPORT_CONDITIONS); // An imports target that is not "./"-relative is PACKAGE_RESOLVE'd as // a bare specifier (Node's PACKAGE_IMPORTS_EXPORTS_RESOLVE): the diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 52964e1bd..1e1bedc39 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -996,6 +996,10 @@ export type TypeParamTsResolver = (t: ts.Type) => ts.Type | null; * one new field here, not a new parameter at every call site. */ export interface TypeMapperCtx { checker: ts.TypeChecker; + /** JavaScript declarations whose instance or object-literal types only + * the checked-dynamic representation holds (js-dynamic-objects.ts). + * Absent when the program has none: every mapping is unchanged. */ + jsDynamicDeclaration?: (decl: ts.Node) => boolean; /** Set while mapping a generic callable member's erased type * (erasedGenericMemberType): the signature's own type parameters * resolve to `unknown` instead of refusing the mapping. */ @@ -1368,6 +1372,16 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { const intrinsic = type.getSymbol(); if (intrinsic?.name === "globalThis" && checker.declarationsOf(intrinsic).length === 0) return DYN; + if (ctx.jsDynamicDeclaration !== undefined && intrinsic !== undefined) { + const objectLiteral = (intrinsic.flags & ts.SymbolFlags.ObjectLiteral) !== 0; + const classInstance = + (intrinsic.flags & ts.SymbolFlags.Class) !== 0 && type.isClassOrInterface(); + if ( + (objectLiteral || classInstance) && + checker.declarationsOf(intrinsic).some((decl) => ctx.jsDynamicDeclaration!(decl)) + ) + return DYN; + } { const moduleId = ctx.moduleNamespaceId?.(type) ?? null; if (moduleId !== null) return { kind: "moduleNs", moduleId }; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-builder-string-method-names/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-builder-string-method-names/main.ts.json new file mode 100644 index 000000000..d1f487f89 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-builder-string-method-names/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/js-builder-string-method-names/builder.js", + "/tests/corpus/js-builder-string-method-names/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-callable-builder.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-callable-builder.js.json new file mode 100644 index 000000000..8f1025c47 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-callable-builder.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/js-callable-builder.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-class-constructor-returns/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-class-constructor-returns/main.ts.json new file mode 100644 index 000000000..e05f1760c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-class-constructor-returns/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/js-class-constructor-returns/factory.js", + "/tests/corpus/js-class-constructor-returns/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-function-prototype-value.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-function-prototype-value.js.json new file mode 100644 index 000000000..b0fa827e1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-function-prototype-value.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/js-function-prototype-value.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-number-parse-dynamic.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-number-parse-dynamic.js.json new file mode 100644 index 000000000..608e24d40 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-number-parse-dynamic.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/js-number-parse-dynamic.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-process-destructure.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-process-destructure.mjs.json new file mode 100644 index 000000000..87d43324e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-process-destructure.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/js-process-destructure.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-reshaped-object-literal.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-reshaped-object-literal.js.json new file mode 100644 index 000000000..939240b2c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/js-reshaped-object-literal.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/js-reshaped-object-literal.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/truthy-object-logical.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/truthy-object-logical.ts.json new file mode 100644 index 000000000..96661c630 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/truthy-object-logical.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/truthy-object-logical.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json new file mode 100644 index 000000000..065c96347 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/chalk5/main.ts" + ], + "diags": [] +} diff --git a/tests/corpus/js-builder-string-method-names/builder.js b/tests/corpus/js-builder-string-method-names/builder.js new file mode 100644 index 000000000..36824c317 --- /dev/null +++ b/tests/corpus/js-builder-string-method-names/builder.js @@ -0,0 +1,22 @@ +// Prototype getters named like String.prototype's HTML methods (bold, +// italics, link, big): each read builds a callable that wraps its input. +const wrap = (tag) => ({ + get() { + const parent = this; + const builder = (text) => builder.prefix(text); + builder.prefix = (text) => parent.prefix(`<${tag}>` + text + ``); + Object.setPrototypeOf(builder, proto); + return builder; + }, +}); +const proto = Object.defineProperties(() => {}, { + bold: wrap("b"), + italics: wrap("i"), + link: wrap("a"), + big: wrap("big"), + red: wrap("red"), +}); +const root = (text) => text; +root.prefix = (text) => text; +Object.setPrototypeOf(root, proto); +export default root; diff --git a/tests/corpus/js-builder-string-method-names/main.ts b/tests/corpus/js-builder-string-method-names/main.ts new file mode 100644 index 000000000..5cab8e4ca --- /dev/null +++ b/tests/corpus/js-builder-string-method-names/main.ts @@ -0,0 +1,14 @@ +// A TypeScript caller reaching JavaScript builders whose member names +// collide with String.prototype methods: the receiver is a function, so +// each call reads the function's inherited getter, not the string method. +import builder from "./builder.js"; + +// TypeScript infers no members for the builder's prototype getters. +const tags: any = builder; + +console.log(tags.bold("strong")); +console.log(tags.red.bold("nested")); +console.log(tags.italics.link("deep").length); +console.log(tags.big.red.italics("three")); +const chain = tags.link; +console.log(chain.bold("from a binding")); diff --git a/tests/corpus/js-callable-builder.js b/tests/corpus/js-callable-builder.js new file mode 100644 index 000000000..3697d788d --- /dev/null +++ b/tests/corpus/js-callable-builder.js @@ -0,0 +1,110 @@ +// A chalk-style builder: every style read through a function's runtime +// prototype chain runs a getter that creates a new callable builder, +// links it to a shared prototype with Object.setPrototypeOf, and caches +// it on the receiver with Object.defineProperty. +const GENERATOR = Symbol("GENERATOR"); +const STYLER = Symbol("STYLER"); +const IS_EMPTY = Symbol("IS_EMPTY"); +const codes = { red: [31, 39], green: [32, 39], bold: [1, 22], underline: [4, 24] }; +let getterRuns = 0; + +const styles = Object.create(null); +for (const [name, [open, close]] of Object.entries(codes)) { + styles[name] = { + get() { + getterRuns++; + const builder = createBuilder(this, createStyler(`<${open}>`, ``, this[STYLER]), this[IS_EMPTY]); + Object.defineProperty(this, name, { value: builder }); + return builder; + }, + }; +} +styles.visible = { + get() { + const builder = createBuilder(this, this[STYLER], true); + Object.defineProperty(this, "visible", { value: builder }); + return builder; + }, +}; + +const proto = Object.defineProperties(() => {}, { + ...styles, + level: { + enumerable: true, + get() { + return this[GENERATOR].level; + }, + set(level) { + this[GENERATOR].level = level; + }, + }, +}); + +function createStyler(open, close, parent) { + if (parent === undefined) return { open, close, openAll: open, closeAll: close, parent }; + return { open, close, openAll: parent.openAll + open, closeAll: close + parent.closeAll, parent }; +} + +function createBuilder(self, styler, isEmpty) { + const builder = (...args) => applyStyle(builder, args.length === 1 ? "" + args[0] : args.join(" ")); + Object.setPrototypeOf(builder, proto); + builder[GENERATOR] = self; + builder[STYLER] = styler; + builder[IS_EMPTY] = isEmpty; + return builder; +} + +function applyStyle(self, text) { + if (self.level <= 0 || !text) return self[IS_EMPTY] ? "" : text; + let styler = self[STYLER]; + if (styler === undefined) return text; + const { openAll, closeAll } = styler; + if (text.includes(" strings.join(" "); + chalk.level = options && options.level !== undefined ? options.level : 1; + Object.setPrototypeOf(chalk, createChalk.prototype); + return chalk; +} +Object.setPrototypeOf(createChalk.prototype, Function.prototype); +Object.defineProperties(createChalk.prototype, styles); + +const chalk = createChalk(); +console.log(chalk.red("x")); +console.log(chalk.red.bold("nested")); +console.log(chalk.green("a " + chalk.red("b") + " c")); +console.log(chalk.underline.green.bold("three", "args", 3)); +console.log(JSON.stringify(chalk.red("")), chalk.visible("v"), chalk.red.visible("rv")); +console.log(chalk("plain", "call"), typeof chalk, typeof chalk.red, typeof chalk.red.bold); +console.log(chalk.red === chalk.red, chalk.red.bold === chalk.red.bold, getterRuns); +console.log(Object.getPrototypeOf(chalk) === createChalk.prototype); +console.log(Object.getPrototypeOf(chalk.red) === proto, Object.getPrototypeOf(chalk.red.bold) === proto); +console.log(Object.getPrototypeOf(createChalk.prototype) === Function.prototype); +console.log(chalk.apply(null, ["via", "apply"])); +console.log(Object.keys(chalk).join(","), Object.hasOwn(chalk, "red"), "red" in chalk); + +const red = chalk.red; +chalk.level = 0; +console.log(red("off"), red.level, chalk.level, JSON.stringify(red.visible("hidden"))); +red.level = 2; +console.log(chalk.level, chalk.green.level, red("on")); +const quiet = createChalk({ level: 0 }); +console.log(quiet.red.bold("quiet"), quiet.level, chalk.level); diff --git a/tests/corpus/js-class-constructor-returns/factory.js b/tests/corpus/js-class-constructor-returns/factory.js new file mode 100644 index 000000000..9fe0b84c4 --- /dev/null +++ b/tests/corpus/js-class-constructor-returns/factory.js @@ -0,0 +1,35 @@ +// Classes whose constructor returns a value: `new` answers that value. +const make = (options = {}) => { + const fn = (...parts) => parts.join(options.separator ?? " "); + fn.level = options.level ?? 1; + return fn; +}; + +export class Joiner { + constructor(options) { + return make(options); + } +} + +export class Record { + constructor(name, size) { + const value = { name, size, kind: "record" }; + if (size > 10) return { ...value, large: true }; + return value; + } +} + +let constructed = 0; +export class Counted { + constructor() { + constructed++; + return { id: constructed }; + } +} + +const j = new Joiner({ separator: "-", level: 3 }); +console.log(typeof j, j("a", "b", "c"), j.level); +const plain = new Joiner(); +console.log(plain("x", "y"), plain.level); +console.log(JSON.stringify(new Record("box", 4)), JSON.stringify(new Record("crate", 40))); +console.log(new Counted().id, new Counted().id, constructed); diff --git a/tests/corpus/js-class-constructor-returns/main.ts b/tests/corpus/js-class-constructor-returns/main.ts new file mode 100644 index 000000000..800016329 --- /dev/null +++ b/tests/corpus/js-class-constructor-returns/main.ts @@ -0,0 +1,11 @@ +// The same classes constructed from TypeScript: the values come from the +// constructors' returns. +import { Counted, Joiner, Record } from "./factory.js"; + +// TypeScript types `new` by the class; the values are what the constructors return. +const joiner: any = new Joiner({ separator: "+" }); +console.log(joiner("1", "2")); +const record = new Record("tube", 11); +console.log(JSON.stringify(record)); +const counted: any = new Counted(); +console.log(counted.id); diff --git a/tests/corpus/js-function-prototype-value.js b/tests/corpus/js-function-prototype-value.js new file mode 100644 index 000000000..3efe4540e --- /dev/null +++ b/tests/corpus/js-function-prototype-value.js @@ -0,0 +1,17 @@ +// Function.prototype as a value: a callable answering undefined, with an +// empty name and length 0, usable as a prototype-chain link. +const fp = Function.prototype; +console.log(typeof fp, fp === Function.prototype, JSON.stringify(fp.name), fp.length); +console.log(fp(), fp(1, 2, 3)); + +function Base() {} +Object.setPrototypeOf(Base.prototype, Function.prototype); +console.log(Object.getPrototypeOf(Base.prototype) === Function.prototype); + +const callable = (...args) => args.length; +Object.setPrototypeOf(callable, Base.prototype); +console.log(callable(1, 2), Object.getPrototypeOf(callable) === Base.prototype); +console.log(callable.apply(null, [1, 2, 3]), callable.call(null, 1)); + +const plain = Object.setPrototypeOf({ own: 1 }, Function.prototype); +console.log(typeof plain, plain.own, Object.getPrototypeOf(plain) === Function.prototype); diff --git a/tests/corpus/js-number-parse-dynamic.js b/tests/corpus/js-number-parse-dynamic.js new file mode 100644 index 000000000..e4b050046 --- /dev/null +++ b/tests/corpus/js-number-parse-dynamic.js @@ -0,0 +1,8 @@ +// Number.parseInt / Number.parseFloat over checked-dynamic values apply +// the parsers' own ToString, as supports-color does with FORCE_COLOR. +const env = JSON.parse('{"FORCE_COLOR":"2","DEPTH":" 3.5px","EMPTY":"","HEX":"ff"}'); +console.log(Number.parseInt(env.FORCE_COLOR, 10), Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3)); +console.log(Number.parseInt(env.MISSING, 10), Number.parseInt(env.EMPTY, 10), Number.parseInt(env.HEX, 16)); +console.log(Number.parseFloat(env.DEPTH), Number.parseFloat(env.MISSING)); +const values = JSON.parse("[12, true, null]"); +console.log(Number.parseInt(values[0], 10), Number.parseInt(values[1], 36), Number.parseInt(values[2], 36)); diff --git a/tests/corpus/js-process-destructure.mjs b/tests/corpus/js-process-destructure.mjs new file mode 100644 index 000000000..81660e22c --- /dev/null +++ b/tests/corpus/js-process-destructure.mjs @@ -0,0 +1,12 @@ +// Data members of the process object taken off by destructuring. +import process from "node:process"; + +const { env, argv, platform } = process; +console.log(env.SCRIPTC_TEST_ENV, "SCRIPTC_TEST_ENV" in env, "SCRIPTC_NOT_SET_ANYWHERE" in env); +console.log(Array.isArray(argv), typeof argv[0], platform === process.platform); + +function readFlags() { + const { env: environment, pid } = process; + return [typeof environment.SCRIPTC_TEST_ENV, pid === process.pid]; +} +console.log(readFlags().join(" ")); diff --git a/tests/corpus/js-reshaped-object-literal.js b/tests/corpus/js-reshaped-object-literal.js new file mode 100644 index 000000000..c184cc388 --- /dev/null +++ b/tests/corpus/js-reshaped-object-literal.js @@ -0,0 +1,42 @@ +// An object literal the program reshapes at run time (runtime-keyed +// writes, defineProperty, delete): every read sees the live object, not +// the layout TypeScript inferred for the literal (ansi-styles' +// assembleStyles shape). +const styles = { + modifier: { reset: [0, 0], bold: [1, 22] }, + color: { red: [31, 39], green: [32, 39] }, +}; + +function assemble() { + const codes = new Map(); + for (const [groupName, group] of Object.entries(styles)) { + for (const [styleName, style] of Object.entries(group)) { + styles[styleName] = { open: `<${style[0]}>`, close: `` }; + group[styleName] = styles[styleName]; + codes.set(style[0], style[1]); + } + Object.defineProperty(styles, groupName, { value: group, enumerable: false }); + } + Object.defineProperty(styles, "codes", { value: codes, enumerable: false }); + styles.color.close = ""; + styles.color.ansi = (code) => `[${code}]`; + Object.defineProperties(styles, { + double: { value: (n) => n * 2, enumerable: false }, + }); + return styles; +} + +const ansi = assemble(); +console.log(Object.keys(ansi).join(",")); +console.log(ansi.red.open, ansi.color.red.close, ansi.color.close, ansi.color.ansi(5)); +console.log(ansi.codes.get(31), ansi.codes.size, ansi.double(21)); +console.log(ansi.modifier.bold === ansi.bold, Object.keys(ansi.color).join(",")); +for (const [name, style] of Object.entries(ansi)) console.log(name, style.open, style.close); + +const table = { a: 1, b: 2, c: 3 }; +const drop = (key) => { + delete table[key]; +}; +drop("b"); +table["d" + 1] = 4; +console.log(JSON.stringify(table), Object.keys(table).length, "b" in table); diff --git a/tests/corpus/truthy-object-logical.ts b/tests/corpus/truthy-object-logical.ts new file mode 100644 index 000000000..0b84b760b --- /dev/null +++ b/tests/corpus/truthy-object-logical.ts @@ -0,0 +1,31 @@ +// `&&` and `||` whose left operand is an object, array or function value: +// every object is truthy, so `o && x` evaluates `o` and answers `x`, and +// `o || x` answers `o` without evaluating `x`. +interface Stream { + isTTY: boolean; + columns: number; +} +let reads = 0; +const stream = (): Stream => { + reads++; + return { isTTY: reads % 2 === 1, columns: 80 }; +}; +function tty(s: Stream): boolean { + return s && s.isTTY; +} +console.log(tty({ isTTY: true, columns: 1 }), tty({ isTTY: false, columns: 2 })); +const width = stream() && stream().columns; +console.log(width, reads); +const list = [3, 1, 2]; +const first = list && list.length; +console.log(first); +const fn = (n: number): number => n * 2; +const doubled = fn && fn(21); +console.log(doubled); +let evaluated = false; +const fallback = (): Stream => { + evaluated = true; + return { isTTY: false, columns: 0 }; +}; +const chosen = stream() || fallback(); +console.log(chosen.columns, evaluated, reads); diff --git a/tests/fixtures/npm/cases/chalk5/main.ts b/tests/fixtures/npm/cases/chalk5/main.ts new file mode 100644 index 000000000..6a33a1466 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/main.ts @@ -0,0 +1,64 @@ +// chalk 5 (the real package, pinned in node_modules): the callable +// builder whose styles are prototype getters on a function chain, every +// color model, nested styles, chalk.level and new Chalk({ level }) at all +// four levels. chalk.test.ts runs the same program under FORCE_COLOR and +// the --color flags. +import chalk, { Chalk, chalkStderr, supportsColor, modifierNames, foregroundColorNames, backgroundColorNames, colorNames } from "chalk"; + +const show = (label: string, value: string): void => { + console.log(label + " " + JSON.stringify(value)); +}; + +console.log("default level " + String(chalk.level) + " stderr " + String(chalkStderr.level)); +console.log("supportsColor " + JSON.stringify(supportsColor)); +console.log(modifierNames.join(",")); +console.log(foregroundColorNames.length + " " + backgroundColorNames.length + " " + colorNames.length); + +show("red", chalk.red("red")); +show("red.bold", chalk.red.bold("bold red")); +show("nested", chalk.blue("a " + chalk.red("b") + " c")); +show("multi-arg", chalk.green("one", "two", 3)); +show("number", chalk.yellow(42 as unknown as string)); +show("empty", chalk.red("")); +show("newline", chalk.magenta.underline("line1\nline2\r\nline3")); +show("bg", chalk.bgCyan.black("bg")); +show("bright", chalk.redBright.bgBlueBright("bright")); +show("modifiers", chalk.italic.inverse.strikethrough.overline("mods")); +show("hidden-visible", chalk.hidden("h") + "|" + chalk.visible("v")); +show("rgb", chalk.rgb(10, 20, 30)("rgb")); +show("hex", chalk.hex("#ff8800").bold("hex")); +show("hex-short", chalk.bgHex("#0f0")("bg hex")); +show("ansi256", chalk.ansi256(201)("ansi256")); +show("bgAnsi256", chalk.bgAnsi256(17).white("bgAnsi256")); +show("callable", chalk("plain", "args")); +show("gray-grey", chalk.gray("x") + chalk.grey("y")); + +for (const level of [0, 1, 2, 3] as const) { + const c = new Chalk({ level }); + show(`L${level} red.bold`, c.red.bold("x")); + show(`L${level} hex`, c.hex("#123456")("x")); + show(`L${level} rgb`, c.rgb(255, 255, 255).bgRgb(0, 0, 0)("x")); + show(`L${level} ansi256`, c.ansi256(100).bgAnsi256(200)("x")); + show(`L${level} visible`, c.visible.red("v")); + show(`L${level} nested`, c.green("g" + c.yellow("y") + "g")); +} + +const mutable = new Chalk({ level: 3 }); +const red = mutable.red; +show("before", red("r")); +mutable.level = 0; +show("after level 0", red("r") + "|" + mutable.blue("b")); +console.log("level via builder " + String(red.level)); +red.level = 2; +console.log("shared level " + String(mutable.level)); +show("restored", mutable.cyan("c")); + +try { + new Chalk({ level: 5 as 0 }); +} catch (error) { + console.log("error " + (error as Error).message); +} + +chalk.level = 1; +show("global after set", chalk.red.bold("x")); +console.log("global level " + String(chalk.level)); diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/license b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/license new file mode 100644 index 000000000..fa7ceba3e --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/package.json b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/package.json new file mode 100644 index 000000000..c9e0dc52b --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/package.json @@ -0,0 +1,83 @@ +{ + "name": "chalk", + "version": "5.6.2", + "description": "Terminal string styling done right", + "license": "MIT", + "repository": "chalk/chalk", + "funding": "https://github.com/chalk/chalk?sponsor=1", + "type": "module", + "main": "./source/index.js", + "exports": "./source/index.js", + "imports": { + "#ansi-styles": "./source/vendor/ansi-styles/index.js", + "#supports-color": { + "node": "./source/vendor/supports-color/index.js", + "default": "./source/vendor/supports-color/browser.js" + } + }, + "types": "./source/index.d.ts", + "sideEffects": false, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "scripts": { + "test": "xo && c8 ava && tsd", + "bench": "matcha benchmark.js" + }, + "files": [ + "source", + "!source/index.test-d.ts" + ], + "keywords": [ + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "ansi", + "style", + "styles", + "tty", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "devDependencies": { + "@types/node": "^16.11.10", + "ava": "^3.15.0", + "c8": "^7.10.0", + "color-convert": "^2.0.1", + "execa": "^6.0.0", + "log-update": "^5.0.0", + "matcha": "^0.7.0", + "tsd": "^0.19.0", + "xo": "^0.57.0", + "yoctodelay": "^2.0.0" + }, + "xo": { + "rules": { + "unicorn/prefer-string-slice": "off", + "@typescript-eslint/consistent-type-imports": "off", + "@typescript-eslint/consistent-type-exports": "off", + "@typescript-eslint/consistent-type-definitions": "off", + "unicorn/expiring-todo-comments": "off" + } + }, + "c8": { + "reporter": [ + "text", + "lcov" + ], + "exclude": [ + "source/vendor" + ] + } +} diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.d.ts b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.d.ts new file mode 100644 index 000000000..8295d9252 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.d.ts @@ -0,0 +1,325 @@ +// TODO: Make it this when TS suports that. +// import {ModifierName, ForegroundColor, BackgroundColor, ColorName} from '#ansi-styles'; +// import {ColorInfo, ColorSupportLevel} from '#supports-color'; +import { + ModifierName, + ForegroundColorName, + BackgroundColorName, + ColorName, +} from './vendor/ansi-styles/index.js'; +import {ColorInfo, ColorSupportLevel} from './vendor/supports-color/index.js'; + +export interface Options { + /** + Specify the color support for Chalk. + + By default, color support is automatically detected based on the environment. + + Levels: + - `0` - All colors disabled. + - `1` - Basic 16 colors support. + - `2` - ANSI 256 colors support. + - `3` - Truecolor 16 million colors support. + */ + readonly level?: ColorSupportLevel; +} + +/** +Return a new Chalk instance. +*/ +export const Chalk: new (options?: Options) => ChalkInstance; // eslint-disable-line @typescript-eslint/naming-convention + +export interface ChalkInstance { + (...text: unknown[]): string; + + /** + The color support for Chalk. + + By default, color support is automatically detected based on the environment. + + Levels: + - `0` - All colors disabled. + - `1` - Basic 16 colors support. + - `2` - ANSI 256 colors support. + - `3` - Truecolor 16 million colors support. + */ + level: ColorSupportLevel; + + /** + Use RGB values to set text color. + + @example + ``` + import chalk from 'chalk'; + + chalk.rgb(222, 173, 237); + ``` + */ + rgb: (red: number, green: number, blue: number) => this; + + /** + Use HEX value to set text color. + + @param color - Hexadecimal value representing the desired color. + + @example + ``` + import chalk from 'chalk'; + + chalk.hex('#DEADED'); + ``` + */ + hex: (color: string) => this; + + /** + Use an [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color. + + @example + ``` + import chalk from 'chalk'; + + chalk.ansi256(201); + ``` + */ + ansi256: (index: number) => this; + + /** + Use RGB values to set background color. + + @example + ``` + import chalk from 'chalk'; + + chalk.bgRgb(222, 173, 237); + ``` + */ + bgRgb: (red: number, green: number, blue: number) => this; + + /** + Use HEX value to set background color. + + @param color - Hexadecimal value representing the desired color. + + @example + ``` + import chalk from 'chalk'; + + chalk.bgHex('#DEADED'); + ``` + */ + bgHex: (color: string) => this; + + /** + Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set background color. + + @example + ``` + import chalk from 'chalk'; + + chalk.bgAnsi256(201); + ``` + */ + bgAnsi256: (index: number) => this; + + /** + Modifier: Reset the current style. + */ + readonly reset: this; + + /** + Modifier: Make the text bold. + */ + readonly bold: this; + + /** + Modifier: Make the text have lower opacity. + */ + readonly dim: this; + + /** + Modifier: Make the text italic. *(Not widely supported)* + */ + readonly italic: this; + + /** + Modifier: Put a horizontal line below the text. *(Not widely supported)* + */ + readonly underline: this; + + /** + Modifier: Put a horizontal line above the text. *(Not widely supported)* + */ + readonly overline: this; + + /** + Modifier: Invert background and foreground colors. + */ + readonly inverse: this; + + /** + Modifier: Print the text but make it invisible. + */ + readonly hidden: this; + + /** + Modifier: Puts a horizontal line through the center of the text. *(Not widely supported)* + */ + readonly strikethrough: this; + + /** + Modifier: Print the text only when Chalk has a color level above zero. + + Can be useful for things that are purely cosmetic. + */ + readonly visible: this; + + readonly black: this; + readonly red: this; + readonly green: this; + readonly yellow: this; + readonly blue: this; + readonly magenta: this; + readonly cyan: this; + readonly white: this; + + /* + Alias for `blackBright`. + */ + readonly gray: this; + + /* + Alias for `blackBright`. + */ + readonly grey: this; + + readonly blackBright: this; + readonly redBright: this; + readonly greenBright: this; + readonly yellowBright: this; + readonly blueBright: this; + readonly magentaBright: this; + readonly cyanBright: this; + readonly whiteBright: this; + + readonly bgBlack: this; + readonly bgRed: this; + readonly bgGreen: this; + readonly bgYellow: this; + readonly bgBlue: this; + readonly bgMagenta: this; + readonly bgCyan: this; + readonly bgWhite: this; + + /* + Alias for `bgBlackBright`. + */ + readonly bgGray: this; + + /* + Alias for `bgBlackBright`. + */ + readonly bgGrey: this; + + readonly bgBlackBright: this; + readonly bgRedBright: this; + readonly bgGreenBright: this; + readonly bgYellowBright: this; + readonly bgBlueBright: this; + readonly bgMagentaBright: this; + readonly bgCyanBright: this; + readonly bgWhiteBright: this; +} + +/** +Main Chalk object that allows to chain styles together. + +Call the last one as a method with a string argument. + +Order doesn't matter, and later styles take precedent in case of a conflict. + +This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`. +*/ +declare const chalk: ChalkInstance; + +export const supportsColor: ColorInfo; + +export const chalkStderr: typeof chalk; +export const supportsColorStderr: typeof supportsColor; + +export { + ModifierName, ForegroundColorName, BackgroundColorName, ColorName, + modifierNames, foregroundColorNames, backgroundColorNames, colorNames, +// } from '#ansi-styles'; +} from './vendor/ansi-styles/index.js'; + +export { + ColorInfo, + ColorSupport, + ColorSupportLevel, +// } from '#supports-color'; +} from './vendor/supports-color/index.js'; + +// TODO: Remove these aliases in the next major version +/** +@deprecated Use `ModifierName` instead. + +Basic modifier names. +*/ +export type Modifiers = ModifierName; + +/** +@deprecated Use `ForegroundColorName` instead. + +Basic foreground color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type ForegroundColor = ForegroundColorName; + +/** +@deprecated Use `BackgroundColorName` instead. + +Basic background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type BackgroundColor = BackgroundColorName; + +/** +@deprecated Use `ColorName` instead. + +Basic color names. The combination of foreground and background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type Color = ColorName; + +/** +@deprecated Use `modifierNames` instead. + +Basic modifier names. +*/ +export const modifiers: readonly Modifiers[]; + +/** +@deprecated Use `foregroundColorNames` instead. + +Basic foreground color names. +*/ +export const foregroundColors: readonly ForegroundColor[]; + +/** +@deprecated Use `backgroundColorNames` instead. + +Basic background color names. +*/ +export const backgroundColors: readonly BackgroundColor[]; + +/** +@deprecated Use `colorNames` instead. + +Basic color names. The combination of foreground and background color names. +*/ +export const colors: readonly Color[]; + +export default chalk; diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.js b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.js new file mode 100644 index 000000000..8bc993da5 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/index.js @@ -0,0 +1,225 @@ +import ansiStyles from '#ansi-styles'; +import supportsColor from '#supports-color'; +import { // eslint-disable-line import/order + stringReplaceAll, + stringEncaseCRLFWithFirstIndex, +} from './utilities.js'; + +const {stdout: stdoutColor, stderr: stderrColor} = supportsColor; + +const GENERATOR = Symbol('GENERATOR'); +const STYLER = Symbol('STYLER'); +const IS_EMPTY = Symbol('IS_EMPTY'); + +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = [ + 'ansi', + 'ansi', + 'ansi256', + 'ansi16m', +]; + +const styles = Object.create(null); + +const applyOptions = (object, options = {}) => { + if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) { + throw new Error('The `level` option should be an integer from 0 to 3'); + } + + // Detect level if not set manually + const colorLevel = stdoutColor ? stdoutColor.level : 0; + object.level = options.level === undefined ? colorLevel : options.level; +}; + +export class Chalk { + constructor(options) { + // eslint-disable-next-line no-constructor-return + return chalkFactory(options); + } +} + +const chalkFactory = options => { + const chalk = (...strings) => strings.join(' '); + applyOptions(chalk, options); + + Object.setPrototypeOf(chalk, createChalk.prototype); + + return chalk; +}; + +function createChalk(options) { + return chalkFactory(options); +} + +Object.setPrototypeOf(createChalk.prototype, Function.prototype); + +for (const [styleName, style] of Object.entries(ansiStyles)) { + styles[styleName] = { + get() { + const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]); + Object.defineProperty(this, styleName, {value: builder}); + return builder; + }, + }; +} + +styles.visible = { + get() { + const builder = createBuilder(this, this[STYLER], true); + Object.defineProperty(this, 'visible', {value: builder}); + return builder; + }, +}; + +const getModelAnsi = (model, level, type, ...arguments_) => { + if (model === 'rgb') { + if (level === 'ansi16m') { + return ansiStyles[type].ansi16m(...arguments_); + } + + if (level === 'ansi256') { + return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_)); + } + + return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_)); + } + + if (model === 'hex') { + return getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_)); + } + + return ansiStyles[type][model](...arguments_); +}; + +const usedModels = ['rgb', 'hex', 'ansi256']; + +for (const model of usedModels) { + styles[model] = { + get() { + const {level} = this; + return function (...arguments_) { + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); + }; + }, + }; + + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const {level} = this; + return function (...arguments_) { + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); + }; + }, + }; +} + +const proto = Object.defineProperties(() => {}, { + ...styles, + level: { + enumerable: true, + get() { + return this[GENERATOR].level; + }, + set(level) { + this[GENERATOR].level = level; + }, + }, +}); + +const createStyler = (open, close, parent) => { + let openAll; + let closeAll; + if (parent === undefined) { + openAll = open; + closeAll = close; + } else { + openAll = parent.openAll + open; + closeAll = close + parent.closeAll; + } + + return { + open, + close, + openAll, + closeAll, + parent, + }; +}; + +const createBuilder = (self, _styler, _isEmpty) => { + // Single argument is hot path, implicit coercion is faster than anything + // eslint-disable-next-line no-implicit-coercion + const builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); + + // We alter the prototype because we must return a function, but there is + // no way to create a function with a different prototype + Object.setPrototypeOf(builder, proto); + + builder[GENERATOR] = self; + builder[STYLER] = _styler; + builder[IS_EMPTY] = _isEmpty; + + return builder; +}; + +const applyStyle = (self, string) => { + if (self.level <= 0 || !string) { + return self[IS_EMPTY] ? '' : string; + } + + let styler = self[STYLER]; + + if (styler === undefined) { + return string; + } + + const {openAll, closeAll} = styler; + if (string.includes('\u001B')) { + while (styler !== undefined) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + string = stringReplaceAll(string, styler.close, styler.open); + + styler = styler.parent; + } + } + + // We can move both next actions out of loop, because remaining actions in loop won't have + // any/visible effect on parts we add here. Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 + const lfIndex = string.indexOf('\n'); + if (lfIndex !== -1) { + string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); + } + + return openAll + string + closeAll; +}; + +Object.defineProperties(createChalk.prototype, styles); + +const chalk = createChalk(); +export const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0}); + +export { + modifierNames, + foregroundColorNames, + backgroundColorNames, + colorNames, + + // TODO: Remove these aliases in the next major version + modifierNames as modifiers, + foregroundColorNames as foregroundColors, + backgroundColorNames as backgroundColors, + colorNames as colors, +} from './vendor/ansi-styles/index.js'; + +export { + stdoutColor as supportsColor, + stderrColor as supportsColorStderr, +}; + +export default chalk; diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/utilities.js b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/utilities.js new file mode 100644 index 000000000..4366dee0d --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/utilities.js @@ -0,0 +1,33 @@ +// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`. +export function stringReplaceAll(string, substring, replacer) { + let index = string.indexOf(substring); + if (index === -1) { + return string; + } + + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ''; + do { + returnValue += string.slice(endIndex, index) + substring + replacer; + endIndex = index + substringLength; + index = string.indexOf(substring, endIndex); + } while (index !== -1); + + returnValue += string.slice(endIndex); + return returnValue; +} + +export function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) { + let endIndex = 0; + let returnValue = ''; + do { + const gotCR = string[index - 1] === '\r'; + returnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\r\n' : '\n') + postfix; + endIndex = index + 1; + index = string.indexOf('\n', endIndex); + } while (index !== -1); + + returnValue += string.slice(endIndex); + return returnValue; +} diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.d.ts b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.d.ts new file mode 100644 index 000000000..58f133abe --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.d.ts @@ -0,0 +1,236 @@ +export interface CSPair { // eslint-disable-line @typescript-eslint/naming-convention + /** + The ANSI terminal control sequence for starting this style. + */ + readonly open: string; + + /** + The ANSI terminal control sequence for ending this style. + */ + readonly close: string; +} + +export interface ColorBase { + /** + The ANSI terminal control sequence for ending this color. + */ + readonly close: string; + + ansi(code: number): string; + + ansi256(code: number): string; + + ansi16m(red: number, green: number, blue: number): string; +} + +export interface Modifier { + /** + Resets the current color chain. + */ + readonly reset: CSPair; + + /** + Make text bold. + */ + readonly bold: CSPair; + + /** + Emitting only a small amount of light. + */ + readonly dim: CSPair; + + /** + Make text italic. (Not widely supported) + */ + readonly italic: CSPair; + + /** + Make text underline. (Not widely supported) + */ + readonly underline: CSPair; + + /** + Make text overline. + + Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash. + */ + readonly overline: CSPair; + + /** + Inverse background and foreground colors. + */ + readonly inverse: CSPair; + + /** + Prints the text, but makes it invisible. + */ + readonly hidden: CSPair; + + /** + Puts a horizontal line through the center of the text. (Not widely supported) + */ + readonly strikethrough: CSPair; +} + +export interface ForegroundColor { + readonly black: CSPair; + readonly red: CSPair; + readonly green: CSPair; + readonly yellow: CSPair; + readonly blue: CSPair; + readonly cyan: CSPair; + readonly magenta: CSPair; + readonly white: CSPair; + + /** + Alias for `blackBright`. + */ + readonly gray: CSPair; + + /** + Alias for `blackBright`. + */ + readonly grey: CSPair; + + readonly blackBright: CSPair; + readonly redBright: CSPair; + readonly greenBright: CSPair; + readonly yellowBright: CSPair; + readonly blueBright: CSPair; + readonly cyanBright: CSPair; + readonly magentaBright: CSPair; + readonly whiteBright: CSPair; +} + +export interface BackgroundColor { + readonly bgBlack: CSPair; + readonly bgRed: CSPair; + readonly bgGreen: CSPair; + readonly bgYellow: CSPair; + readonly bgBlue: CSPair; + readonly bgCyan: CSPair; + readonly bgMagenta: CSPair; + readonly bgWhite: CSPair; + + /** + Alias for `bgBlackBright`. + */ + readonly bgGray: CSPair; + + /** + Alias for `bgBlackBright`. + */ + readonly bgGrey: CSPair; + + readonly bgBlackBright: CSPair; + readonly bgRedBright: CSPair; + readonly bgGreenBright: CSPair; + readonly bgYellowBright: CSPair; + readonly bgBlueBright: CSPair; + readonly bgCyanBright: CSPair; + readonly bgMagentaBright: CSPair; + readonly bgWhiteBright: CSPair; +} + +export interface ConvertColor { + /** + Convert from the RGB color space to the ANSI 256 color space. + + @param red - (`0...255`) + @param green - (`0...255`) + @param blue - (`0...255`) + */ + rgbToAnsi256(red: number, green: number, blue: number): number; + + /** + Convert from the RGB HEX color space to the RGB color space. + + @param hex - A hexadecimal string containing RGB data. + */ + hexToRgb(hex: string): [red: number, green: number, blue: number]; + + /** + Convert from the RGB HEX color space to the ANSI 256 color space. + + @param hex - A hexadecimal string containing RGB data. + */ + hexToAnsi256(hex: string): number; + + /** + Convert from the ANSI 256 color space to the ANSI 16 color space. + + @param code - A number representing the ANSI 256 color. + */ + ansi256ToAnsi(code: number): number; + + /** + Convert from the RGB color space to the ANSI 16 color space. + + @param red - (`0...255`) + @param green - (`0...255`) + @param blue - (`0...255`) + */ + rgbToAnsi(red: number, green: number, blue: number): number; + + /** + Convert from the RGB HEX color space to the ANSI 16 color space. + + @param hex - A hexadecimal string containing RGB data. + */ + hexToAnsi(hex: string): number; +} + +/** +Basic modifier names. +*/ +export type ModifierName = keyof Modifier; + +/** +Basic foreground color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type ForegroundColorName = keyof ForegroundColor; + +/** +Basic background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type BackgroundColorName = keyof BackgroundColor; + +/** +Basic color names. The combination of foreground and background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type ColorName = ForegroundColorName | BackgroundColorName; + +/** +Basic modifier names. +*/ +export const modifierNames: readonly ModifierName[]; + +/** +Basic foreground color names. +*/ +export const foregroundColorNames: readonly ForegroundColorName[]; + +/** +Basic background color names. +*/ +export const backgroundColorNames: readonly BackgroundColorName[]; + +/* +Basic color names. The combination of foreground and background color names. +*/ +export const colorNames: readonly ColorName[]; + +declare const ansiStyles: { + readonly modifier: Modifier; + readonly color: ColorBase & ForegroundColor; + readonly bgColor: ColorBase & BackgroundColor; + readonly codes: ReadonlyMap; +} & ForegroundColor & BackgroundColor & Modifier & ConvertColor; + +export default ansiStyles; diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.js b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.js new file mode 100644 index 000000000..eaa7bed6c --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/ansi-styles/index.js @@ -0,0 +1,223 @@ +const ANSI_BACKGROUND_OFFSET = 10; + +const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`; + +const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`; + +const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`; + +const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + overline: [53, 55], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29], + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + + // Bright color + blackBright: [90, 39], + gray: [90, 39], // Alias of `blackBright` + grey: [90, 39], // Alias of `blackBright` + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39], + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], + + // Bright color + bgBlackBright: [100, 49], + bgGray: [100, 49], // Alias of `bgBlackBright` + bgGrey: [100, 49], // Alias of `bgBlackBright` + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49], + }, +}; + +export const modifierNames = Object.keys(styles.modifier); +export const foregroundColorNames = Object.keys(styles.color); +export const backgroundColorNames = Object.keys(styles.bgColor); +export const colorNames = [...foregroundColorNames, ...backgroundColorNames]; + +function assembleStyles() { + const codes = new Map(); + + for (const [groupName, group] of Object.entries(styles)) { + for (const [styleName, style] of Object.entries(group)) { + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m`, + }; + + group[styleName] = styles[styleName]; + + codes.set(style[0], style[1]); + } + + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false, + }); + } + + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false, + }); + + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; + + styles.color.ansi = wrapAnsi16(); + styles.color.ansi256 = wrapAnsi256(); + styles.color.ansi16m = wrapAnsi16m(); + styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET); + styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET); + styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET); + + // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js + Object.defineProperties(styles, { + rgbToAnsi256: { + value(red, green, blue) { + // We use the extended greyscale palette here, with the exception of + // black and white. normal palette only has 4 greyscale shades. + if (red === green && green === blue) { + if (red < 8) { + return 16; + } + + if (red > 248) { + return 231; + } + + return Math.round(((red - 8) / 247) * 24) + 232; + } + + return 16 + + (36 * Math.round(red / 255 * 5)) + + (6 * Math.round(green / 255 * 5)) + + Math.round(blue / 255 * 5); + }, + enumerable: false, + }, + hexToRgb: { + value(hex) { + const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16)); + if (!matches) { + return [0, 0, 0]; + } + + let [colorString] = matches; + + if (colorString.length === 3) { + colorString = [...colorString].map(character => character + character).join(''); + } + + const integer = Number.parseInt(colorString, 16); + + return [ + /* eslint-disable no-bitwise */ + (integer >> 16) & 0xFF, + (integer >> 8) & 0xFF, + integer & 0xFF, + /* eslint-enable no-bitwise */ + ]; + }, + enumerable: false, + }, + hexToAnsi256: { + value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)), + enumerable: false, + }, + ansi256ToAnsi: { + value(code) { + if (code < 8) { + return 30 + code; + } + + if (code < 16) { + return 90 + (code - 8); + } + + let red; + let green; + let blue; + + if (code >= 232) { + red = (((code - 232) * 10) + 8) / 255; + green = red; + blue = red; + } else { + code -= 16; + + const remainder = code % 36; + + red = Math.floor(code / 36) / 5; + green = Math.floor(remainder / 6) / 5; + blue = (remainder % 6) / 5; + } + + const value = Math.max(red, green, blue) * 2; + + if (value === 0) { + return 30; + } + + // eslint-disable-next-line no-bitwise + let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red)); + + if (value === 2) { + result += 60; + } + + return result; + }, + enumerable: false, + }, + rgbToAnsi: { + value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)), + enumerable: false, + }, + hexToAnsi: { + value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), + enumerable: false, + }, + }); + + return styles; +} + +const ansiStyles = assembleStyles(); + +export default ansiStyles; diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.d.ts b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.d.ts new file mode 100644 index 000000000..0e8a9ccb8 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.d.ts @@ -0,0 +1 @@ +export {default} from './index.js'; diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.js b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.js new file mode 100644 index 000000000..fbb6ce0fc --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/browser.js @@ -0,0 +1,34 @@ +/* eslint-env browser */ + +const level = (() => { + if (!('navigator' in globalThis)) { + return 0; + } + + if (globalThis.navigator.userAgentData) { + const brand = navigator.userAgentData.brands.find(({brand}) => brand === 'Chromium'); + if (brand && brand.version > 93) { + return 3; + } + } + + if (/\b(Chrome|Chromium)\//.test(globalThis.navigator.userAgent)) { + return 1; + } + + return 0; +})(); + +const colorSupport = level !== 0 && { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, +}; + +const supportsColor = { + stdout: colorSupport, + stderr: colorSupport, +}; + +export default supportsColor; diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.d.ts b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.d.ts new file mode 100644 index 000000000..db44a7851 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.d.ts @@ -0,0 +1,55 @@ +import type {WriteStream} from 'node:tty'; + +export type Options = { + /** + Whether `process.argv` should be sniffed for `--color` and `--no-color` flags. + + @default true + */ + readonly sniffFlags?: boolean; +}; + +/** +Levels: +- `0` - All colors disabled. +- `1` - Basic 16 colors support. +- `2` - ANSI 256 colors support. +- `3` - Truecolor 16 million colors support. +*/ +export type ColorSupportLevel = 0 | 1 | 2 | 3; + +/** +Detect whether the terminal supports color. +*/ +export type ColorSupport = { + /** + The color level. + */ + level: ColorSupportLevel; + + /** + Whether basic 16 colors are supported. + */ + hasBasic: boolean; + + /** + Whether ANSI 256 colors are supported. + */ + has256: boolean; + + /** + Whether Truecolor 16 million colors are supported. + */ + has16m: boolean; +}; + +export type ColorInfo = ColorSupport | false; + +export function createSupportsColor(stream?: WriteStream, options?: Options): ColorInfo; + +declare const supportsColor: { + stdout: ColorInfo; + stderr: ColorInfo; +}; + +export default supportsColor; diff --git a/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.js b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.js new file mode 100644 index 000000000..265d7f858 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/node_modules/chalk/source/vendor/supports-color/index.js @@ -0,0 +1,190 @@ +import process from 'node:process'; +import os from 'node:os'; +import tty from 'node:tty'; + +// From: https://github.com/sindresorhus/has-flag/blob/main/index.js +/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) { +function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) { + const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf('--'); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); +} + +const {env} = process; + +let flagForceColor; +if ( + hasFlag('no-color') + || hasFlag('no-colors') + || hasFlag('color=false') + || hasFlag('color=never') +) { + flagForceColor = 0; +} else if ( + hasFlag('color') + || hasFlag('colors') + || hasFlag('color=true') + || hasFlag('color=always') +) { + flagForceColor = 1; +} + +function envForceColor() { + if ('FORCE_COLOR' in env) { + if (env.FORCE_COLOR === 'true') { + return 1; + } + + if (env.FORCE_COLOR === 'false') { + return 0; + } + + return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); + } +} + +function translateLevel(level) { + if (level === 0) { + return false; + } + + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, + }; +} + +function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) { + const noFlagForceColor = envForceColor(); + if (noFlagForceColor !== undefined) { + flagForceColor = noFlagForceColor; + } + + const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; + + if (forceColor === 0) { + return 0; + } + + if (sniffFlags) { + if (hasFlag('color=16m') + || hasFlag('color=full') + || hasFlag('color=truecolor')) { + return 3; + } + + if (hasFlag('color=256')) { + return 2; + } + } + + // Check for Azure DevOps pipelines. + // Has to be above the `!streamIsTTY` check. + if ('TF_BUILD' in env && 'AGENT_NAME' in env) { + return 1; + } + + if (haveStream && !streamIsTTY && forceColor === undefined) { + return 0; + } + + const min = forceColor || 0; + + if (env.TERM === 'dumb') { + return min; + } + + if (process.platform === 'win32') { + // Windows 10 build 10586 is the first Windows release that supports 256 colors. + // Windows 10 build 14931 is the first release that supports 16m/TrueColor. + const osRelease = os.release().split('.'); + if ( + Number(osRelease[0]) >= 10 + && Number(osRelease[2]) >= 10_586 + ) { + return Number(osRelease[2]) >= 14_931 ? 3 : 2; + } + + return 1; + } + + if ('CI' in env) { + if (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key in env)) { + return 3; + } + + if (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + return 1; + } + + return min; + } + + if ('TEAMCITY_VERSION' in env) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + } + + if (env.COLORTERM === 'truecolor') { + return 3; + } + + if (env.TERM === 'xterm-kitty') { + return 3; + } + + if (env.TERM === 'xterm-ghostty') { + return 3; + } + + if (env.TERM === 'wezterm') { + return 3; + } + + if ('TERM_PROGRAM' in env) { + const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + + switch (env.TERM_PROGRAM) { + case 'iTerm.app': { + return version >= 3 ? 3 : 2; + } + + case 'Apple_Terminal': { + return 2; + } + // No default + } + } + + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } + + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } + + if ('COLORTERM' in env) { + return 1; + } + + return min; +} + +export function createSupportsColor(stream, options = {}) { + const level = _supportsColor(stream, { + streamIsTTY: stream && stream.isTTY, + ...options, + }); + + return translateLevel(level); +} + +const supportsColor = { + stdout: createSupportsColor({isTTY: tty.isatty(1)}), + stderr: createSupportsColor({isTTY: tty.isatty(2)}), +}; + +export default supportsColor; diff --git a/tests/fixtures/npm/cases/chalk5/package.json b/tests/fixtures/npm/cases/chalk5/package.json new file mode 100644 index 000000000..3804daa8d --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5/package.json @@ -0,0 +1 @@ +{ "name": "chalk5-case", "private": true, "type": "module" } diff --git a/tests/harness/chalk.test.ts b/tests/harness/chalk.test.ts new file mode 100644 index 000000000..4d99bf3ee --- /dev/null +++ b/tests/harness/chalk.test.ts @@ -0,0 +1,97 @@ +/* chalk 5 compiled from its published JavaScript (tests/fixtures/npm/cases/ + * chalk5): the program runs under Node and as a native binary with each + * color-detection input supports-color reads — FORCE_COLOR values and the + * --color/--no-color flags — and stdout, stderr and the exit status must + * match byte for byte. npm.test.ts runs the same case once in the + * harness's own environment. */ +import { execFile } from "node:child_process"; +import { mkdirSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { promisify } from "node:util"; +import { beforeAll, describe, expect, test } from "vitest"; +import { compile } from "@scriptc/compiler"; + +const execFileAsync = promisify(execFile); +const repoRoot = join(import.meta.dirname, "../.."); +const entry = join(repoRoot, "tests/fixtures/npm/cases/chalk5/main.ts"); +const outDir = join(repoRoot, "node_modules/.cache/scriptc-tests/chalk5"); +const sanitize = process.env["SCRIPTC_SAN"] === "1"; + +interface RunResult { + stdout: string; + stderr: string; + exitCode: number; +} + +async function run(cmd: string, args: string[], env: NodeJS.ProcessEnv): Promise { + try { + const pending = execFileAsync(cmd, args, { cwd: dirname(entry), env, encoding: "utf8" }); + pending.child.stdin?.end(); + const { stdout, stderr } = await pending; + return { stdout, stderr, exitCode: 0 }; + } catch (err) { + const e = err as { code?: unknown; stdout?: string; stderr?: string }; + if (typeof e.stdout !== "string" || typeof e.stderr !== "string") throw err; + return { + stdout: e.stdout, + stderr: e.stderr, + exitCode: typeof e.code === "number" ? e.code : -1, + }; + } +} + +/** The harness environment without the color inputs, plus `force`. */ +function colorEnv(force: string | undefined): NodeJS.ProcessEnv { + const env = { ...process.env }; + delete env["FORCE_COLOR"]; + delete env["NO_COLOR"]; + delete env["NODE_DISABLE_COLORS"]; + if (force !== undefined) env["FORCE_COLOR"] = force; + return env; +} + +const cases: { name: string; force: string | undefined; argv: string[] }[] = [ + { name: "FORCE_COLOR unset", force: undefined, argv: [] }, + ...["0", "1", "2", "3", "true", "false", ""].map((force) => ({ + name: `FORCE_COLOR=${JSON.stringify(force)}`, + force, + argv: [], + })), + ...[ + ["--no-color"], + ["--color"], + ["--color=256"], + ["--color=16m"], + ["--color", "--", "--no-color"], + ].map((argv) => ({ name: argv.join(" "), force: undefined, argv })), + { name: "FORCE_COLOR=3 --no-color", force: "3", argv: ["--no-color"] }, +]; + +let binary = ""; + +beforeAll(async () => { + mkdirSync(outDir, { recursive: true }); + const result = await compile(entry, { outPath: join(outDir, "program"), outDir, sanitize }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + binary = result.binaryPath; +}, 300_000); + +describe("chalk 5 color detection matches Node", () => { + for (const c of cases) { + test( + c.name, + async () => { + const env = colorEnv(c.force); + const [node, native] = await Promise.all([ + run(process.execPath, [entry, ...c.argv], env), + run(binary, c.argv, env), + ]); + expect(native.stdout).toBe(node.stdout); + expect(native.stderr).toBe(node.stderr); + expect(native.exitCode).toBe(node.exitCode); + }, + 60_000, + ); + } +}); From d3dba4c07f56b0b719ca37d811d23418708379cf Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 10:59:27 -0500 Subject: [PATCH 100/117] Run module-level before and after hooks node:test changes, matching Node 24.22: - before and after hooks outside any suite run, with the root's context, whose name is "". They did not run before. - A module-level before hook runs at its before() call, as Node runs the hooks of its already-started root at once: its synchronous part runs before the code after the call, and the first top-level test waits for an async hook's promise. Every module-level before hook runs, and an async hook's rejection is not reported as an unhandled rejection. - Module-level after hooks run after the last top-level test or suite. - A throwing root before hook fails each top-level test with the first failure; the test's body and beforeEach hooks do not run, and its afterEach hooks do. Each top-level suite fails with the error, and the tests and suites in it are cancelled before they start: they report without a duration and fail with "test did not finish before its parent and was cancelled", listed in the failing section in completion order. - A throwing root after hook reports the entry file as a failed result, after the top-level results, and lists it in the failing section at the hook's location. It is not counted, and the exit code is unchanged. - Hooks record the "file:line:col" of their call for that location. The root-hooks, root-before-throws and root-after-throws fixtures compare the reporter output, the order of the hooks against the module code, and the exit codes with Node, plain and with SCRIPTC_SAN=1. --- .../limitations/builtin-apis/test-runner.mdx | 1 + .../src/frontend/lowering/lower-test.ts | 2 +- .../compiler/src/ir/builtin-signatures.ts | 3 +- packages/runtime/src/scr_test.c | 147 +++++++++++++++++- packages/runtime/src/scr_test.h | 6 +- .../node-test/cases/root-after-throws.ts | 10 ++ .../node-test/cases/root-before-throws.ts | 30 ++++ tests/fixtures/node-test/cases/root-hooks.ts | 44 ++++++ 8 files changed, 233 insertions(+), 10 deletions(-) create mode 100644 tests/fixtures/node-test/cases/root-after-throws.ts create mode 100644 tests/fixtures/node-test/cases/root-before-throws.ts create mode 100644 tests/fixtures/node-test/cases/root-hooks.ts diff --git a/docs/content/limitations/builtin-apis/test-runner.mdx b/docs/content/limitations/builtin-apis/test-runner.mdx index e1baac963..6583a2873 100644 --- a/docs/content/limitations/builtin-apis/test-runner.mdx +++ b/docs/content/limitations/builtin-apis/test-runner.mdx @@ -2,3 +2,4 @@ - **Snapshots:** `t.assert.snapshot` and `t.assert.fileSnapshot` compile, with Node's default serializer, `JSON.stringify(value, null, 2)`, or an `options.serializers` array literal. A compiled test reads the snapshot file Node writes beside the entry file, `.snapshot`, at the entry file's path when the program was compiled. Running the binary with Node's flag `--test-update-snapshots` as its first argument writes the snapshot files instead; as in Node, the flag is kept out of `process.argv` and appears in `process.execArgv`. Snapshot files are read in the form Node writes them, `` exports[`key`] = `value`; `` statements. The `snapshot.setDefaultSnapshotSerializers` and `snapshot.setResolveSnapshotPath` module functions throw `SC2020`. - **TestContext values:** `t.filePath` is the entry file's path when the program was compiled. `t.attempt` is `0`, since a test runs once. `t.passed` is `false` while the body runs and the test's outcome in its `afterEach` and `t.after` hooks. `t.workerId` is `Number(process.env.NODE_TEST_WORKER_ID) || undefined`, as in Node. `t.tags` is `[]`, since the `tags` test option throws `SC2020`; the array is not frozen as Node's is. - **Suite and hook contexts:** a `describe` body may take its `SuiteContext`, which has `name`, `fullName`, `filePath`, `attempt`, `passed` and `diagnostic`. Hooks may take their context, as in Node: the suite's for `before` and `after`, the test's for `beforeEach`, `afterEach`, `t.before` and `t.after`. The `SuiteContext` `signal` and `log` members, and hook `done` callbacks, throw `SC2020`. +- **Module-level hooks:** `before` hooks outside any suite run at their `before()` call, and the first top-level test waits for the async ones; `after` hooks outside any suite run after the last top-level test. Both get the root's context, named ``. As in Node, a throwing root `before` fails each top-level test with its error, without running its body, and cancels the tests and suites inside each top-level suite. A throwing root `after` reports the entry file as a failed result, and the exit code is unchanged. diff --git a/packages/compiler/src/frontend/lowering/lower-test.ts b/packages/compiler/src/frontend/lowering/lower-test.ts index b9d4e8df1..e36518559 100644 --- a/packages/compiler/src/frontend/lowering/lower-test.ts +++ b/packages/compiler/src/frontend/lowering/lower-test.ts @@ -473,7 +473,7 @@ function lowerHook( return { kind: "libCall", fn: "test.hook", - args: [numLit(which, loc), cb, numLit(flags, loc)], + args: [numLit(which, loc), cb, numLit(flags, loc), strLit(atStringOf(expr), loc)], type: VOID, loc, }; diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 780918333..08c493ae4 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1438,7 +1438,8 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ }, // The suite body takes no parameters or its SuiteContext (flag 2). "test.suite": { argTypes: [STRING, F64, STRING, null, STRING, F64, F64], result: VOID }, - "test.hook": { argTypes: [F64, null, F64], result: VOID }, + // The trailing string is the hook call's "file:line:col". + "test.hook": { argTypes: [F64, null, F64, STRING], result: VOID }, "test.sub": { argTypes: [TESTCTX_T, STRING, F64, STRING, null, F64, STRING, F64, F64, F64], result: { kind: "promise", inner: VOID }, diff --git a/packages/runtime/src/scr_test.c b/packages/runtime/src/scr_test.c index cb2c81971..cc52513a6 100644 --- a/packages/runtime/src/scr_test.c +++ b/packages/runtime/src/scr_test.c @@ -80,6 +80,7 @@ enum { typedef struct { ScrClosure *cb; int flags; + ScrStr *at; /* "file:line:col" of the hook call, owned; NULL for t.* hooks */ } ScrTestHook; typedef struct { @@ -123,6 +124,7 @@ struct ScrTestCtx { ScrPromise *slot; /* owned; the parent waiting for its next subtest to finish */ struct ScrMockTimers *mock_timers; /* t.mock.timers, made on first use; freed at exit */ bool passed; /* t.passed: set when the body passes, as Node's pass() does */ + bool listed; /* a suite listed in the failing section (a failing root before) */ }; static SCR_TL ScrTestCtx *scr_test_root = NULL; @@ -136,6 +138,18 @@ static SCR_TL long scr_test_ct_tests = 0, scr_test_ct_suites = 0, scr_test_ct_pa scr_test_ct_todo = 0; static SCR_TL double scr_test_t0 = 0; static SCR_TL bool scr_test_suite_hook_failed = false; +/* The promises of async module-level before hooks, which the runner waits + * for before the first top-level test. */ +static SCR_TL ScrPromise **scr_test_root_pending = NULL; +static SCR_TL size_t scr_test_root_npending = 0, scr_test_root_pending_cap = 0; + +/* A module-level before hook threw or rejected: the first failure is kept + * for the top-level tests and suites, later ones are dropped. */ +static void scr_test_root_before_failed(ScrTestCtx *root) { + if (!scr_exc_pending()) return; + if (!root->before_err) root->before_err = scr_exc_take(); + else scr_exc_clear(); +} /* Above 0 while subtests run concurrently: result lines are held, and the * outermost concurrent parent prints its subtrees in declaration order, * as Node's reporter does, once they all finish. */ @@ -164,7 +178,10 @@ ScrTestCtx *scr_testctx_retain(ScrTestCtx *t) { } static void scr_test_hooks_free(ScrTestHooks *h) { - for (size_t i = 0; i < h->n; i++) scr_closure_release(h->v[i].cb); + for (size_t i = 0; i < h->n; i++) { + scr_closure_release(h->v[i].cb); + scr_str_release(h->v[i].at); + } free(h->v); h->v = NULL; h->n = h->cap = 0; @@ -277,7 +294,9 @@ static void scr_test_indent(int depth) { /* "(1.234567ms)" — durations print microsecond-rounded (Node's hrtime * granularity), not with double noise. */ +/* NaN prints nothing: a test cancelled before it started has no duration. */ static void scr_test_print_dur(double ms) { + if (isnan(ms)) return; char num[32]; fputs(" (", stdout); size_t n = scr_f64_to_str(round(ms * 1e6) / 1e6, num); @@ -409,10 +428,14 @@ static void scr_test_mocks_restore(ScrTestHooks *mocks, bool forget) { /* `ctx` is the context a hook that takes one receives: the suite or test * for its own before/after hooks, the test for the beforeEach/afterEach * chain. */ -static void scr_test_run_hooks_of(ScrTestCtx *owner, int which, ScrTestCtx *ctx) { - for (size_t i = 0; i < owner->hooks[which].n && !scr_exc_pending(); i++) { - scr_test_call(owner->hooks[which].v[i].cb, owner->hooks[which].v[i].flags, ctx, NULL); +static ScrTestHook *scr_test_run_hooks_of(ScrTestCtx *owner, int which, ScrTestCtx *ctx) { + if (scr_exc_pending()) return NULL; /* an earlier hook in the chain threw */ + for (size_t i = 0; i < owner->hooks[which].n; i++) { + ScrTestHook *h = &owner->hooks[which].v[i]; + scr_test_call(h->cb, h->flags, ctx, NULL); + if (scr_exc_pending()) return h; /* the hook that threw */ } + return NULL; } /* Returns whether the chain has any `which` hooks. */ @@ -559,6 +582,36 @@ static void scr_test_finish_concurrent(ScrTestCtx *t) { for (size_t i = 0; i < t->nchildren; i++) scr_test_report_tree(t->children[i]); } +/* A failing root before hook (Node): each top-level test fails with its + * error without running its body or beforeEach hooks, though its + * afterEach hooks run; a top-level suite fails with it, and the tests and + * suites in it are cancelled before they start. */ +static void scr_test_cancel_unrun(ScrTestCtx *c) { + for (size_t i = 0; i < c->nchildren; i++) scr_test_cancel_unrun(c->children[i]); + static const char msg[] = "test did not finish before its parent and was cancelled"; + scr_throw_str(scr_str_new(msg, sizeof msg - 1)); + c->err = scr_exc_take(); + c->listed = true; + c->dur_ms = NAN; + c->state = SCR_TS_CANCELLED; + scr_test_report_result(c); +} + +static void scr_test_fail_unrun(ScrTestCtx *c, ScrCaught *err) { + double start = scr_now_ms(); + c->err = scr_caught_retain(err); + c->listed = true; + if (c->is_suite) { + for (size_t i = 0; i < c->nchildren; i++) scr_test_cancel_unrun(c->children[i]); + } else { + scr_test_run_each_hooks(c, SCR_HOOK_AFTER_EACH, false); + if (scr_exc_pending()) scr_exc_clear(); + } + c->dur_ms = scr_now_ms() - start; + c->state = SCR_TS_FAIL; + scr_test_report_result(c); +} + static void scr_test_run_children(ScrTestCtx *t) { /* `only` at this level: when a child is marked, or contains a marked * test or suite, only those children run. The others are dropped entirely @@ -572,6 +625,10 @@ static void scr_test_run_children(ScrTestCtx *t) { /* Subtests t.test already ran INLINE at their call site, or started on * their own fiber. */ if (c->state != SCR_TS_PENDING || c->done) continue; + if (t == scr_test_root && t->before_err) { + scr_test_fail_unrun(c, t->before_err); + continue; + } if (t->concurrency > 1) scr_test_start(c); else scr_test_run_node(c); } @@ -813,7 +870,7 @@ static void scr_test_print_failures(ScrTestCtx *t, bool *any) { for (size_t i = 0; i < t->nchildren; i++) { ScrTestCtx *c = t->children[i]; scr_test_print_failures(c, any); - if (!c->is_suite && + if ((!c->is_suite || c->listed) && (c->state == SCR_TS_FAIL || c->state == SCR_TS_TODO_FAIL || c->state == SCR_TS_CANCELLED) && c->err) { @@ -1404,7 +1461,41 @@ static void scr_test_runner_entry(ScrFiber *self, void *argpack) { * the first test only after the file's synchronous body completes. */ scr_await_hop(); ScrTestCtx *root = scr_test_root; + /* The root's before hooks ran at their before() calls; the first test + * waits for the async ones. */ + for (size_t i = 0; i < scr_test_root_npending; i++) { + scr_await_void(scr_test_root_pending[i]); + scr_test_root_before_failed(root); + scr_promise_release(scr_test_root_pending[i]); + } + free(scr_test_root_pending); + scr_test_root_pending = NULL; + scr_test_root_npending = scr_test_root_pending_cap = 0; scr_test_run_children(root); + /* Its after hooks: a throw reports the root as "✖ " with the hook's + * location, after the top-level results, without counting it or changing + * the exit code, as Node does. */ + double after_start = scr_now_ms(); + ScrTestHook *after_failed = scr_test_run_hooks_of(root, SCR_HOOK_AFTER, root); + if (scr_exc_pending()) { + root->err = scr_exc_take(); + root->dur_ms = scr_now_ms() - after_start; + root->state = SCR_TS_FAIL; + if (after_failed && after_failed->at) { + root->at = scr_str_retain(after_failed->at); + /* The name is the file: the location without its ":line:col". */ + size_t end = root->at->len; + for (int colons = 0; end > 0 && colons < 2; end--) { + if (root->at->data[end - 1] == ':') colons++; + } + scr_str_release(root->name); + root->name = scr_str_new(root->at->data, end); + } + fputs("\xE2\x9C\x96 ", stdout); + scr_test_print_str(root->name); + scr_test_print_dur(root->dur_ms); + fputc('\n', stdout); + } scr_test_run_done = true; scr_snap_write_all(); scr_test_count(root); @@ -1418,6 +1509,10 @@ static void scr_test_runner_entry(ScrFiber *self, void *argpack) { scr_test_info_line("duration_ms", round((scr_now_ms() - scr_test_t0) * 1e6) / 1e6); bool any = false; scr_test_print_failures(root, &any); + if (root->err) { + if (!any) fputs("\n\xE2\x9C\x96 failing tests:\n", stdout); + scr_test_print_failure(root); + } /* The tree is done reporting: release it (test bodies may still hold * their TestContext refs — the boxes stay alive through those). */ scr_test_reg_parent = NULL; @@ -1534,7 +1629,41 @@ void scr_test_suite(ScrStr *name /*borrowed*/, double mode, ScrStr *msg /*borrow scr_closure_release(cb); } -void scr_test_hook(double which, ScrClosure *cb /*moves*/, double flags) { +/* A module-level before hook runs at its before() call, as Node runs the + * hooks of its already-started root at once: the synchronous part runs + * now, on the caller's stack, and the runner waits for an async hook's + * promise before the first top-level test. The first failure fails the + * top-level tests and suites (scr_test_fail_unrun). */ +static void scr_test_root_before_now(ScrTestCtx *root, ScrClosure *cb, int flags) { + bool takes_ctx = (flags & SCR_TEST_F_CTX) != 0; + if (flags & SCR_TEST_F_ASYNC) { + ScrPromise *p = + takes_ctx + ? ((ScrPromise * (*)(ScrClosure *, ScrTestCtx *)) cb->fn)(cb, scr_testctx_retain(root)) + : ((ScrPromise * (*)(ScrClosure *)) cb->fn)(cb); + if (p && !scr_exc_pending()) { + if (scr_test_root_npending == scr_test_root_pending_cap) { + scr_test_root_pending_cap = scr_test_root_pending_cap ? scr_test_root_pending_cap * 2 : 2; + scr_test_root_pending = realloc(scr_test_root_pending, + scr_test_root_pending_cap * sizeof *scr_test_root_pending); + if (!scr_test_root_pending) scr_test_oom(); + } + /* The runner observes it: a rejection is the hook's failure, not an + * unhandled rejection. */ + scr_promise_mark_handled(p); + scr_test_root_pending[scr_test_root_npending++] = p; + return; + } + scr_promise_release(p); + } else if (takes_ctx) { + ((void (*)(ScrClosure *, ScrTestCtx *))cb->fn)(cb, scr_testctx_retain(root)); + } else { + ((void (*)(ScrClosure *))cb->fn)(cb); + } + scr_test_root_before_failed(root); +} + +void scr_test_hook(double which, ScrClosure *cb /*moves*/, double flags, ScrStr *at) { scr_test_ensure_root(); ScrTestCtx *owner = scr_test_parent_get(); ScrTestHooks *h = &owner->hooks[(int)which]; @@ -1545,7 +1674,10 @@ void scr_test_hook(double which, ScrClosure *cb /*moves*/, double flags) { } h->v[h->n].cb = cb; h->v[h->n].flags = (int)flags; + h->v[h->n].at = at && at->len > 0 ? scr_str_retain(at) : NULL; h->n++; + if ((int)which == SCR_HOOK_BEFORE && owner == scr_test_root) + scr_test_root_before_now(owner, cb, (int)flags); } /* t.test(...): registers under `t` and — because subtests run inline on @@ -1620,6 +1752,7 @@ void scr_test_ctx_hook(ScrTestCtx *t, double which, ScrClosure *cb /*moves*/, do } h->v[h->n].cb = cb; h->v[h->n].flags = (int)flags; + h->v[h->n].at = NULL; h->n++; } @@ -1631,6 +1764,7 @@ static void scr_test_mocks_add(ScrTestHooks *h, ScrClosure *restore /*moves*/) { } h->v[h->n].cb = restore; h->v[h->n].flags = 0; + h->v[h->n].at = NULL; h->n++; } @@ -2172,6 +2306,7 @@ void scr_test_ctx_diagnostic(ScrTestCtx *t, ScrStr *msg /*borrowed*/) { } ScrStr *scr_test_ctx_name(ScrTestCtx *t) { + if (!t->name && !t->parent) return scr_str_new("", 6); /* Node's root test */ return t->name ? scr_str_retain(t->name) : scr_str_new("", 0); } diff --git a/packages/runtime/src/scr_test.h b/packages/runtime/src/scr_test.h index 26f8928f3..64a280bf7 100644 --- a/packages/runtime/src/scr_test.h +++ b/packages/runtime/src/scr_test.h @@ -33,8 +33,10 @@ void scr_test_register(ScrStr *name, double mode, ScrStr *msg, ScrClosure *cb, d void scr_test_suite(ScrStr *name, double mode, ScrStr *msg, ScrClosure *cb, ScrStr *at, double flags, double concurrency); /* before/after/beforeEach/afterEach on the CURRENT registration parent - * (`which`: 0 before, 1 after, 2 beforeEach, 3 afterEach). */ -void scr_test_hook(double which, ScrClosure *cb, double flags); + * (`which`: 0 before, 1 after, 2 beforeEach, 3 afterEach); `at` is the + * hook call's "file:line:col". The root's before and after hooks run + * around the top-level tests. */ +void scr_test_hook(double which, ScrClosure *cb, double flags, ScrStr *at); /* t.test(...): registers under `t`, runs the subtest INLINE on the * runner fiber, and returns the settled promise the `await` consumes (+1). */ ScrPromise *scr_test_sub(ScrTestCtx *t, ScrStr *name, double mode, ScrStr *msg, ScrClosure *cb, double flags, ScrStr *at, diff --git a/tests/fixtures/node-test/cases/root-after-throws.ts b/tests/fixtures/node-test/cases/root-after-throws.ts new file mode 100644 index 000000000..f7c20b9b0 --- /dev/null +++ b/tests/fixtures/node-test/cases/root-after-throws.ts @@ -0,0 +1,10 @@ +// A throwing module-level after hook: the run reports the entry file as a +// failed result with the hook's location, after the top-level results, +// without counting it, and the exit code stays 0, as in Node. +import { after, test } from "node:test"; + +after(() => { + throw new Error("root after failed"); +}); + +test("t", () => {}); diff --git a/tests/fixtures/node-test/cases/root-before-throws.ts b/tests/fixtures/node-test/cases/root-before-throws.ts new file mode 100644 index 000000000..b12c50060 --- /dev/null +++ b/tests/fixtures/node-test/cases/root-before-throws.ts @@ -0,0 +1,30 @@ +// @exit: 1 +// A throwing module-level before hook: each top-level test fails with its +// error without running its body or beforeEach hooks, and each top-level +// suite fails with it while the tests and suites in it are cancelled +// before they start. Later module-level before hooks still run at their +// before() calls, and the first failure is the one reported. +import { before, beforeEach, describe, it, test } from "node:test"; + +before(() => { + throw new Error("root before failed"); +}); +before(async () => { + await Promise.resolve(); + throw new Error("a later failure"); +}); +beforeEach(() => { + throw new Error("beforeEach never runs"); +}); + +describe("s", () => { + it("x", () => {}); + describe("inner", () => { + it("y", () => {}); + }); + it("z", () => {}); +}); + +test("t", () => { + throw new Error("the body never runs"); +}); diff --git a/tests/fixtures/node-test/cases/root-hooks.ts b/tests/fixtures/node-test/cases/root-hooks.ts new file mode 100644 index 000000000..8159aa7bb --- /dev/null +++ b/tests/fixtures/node-test/cases/root-hooks.ts @@ -0,0 +1,44 @@ +// Module-level before hooks run at their before() calls, with the root's +// context (named ""), and the first top-level test waits for the +// async ones; module-level after hooks run after the last top-level test +// or suite, and module-level beforeEach hooks run before each test, with +// that test's context. +import { after, before, beforeEach, describe, it, test } from "node:test"; +import * as assert from "node:assert"; + +const seen: string[] = []; + +before((c) => { + seen.push(`before: ${c.name}`); +}); +seen.push("after the before() call"); +before(async () => { + seen.push("async before starts"); + await new Promise((resolve) => setTimeout(resolve, 5)); + seen.push("async before ends"); +}); +beforeEach((c) => { + seen.push(`beforeEach: ${c.name}`); +}); +after(() => { + // Throws, and so fails the run visibly, unless every hook ran in order. + assert.deepStrictEqual(seen, [ + "before: ", + "after the before() call", + "async before starts", + "suite body", + "async before ends", + "beforeEach: x", + "beforeEach: t", + "report", + ]); +}); + +describe("s", () => { + seen.push("suite body"); + it("x", () => {}); +}); + +test("t", () => { + seen.push("report"); +}); From 571ffb10a9685ed6456025bbc76bbea232dc5b96 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 09:03:08 -0700 Subject: [PATCH 101/117] Refresh the measured corpus costs from recent main runs 298 of the 3008 corpus programs had no measured cost, which left main three unmeasured programs above the shard harness's 90% coverage floor: any PR adding a few corpus programs failed shard.test.ts. Rerun scripts/ci-corpus-costs.mjs over the 120 green Linux corpus shard logs of main runs 39131161610, 39130670620 and 39126633135 (31b52e215, aba3c3a97, 572b26ef8), and drop the entry of the renumbered 5942-local-class-observed-methods.ts. 2989 programs are now measured. Co-Authored-By: Claude Opus 5.5 --- tests/harness/corpus-costs.json | 11330 ++++++++++++++++-------------- 1 file changed, 5944 insertions(+), 5386 deletions(-) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 9f3c007f3..dee54f628 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1,5427 +1,5985 @@ { "note": "Milliseconds per corpus program on a GitHub-hosted ubuntu-24.04 runner: its differential plus llvm-differential case, per flavor (medians of green main runs). scripts/ci-corpus-costs.mjs refreshes it from CI logs.", "plain": { - "001-hello.ts": 3069, - "002-log-args.ts": 2728, - "100-number-format.ts": 3733, - "1000-json-stringify-basics.ts": 4746, - "1001-json-escapes-unicode.ts": 3114, - "1002-json-parse-cast.ts": 4816, - "1003-json-parse-unions.ts": 3373, - "1004-json-parse-errors.ts": 2257, - "1005-json-nested.ts": 3430, - "1006-json-fs-config.ts": 3508, - "1007-json-rc-stress.ts": 4738, - "1008-json-null-arms.ts": 3237, - "1009-json-optional-fields.ts": 3598, - "101-arithmetic.ts": 2904, - "1010-json-stringify-space.ts": 4663, - "1011-json-unknown-typeof.ts": 2914, - "102-comparisons.ts": 2408, - "1020-async-basics.ts": 2514, - "1021-async-ordering.ts": 2150, - "1022-async-exceptions.ts": 2155, - "1023-async-rc-stress.ts": 3249, - "1024-async-pending-exit.ts": 3248, - "1025-async-promise-capture.ts": 4134, - "1026-throw-promise.ts": 2862, - "1027-async-return-promise.ts": 3195, - "1028-async-return-record-literals.ts": 2979, - "1029-async-eager-chains.ts": 3200, - "103-ternary.ts": 2586, - "104-ternary-empty-arrays.ts": 3925, - "1050-comptime-tables.ts": 3449, - "1051-comptime-strings.ts": 4033, - "1052-comptime-records.ts": 4539, - "1053-comptime-json.ts": 2953, - "1054-comptime-modules/main.ts": 2477, - "110-number-radix.ts": 2253, - "111-record-entries.ts": 4124, - "1110-math-members.ts": 3859, - "1111-math-random.ts": 2956, - "1113-string-methods.ts": 3292, - "1114-string-unicode-island.ts": 2830, - "1115-parse-globals.ts": 2990, + "001-hello.ts": 3065, + "002-log-args.ts": 4101, + "100-number-format.ts": 4051, + "1000-json-stringify-basics.ts": 5187, + "1001-json-escapes-unicode.ts": 4569, + "1002-json-parse-cast.ts": 3516, + "1003-json-parse-unions.ts": 3382, + "1004-json-parse-errors.ts": 4383, + "1005-json-nested.ts": 5206, + "1006-json-fs-config.ts": 3979, + "1007-json-rc-stress.ts": 3920, + "1008-json-null-arms.ts": 3823, + "1009-json-optional-fields.ts": 4367, + "101-arithmetic.ts": 3258, + "1010-json-stringify-space.ts": 3979, + "1011-json-unknown-typeof.ts": 4108, + "102-comparisons.ts": 4061, + "1020-async-basics.ts": 3165, + "1021-async-ordering.ts": 3062, + "1022-async-exceptions.ts": 3356, + "1023-async-rc-stress.ts": 3530, + "1024-async-pending-exit.ts": 2901, + "1025-async-promise-capture.ts": 3471, + "1026-throw-promise.ts": 3173, + "1027-async-return-promise.ts": 2405, + "1028-async-return-record-literals.ts": 3561, + "1029-async-eager-chains.ts": 3698, + "103-ternary.ts": 3292, + "104-ternary-empty-arrays.ts": 4072, + "1050-comptime-tables.ts": 3518, + "1051-comptime-strings.ts": 2082, + "1052-comptime-records.ts": 3252, + "1053-comptime-json.ts": 3388, + "1054-comptime-modules/main.ts": 3286, + "110-number-radix.ts": 3749, + "111-record-entries.ts": 4017, + "1110-math-members.ts": 2615, + "1111-math-random.ts": 2691, + "1113-string-methods.ts": 3490, + "1114-string-unicode-island.ts": 2532, + "1115-parse-globals.ts": 2850, "1116-island-static-mix.ts": 3032, - "1117-typeof-static-union.ts": 2965, - "1118-object-spread-conditional.ts": 2667, - "1119-switch-union.ts": 3067, - "112-class-descriptor-key.js": 2522, - "1121-infinity-number-tostring.ts": 3370, - "1122-any-captures.ts": 3176, - "1124-union-narrowed-retag.ts": 2492, - "113-promise-checked-exits.ts": 2859, - "114-live-record-delete.ts": 2500, - "115-array-compound.js": 3135, - "116-text-decoder-runtime.js": 2862, - "117-weak-cache-cycle.js": 2266, - "118-fs-stored-callbacks.cjs": 3485, - "119-native-patterns.js": 3500, - "1200-regex-test-basics.ts": 3223, - "1201-regex-replace.ts": 3086, - "1202-regex-substitutions.ts": 3684, - "1203-regex-split.ts": 3320, - "1204-regex-empty-unicode.ts": 2968, - "1205-regex-rc-stress.ts": 2448, - "1300-errors-basics.ts": 2709, - "1301-errors-subclass.ts": 3447, - "1302-errors-typed-catch.ts": 3128, - "1303-errors-rc-stress.ts": 2776, - "1304-errors-uncaught.ts": 2907, - "1305-errors-async-rejections.ts": 2863, - "1306-errors-runtime-instances.ts": 2803, - "1350-path-normalize-join.ts": 2394, - "1351-path-parts.ts": 2228, - "1352-path-resolve-relative.ts": 3019, - "1353-os-basics.ts": 2682, - "1354-builtin-bare-specifiers.ts": 2284, - "1355-url-parse.ts": 2467, - "1356-url-file-bridge.ts": 3063, - "1357-fsp-roundtrip.ts": 3440, - "1358-crypto-random.ts": 2124, - "1359-json-module/main.ts": 2889, - "1360-spawn-sync.ts": 3158, - "1361-spawn-events.ts": 3000, - "1362-spawn-timers.ts": 8505, - "1363-spawn-unhandled-error.ts": 2724, - "1364-union-truthiness.ts": 2131, - "1365-union-logical.ts": 2948, - "1366-union-equality.ts": 2233, - "1367-destructuring.ts": 3492, - "1368-constructor-functions.ts": 2941, - "1369-promise-union.ts": 2048, - "1370-spread.ts": 2658, - "1371-union-template-tostring.ts": 2681, - "1372-loose-null-tests.ts": 2819, - "1373-union-array-arms.ts": 2414, - "140-bitwise-operators.ts": 3378, - "1400-typedarray-basics.ts": 3056, - "1401-typedarray-slice-set.ts": 2697, - "1402-buffer-encodings.ts": 3146, - "1403-buffer-fs.ts": 3327, - "1404-zlib-crypto-bytes.ts": 3318, - "1405-bytes-unions-arrays.ts": 2463, - "1406-dataview-mp4.ts": 2536, - "1407-dataview-bounds.ts": 3301, - "1408-string-indexing.ts": 2027, - "1409-typedarray-integer-loops.ts": 2940, - "1420-number-statics.ts": 2894, - "1421-number-parse-strings.ts": 2645, - "1422-date-iso.ts": 2686, - "1423-text-codec.ts": 4188, - "1424-fs-options.ts": 2662, - "1425-stdin-tty.ts": 2638, - "1426-stdin-read.ts": 2379, - "1427-fromcharcode-lastindexof.ts": 2109, - "1428-settled-await-order.ts": 2663, - "1429-promise-catch-finally.ts": 3486, - "1430-promise-race.ts": 4032, - "1431-caught-tostring.ts": 2082, - "1432-destructured-params.ts": 3251, - "1433-filter-narrow.ts": 3353, - "1434-async-never.ts": 2711, - "1435-math-spread.ts": 2665, - "1436-default-undef-param.ts": 2896, - "1437-pad-default.ts": 3003, - "1438-promise-all.ts": 6347, - "1440-interval-basics.ts": 3004, - "1441-interval-clear-cross.ts": 5524, - "1442-interval-throw.ts": 3148, - "1443-signal-handlers.ts": 5739, - "1444-exit-listeners.ts": 3270, - "1445-exit-process-exit.ts": 2515, - "1446-exit-uncaught.ts": 2709, - "1447-stdin-closed-events.ts": 2034, - "1448-stream-columns.ts": 2668, - "1450-incdec-expression.ts": 3189, - "1451-instanceof-uint8array-unknown.ts": 3003, - "1452-return-through-finally.ts": 2097, - "1453-pmap-settled.ts": 3863, - "1454-nonnull-narrow-and-fcc-bytes.ts": 2192, - "1455-lambda-union-return-adoption.ts": 3144, - "1460-console-error-warn.ts": 2229, - "1461-process-pid-getuid-kill.ts": 2853, - "1462-exec-sync.ts": 3145, - "1463-timeout-unref.ts": 2935, - "1464-env-writes.ts": 2594, - "1465-env-value.ts": 3233, - "1466-child-containers.ts": 2674, - "1467-string-match.ts": 2677, - "1468-exec-path.ts": 2974, - "1469-remove-listener.ts": 4038, - "1470-child-lifecycle.ts": 1948, - "1471-child-unref.ts": 6913, - "1472-errno-code.ts": 2768, - "1473-promisify-execfile.ts": 3155, - "1474-string-decoder.ts": 3057, - "1475-readline-closed-stdin.ts": 2826, - "1476-assign-expression.ts": 2557, - "1477-in-expressions.ts": 2740, - "1478-promise-reject.ts": 3143, - "1479-destructuring-assign.ts": 2933, - "1480-os-network-interfaces.ts": 3749, - "1481-string-case-static.ts": 1949, - "1482-spawnsync-error.ts": 2332, - "1483-array-slice.ts": 3329, - "1520-fs-wider-surface.ts": 3206, - "1520-string-split-static.ts": 2787, - "1521-fs-lstat-lock.ts": 2868, - "1521-string-trim-pad-static.ts": 2727, - "1522-parseint-static.ts": 2059, - "1522-spawnsync-options.ts": 3990, - "1523-isnan-floor-static.ts": 2552, - "1523-spawn-options.ts": 2955, - "1524-atomics-sleep-static.ts": 3221, - "1524-catch-narrowing.ts": 2221, - "1525-child-exit-signal.ts": 2022, - "1525-unknown-typeof-validation.ts": 2311, - "1526-set-spread.ts": 3277, - "1527-logical-mixed-operands.ts": 2920, - "1528-delete-records-env.ts": 3318, - "1529-class-with-statics.ts": 2626, - "1530-array-push-variadic.ts": 2272, - "1530-spread-override-completion.ts": 2333, - "1531-delete-optional-fields.ts": 2822, - "1531-process-arch-versions.ts": 2409, - "1532-array-splice-shift.ts": 2440, - "1532-union-shared-field-read.ts": 2449, - "1533-bool-equality.ts": 3130, - "1533-path-platform-namespaces.ts": 2472, - "1534-crypto-hash-chain.ts": 3303, - "1534-union-as-arm-cast.ts": 2773, - "1535-spawn-fd-stdio.ts": 3617, - "1535-union-param-defaults.ts": 2848, - "1536-destructuring-defaults.ts": 2783, - "1536-string-array-sweep.ts": 2930, - "1537-chalk-hybrid/main.ts": 3161, - "1537-os-release-spawnsync-stdio.ts": 2411, - "1538-await-promiselike-return.ts": 2433, - "1538-math-static-scalar.ts": 2674, - "1539-readonly-set-map.ts": 2573, - "1539-unknown-truthiness.ts": 2629, - "1540-os-userinfo.ts": 2636, - "1540-void-statement.ts": 2658, - "1541-fs-readdir-dirent.ts": 3093, - "1541-union-keyed-reads.ts": 4144, - "1542-map-promise-values.ts": 2657, - "1542-record-literal-into-union.ts": 3004, - "1543-rest-destructuring.ts": 2897, - "1543-set-server-handles.ts": 2927, - "1544-dyn-json-reads.ts": 3602, - "1544-string-matchall.ts": 2940, - "1545-spread-order-and-optional.ts": 2963, - "1546-union-element-reads.ts": 2716, - "1547-computed-key-fold.ts": 4334, - "1548-boolean-condition-forms.ts": 4675, - "1549-array-isarray-unions.ts": 3420, - "1550-param-defaults-func-set.ts": 3314, - "1551-dyn-receiver-methods.ts": 4271, - "1552-exec-options-record.ts": 3353, - "1553-truthy-hof-predicates.ts": 2475, - "1554-caught-into-unknown.ts": 2996, - "1555-index-spread-into-declared.ts": 3100, - "1556-union-retag-width-arms.ts": 2198, - "1557-url-host.ts": 2745, - "1558-any-joins-and-dyn-validation.ts": 2600, - "1559-conditional-spread-index-merge.ts": 3037, - "1560-forof-homogeneous-tuples.ts": 2478, - "1561-forof-strings.ts": 2503, - "1561-promise-then.ts": 3156, - "1562-optional-chain-tails.ts": 3390, - "1562-spawn-conditional-spread.ts": 3006, - "1563-forof-iterator-projections.ts": 3054, - "1563-string-raw-fold.ts": 2666, - "1564-fs-watch.ts": 3415, - "1564-string-raw.ts": 2651, - "1565-spawn-pipe-streams.ts": 3154, - "1565-union-element-join.ts": 2733, - "1566-child-duck-interface.ts": 2463, - "1567-server-close-override.ts": 2863, - "1568-x509-fingerprint.ts": 2419, - "1569-fsp-mkdir-unlink-chmod.ts": 2704, - "1570-child-unref-kill-reffed.ts": 8818, - "1571-optional-call-tostring-tail.ts": 4280, - "1571-stdin-set-raw-mode-non-tty.ts": 2435, - "1572-promise-reject-all-tuple.ts": 3046, - "1572-x509-validity-date-gettime.ts": 2933, - "1573-promisify-execfile-env-spread.ts": 3140, - "1573-tdz-scalar-forward-capture.ts": 2068, - "1574-dyn-optional-method-number-keys.ts": 3318, - "1574-promise-all-tuple-literal.ts": 3025, - "1575-unknown-assert-into-record.ts": 3248, - "1576-width-coercions.ts": 2888, - "1577-url-hostname.ts": 2352, - "1578-exec-input-optional.ts": 3178, - "1579-matchall-index.ts": 3025, - "1580-exec-env-conditional-spread.ts": 3275, - "1581-declare-const-read.ts": 2341, - "1582-timer-sleep-resolve.ts": 2315, - "1583-loops-and-stream-captures.ts": 3154, - "1584-union-field-unassigned.ts": 2858, - "1585-union-field-conditional-ctor.ts": 2073, - "1586-derived-field-before-super-init.ts": 2823, - "1590-js-unannotated.js": 2965, - "1591-js-closures.js": 2113, - "1592-js-classes.js": 4260, - "1593-js-jsdoc-records.js": 3366, - "1594-js-async.js": 2772, - "1595-js-island-gap/main.js": 2168, - "1596-cjs-modules/main.js": 2751, - "1597-mjs-graph/main.mjs": 2858, - "1598-cjs-builtin-require/main.js": 2109, - "1599-js-uncaught-throw.js": 1870, - "1600-assert-passing.ts": 3321, - "1601-assert-fail-exit.ts": 2842, - "1602-assert-caught-error.ts": 2041, - "1603-assert-scalar-messages.ts": 2650, - "1604-assert-deep-structures.ts": 3035, - "1605-assert-import-forms.ts": 3128, - "1606-assert-strict-module.ts": 2927, - "1607-assert-throws-match.ts": 2731, - "1608-cjs-assert/main.js": 3193, - "1609-assert-async.ts": 1990, - "1610-path-win32-full.ts": 1939, - "1611-url-file-bridge-neutral.ts": 2575, - "1612-cjs-module-globals.cjs": 2846, - "1613-cjs-esm-proxy-named/main.mjs": 2282, - "1614-js-fence-dodges.cjs": 2910, - "1615-cjs-export-shapes/main.cjs": 3349, - "1616-cjs-esm-lexer-invisible/main.mjs": 2499, - "1617-cjs-esm-lexer-visible/main.mjs": 2355, - "1618-cjs-esm-poisoned-tail/main.mjs": 2404, - "1619-cjs-esm-reexport-invisible/main.mjs": 2675, - "1620-cjs-require-effects-order/main.js": 2586, - "1621-cjs-require-cache-hit/main.js": 2101, - "1622-cjs-require-conditional/main.js": 2194, - "1623-cjs-require-diamond/main.js": 2241, - "1624-cjs-require-dir-mid-file/main.js": 2559, - "1625-cjs-require-lazy-fn/main.js": 2333, - "1626-cjs-require-mjs/main.js": 2430, - "1627-mjs-import-cjs-requires/main.mjs": 2803, - "1628-checked-dynamic-builtin-args.cjs": 2085, - "1629-require-main-filename.cjs": 2419, - "1630-inspect-scalars.ts": 2701, - "1630-rmsync-retry-options.cjs": 2427, - "1631-inspect-arrays.ts": 3949, - "1632-inspect-records.ts": 3013, - "1633-inspect-map-set.ts": 2316, - "1634-inspect-classes.ts": 3062, - "1635-inspect-buffer.ts": 2271, - "1636-util-format.ts": 2132, - "1637-inspect-dyn.ts": 3164, - "1638-inspect-cjs.cjs": 2023, - "1639-versions-openssl-probe.ts": 2845, - "1640-fd-read-decode.ts": 3219, - "1641-string-search.ts": 3172, - "1642-object-fromentries-rows.ts": 2713, - "1643-metadata-dyn-return.cjs": 3460, - "1644-ee-basics.ts": 2495, - "1645-ee-extends.ts": 2603, - "1646-ee-once-remove.ts": 2849, - "1647-ee-meta-events.ts": 2040, - "1648-ee-error-event.ts": 2703, - "1649-ee-names-counts.ts": 2487, - "1650-ee-prepend.ts": 2672, - "1651-ee-max-listeners.ts": 2331, - "1652-ee-snapshot.ts": 2031, - "1653-ee-cjs.cjs": 2472, - "1654-ee-namespace.ts": 2390, - "1655-spawnsync-neutral.ts": 4056, - "1656-execsync-neutral.ts": 2824, - "1657-spawn-async-neutral.ts": 3268, - "1660-buffer-read-write-num.ts": 3727, - "1661-buffer-encodings-full.ts": 2670, - "1662-string-decoder-encodings.ts": 2362, - "1663-buffer-compare-search-fill.ts": 3956, - "1664-dyn-fn-boundary.cjs": 2792, - "1665-dyn-fn-mustcall/main.cjs": 2827, - "1666-dyn-fn-identity.ts": 2623, - "1667-dyn-fn-not-callable.cjs": 2618, - "1668-dyn-fn-throws.cjs": 2216, - "1669-symbol-identity.ts": 2335, - "1670-symbol-registry.ts": 1852, - "1671-symbol-typeof.ts": 2343, - "1672-symbol-containers.ts": 2800, - "1673-symbol-cjs.cjs": 2407, - "1674-symbol-inspect.ts": 1818, - "1676-func-array-surface.ts": 2784, - "1677-emitter-listeners.ts": 2400, - "1678-emitter-dyn-listeners.cjs": 2358, - "1679-console-dyn.js": 2880, - "1680-assert-bytes.ts": 3465, - "1681-assert-funcs.ts": 2454, - "1685-stream-readable-basics.ts": 2506, - "1686-stream-readable-paused.ts": 2711, - "1687-stream-readable-flow-control.ts": 2359, - "1688-stream-writable-basics.ts": 2613, - "1689-stream-writable-async-drain.ts": 2671, - "1690-stream-duplex.ts": 2112, - "1691-stream-transform.ts": 1780, - "1692-stream-pipe.ts": 3345, - "1693-stream-pipe-backpressure.ts": 2344, - "1694-stream-destroy.ts": 1870, - "1695-stream-props.ts": 2766, - "1696-stream-read-inside-read.ts": 3023, - "1697-stream-tick-vs-timer.ts": 2275, - "1698-stream-uncaught-error.ts": 2523, - "1699-stream-callback-shapes.ts": 1972, - "1700-mustcall-common/main.cjs": 3401, - "1701-mustcall-exit-report/main.cjs": 3316, - "1702-dyn-proto-dispatch.cjs": 2744, - "1703-arguments-rest-props.cjs": 2431, - "1710-cjs-export-class/main.js": 2997, - "1711-cjs-export-single-values/main.js": 2866, - "1712-field-incdec.ts": 1828, - "1713-js-dyn-fields.js": 2492, - "1720-assert-throws-shape.ts": 2372, - "1721-assert-throws-regex-class.ts": 2125, - "1722-assert-rejects.ts": 2761, - "1723-assert-does-not-reject.ts": 2536, - "1724-assert-iferror.ts": 2883, - "1725-assert-symbols.ts": 2626, - "1726-promise-with-resolvers.ts": 2320, - "1727-assert-throws-shape-exit.ts": 2580, - "1730-countdown-symbol-keys/main.js": 2657, - "1731-symbol-field-shapes.cjs": 3005, - "1732-symbol-field-cross-module/main.js": 2509, - "1740-stream-extends-readable.ts": 2167, - "1741-stream-extends-writable.ts": 2479, - "1742-stream-extends-duplex-transform.ts": 2640, - "1743-stream-extends-vt-dispatch.ts": 2388, - "1744-stream-set-encoding.ts": 2886, - "1745-stream-encoding-js.cjs": 2861, - "1746-stream-for-await.ts": 2864, - "1747-stream-for-await-js.cjs": 2685, - "1750-http-agent-options.ts": 2435, - "1751-options-record-stance.ts": 3010, - "1760-surplus-args-drop.cjs": 2845, - "1761-emitter-special-event-names.cjs": 2672, - "1770-assert-dyn-strict.ts": 2841, - "1771-assert-dyn-deep.ts": 2098, - "1772-assert-dyn-js.cjs": 2493, - "1773-assert-dyn-exit.ts": 2809, - "1780-http-res-surface.ts": 3019, - "1781-http-server-shapes.cjs": 2697, - "1790-computed-key-folds.ts": 2567, - "1791-searchparams-core.ts": 2632, - "1792-searchparams-encoding.ts": 2548, - "1793-searchparams-iteration.ts": 2977, - "1794-searchparams-url-live.ts": 2027, - "1795-dyn-handle-request.cjs": 2079, - "1796-dyn-handle-body.cjs": 3120, - "1797-dyn-handle-socket.cjs": 2724, - "1798-dyn-handle-typed-box.ts": 2104, - "1800-immediate-basics.ts": 2313, - "1801-immediate-handle.ts": 2272, - "1802-immediate-unref-exit.ts": 2368, - "1803-timeout-refresh.ts": 2346, - "1804-timers-module.ts": 2379, - "1805-timer-callback-args.ts": 2475, - "1806-timer-delay-trunc.ts": 2847, - "1810-stream-options-const-record.ts": 2576, - "1811-stream-option-value-callbacks.cjs": 2945, - "1812-stream-super-options-forwarding.cjs": 3075, - "1813-stream-finished.ts": 2644, - "1814-stream-pipeline.cjs": 2915, - "1815-stream-state-reads.cjs": 2499, - "1820-static-block-basics.ts": 2475, - "1821-static-block-order.ts": 2605, - "1822-static-block-js.js": 1831, - "1823-static-instance-method-names.ts": 2522, - "1824-for-of-destructuring-defaults.ts": 2238, - "1825-exhaustive-typeof-switch.ts": 1814, - "1826-settimeout-arguments-callback.js": 2356, - "1830-enum-numeric-basics.ts": 2431, - "1831-enum-string-const-reverse.ts": 2780, - "1832-enum-modules/main.ts": 2343, - "1835-var-basics.ts": 2924, - "1836-var-loop-capture.ts": 2857, - "1837-var-undefined-hoisting.ts": 2785, - "1838-var-modules/main.ts": 2572, - "1839-var-js/main.cjs": 2766, - "1840-jsdoc-import-type-only/main.js": 2328, - "1850-overload-basics.ts": 2354, - "1851-overload-return-narrowing.ts": 2268, - "1852-overload-class-members.ts": 2874, - "1853-overload-modules/main.ts": 2339, - "1854-ambient-declare-fn.ts": 2384, - "1855-ambient-declare-fn-uncaught.ts": 2441, - "1870-unit-type-values.ts": 2730, - "1871-empty-array-never.ts": 2177, - "1872-template-tostring-composite.ts": 2526, - "1880-json-declared-field-order.ts": 2276, - "1881-default-anon/main.ts": 2233, - "1882-default-cjs-interop/main.ts": 2407, - "1883-default-exports/main.ts": 2358, - "1890-ns-imports/main.ts": 2428, - "1891-ns-reexport/main.ts": 2422, - "1940-class-values-basics.ts": 2483, - "1941-class-values-registry.ts": 2632, - "1942-class-expressions.ts": 2765, - "1943-class-statics-expanded.ts": 2459, - "1944-class-values-modules/main.ts": 2440, - "1950-generic-fn-values.ts": 2561, - "1951-generic-classes-basics.ts": 2197, - "1952-generic-class-statics-values.ts": 2662, - "1953-generic-class-hierarchy.ts": 3001, - "1954-generic-modules/main.ts": 2756, - "1960-namespace-basics.ts": 2647, - "1961-namespace-nested.ts": 2257, - "1962-namespace-classes.ts": 2660, - "1963-namespace-aliases.ts": 2070, - "1964-namespace-type-only.ts": 2445, - "1965-namespace-ambient.ts": 2332, - "1966-namespace-modules/main.ts": 2434, - "1967-namespace-alias-typeonly.ts": 2455, - "1968-namespace-import-eq-snapshot.ts": 2251, - "1970-decorators-basics.ts": 2885, - "1971-decorators-rebinding.ts": 2022, - "1972-decorators-throwing.ts": 2312, - "1973-decorators-ambient.ts": 2390, - "1980-primitive-proto-statics.ts": 3122, - "1981-date-utc.ts": 3440, - "1982-freeze-resolve-passthrough.ts": 2302, - "1983-array-tuple-surfaces.ts": 3057, - "1990-labels-basics.ts": 2548, - "1991-for-in-loops.ts": 2966, - "1992-small-syntax.ts": 1927, - "200-strings.ts": 2314, - "2000-generic-methods-basic.ts": 2743, - "2001-generic-methods-generic-class.ts": 2632, - "2002-generic-methods-inheritance.ts": 3264, - "2003-generic-methods-object-literal.ts": 2644, - "2004-generic-methods-statics.ts": 2578, - "201-templates.ts": 2516, - "2010-generators-basics.ts": 1908, - "2011-generators-forof.ts": 2574, - "2012-generators-return-throw.ts": 2779, - "2013-generators-sent-values.ts": 2065, - "2014-generators-values.ts": 2940, - "2015-generators-yieldstar.ts": 1953, - "2016-generators-rc-stress.ts": 2595, - "2017-generators-async.ts": 2715, - "2018-generators-uncaught.ts": 2356, - "2019-generators-loops.ts": 2496, - "2020-generic-value-bindings.ts": 2351, - "2021-generic-value-binding-modules/main.ts": 2687, - "2022-width-index-capture.ts": 2751, - "2023-width-readonly.ts": 2800, - "2024-width-array-elems.ts": 2726, - "2025-width-union-compose.ts": 2851, - "2026-width-spread.ts": 2485, - "2030-width-nested.ts": 2774, - "2031-width-tuples.ts": 2693, - "2032-cjs-export-assigned-class-expression/main.cjs": 2477, - "2033-property-assigned-class-extends.cjs": 2618, - "2035-ternary-array-retag.cjs": 2404, - "2036-evolving-array-decl.cjs": 2542, - "2037-fn-decl-hoisting.cjs": 2645, - "2038-evolving-array-js.cjs": 3054, - "2040-any-bindings.ts": 2984, - "2040-mixin-heritage.ts": 2131, - "2041-any-params-returns.ts": 2687, - "2041-mixin-values.ts": 2744, - "2042-any-flow-loops.ts": 2769, - "2042-mixin-modules/main.ts": 1924, - "2043-any-dom-values.ts": 2778, - "2043-mixin-rc-stress.ts": 2775, - "2044-vtable-sibling-slots.ts": 2571, - "2045-objlit-accessors-basic.ts": 2640, - "2045-parameter-properties.ts": 2113, - "2046-abstract-classes.ts": 3000, - "2046-objlit-accessors-effects.ts": 2795, - "2047-objlit-accessors-shapes.ts": 2983, - "2047-optional-class-fields.ts": 2949, - "2050-dynamic-import-own-module/main.ts": 2608, - "2051-dynamic-import-then/main.ts": 2467, - "2052-dynamic-import-self.ts": 2449, - "2053-typeof-static-fold.ts": 2181, - "2054-destructuring-island-source.ts": 2707, - "2060-empty-tuple.ts": 2373, - "2070-computed-key-folds.ts": 2645, - "2071-integer-key-enumeration-order.ts": 3006, - "2072-expando-function-members.ts": 2512, - "2073-destructuring-assignment.ts": 2535, - "2074-island-destructuring.ts": 2609, - "2075-index-signature-runtime-keys.ts": 1981, - "2080-destructuring-defaults.ts": 2417, - "2081-destructuring-rest.ts": 2774, - "2082-destructuring-assignment.ts": 2489, - "2085-destructuring-heads-rest-params.ts": 2668, - "2087-destructuring-for-heads.ts": 2521, - "2090-index-signature-number-keys.ts": 1958, - "2091-index-signature-string-intersection.ts": 2567, - "2092-package-imports/main.ts": 2340, - "2093-timers-promises.ts": 2743, - "2094-diagnostics-channel.ts": 1983, - "2095-js-catch-unknown.js": 2499, - "2096-os-type.ts": 2709, - "2097-js-evolving-globals.js": 2560, - "210-string-methods.ts": 2593, - "2100-stream-default-hwm.ts": 2961, - "2101-dyn-param-defaults.ts": 2737, - "2102-empty-pattern-decls.ts": 2787, - "2105-computed-key-static-folds.ts": 2507, - "2106-comma-expressions.ts": 2500, - "211-string-unicode.ts": 1823, - "2110-top-object-types.ts": 1971, - "2111-json-stringify-unknown.ts": 2830, - "2112-array-at-findlast.ts": 2001, - "2113-string-index-methods.js": 2989, - "212-string-aliasing-append.ts": 1909, - "2120-package-self-import/main.ts": 1825, - "2121-esm-cycle-inert-backedge/main.ts": 1748, - "2123-ambient-import-crash/main.ts": 1870, - "2124-imports-field-wildcard/main.ts": 2082, - "2140-uri-component-codecs.ts": 1955, - "2160-dc-tracing-channel.cjs": 2212, - "2161-js-object-literal-identity.cjs": 2587, - "2162-js-dyn-destructure.cjs": 2628, - "2163-js-selfref-const.cjs": 2533, - "2164-js-then-dyn-handler.cjs": 2503, - "2165-js-throw-dyn.cjs": 2509, - "2166-cjs-getter-this/main.cjs": 2420, - "2170-island-array-exits.ts": 3096, - "2171-island-json-stringify.ts": 2652, - "2172-island-regexp-boundary.ts": 2763, - "2190-new-object-and-string-wrappers.ts": 1860, - "2191-uri-encoders.ts": 2586, - "2192-object-default-tostring.ts": 2607, - "2193-discarded-stdlib-reads.ts": 2445, - "2194-ambient-undef-chains.ts": 2022, - "2195-require-missing-package/main.mjs": 2412, - "2196-island-computed-key-chain.ts": 2831, - "2210-dyn-promise-crossing.cjs": 1918, - "2211-dc-trace-promise.cjs": 2793, - "2212-unhandled-rejection-listener.cjs": 2511, - "2213-async-local-storage.cjs": 2825, - "2214-dc-bind-store.cjs": 2651, - "2215-process-emit-warning-exit.cjs": 2666, - "2240-width-class-into-record.ts": 2573, - "2241-width-record-into-class.ts": 2686, - "2242-width-statics-into-record.ts": 2654, - "2243-width-assert-satisfies-shapes.ts": 2411, - "2250-tagged-templates.ts": 2617, - "2252-class-iterators.ts": 3448, - "2253-union-coercions.ts": 2899, - "2260-http2-constants.cjs": 2471, - "2280-builtin-namespace-destructure.cjs": 2645, - "2281-domexception-atob-btoa.cjs": 2853, - "2282-queue-microtask.cjs": 2526, - "2283-structured-clone.cjs": 3050, - "2284-regexp-constructor.cjs": 1945, - "2285-iferror-dyn.cjs": 2665, - "2286-dyn-object-walks.cjs": 2662, - "2300-dyn-record-spread-and-keyed-access.cjs": 2261, - "2301-cjs-export-table-dom-attach.cjs": 2384, - "2310-process-next-tick.ts": 2843, - "2311-next-tick-js-callbacks.js": 2254, - "2312-stream-underscore-assign.ts": 2790, - "2313-stream-underscore-assign-js.cjs": 2842, - "2314-process-introspection.ts": 2971, - "2320-await-unit.ts": 2748, - "2321-emitter-static-setmax.cjs": 2272, - "2322-dyn-array-sort.cjs": 1886, - "2323-timer-callback-returns.ts": 2523, - "2330-tls-server-runtime-options.cjs": 2677, - "2331-tls-server-options-typed.ts": 2790, - "2350-nan-global.ts": 2734, - "2351-async-methods.ts": 2622, - "2352-void-coercions.ts": 1788, - "2353-decorators-member-ambient.ts": 2547, - "2354-decorators-expression-ambient.ts": 2465, - "2360-tuple-to-array.ts": 2471, - "2361-assign-index-record.ts": 3021, - "2362-execsync-inherit.ts": 2693, - "2363-nullish-retag.ts": 2801, - "2364-in-runtime-key.ts": 2572, - "2365-dyn-into-island.ts": 1996, - "2366-string-well-formed.ts": 2147, - "2367-regexp-escape.ts": 2470, - "2368-set-methods.ts": 2846, - "2369-promise-try.ts": 2170, - "2370-group-by.ts": 2298, - "2371-iterator-helpers.ts": 2730, - "2380-buffer-module-named-import.ts": 2400, - "2381-builtin-default-imports.js": 2365, - "2382-cycle-two-decl/main.ts": 1682, - "2383-cycle-assertdoc/main.js": 2760, - "2384-cycle-mixed-bindings/main.ts": 1815, - "2385-builtin-reexport-facade/main.ts": 1834, - "2386-string-to-chars.ts": 2748, - "2387-tonumber-argv.ts": 2345, - "2388-tonumber-grammar-zoo.ts": 2619, - "2389-tonumber-unary-plus.ts": 2473, - "2390-dot-requires/main.cjs": 2365, - "2391-default-builtin-imports/main.ts": 3036, - "2392-block-guard-alias-scope.ts": 2477, - "2393-loop-exit-guard-narrow.ts": 2791, - "2394-loop-narrow-containment.ts": 2749, - "2395-while-cond-guard.ts": 2574, - "2396-born-narrowed-decl.ts": 2435, - "2397-branch-kill-merge.ts": 2334, - "2398-switch-arm-kill.ts": 2438, - "2399-reassign-kill-polarity.ts": 2238, - "240-stdout-write.ts": 2820, - "2400-kill-return-edge.ts": 2315, - "2401-kill-break-staging.ts": 2347, - "2402-labeled-break-kill.ts": 2610, - "2403-kill-continue-backedge.ts": 2391, - "2404-kill-throw-catch.ts": 2611, - "2405-sibling-arm-narrow.ts": 2300, - "2406-switch-clause-sibling-narrow.ts": 1885, - "2407-infinite-loop-seal.ts": 2596, - "2408-loop-terminality-reopen.ts": 2452, - "2409-loop-body-return-not-terminal.ts": 1860, - "2410-stacked-cases-terminality.ts": 2588, - "2411-exhaustive-switch-terminality.ts": 2704, - "2412-dowhile-guard-trailing-test.ts": 2401, - "2413-dowhile-kill-renarrow.ts": 2389, - "2414-dowhile-continue-kill.ts": 2546, - "2415-dowhile-break-trailing-test.ts": 2461, - "2416-spread-ternary-positions.ts": 2790, - "2417-ternary-local-inference.ts": 2737, - "2418-wrapped-ternary-arms.ts": 2485, - "2419-selector-ternary-union.ts": 2554, - "2420-nullish-null-identity.ts": 2418, - "2421-float-lane-inference.ts": 2337, - "2422-ieee-div-rem-corners.ts": 2498, - "2423-param-null-reassign.ts": 2447, - "2424-ternary-miss-first-narrowing.ts": 2373, - "2425-elseif-head-exit-narrow.ts": 2194, - "2426-default-snapshot-mutable/main.ts": 2194, - "2427-perf-hooks-now.ts": 2489, - "2428-field-redeclare-inherited.ts": 2204, - "2429-destructure-class-instance.ts": 2362, - "2430-empty-literal-unknown-field.js": 2633, - "2431-primitive-ctor-values.ts": 2702, - "2432-generic-member-fields-async.ts": 2679, - "2433-as-const-command-tables.ts": 2271, - "2434-deferred-init-fields.ts": 2673, - "2435-loose-same-kind-equality.ts": 2441, - "2440-console-inspect-args.ts": 3150, - "2441-console-process-argv.ts": 2027, - "2442-union-literal-arm-widening.ts": 2300, - "2443-union-literal-shadow-narrowing.ts": 2799, - "2444-union-literal-reducer-spread.ts": 2545, - "2445-math-minmax-nary.ts": 2355, - "2446-performance-global.ts": 2453, - "2447-island-boundary-slots/main.ts": 3241, - "2448-entries-null-arms-regex-arrays.ts": 3215, - "2450-private-instance-methods.ts": 2581, - "2451-private-fields.ts": 2918, - "2452-private-statics.ts": 2431, - "2453-private-accessors.ts": 2589, - "2454-private-generator-methods.ts": 2809, - "2455-private-brand-checks.ts": 2369, - "2456-private-async-methods.ts": 2625, - "2457-private-members.js": 2014, - "2460-qs-parse-grammar.ts": 2706, - "2461-qs-parse-options.ts": 2139, - "2462-qs-stringify.ts": 2756, - "2463-qs-escape-unescape.ts": 2677, - "2464-qs-require-forms.cjs": 2768, - "2470-mockable-module-shape.js": 3152, - "2471-record-keyed-write-hasown.js": 2699, - "2472-string-regexp-union.ts": 2532, - "2473-option-table-widths.js": 2095, - "2474-island-literal-forms.ts": 2881, - "2475-variadic-wrapper-island.js": 2240, - "2476-map-regex-values.ts": 2431, - "2480-recursive-record-tree.ts": 2075, - "2481-mutual-recursive-records.ts": 2525, - "2482-recursive-union-tree.ts": 2633, - "2483-recursive-record-cycles.ts": 2479, - "2484-json-stringify-circular.ts": 2869, - "2485-inspect-circular-refs.ts": 2957, - "2486-recursive-record-boundaries.ts": 2857, - "2487-recursive-deep-equal.ts": 2516, - "2488-ast-walker.ts": 2925, - "2490-find-miss-null-compare.ts": 2051, - "2491-strict-unit-compare-no-arm.ts": 2381, - "2492-loose-null-compare-unions.ts": 2451, - "2493-switch-unit-cases.ts": 2503, - "2494-no-arm-compare-effects.ts": 2501, - "2500-net-autosel-timeout.ts": 2202, - "2510-dyn-evolving-array-map.ts": 2611, - "2511-dyn-evolving-array-filter-foreach.ts": 2729, - "2512-dyn-evolving-array-mixed-push.ts": 2656, - "2520-private-statics-class-name-calls.ts": 2568, - "2521-private-statics-class-expression.ts": 2429, - "2522-private-statics-decorated.ts": 2492, - "2523-private-statics-aliased-class.ts": 2618, - "2530-object-destructuring-decl.ts": 2513, - "2531-array-tuple-destructuring-decl.ts": 2504, - "2532-param-destructuring-options.ts": 2714, - "2533-forof-destructuring.ts": 2583, - "2534-object-rest-decl.ts": 2277, - "2535-destructuring-assign-basics.ts": 2758, - "2536-destructuring-assign-nested.ts": 2761, - "2537-destructuring-assign-member-targets.ts": 2552, - "2538-destructuring-assign-class-source.ts": 2658, - "2539-class-instance-rest.ts": 2852, - "2540-accessor-destructuring-defaults.ts": 2732, - "2541-destructuring-eval-order.ts": 2121, - "2550-generics-keyof-pick.ts": 2790, - "2551-generics-value-aliases.ts": 2489, - "2552-generics-iface-methods.ts": 2118, - "2553-generics-signature-bindings.ts": 2838, - "2554-generics-frontier-mix.ts": 2857, - "2555-generics-keyof-writes.ts": 2600, - "2556-crypto-introspection.ts": 2362, - "2556-width-hybrid-shapes.ts": 3063, - "2557-tls-ca-store.ts": 2877, - "2557-width-field-lifts.ts": 2899, - "2558-index-signature-func-values.ts": 2980, - "2558-rejection-events.cjs": 2741, - "2559-index-signature-container-values.ts": 2921, - "2560-arraybuffer-dataview-set.ts": 2985, - "2561-object-is.ts": 3314, - "2562-intl-numberformat-en-us.ts": 1713, - "2563-stream-promises-pipeline.ts": 2673, - "2564-stream-promises-finished.ts": 2596, - "2565-stream-promises-js.cjs": 2121, - "2566-promise-reject-dyn-reason.js": 2527, - "2567-rest-spread-forward.js": 3263, - "2568-rest-spread-forward-dynamic.js": 2990, - "2569-upcast-identity.ts": 1878, - "2570-buffer-arg-validation.cjs": 4190, - "2571-searchparams-arg-validation.cjs": 2897, - "2572-readable-emitted-readable-flag.cjs": 2583, - "2573-fs-url-arg-ladders.cjs": 2789, - "2574-emitter-max-listeners-ladders.cjs": 2728, - "2575-string-destructuring-decl.ts": 2831, - "2576-string-destructuring-assign.ts": 2718, - "2577-builtin-global-destructuring.js": 2482, - "2578-jsval-into-unknown-rows.ts": 2821, - "2579-jsval-object-param-crossing.js": 2723, - "2580-jsval-routed-keyed-ops.js": 2125, - "2581-jsval-routed-calls.js": 3090, - "2582-jsval-object-statics.js": 2972, - "2582-jsval-routed-keyed-ops.js": 2851, - "2583-dyn-nullish-coalesce.js": 2185, - "2583-jsval-routed-calls.js": 2972, - "2584-jsval-object-statics.js": 2832, - "2584-union-dyn-collapse.ts": 2220, - "2585-dyn-nullish-coalesce.js": 2398, - "2585-unknown-array.ts": 2751, - "2586-object-assign-spread.js": 3004, - "2587-array-entries-forof.ts": 2555, - "2588-array-entries-chains.ts": 3001, - "2589-object-create-null.cjs": 2994, - "2590-object-create-dynamic.js": 3188, - "2591-ambient-generic-traps.ts": 2461, - "2592-ambient-trap-uncaught.ts": 2508, - "2593-generic-inert-bindings.ts": 2003, - "2594-nullish-generic-bindings.ts": 2473, - "2595-fs-arg-ladders.cjs": 3590, - "2596-net-arg-ladders.cjs": 2708, - "2597-dgram-send-ladders.cjs": 3185, - "2598-tls-arg-ladders.cjs": 3457, - "2599-stream-arg-ladders.cjs": 2639, - "2600-dyn-keyed-write-harness.js": 2645, - "2601-dyn-keyed-write-ops.js": 2850, - "2602-dyn-array-destructure.js": 3140, - "2603-island-keyed-write-dyn.js": 2307, - "2604-cycle-classes-mutual/main.ts": 2453, - "2605-cycle-three-module/main.ts": 2707, - "2606-dynamic-import-cycle/main.ts": 2783, - "2608-regex-named-groups.ts": 3177, - "2609-regex-named-replace.ts": 2707, - "2610-regex-named-matchall.ts": 2590, - "2611-regex-named-groups-js.cjs": 2302, - "2613-for-init-uninitialized-let.ts": 2413, - "2614-trap-binding-later-writes.ts": 2362, - "2615-nullish-field-record-binding.ts": 2480, - "2616-js-collect-probe-defers.js": 2756, - "2617-enum-static-field-import/main.ts": 2551, - "2618-ee-emit-override.ts": 2613, - "2619-ee-override-chain.ts": 2034, - "2620-ee-override-once-order.ts": 2930, - "2621-ee-override-error-throw.ts": 2533, - "2622-ee-override-filter.ts": 2677, - "2623-ee-job-queue.ts": 2500, - "2624-ee-override-js.cjs": 2183, - "2625-bytes-views.ts": 2152, - "2626-stream-event-names.ts": 2499, - "2627-stream-ticks-are-nextticks.ts": 2708, - "2628-stream-push-encodings.cjs": 2440, - "2629-stream-consumers.ts": 2913, - "2630-stream-consumers-errors.ts": 2991, - "2631-create-require/main.ts": 3044, - "2632-dyn-jsval-iterate.js": 2878, - "2633-island-promise-crossing.js": 3370, - "2634-stream-pipeline-arg-ladders.cjs": 2714, - "2635-trap-binding-unmappable-written.ts": 2160, - "2636-trap-binding-ambient-rooted-rewrite.ts": 2374, - "2637-create-require-bare/main.ts": 2239, - "2638-http-dyn-res-compat.cjs": 3131, - "2639-http-dyn-req-pause.cjs": 2921, - "2640-net-dyn-socket-compat.cjs": 2968, - "2641-http-agent-surface.cjs": 3429, - "2642-http-agent-maxsockets.cjs": 2699, - "2643-or-default-retag.ts": 2845, - "2644-http-client-url-argument.ts": 2453, - "2645-https-client-url-argument.ts": 2836, - "2646-top-level-await.ts": 2403, - "2647-top-level-await-modules/main.ts": 2235, - "2648-top-level-await-rejection.ts": 1959, - "2649-top-level-await-pending.ts": 2384, - "2650-top-level-await-self-import.ts": 1987, - "2651-top-level-await-pending-unhandled.ts": 2002, - "2652-top-level-await-dynamic/main.ts": 2598, - "2653-top-level-await-rejection-stops-loop.ts": 2523, - "2654-top-level-await-unrelated-rejection.ts": 2015, - "2655-top-level-await-cycle/main.ts": 2308, - "2656-top-level-await-cycle-order/main.ts": 4054, - "2657-top-level-await-cycle-dynamic/main.ts": 2392, - "2658-top-level-await-sync-completion/main.ts": 2314, - "2659-top-level-await-dynamic-cycle/main.ts": 2467, - "2660-top-level-await-cycle-rejection/main.ts": 2494, - "2661-top-level-await-dynamic-runtime-root/main.ts": 2327, - "2662-top-level-await-cycle-external-wait/main.ts": 2397, - "2663-top-level-await-dependency-errors/main.ts": 2080, - "2664-top-level-await-same-checkpoint-rejection.ts": 2543, - "2665-top-level-await-unhandled-listener-liveness.ts": 2570, - "2666-array-to-sorted.ts": 6667, - "2668-stored-number-array-iterator.ts": 2876, - "2669-array-copying-methods.ts": 3089, - "2670-uint8array-copy-iterate.ts": 2885, - "2671-array-copying-js.cjs": 2315, - "2672-http-request-response-callback.ts": 2962, - "2673-top-level-await-implicit-module.ts": 2333, - "2674-top-level-for-await-implicit-module.ts": 2353, - "2675-create-require-nested-esm.js": 2188, - "2675-process-self-reexec.ts": 2836, - "2676-indexed-read-strict-equality.ts": 2408, - "2676-record-clone-overrides.ts": 2543, - "2676-top-level-await-ambiguous/main.ts": 2576, - "2677-runtime-optional-closure.ts": 4255, - "2677-top-level-await-module-scope/main.ts": 2463, - "2678-date-instances.ts": 2194, - "2678-large-string-sparse-index.ts": 2586, - "2678-util-parseargs.ts": 4462, - "2679-util-parseargs-cjs.cjs": 4905, - "2680-util-parseargs-default.ts": 1889, - "2681-util-parseargs-dynamic.js": 2618, - "2682-fs-rename.ts": 3414, - "2683-filter-truthy-predicate.ts": 3055, - "2683-fs-rename-js.cjs": 4058, - "2684-filter-no-predicate-dyn.cjs": 2608, - "2684-fs-rename-abort.ts": 2639, - "2685-array-unshift-reverse.ts": 3540, - "2685-fs-write-sync.ts": 2779, - "2686-fs-file-handle.ts": 3096, - "2687-fsp-write-file-options.ts": 2864, - "2687-process-write-args.ts": 2396, - "2688-fs-stats-disk-fields.ts": 3953, - "2689-http-server-timeout-properties.ts": 2717, - "2690-https-server-timeout-option.ts": 2702, - "2691-retained-lowering-record-order.ts": 2988, - "2692-inline-record-assert-index.ts": 2526, - "2692-string-accumulation.ts": 2081, - "2693-math-constants.ts": 1991, - "2700-array-sort-complexity.ts": 2921, - "2700-http-static-trailers.ts": 2864, - "2700-wasi-core.ts": 2423, - "2701-array-sort-snapshot.ts": 2953, - "2701-http-static-trailer-wire.ts": 4541, - "2701-import-meta/main.mjs": 2520, - "2702-http-static-trailer-end.ts": 2827, - "2702-type-import-link-static/main.ts": 2535, - "2702-uint8array-to-sorted.ts": 2284, - "2703-array-sparse-sort.ts": 4504, - "2703-type-import-link-static-reexport/main.ts": 3626, - "2704-array-sparse-to-sorted.ts": 4339, - "2704-type-import-link-static-success/main.ts": 2363, - "2705-array-sparse-sort-append.ts": 4401, - "2705-type-import-link-dynamic/main.ts": 1851, - "2706-array-search-missing-needle.ts": 2603, - "2706-type-import-link-dynamic-success/main.ts": 2413, - "2707-array-search-huge-sparse.ts": 45742, - "2707-type-import-link-static-default-reexport/main.ts": 2437, - "2708-type-import-link-dynamic/main.ts": 2892, - "2720-array-read-parity.ts": 3049, - "2721-array-nested-missing-receiver.ts": 2315, - "2750-array-sparse-foundation.ts": 3742, - "2751-buffer-concat-sparse-list.ts": 4185, - "2752-array-optional-stores.ts": 2347, - "2753-array-optional-method-values.ts": 3965, - "2754-array-property-undefined.ts": 2255, - "2755-array-optional-literal-forwarding.ts": 2583, - "2780-array-parity-composition.ts": 6251, - "2781-array-missing-value-escape.ts": 2554, - "2782-array-sparse-callbacks.ts": 3284, - "2783-array-defaults-rest.ts": 2724, - "2784-array-reduce-missing-result.ts": 2691, - "2785-array-missing-destructuring.ts": 2806, - "2786-array-sparse-serialization.ts": 2888, - "2787-array-missing-string-arithmetic.ts": 1877, - "2788-array-missing-builtin-conversions.ts": 1930, - "2789-array-missing-optional-tostring.ts": 1731, - "2790-dynamic-import-self-name/main.ts": 2308, - "2791-record-optional-keys.ts": 2478, - "2792-record-optional-spread-entries.ts": 2703, - "2793-union-conversion-identity-capture.ts": 1753, - "2794-array-generic-callback-values.ts": 2420, - "2795-array-optional-typedarray-source.ts": 1737, - "2796-array-sparse-class-value-instanceof.ts": 2296, - "2800-array-expression-consumers.ts": 2565, - "2801-array-switch-consumers.ts": 2471, - "2820-array-missing-method-receivers.ts": 2123, - "2821-array-optional-numeric-comparisons.ts": 2408, - "2830-cjs-require-self-name/main.cjs": 2633, - "2840-finally-completions.ts": 2505, - "2841-using-sync.ts": 2632, - "2842-await-using.ts": 1790, - "2843-using-suppressed-error.ts": 2235, - "2844-node-disposable-resources.ts": 2658, - "2845-for-using-of.ts": 4410, - "2846-generator-using.ts": 2392, - "2850-async-generators-protocol.ts": 3002, - "2851-async-generators-values.ts": 4379, - "2852-timers-promises-interval.ts": 2511, - "2854-leading-bom-literals.ts": 2528, - "2855-searchparams-sort-complexity.ts": 2416, - "2856-dynamic-any-local-operators.ts": 1839, - "2857-branded-primitives.ts": 1736, - "2858-import-meta-resolve/main.mjs": 2679, - "2859-import-meta-resolve-dynamic/main.mjs": 2295, - "2860-require-resolve/main.cjs": 2780, - "2861-readable-iterator-close.ts": 3207, - "2862-web-readable-async-iteration.ts": 3375, - "2863-class-async-iterator.ts": 2531, - "2864-array-class-method-receivers.ts": 1837, - "2865-cjs-process-alias.cjs": 2734, - "2866-dyn-switch.ts": 1772, - "2867-array-shift-length.js": 2411, - "2868-empty-record-promise-presence.js": 2531, - "2869-nullish-mixed-lazy.ts": 2433, - "2870-and-dropped-truthy-arm.ts": 2606, - "2871-optional-promise-to-unknown.ts": 2387, - "2872-unobserved-dynamic-event.ts": 2191, - "2873-optional-receiver-loop-lifetime.js": 2453, - "2874-nullable-callback-field-cycle.js": 2707, - "2875-evolving-let-read-before-write.js": 3668, - "2876-class-unknown-roundtrip.ts": 2817, - "2877-child-unknown-roundtrip.ts": 2660, - "2878-class-private-unknown.cjs": 4040, - "2880-cjs-module-graph/main.cjs": 2924, - "2890-crypto-static-utility.ts": 2261, - "2891-json-record-key-escapes.ts": 2705, - "2892-windows-console-unicode.ts": 2266, - "2893-child-stdin-duplex.ts": 3340, - "2894-child-stdin-backpressure.ts": 3131, - "2895-child-stdin-write-after-end.ts": 2384, - "2896-child-stdin-write-after-finish.ts": 2871, - "2897-child-stdin-destroy.ts": 2871, - "2898-child-stdin-spawn-failure.ts": 2549, - "2899-nested-mutual-recursion.ts": 2721, - "2900-float64array-static.ts": 2799, - "2900-void-conditional-arrow.ts": 2537, - "2901-bigint-core.ts": 2424, - "2902-bigint-bytes.ts": 2498, - "2903-bigint-storage.ts": 2708, - "2904-bigint-errors.ts": 2577, - "2905-bigint-edges.ts": 2439, - "2906-bigint-wasi-width.ts": 1786, - "2910-overloaded-callable-alias.ts": 2648, - "2911-execfile-callback.ts": 2191, - "2912-execfile-callback-options.ts": 2127, - "2912-promisify-fs-readfile.ts": 2460, - "2913-builtin-callable-alias.ts": 2481, - "2914-fixed-tuple-call-spread.ts": 2974, - "2915-path-function-values.ts": 2177, - "2916-path-function-values-cjs.ts": 2451, - "2917-builtin-callable-widths.ts": 2149, - "2918-builtin-callable-widths-cjs.ts": 2749, - "2919-fs-function-values.ts": 2635, - "2920-fs-promises-function-values.ts": 1999, - "2921-zlib-callbacks.ts": 2825, - "2922-dyn-bitwise-not.cjs": 2337, - "2923-cjs-factory-export/main.cjs": 2557, - "2930-union-receiver-calls.ts": 3403, - "2931-union-dynamic-field-call.js": 3002, - "2932-create-require-program/main.ts": 2467, - "2933-static-dynamic-import/main.ts": 2896, - "2934-static-import-stored.ts": 2404, - "2935-module-namespace-values/main.ts": 2608, - "2936-static-loose-equality.ts": 3140, - "2937-bitwise-hot-loop.ts": 2268, - "2938-fs-sync-overloads.cjs": 1857, - "2939-child-shell-text.ts": 3041, - "2940-date-parse.ts": 2483, - "2940-fsp-realpath.ts": 2587, - "2941-fsp-lstat-identity.ts": 2657, - "2941-process-exit-code.ts": 1743, - "2942-fsp-readdir-dirent.ts": 2911, - "2942-process-exit-code-override.ts": 1751, - "2943-process-exit-code-invalid.ts": 2583, - "2944-process-exit-code-wrap.ts": 2435, - "2945-url-origin-username.ts": 1863, - "2946-child-fork-ipc/main.ts": 3271, - "2946-url-port-hash.ts": 2587, - "2947-set-readonly-seeds.ts": 2456, - "2948-child-fork-eof-callback/main.ts": 3043, - "2948-stdio-callback-record.ts": 2421, - "2949-child-fork-default/main.mjs": 2736, - "2949-url-password.ts": 2744, - "2950-fs-descriptor-publication.ts": 2681, - "2951-math-static-analytic.ts": 3121, - "2952-math-static-remaining.ts": 2862, - "2953-http-header-validation.ts": 2956, - "2954-http-outgoing-headers.ts": 2822, - "2955-http-static-state.ts": 2955, - "2956-http-static-informational.ts": 3085, - "2957-http-static-response-controls.ts": 2273, - "2961-emitter-computed-names.cjs": 2632, - "2962-emitter-computed-optional.ts": 2051, - "2963-child-fork-dispatch/main.ts": 2809, - "2964-indexed-compound.ts": 2982, - "2966-numeric-array-read-fusion.ts": 2045, - "2967-numeric-array-read-lifetime.ts": 3048, - "2968-numeric-array-borrow.ts": 2914, - "2969-scalar-record-results.ts": 2620, - "2970-constant-numeric-tables.ts": 2078, - "2971-constant-table-modules/main.ts": 2587, - "2972-http-static-distinct-snapshots.ts": 2220, - "2972-math-receiver-borrow.ts": 3503, - "2973-http-static-agent.ts": 3163, - "2973-integer-bitwise-arithmetic.ts": 2756, - "2974-array-search-from-index.ts": 120636, - "2974-http-static-module-values.ts": 2696, - "2974-numeric-remainder.ts": 2784, - "2975-bigint-default-radix.ts": 1741, - "2975-http-static-client-controls.ts": 2204, - "2976-http-static-incoming-state.ts": 2949, - "2976-json-stringify-no-arguments.js": 2583, - "2977-http-static-incoming-timeout.ts": 2724, - "2977-nested-array-binding-defaults.js": 2760, - "2978-http-static-client-timeout.ts": 3060, - "2978-regexp-optional-subject.js": 2540, - "2979-array-search-mixed-needles.js": 2011, - "2979-http-static-server-timeout.ts": 2740, - "2980-http-static-server-timeout-default.ts": 2671, - "2980-string-position-arguments.js": 2246, - "2981-http-static-events.ts": 1817, - "2981-string-optional-positions.ts": 1836, - "2982-http-static-close-all.ts": 2421, - "2982-string-position-coercion-order.js": 3081, - "2983-http-static-close-idle.ts": 2006, - "2984-http-static-close-upgrade.ts": 2129, - "2985-http-static-message-destroy.ts": 2630, - "2986-http-static-client-socket-finish.ts": 1940, - "2987-http-static-timeout-errors.ts": 2737, - "2988-http-static-client-abort.ts": 2025, - "2989-http-static-response-timeout-handled.ts": 2928, - "2990-http-static-request-timeout-handled.ts": 2599, - "2991-array-indexed-equality.ts": 2993, - "2992-stream-rows.ts": 2556, - "2993-fiber-stack-lifetimes.ts": 3202, - "2994-fromcharcode-scalar.ts": 2833, - "2995-math-hyperbolic.ts": 2687, - "2996-math-near-one.ts": 2252, - "2997-math-integer-float.ts": 3190, - "300-if-else.ts": 2219, - "3001-caught-typeof-object.js": 2450, - "3002-promise-then-two.ts": 2484, - "301-while.ts": 2153, - "302-for.ts": 1918, - "3020-string-last-index-position.ts": 2434, - "3021-buffer-union-narrow-callback.ts": 2866, - "3022-string-affix-positions.ts": 2229, - "3023-string-affix-position-coercion.js": 3333, - "3024-string-number-narrow-for-in.ts": 2650, - "3025-string-search-position-coercion.js": 2447, - "3026-array-last-index-of.js": 2579, - "3027-array-last-index-of-records.ts": 2304, - "3028-string-search-dynamic-needle.js": 2564, - "3029-string-search-union-needle.js": 1657, - "303-break-continue.ts": 2442, - "3030-array-search-no-arg.js": 3027, - "3031-array-relative-index-coercion.js": 2940, - "3031-string-last-index-search-value.js": 2407, - "3032-string-search-value.js": 2579, - "3033-string-search-needle-coercion.js": 2232, - "3034-arguments-with-parameters.js": 2126, - "3035-string-positioned-search-value.js": 2449, - "3036-string-object-search-value.js": 1849, - "3037-number-nullish-conversion.js": 2478, - "3038-number-scalar-unions.ts": 1881, - "3039-string-repeat-count.js": 2372, - "304-compound-incdec.ts": 2266, - "3040-string-prototype-call.js": 2389, - "3041-string-prototype-object-call.js": 2679, - "3042-string-padding-coercion.js": 2923, - "3043-string-split-arguments.js": 3247, - "3044-array-slice-splice-positions.js": 2966, - "3045-array-indexed-mutation.js": 2960, - "3046-array-indexed-ref-identity.ts": 2358, - "3047-object-prototype-tag.js": 2265, - "3048-object-own-prototype.ts": 3162, - "3049-array-flat-depth.ts": 2904, - "305-truthiness.ts": 2588, - "3050-array-splice-insert.ts": 2779, - "3051-array-join-default.ts": 2220, - "3052-array-construction.ts": 2520, - "3053-array-construction-js.js": 2821, - "3054-dynamic-abort-record.ts": 2818, - "3055-default-builtin-nodenext/main.ts": 2044, - "3056-default-builtin-bundler/main.ts": 2874, - "3057-default-builtin-nodenext-dynamic/main.ts": 1912, - "3058-optional-array-chain-join.ts": 2986, - "3059-arguments-property-names.ts": 1856, - "3061-concurrent-fiber-stacks.ts": 2766, - "3062-runtime-optional-record-guards.ts": 3210, - "3063-runtime-optional-class-guards.ts": 2677, - "3064-installed-entry-imports/main.ts": 1867, - "3065-installed-entry-js/main.js": 2294, - "3066-source-debugging/main.ts": 2276, - "3067-cjs-function-export-require/main.cjs": 1963, - "3068-debug-variables/main.ts": 2578, - "3068-url-checked-identity.ts": 2207, - "3069-set-checked-seed.js": 2608, - "3069-tuple-spread.ts": 2969, - "3070-checked-object-accessors.js": 2496, - "3070-collection-views.ts": 2799, - "3071-checked-specialization-narrowing.js": 2715, - "3071-map-contextual-record-seeds.ts": 3095, - "3072-optional-union-receivers.ts": 2303, - "3072-weak-process-streams.js": 2885, - "3073-optional-callable-module.js": 2520, - "3073-union-keyed-reads.ts": 2905, - "3074-discriminated-intersections.ts": 2460, - "3075-recursive-contextual-literals.ts": 3335, - "3076-nullish-record-defaults.ts": 2894, - "3077-optional-union-array-reads.ts": 2500, - "3078-forward-mutable-captures.ts": 3097, - "3079-forward-mutable-tdz.ts": 2796, - "3080-exhaustive-never-bindings.ts": 2704, - "3081-recursive-array-destinations.ts": 2667, - "3082-forward-write-unwind.ts": 2538, - "3083-set-string-seed.ts": 2595, - "3084-record-own-membership.ts": 2879, - "3085-conditional-record-construction.ts": 2874, - "3086-error-constructor-options.ts": 2970, - "3087-error-options-lifetime.ts": 2675, - "3088-array-wide-callbacks.ts": 2690, - "3089-array-find-narrowing.ts": 2833, - "3090-json-discriminated-records.ts": 3066, - "3091-json-recursive-discriminants.ts": 2220, - "3092-number-union-predicates.ts": 2324, - "3093-error-option-data.ts": 2104, - "3094-json-replacer-traversal.ts": 2818, - "3095-json-reviver-traversal.ts": 2804, - "3096-json-callback-nonfinite.ts": 2753, - "3097-json-callback-reentrancy.ts": 2198, - "3098-json-callback-space.ts": 2839, - "3099-json-callback-functions.ts": 3102, - "3100-json-callback-holder.js": 2748, - "3101-json-callback-bytes.ts": 2087, - "3102-json-unknown-fields.ts": 2238, - "3103-scalar-record-nested-control-flow.ts": 2806, - "3104-native-analysis-tables-loops.ts": 2680, - "3105-nullable-collections.ts": 2913, - "3106-mixed-insertion-spreads.ts": 3159, - "3107-nullable-collection-lifetimes.ts": 3025, - "3108-for-await-sync-arrays.js": 3537, - "3108-identity-map-keys.ts": 3249, - "3109-destructuring-unknown-defaults.js": 2565, - "3109-identity-union-collections.ts": 3588, - "3110-builtin-error-families.ts": 2812, - "3110-identity-collection-mutation.ts": 2831, - "3111-identity-collection-cycles.ts": 2915, - "3112-union-switch-control-flow.ts": 2075, - "3113-union-array-removal.ts": 3111, - "3114-union-record-field-write.ts": 2886, - "3115-zlib-static-compression-levels.ts": 2667, - "3116-sequence-expression-lifetimes.ts": 2953, - "3117-unknown-switch-control-flow.ts": 2388, - "3118-recursive-union-spread.ts": 3091, - "3119-runtime-optional-spread.ts": 3563, - "3120-dynamic-property-descriptors.js": 2806, - "3120-generator-method-loop-bindings.ts": 2970, - "3120-ir-nonfinite-numbers.ts": 2756, - "3121-compound-assignment-values.js": 2784, - "3121-dynamic-accessor-descriptors.js": 2889, - "3122-dynamic-delete-descriptors.cjs": 2435, - "3122-dynamic-delete-descriptors.js": 2554, - "3122-js-async-class-methods.js": 2294, - "3123-destructured-global-tdz.js": 2755, - "3124-array-prototype-borrow.js": 2322, - "3125-regex-global-match.ts": 2783, - "3126-js-number-radix/main.ts": 2820, - "3127-spawn-runtime-options.ts": 3072, - "3128-regex-last-index.ts": 1823, - "3129-js-token-union/main.ts": 2769, - "3130-child-generic-streams.ts": 2981, - "3131-child-rest-listeners.js": 2627, - "3132-child-generic-stream-completion.ts": 5669, - "3133-text-decoder-streaming.ts": 2916, - "3134-fs-vectors.ts": 2782, - "3135-fs-file-handle-controls.ts": 3077, - "3136-fs-file-handle-options.ts": 3203, - "3137-fs-vector-callbacks.cjs": 3063, - "3138-array-large-storage.ts": 4112, - "3139-regex-native-deep-alternatives.ts": 26910, - "3140-array-dense-access.ts": 3431, - "3141-map-string-key-hash.ts": 3132, - "3150-integer-remainder.ts": 3203, - "3151-array-push-writes.ts": 3025, - "3170-number-conversion-fast-paths.ts": 2101, - "3171-method-census-data-writes.ts": 3216, - "400-fib.ts": 2634, - "401-mutual-recursion.ts": 2541, - "402-string-functions.ts": 2183, - "403-void-and-params.ts": 2239, - "4030-runtime-object-truthiness.ts": 2407, - "4031-event-emitter-long-tuples.ts": 2624, - "4032-inline-rc-fast-paths.ts": 3924, - "404-rc-stress.ts": 2608, - "4040-adapted-function-identity.ts": 3296, - "4041-adapted-function-properties.ts": 2613, - "4042-object-is-union-subclass.ts": 2694, - "4043-nonnull-missing-element.ts": 2672, - "4044-adapted-callback-modules/main.ts": 2828, - "4045-optional-element-projections.ts": 2963, - "4046-captured-parameter-values.ts": 3070, - "4047-captured-parameter-rebinding.ts": 2848, - "405-params-optional.ts": 1924, - "406-params-defaults.ts": 1978, - "4060-cycle-shared-instance/main.ts": 2198, - "4060-stack-union-reads.ts": 3362, - "4061-cycle-evaluation-order/main.ts": 2399, - "4061-nullable-ref-fields.ts": 4246, - "4062-cycle-tdz-read/main.ts": 2254, - "4063-cycle-hoisted-calls/main.ts": 2402, - "4064-cycle-classes-after-init/main.ts": 2048, - "4065-cycle-init-throws/main.ts": 2640, - "4066-cycle-top-level-tdz/main.ts": 2245, - "4067-dynamic-import-cycle-tdz/main.ts": 2515, - "407-params-rest.ts": 2698, - "408-params-ctors-inheritance.ts": 2092, - "4080-optional-read-presence-tests.ts": 2936, - "4080-string-index-bounds.ts": 2863, - "4081-hoisted-function-tdz.ts": 2788, - "4081-string-index-unproven.ts": 2335, - "4082-hoisted-function-tdz-uncaught.ts": 1949, - "4083-dynamic-import-failure/main.ts": 2717, - "4084-record-optional-field-copies.ts": 2527, - "4085-generator-loop-close.ts": 2591, - "4086-optional-capture-defaults.ts": 2395, - "4088-class-static-tdz.ts": 2363, - "4089-class-wrapper-tdz.js": 2402, - "409-params-async-generics.ts": 2098, - "4090-computed-key-tdz.js": 2605, - "4091-class-evaluation-deferred.ts": 2199, - "410-params-rc-stress.ts": 2565, - "4140-array-callback-split-visit.ts": 4386, - "4141-array-callback-ambient-receiver/main.ts": 2299, - "4142-array-callback-factories.ts": 3208, - "4143-union-refinement-intersection-arms.ts": 2685, - "420-dead-strip-modules/main.ts": 2527, - "4290-acyclic-immutable-trees.ts": 3246, - "4291-acyclic-constructor-escapes.ts": 2909, - "4292-acyclic-readonly-bypass.ts": 3024, - "4293-acyclic-dynamic-writes.ts": 2956, - "4294-console-line-sizes.ts": 5873, - "4295-console-template-parts.ts": 2597, - "4296-console-glued-long-parts.ts": 2868, - "4410-inline-object-allocation.ts": 3093, - "4411-nullable-ref-values.ts": 4434, - "4412-nullable-record-values.ts": 3635, - "4413-cycle-old-late-death.ts": 2102, - "4413-nullable-null-and-undefined.ts": 2783, - "4414-cycle-old-weak-keys.ts": 2960, - "4414-nullable-string-values.ts": 3874, - "4415-identity-borrowed-operands.ts": 2087, - "4415-nullable-container-values.ts": 3581, - "4431-exception-pending-contexts.ts": 3035, - "4432-checked-downcast-failures.ts": 3246, - "4451-int32-field-storage.ts": 3457, - "4452-int32-field-dynamic-writes.ts": 3861, - "4453-int32-closed-locals.ts": 2280, - "4471-unassigned-field-reads.ts": 3309, - "4476-string-ascii-header-fact.ts": 2846, - "4477-buffer-write-ascii-runs.ts": 2125, - "4478-string-large-index-reads.ts": 3334, - "4481-array-optional-push.ts": 3059, - "4482-instanceof-static-class-optional.ts": 2994, - "4483-array-splice-statement.ts": 3331, - "4484-array-length-reset.ts": 2664, - "4485-array-splice-optional-item.ts": 2526, - "4486-array-field-element-borrows.ts": 2341, - "4487-array-literal-optional-values.ts": 2248, - "4520-optional-guard-narrowing.ts": 2281, - "4521-array-callback-element-presence.ts": 4131, - "4522-captured-parameter-lifetimes.ts": 2903, - "4523-array-pop-removal.ts": 2536, - "4524-array-callback-supertype-params.ts": 3251, - "4541-nullable-wrap-borrows.ts": 2882, - "4542-preserving-call-borrows.ts": 3130, - "4543-walk-borrowed-locals.ts": 3034, - "4544-checked-cast-aliases.ts": 2574, - "4545-borrowed-returns.ts": 3551, - "4546-rebound-borrowed-params.ts": 2811, - "4560-field-store-borrowed-receivers.ts": 3116, - "4561-virtual-borrowed-parameters.ts": 3237, - "4562-string-self-concat-move.ts": 2061, - "4563-array-read-projection-receivers.ts": 2512, - "4564-literal-choice-strings.ts": 2795, - "4568-for-of-hole-elements.ts": 2661, - "4569-shorthand-missing-elements.ts": 3064, - "4570-map-lookup-default-record.ts": 2901, - "4591-weak-keys-union-records.ts": 2778, - "4592-cycle-const-from-import/main.ts": 2529, - "4593-weak-keys-empty-objects.ts": 2806, - "4594-union-class-field-mixed-types.ts": 3153, - "4595-union-class-field-optional-receiver.ts": 1997, - "4596-error-subclass-int-fields.ts": 2606, - "4596-tdz-nullable-forward-capture.ts": 3433, - "4597-callback-field-method-name.ts": 2519, - "4598-live-array-ref-element-access.ts": 4363, - "4598-map-set-clear-reuse.ts": 4118, - "4598-os-available-parallelism.ts": 2474, - "4598-publish-constructor-stores.ts": 2635, - "4599-construction-only-field-borrows.ts": 3147, - "4600-construction-only-fields-dynamic-writes.ts": 2319, - "4601-cycle-holders.ts": 2904, - "4602-constructor-escape-order.ts": 2703, - "4610-array-ext-dyn-refresh.ts": 3049, - "4620-optional-chain-borrowed-receivers.ts": 3006, - "4621-edge-preserving-callees/main.ts": 2464, - "4630-contract-int32.ts": 2586, - "4630-reference-write-call-arguments.ts": 2892, - "4631-contract-nothrow.ts": 2842, - "4631-reference-write-aliases.ts": 2922, - "4632-contract-immutable.ts": 2582, - "4632-reference-write-loops-and-walks.ts": 2399, - "4633-contract-program-lifetime.ts": 3449, - "4633-reference-write-callbacks-returns.ts": 2678, - "4634-contract-program-lifetime-publish.ts": 4573, - "4634-optional-element-borrowed-returns.ts": 2111, - "4640-bitwise-identity-ranges.ts": 2671, - "4641-nothrow-try-catch.ts": 2141, - "4642-acyclic-contract.ts": 2859, - "4650-stale-property-narrowing.ts": 2759, - "4651-map-string-get-entry.ts": 3114, - "4652-stale-closure-binding-narrowing.ts": 3092, - "4660-typed-rest-spread-forwarding.ts": 2331, - "4671-scoped-array-read-borrows.ts": 2575, - "4690-cycle-bypass-long-lived.ts": 4228, - "4691-publish-constructor-self-alias.ts": 2964, - "4692-borrowed-result-mutating-callees.ts": 2766, - "4720-cold-throw-paths.ts": 3228, - "4721-integer-induction-numbers.ts": 2974, - "4730-touint32-large-magnitudes.ts": 2198, - "4731-string-mixed-ascii-slices.ts": 3160, - "4732-buffer-write-utf16le-runs.ts": 3120, - "4733-typed-array-read-compares.ts": 2977, - "4750-map-string-absent-filter.ts": 3464, - "4751-string-search-multibyte-needles.ts": 2454, - "4795-published-untyped-member-reads.ts": 3340, - "4806-uint32-loop-accumulators.ts": 2740, - "4810-union-identity-retags.ts": 4045, - "4811-union-retag-checked-cast.ts": 2819, - "4812-int32-wrapping-sums.ts": 3339, - "4813-typed-array-read-equality-bindings.ts": 3997, - "4820-sort-comparator-lent-arguments.ts": 2782, - "4821-callback-lent-arguments.ts": 3485, - "4822-stable-capture-reads.ts": 2483, - "4823-array-store-receivers.ts": 2858, - "4830-typed-teardown-chains.ts": 3292, - "4831-cycle-bypass-probe-windows.ts": 3738, - "4840-array-hole-free-prefix.ts": 3550, - "4860-int32-local-storage.ts": 3699, - "4870-array-pipeline-fusion.ts": 6694, - "4871-array-pipeline-analytics.ts": 4274, - "4872-array-pipeline-temporaries.ts": 7763, - "4875-stream-consumers-array-buffer.ts": 3017, - "4876-array-buffer-inspect.ts": 2569, - "4880-await-call-turn-order.ts": 2784, - "4881-await-call-exceptions.ts": 2757, - "4882-await-call-request-chain.ts": 2151, - "4883-await-values-and-hops.ts": 2520, - "4884-await-call-unhandled-sibling.ts": 2379, - "4885-await-call-checkpoints.ts": 2128, - "4890-regex-literal-sites.ts": 3484, - "4891-regex-plain-text-patterns.ts": 2502, - "4892-regex-exec-read-captures.ts": 3120, - "4900-bigint-division-cross-check.ts": 3532, - "4900-console-instances.ts": 3723, - "4901-bigint-radix-text.ts": 3090, - "4901-console-instance-errors.ts": 3055, - "4902-bigint-compound-assign.ts": 2449, - "4903-bigint-fixed-width.ts": 2818, - "4904-bigint-large-products.ts": 2953, - "4905-bigint-fixed-width-fusion.ts": 3047, - "4906-bigint-small-value-trees.ts": 3132, - "4907-bigint-random-trees.ts": 4068, - "4910-hole-free-prefix-upkeep.ts": 3149, - "4920-string-literal-switch.ts": 4588, - "4930-typed-record-reflection.ts": 4183, - "4931-typed-data-generic-walks.ts": 4062, - "4932-typed-json-unknown.ts": 3239, - "4940-async-return-adoption.ts": 2845, - "4941-async-return-adoption-try.ts": 3156, - "4942-async-return-adoption-values.ts": 3620, - "4943-async-return-adoption-interleaved.ts": 2831, - "4950-regex-compiled-captures.ts": 5723, - "4951-regex-compiled-last-index.ts": 3059, - "4952-regex-compiled-anchors-classes.ts": 2426, - "4953-regex-compiled-backtracking.ts": 3365, - "4954-regex-log-report.ts": 3193, - "4955-regex-compiled-differential.ts": 24862, - "4970-int32-call-abi.ts": 2508, - "4980-generator-early-exit-finally.ts": 2836, - "4981-generator-delegation-iterables.ts": 4874, - "4982-generator-sent-values.ts": 2242, - "4983-generator-reuse-iterables.ts": 3066, - "4984-generator-exceptions.ts": 2959, - "4985-generator-lazy-pipeline.ts": 2708, - "4986-generator-default-channels.ts": 3119, - "4987-generator-closures-methods.ts": 2675, - "4988-generator-async-interplay.ts": 2141, - "4989-generator-step-drives.ts": 4185, - "4990-lone-surrogates.ts": 3319, - "4991-lone-surrogate-halves.ts": 2978, - "4992-lone-surrogate-search.ts": 2759, - "4993-lone-surrogate-json.ts": 2994, - "4994-lone-surrogate-uri.ts": 2786, - "4995-lone-surrogate-regex.ts": 3169, - "4996-lone-surrogate-stdio.ts": 2201, - "4997-lone-surrogate-stdout-patch.js": 2754, - "4998-lone-surrogate-buffers.ts": 3060, - "4999-lone-surrogate-io.ts": 4219, - "500-array-basics.ts": 2646, - "501-array-push-pop.ts": 2128, - "5010-lifetime-region-generations.ts": 2950, - "5011-lifetime-region-outside-references.ts": 2816, - "5012-lifetime-region-shapes.ts": 3847, - "5013-lifetime-region-async.ts": 3198, - "5014-lifetime-region-nesting.ts": 2741, - "5015-lifetime-region-publish.ts": 2749, - "5016-lifetime-region-weak-keys.ts": 2541, - "5017-lifetime-region-cycles.ts": 2989, - "5018-lifetime-region-hierarchies.ts": 3642, - "5019-lifetime-region-values.ts": 2516, - "502-array-for-of.ts": 2614, - "5020-lifetime-region-large.ts": 3840, - "5021-lifetime-region-opaque-holders.ts": 2702, - "5022-lifetime-region-workers.ts": 3127, - "503-array-functions.ts": 2610, - "504-array-rc-stress.ts": 2247, - "5040-promise-all-race-turns.ts": 3415, - "5041-promise-all-turns.js": 5156, - "5042-async-generator-return-promise.ts": 3112, - "5043-async-generator-return-forms.ts": 3029, - "5045-generator-delegation-typed-next.ts": 3463, - "5046-generator-delegation-return-throw.ts": 2606, - "5047-generator-delegation-iterables-typed.ts": 4378, - "5048-generator-delegation-async.ts": 4885, - "5049-generator-delegation-edges.ts": 2538, - "5050-inherited-in-membership.ts": 3142, - "5051-typed-record-prototypes.ts": 3140, - "5052-class-for-in-unknown.ts": 2653, - "5053-json-replacer-arrays.ts": 4713, - "5054-required-field-delete.ts": 2632, - "5055-object-create-record-literal.ts": 2065, - "5056-generator-in-unknown.ts": 3903, - "5060-child-fork-exit-after-messages/main.ts": 2572, - "5061-child-fork-local-disconnect/main.ts": 3248, - "5062-child-fork-message-before-eof/main.ts": 4732, - "5065-global-increment-initializers.ts": 3985, - "5066-global-compound-updates.ts": 2635, - "5067-global-updates-in-functions.ts": 2589, - "5068-global-var-let-const-updates.ts": 2726, - "5069-global-update-modules/main.ts": 2372, - "5070-optional-read-bindings.ts": 2144, - "5071-optional-chain-scalars.ts": 2192, - "5072-optional-nullish-ternary.ts": 2587, - "5073-optional-results.ts": 2727, - "5074-optional-pop-shift.ts": 2568, - "5075-optional-reads-unchecked/main.ts": 4996, - "5076-optional-escapes.ts": 2735, - "5080-boolean-array-storage.ts": 5236, - "5081-boolean-array-dynamic-views.ts": 2815, - "5085-promise-allsettled-turns.ts": 3332, - "5086-promise-any-turns.ts": 3297, - "5087-promise-allsettled-any-dyn.js": 3767, - "5088-promise-combinator-thenables.js": 4248, - "5089-promise-settled-records.ts": 3528, - "5090-generator-finished-result-value.ts": 2964, - "5091-generator-delegation-arrays-strings.ts": 2768, - "5092-generator-delegation-sets-maps.ts": 3565, - "5095-console-count-group.ts": 2753, - "5096-console-assert-dir.ts": 4648, - "5097-console-table.ts": 2620, - "5098-console-time-warnings.ts": 6302, - "5099-console-methods-dynamic.cjs": 2644, - "510-array-map-filter-foreach.ts": 2991, - "511-array-indexof-includes.ts": 2657, - "5110-var-hoisting-early-reads.ts": 2806, - "5111-var-hoisting-closures-classes.ts": 2117, - "5112-var-hoisting-function-scope.ts": 2614, - "5113-tdz-let-const-class.ts": 3154, - "5114-var-hoisting-js.js": 4536, - "5115-regex-replace-compiled.ts": 2608, - "5116-regex-capture-reads.ts": 3064, - "5117-regex-log-report-spans.ts": 3404, - "5118-regex-replace-char-chains.ts": 2444, - "512-array-join-chains.ts": 2376, - "5120-frame-records.ts": 2615, - "5121-frame-objects.ts": 2616, - "5122-frame-result-slots.ts": 2622, - "5123-frame-reassigned.ts": 2564, - "5124-frame-objects-control.ts": 3061, - "5125-frame-mutating-methods.ts": 2527, - "5126-frame-returned-params.ts": 2697, - "5127-frame-loop-bindings.ts": 2824, - "513-array-methods-rc-stress.ts": 2641, - "5130-event-target-dispatch.js": 3752, - "5131-event-target-listener-errors.js": 3003, - "5132-event-target-typed.ts": 3341, - "5133-abort-signal-event-target.ts": 3302, - "5134-events-error-monitor.ts": 2664, - "5135-event-target-warnings.js": 2890, - "5136-events-error-monitor-string-name.ts": 2380, - "5137-events-error-monitor-computed-name.js": 3077, - "5138-events-error-monitor-shared-listener.ts": 2001, - "5139-event-target-listener-throw.ts": 1965, - "514-array-find-some-every.ts": 2998, - "5140-os-host-facts.ts": 3248, - "5141-os-constants.ts": 2402, - "5142-path-parse-format.ts": 2850, - "5145-path-matches-glob-basics.ts": 2904, - "5146-path-matches-glob-braces.ts": 4866, - "5147-path-matches-glob-extglob.ts": 2653, - "5148-path-matches-glob-classes.ts": 2765, - "5149-path-matches-glob-win32.ts": 2754, - "515-array-flatmap.ts": 3015, - "5150-small-array-inline-slots.ts": 3276, - "5155-cycle-header-types.ts": 3561, - "516-array-reduce.ts": 3293, - "5160-field-callback-receiver.ts": 3482, - "5161-field-callback-receiver-escape.ts": 2665, - "5162-field-method-reference-receiver.ts": 2779, - "5163-field-callback-receiver.cjs": 2875, - "5164-worker-field-callback-receiver.ts": 3147, - "5165-interface-method-dispatch.ts": 2641, - "5166-interface-method-values.ts": 4036, - "5167-interface-method-order.ts": 3679, - "5168-interface-method-hierarchy.ts": 4400, - "5169-interface-method-chains.ts": 2934, - "517-array-hof-index-args.ts": 2918, - "5170-string-scan-eviction.ts": 2885, - "5171-lone-surrogate-replace-seams.ts": 3463, - "5175-forin-typed-as-unknown.ts": 3333, - "5176-object-keys-typed-as-unknown.ts": 3148, - "5177-forin-dynamic-objects.ts": 2926, - "5178-forin-keys-js.js": 2135, - "5179-forin-typed-shapes.ts": 3197, - "518-array-sort.ts": 2699, - "518-promise-void-union-callbacks.ts": 1929, - "5180-interface-arrays.ts": 3267, - "5181-interface-array-methods.ts": 7443, - "5182-interface-array-boundaries.ts": 3225, - "5183-interface-property-reads.ts": 3018, - "5184-interface-property-objects.ts": 3161, - "5185-util-inherits.cjs": 3120, - "5186-util-inherits.ts": 3012, - "5187-util-deprecate.cjs": 3705, - "5188-util-deprecate-flags.cjs": 2866, - "5189-util-deprecate.ts": 2361, - "519-array-from-length.ts": 3817, - "519-promise-union-await-values.ts": 2296, - "5190-util-callbackify.cjs": 3512, - "5191-util-callbackify.ts": 2893, - "5192-util-debuglog.cjs": 3224, - "5193-util-debuglog.ts": 4346, - "5194-process-emit-warning-tick.cjs": 2199, - "5195-object-entries-typed-as-unknown.ts": 2787, - "5196-object-values-typed-as-unknown.ts": 2984, - "5197-object-entries-dynamic-objects.ts": 3371, - "5198-object-entries-values-js.js": 2819, - "5199-object-entries-identity.ts": 3133, - "520-map-basics.ts": 2629, - "5200-array-sort-keyed-numbers.ts": 3636, - "5201-array-sort-keyed-records.ts": 3559, - "5202-array-sort-keyed-lookalikes.ts": 3148, - "5203-typed-array-sort-default.ts": 6169, - "5204-typed-array-sort-comparators.ts": 4152, - "521-map-number-keys.ts": 2529, - "5210-process-memory-usage.ts": 3044, - "5211-process-identity.ts": 2815, - "5212-perf-marks-measures.ts": 2925, - "5213-perf-timing-errors.ts": 3203, - "5214-perf-entry-inspect.ts": 3164, - "5215-perf-timing-validation.js": 4384, - "5216-perf-spread-arguments.js": 3711, - "5217-perf-spread-typed.ts": 3324, - "522-map-foreach.ts": 2813, - "5220-url-parse-warnings.ts": 2906, - "5221-url-parse-shapes.ts": 2400, - "5222-url-parse-hosts.ts": 2972, - "5223-url-parse-query.ts": 2190, - "5224-url-format-objects.ts": 2681, - "5225-url-format-whatwg.ts": 2885, - "5226-url-resolve.ts": 2184, - "5227-url-legacy-dependency/main.ts": 3291, - "5228-url-domain-conversion.ts": 2624, - "5229-url-legacy-errors.cjs": 3698, - "523-map-ref-values.ts": 2904, - "5230-inline-union-fields.ts": 2318, - "5231-inline-union-field-kinds.ts": 3614, - "5232-inline-union-fields-dynamic.ts": 3502, - "5233-inline-union-fields-shapes.ts": 3338, - "5234-inline-union-class-fields.ts": 4285, - "5235-inline-union-fields-publish.ts": 2840, - "5236-inline-union-unchecked-reads.ts": 1998, - "5237-inline-union-frame-objects.ts": 2284, - "524-map-cycles.ts": 3272, - "5240-event-target-subclass.ts": 3668, - "5241-event-subclass.ts": 4201, - "5242-event-target-subclass-hierarchy.ts": 2218, - "5243-event-target-subclass-dynamic.ts": 2613, - "5244-event-target-subclass.js": 3715, - "5245-event-target-subclass-signals.ts": 3077, - "5246-event-target-subclass-listener-throw.ts": 2770, - "5247-event-target-subclass-lifetimes.ts": 3603, - "5248-event-target-subclass-warnings.ts": 2743, - "5249-event-target-subclass-unconstructed.ts": 1632, - "525-map-rc-stress.ts": 3853, - "526-set-basics.ts": 1919, - "5260-record-unknown-identity.ts": 2937, - "5261-optional-field-identity.ts": 2860, - "5262-record-unknown-many.ts": 2984, - "527-set-foreach.ts": 3210, - "5270-url-parse-no-deprecation.cjs": 3158, - "5271-url-parse-throw-deprecation.cjs": 2975, - "5275-http-end-callback-order.ts": 2389, - "5276-style-text-hex-colors.cjs": 2820, - "5277-fs-read-file-buffer-option.cjs": 2710, - "5278-host-null-bytes.cjs": 2114, - "5279-search-params-null-init.cjs": 1781, - "528-set-seeded.ts": 2610, - "5285-blob-construct.ts": 2681, - "5286-blob-readers.ts": 3079, - "5287-blob-inspect.ts": 3817, - "5288-blob-validation.js": 3803, - "5289-blob-read-order.ts": 2829, - "529-map-seeded.ts": 2574, - "5290-blob-dynamic.js": 2354, - "5295-readline-promises-question.ts": 3709, - "5296-readline-lines.ts": 2760, - "5297-readline-callback-events.cjs": 2472, - "5298-readline-abort.cjs": 2757, - "5299-readline-stdin.ts": 3087, - "530-record-arrays.ts": 2787, - "5300-stream-add-abort-signal.ts": 3027, - "5301-stream-add-abort-signal-errors.cjs": 2717, - "5302-stream-promises-options.ts": 3120, - "5303-stream-finished-callback-opts.cjs": 2705, - "5305-json-stringify-typed-arrays.ts": 3153, - "531-record-array-hofs.ts": 2832, - "5315-map-iterate-after-front-deletes.ts": 3911, - "5316-map-lru-eviction.ts": 2782, - "5317-map-iterate-while-mutating.ts": 2769, - "5318-set-iterate-after-deletes.ts": 2291, - "5319-map-iteration-values.ts": 2689, - "532-record-arrays-rc-stress.ts": 2437, - "5320-map-iterate-across-compaction.ts": 3526, - "5325-record-boundary-returns.ts": 1763, - "5326-record-boundary-params.ts": 2634, - "5327-record-boundary-identity.ts": 2323, - "5328-record-boundary-open.ts": 2561, - "5329-record-boundary-recursion.ts": 2680, - "533-array-element-cycles.ts": 2932, - "5330-record-boundary-fields.ts": 1977, - "5331-record-boundary-methods.ts": 3130, - "5333-record-boundary-nullable-argument.ts": 3012, - "5334-fetch-mentions-without-calls.ts": 2532, - "5335-top-level-await-pending-exit-code.ts": 1919, - "5336-top-level-await-pending-exit-listener.ts": 3734, - "5337-dc-subscriber-throw-next-tick.cjs": 2604, - "5338-js-tdz-function-element.js": 2562, - "5339-array-buffer-constructor.js": 2502, - "534-record-width-subtyping.ts": 2615, - "5345-object-values-for-of-unknown.ts": 3008, - "5346-object-values-length-dynamic.ts": 3055, - "5347-object-values-loop-control.ts": 3030, - "5348-object-values-for-of-js.js": 2732, - "5349-object-entries-values-optional.ts": 2083, - "535-object-statics.ts": 2312, - "5350-object-values-wide-record.ts": 2790, - "5351-object-values-methods-index.ts": 3275, - "536-map-seed-array.ts": 2712, - "5360-array-sort-comparator-calls.ts": 3175, - "5361-array-sort-inconsistent-comparators.ts": 3161, - "5362-array-sort-comparator-throws.ts": 2896, - "5363-array-sort-comparator-writes.ts": 6813, - "5364-array-sort-union-and-boolean-elements.ts": 8514, - "5365-array-sort-dynamic-values.js": 2402, - "537-map-iter-drains.ts": 2867, - "538-map-set-for-of.ts": 2756, - "5390-interface-loop-element-lifetimes.ts": 2999, - "5391-interface-dispatch-hierarchies.ts": 3168, - "5392-interface-receiver-bindings.ts": 2015, - "5393-interface-array-holes.ts": 2530, - "5394-interface-implementers.ts": 2992, - "5395-locale-compare-ascii.ts": 3026, - "5396-locale-compare-latin.ts": 3119, - "5397-locale-compare-sorting.ts": 3179, - "540-tuples-basics.ts": 2776, - "5400-json-parse-typed-keys.ts": 3131, - "5405-buffer-arraybuffer-window.ts": 2729, - "5406-util-types-keys.ts": 2747, - "5407-http-header-field-limit.ts": 2785, - "5408-http-unread-request-end.ts": 3226, - "5409-http-held-request-body.ts": 3218, - "541-ref-array-json.ts": 3099, - "5410-inspect-class-values.ts": 1875, - "5411-inspect-class-hierarchies.ts": 2712, - "5412-inspect-dynamic-collections.ts": 2792, - "5413-inspect-class-values.cjs": 3020, - "542-union-element-arrays.ts": 2846, - "5430-dyn-number-string-boxes.ts": 3059, - "5435-crypto-hash-algorithms.ts": 2030, - "5436-crypto-hash-names.js": 2098, - "5437-crypto-hmac-algorithms.ts": 2699, - "5438-crypto-kdf-digests.ts": 2741, - "5439-crypto-kdf-callbacks.js": 2685, - "5440-crypto-hash-encodings.js": 4004, - "5441-crypto-hash-output-length.ts": 3671, - "5442-crypto-random-values.ts": 3947, - "5443-crypto-random-arguments.js": 3548, - "5444-crypto-timing-safe-equal.js": 3213, - "5445-crypto-secret-key-objects.ts": 3869, - "5445-stream-buffer-chunks.ts": 2881, - "5446-crypto-secret-key-errors.js": 3035, - "5446-stream-buffer-chunks-dynamic.js": 2859, - "5447-fs-readdir-order.ts": 2639, - "5448-fs-glob-patterns.ts": 2837, - "5449-fs-glob-options.ts": 3025, - "5450-fs-glob-validation.js": 3327, - "5451-fs-promises-glob.ts": 3059, - "5452-fs-glob-callback.ts": 2936, - "5455-power-of-two-remainder.ts": 2837, - "5456-remainder-large-integer-dividends.ts": 2786, - "5457-lcg-modulus.ts": 1426, - "5458-fractional-remainder.ts": 1394, - "5460-locale-compare-contractions.ts": 2979, - "5461-locale-compare-equivalents.ts": 2661, - "5462-locale-compare-probe-sweep.ts": 3400, - "5463-locale-compare-combining-letters.ts": 2733, - "5464-locale-compare-fractions.ts": 2833, - "5470-strip-vt-osc.cjs": 2497, - "5471-strip-vt-csi.cjs": 2651, - "5472-strip-vt-random.cjs": 2375, - "5473-strip-vt-unterminated.cjs": 3521, - "5474-strip-vt-surrogates.ts": 2534, - "5540-fs-callback-forms.cjs": 3233, - "5541-fs-stats-fields.cjs": 3564, - "5542-fs-promises-parity.cjs": 3940, - "5543-fs-promises-typed.ts": 1655, - "5544-fs-opendir.cjs": 3024, - "5545-fs-options-encoding.cjs": 2994, - "5548-fs-callback-arguments.cjs": 4041, - "5549-fs-callback-option-checks.cjs": 3738, - "5550-locale-compare-ascii-words.ts": 2509, - "5551-array-search-references.ts": 3475, - "5552-string-appends.ts": 2703, - "5553-string-append-char-code.ts": 2870, - "5565-fs-dirent-untyped.mjs": 2600, - "5566-fs-dirent-dyn-boundaries/main.mjs": 2607, - "5585-record-results-inlined.ts": 2922, - "5595-net-ref-unref.ts": 2593, + "1117-typeof-static-union.ts": 3626, + "1118-object-spread-conditional.ts": 2554, + "1119-switch-union.ts": 2726, + "112-class-descriptor-key.js": 2549, + "1121-infinity-number-tostring.ts": 3208, + "1122-any-captures.ts": 3054, + "1124-union-narrowed-retag.ts": 3578, + "113-promise-checked-exits.ts": 3586, + "114-live-record-delete.ts": 3626, + "115-array-compound.js": 3341, + "116-text-decoder-runtime.js": 2988, + "117-weak-cache-cycle.js": 2923, + "118-fs-stored-callbacks.cjs": 4172, + "119-native-patterns.js": 3825, + "1200-regex-test-basics.ts": 3353, + "1201-regex-replace.ts": 3417, + "1202-regex-substitutions.ts": 2747, + "1203-regex-split.ts": 3543, + "1204-regex-empty-unicode.ts": 3255, + "1205-regex-rc-stress.ts": 3482, + "1300-errors-basics.ts": 4832, + "1301-errors-subclass.ts": 1974, + "1302-errors-typed-catch.ts": 3160, + "1303-errors-rc-stress.ts": 3496, + "1304-errors-uncaught.ts": 2419, + "1305-errors-async-rejections.ts": 3908, + "1306-errors-runtime-instances.ts": 3226, + "1350-path-normalize-join.ts": 3294, + "1351-path-parts.ts": 3299, + "1352-path-resolve-relative.ts": 3380, + "1353-os-basics.ts": 3216, + "1354-builtin-bare-specifiers.ts": 3413, + "1355-url-parse.ts": 3188, + "1356-url-file-bridge.ts": 3020, + "1357-fsp-roundtrip.ts": 3377, + "1358-crypto-random.ts": 3134, + "1359-json-module/main.ts": 3195, + "1360-spawn-sync.ts": 3446, + "1361-spawn-events.ts": 3606, + "1362-spawn-timers.ts": 9552, + "1363-spawn-unhandled-error.ts": 3308, + "1364-union-truthiness.ts": 2872, + "1365-union-logical.ts": 3452, + "1366-union-equality.ts": 2813, + "1367-destructuring.ts": 3209, + "1368-constructor-functions.ts": 1858, + "1369-promise-union.ts": 2635, + "1370-spread.ts": 2894, + "1371-union-template-tostring.ts": 3244, + "1372-loose-null-tests.ts": 3198, + "1373-union-array-arms.ts": 3455, + "140-bitwise-operators.ts": 3457, + "1400-typedarray-basics.ts": 2651, + "1401-typedarray-slice-set.ts": 4371, + "1402-buffer-encodings.ts": 3496, + "1403-buffer-fs.ts": 3517, + "1404-zlib-crypto-bytes.ts": 3174, + "1405-bytes-unions-arrays.ts": 4083, + "1406-dataview-mp4.ts": 3511, + "1407-dataview-bounds.ts": 2861, + "1408-string-indexing.ts": 3596, + "1409-typedarray-integer-loops.ts": 3161, + "1420-number-statics.ts": 1931, + "1421-number-parse-strings.ts": 2420, + "1422-date-iso.ts": 3107, + "1423-text-codec.ts": 4835, + "1424-fs-options.ts": 3321, + "1425-stdin-tty.ts": 2403, + "1426-stdin-read.ts": 3082, + "1427-fromcharcode-lastindexof.ts": 3173, + "1428-settled-await-order.ts": 1798, + "1429-promise-catch-finally.ts": 3573, + "1430-promise-race.ts": 3479, + "1431-caught-tostring.ts": 3384, + "1432-destructured-params.ts": 2875, + "1433-filter-narrow.ts": 3756, + "1434-async-never.ts": 3046, + "1435-math-spread.ts": 2761, + "1436-default-undef-param.ts": 2349, + "1437-pad-default.ts": 3147, + "1438-promise-all.ts": 6716, + "1440-interval-basics.ts": 2538, + "1441-interval-clear-cross.ts": 6428, + "1442-interval-throw.ts": 3155, + "1443-signal-handlers.ts": 5897, + "1444-exit-listeners.ts": 2050, + "1445-exit-process-exit.ts": 3031, + "1446-exit-uncaught.ts": 3104, + "1447-stdin-closed-events.ts": 2554, + "1448-stream-columns.ts": 2939, + "1450-incdec-expression.ts": 3366, + "1451-instanceof-uint8array-unknown.ts": 3581, + "1452-return-through-finally.ts": 2366, + "1453-pmap-settled.ts": 3689, + "1454-nonnull-narrow-and-fcc-bytes.ts": 3631, + "1455-lambda-union-return-adoption.ts": 3317, + "1460-console-error-warn.ts": 2928, + "1461-process-pid-getuid-kill.ts": 2613, + "1462-exec-sync.ts": 3611, + "1463-timeout-unref.ts": 2351, + "1464-env-writes.ts": 2366, + "1465-env-value.ts": 3573, + "1466-child-containers.ts": 3261, + "1467-string-match.ts": 2763, + "1468-exec-path.ts": 1874, + "1469-remove-listener.ts": 3366, + "1470-child-lifecycle.ts": 3503, + "1471-child-unref.ts": 7428, + "1472-errno-code.ts": 3503, + "1473-promisify-execfile.ts": 3923, + "1474-string-decoder.ts": 3543, + "1475-readline-closed-stdin.ts": 2561, + "1476-assign-expression.ts": 2094, + "1477-in-expressions.ts": 2351, + "1478-promise-reject.ts": 3535, + "1479-destructuring-assign.ts": 3422, + "1480-os-network-interfaces.ts": 3878, + "1481-string-case-static.ts": 1956, + "1482-spawnsync-error.ts": 3384, + "1483-array-slice.ts": 2259, + "1520-fs-wider-surface.ts": 2338, + "1520-string-split-static.ts": 2323, + "1521-fs-lstat-lock.ts": 2828, + "1521-string-trim-pad-static.ts": 3386, + "1522-parseint-static.ts": 3245, + "1522-spawnsync-options.ts": 5207, + "1523-isnan-floor-static.ts": 2460, + "1523-spawn-options.ts": 3155, + "1524-atomics-sleep-static.ts": 3514, + "1524-catch-narrowing.ts": 3000, + "1525-child-exit-signal.ts": 3280, + "1525-unknown-typeof-validation.ts": 3939, + "1526-set-spread.ts": 3125, + "1527-logical-mixed-operands.ts": 3109, + "1528-delete-records-env.ts": 3666, + "1529-class-with-statics.ts": 2773, + "1530-array-push-variadic.ts": 2981, + "1530-spread-override-completion.ts": 2727, + "1531-delete-optional-fields.ts": 3366, + "1531-process-arch-versions.ts": 3284, + "1532-array-splice-shift.ts": 3298, + "1532-union-shared-field-read.ts": 3134, + "1533-bool-equality.ts": 2685, + "1533-path-platform-namespaces.ts": 2976, + "1534-crypto-hash-chain.ts": 3181, + "1534-union-as-arm-cast.ts": 1932, + "1535-spawn-fd-stdio.ts": 2678, + "1535-union-param-defaults.ts": 3163, + "1536-destructuring-defaults.ts": 2281, + "1536-string-array-sweep.ts": 2437, + "1537-chalk-hybrid/main.ts": 2748, + "1537-os-release-spawnsync-stdio.ts": 1762, + "1538-await-promiselike-return.ts": 3032, + "1538-math-static-scalar.ts": 3194, + "1539-readonly-set-map.ts": 2459, + "1539-unknown-truthiness.ts": 3106, + "1540-os-userinfo.ts": 3344, + "1540-void-statement.ts": 2967, + "1541-fs-readdir-dirent.ts": 3638, + "1541-union-keyed-reads.ts": 3287, + "1542-map-promise-values.ts": 2441, + "1542-record-literal-into-union.ts": 3261, + "1543-rest-destructuring.ts": 2933, + "1543-set-server-handles.ts": 1958, + "1544-dyn-json-reads.ts": 2284, + "1544-string-matchall.ts": 2886, + "1545-spread-order-and-optional.ts": 3651, + "1546-union-element-reads.ts": 3172, + "1547-computed-key-fold.ts": 3047, + "1548-boolean-condition-forms.ts": 2170, + "1549-array-isarray-unions.ts": 3931, + "1550-param-defaults-func-set.ts": 2398, + "1551-dyn-receiver-methods.ts": 3835, + "1552-exec-options-record.ts": 3202, + "1553-truthy-hof-predicates.ts": 3421, + "1554-caught-into-unknown.ts": 3543, + "1555-index-spread-into-declared.ts": 3633, + "1556-union-retag-width-arms.ts": 2627, + "1557-url-host.ts": 2357, + "1558-any-joins-and-dyn-validation.ts": 3196, + "1559-conditional-spread-index-merge.ts": 3131, + "1560-forof-homogeneous-tuples.ts": 3159, + "1561-forof-strings.ts": 2864, + "1561-promise-then.ts": 2385, + "1562-optional-chain-tails.ts": 3642, + "1562-spawn-conditional-spread.ts": 3319, + "1563-forof-iterator-projections.ts": 2786, + "1563-string-raw-fold.ts": 2587, + "1564-fs-watch.ts": 3261, + "1564-string-raw.ts": 2451, + "1565-spawn-pipe-streams.ts": 3391, + "1565-union-element-join.ts": 2486, + "1566-child-duck-interface.ts": 2840, + "1567-server-close-override.ts": 3237, + "1568-x509-fingerprint.ts": 3907, + "1569-fsp-mkdir-unlink-chmod.ts": 2903, + "1570-child-unref-kill-reffed.ts": 8636, + "1571-optional-call-tostring-tail.ts": 2889, + "1571-stdin-set-raw-mode-non-tty.ts": 2975, + "1572-promise-reject-all-tuple.ts": 3556, + "1572-x509-validity-date-gettime.ts": 3310, + "1573-promisify-execfile-env-spread.ts": 2814, + "1573-tdz-scalar-forward-capture.ts": 1712, + "1574-dyn-optional-method-number-keys.ts": 3878, + "1574-promise-all-tuple-literal.ts": 2253, + "1575-unknown-assert-into-record.ts": 1861, + "1576-width-coercions.ts": 2898, + "1577-url-hostname.ts": 2901, + "1578-exec-input-optional.ts": 3273, + "1579-matchall-index.ts": 3564, + "1580-exec-env-conditional-spread.ts": 2271, + "1581-declare-const-read.ts": 3037, + "1582-timer-sleep-resolve.ts": 3206, + "1583-loops-and-stream-captures.ts": 3193, + "1584-union-field-unassigned.ts": 3119, + "1585-union-field-conditional-ctor.ts": 3101, + "1586-derived-field-before-super-init.ts": 2618, + "1590-js-unannotated.js": 2053, + "1591-js-closures.js": 2387, + "1592-js-classes.js": 4973, + "1593-js-jsdoc-records.js": 3116, + "1594-js-async.js": 2589, + "1595-js-island-gap/main.js": 3108, + "1596-cjs-modules/main.js": 3096, + "1597-mjs-graph/main.mjs": 2863, + "1598-cjs-builtin-require/main.js": 2598, + "1599-js-uncaught-throw.js": 1785, + "1600-assert-passing.ts": 3203, + "1601-assert-fail-exit.ts": 2955, + "1602-assert-caught-error.ts": 2978, + "1603-assert-scalar-messages.ts": 3055, + "1604-assert-deep-structures.ts": 3591, + "1605-assert-import-forms.ts": 2429, + "1606-assert-strict-module.ts": 3039, + "1607-assert-throws-match.ts": 2826, + "1608-cjs-assert/main.js": 3263, + "1609-assert-async.ts": 3342, + "1610-path-win32-full.ts": 2405, + "1611-url-file-bridge-neutral.ts": 2476, + "1612-cjs-module-globals.cjs": 2856, + "1613-cjs-esm-proxy-named/main.mjs": 2613, + "1614-js-fence-dodges.cjs": 1967, + "1615-cjs-export-shapes/main.cjs": 2975, + "1616-cjs-esm-lexer-invisible/main.mjs": 2660, + "1617-cjs-esm-lexer-visible/main.mjs": 3090, + "1618-cjs-esm-poisoned-tail/main.mjs": 2780, + "1619-cjs-esm-reexport-invisible/main.mjs": 2185, + "1620-cjs-require-effects-order/main.js": 1410, + "1621-cjs-require-cache-hit/main.js": 2836, + "1622-cjs-require-conditional/main.js": 2564, + "1623-cjs-require-diamond/main.js": 2652, + "1624-cjs-require-dir-mid-file/main.js": 2573, + "1625-cjs-require-lazy-fn/main.js": 2246, + "1626-cjs-require-mjs/main.js": 2951, + "1627-mjs-import-cjs-requires/main.mjs": 2683, + "1628-checked-dynamic-builtin-args.cjs": 1896, + "1629-require-main-filename.cjs": 2867, + "1630-inspect-scalars.ts": 2361, + "1630-rmsync-retry-options.cjs": 2984, + "1631-inspect-arrays.ts": 3811, + "1632-inspect-records.ts": 4779, + "1633-inspect-map-set.ts": 3008, + "1634-inspect-classes.ts": 3344, + "1635-inspect-buffer.ts": 2898, + "1636-util-format.ts": 2261, + "1637-inspect-dyn.ts": 2934, + "1638-inspect-cjs.cjs": 3133, + "1639-versions-openssl-probe.ts": 2209, + "1640-fd-read-decode.ts": 3309, + "1641-string-search.ts": 2951, + "1642-object-fromentries-rows.ts": 3231, + "1643-metadata-dyn-return.cjs": 3375, + "1644-ee-basics.ts": 3158, + "1645-ee-extends.ts": 2448, + "1646-ee-once-remove.ts": 2581, + "1647-ee-meta-events.ts": 2563, + "1648-ee-error-event.ts": 2097, + "1649-ee-names-counts.ts": 2941, + "1650-ee-prepend.ts": 3190, + "1651-ee-max-listeners.ts": 2691, + "1652-ee-snapshot.ts": 2882, + "1653-ee-cjs.cjs": 2645, + "1654-ee-namespace.ts": 2314, + "1655-spawnsync-neutral.ts": 4787, + "1656-execsync-neutral.ts": 3015, + "1657-spawn-async-neutral.ts": 3128, + "1660-buffer-read-write-num.ts": 2511, + "1661-buffer-encodings-full.ts": 3466, + "1662-string-decoder-encodings.ts": 3207, + "1663-buffer-compare-search-fill.ts": 3063, + "1664-dyn-fn-boundary.cjs": 2280, + "1665-dyn-fn-mustcall/main.cjs": 2798, + "1666-dyn-fn-identity.ts": 3303, + "1667-dyn-fn-not-callable.cjs": 2431, + "1668-dyn-fn-throws.cjs": 3052, + "1669-symbol-identity.ts": 3194, + "1670-symbol-registry.ts": 2198, + "1671-symbol-typeof.ts": 2786, + "1672-symbol-containers.ts": 2209, + "1673-symbol-cjs.cjs": 2979, + "1674-symbol-inspect.ts": 2795, + "1676-func-array-surface.ts": 2945, + "1677-emitter-listeners.ts": 4548, + "1678-emitter-dyn-listeners.cjs": 3185, + "1679-console-dyn.js": 2910, + "1680-assert-bytes.ts": 3154, + "1681-assert-funcs.ts": 1828, + "1685-stream-readable-basics.ts": 2976, + "1686-stream-readable-paused.ts": 2831, + "1687-stream-readable-flow-control.ts": 2863, + "1688-stream-writable-basics.ts": 2245, + "1689-stream-writable-async-drain.ts": 1562, + "1690-stream-duplex.ts": 3124, + "1691-stream-transform.ts": 2070, + "1692-stream-pipe.ts": 2661, + "1693-stream-pipe-backpressure.ts": 2944, + "1694-stream-destroy.ts": 2243, + "1695-stream-props.ts": 2801, + "1696-stream-read-inside-read.ts": 2398, + "1697-stream-tick-vs-timer.ts": 2703, + "1698-stream-uncaught-error.ts": 2045, + "1699-stream-callback-shapes.ts": 2523, + "1700-mustcall-common/main.cjs": 3695, + "1701-mustcall-exit-report/main.cjs": 4202, + "1702-dyn-proto-dispatch.cjs": 3277, + "1703-arguments-rest-props.cjs": 2983, + "1710-cjs-export-class/main.js": 3030, + "1711-cjs-export-single-values/main.js": 2594, + "1712-field-incdec.ts": 1845, + "1713-js-dyn-fields.js": 2654, + "1720-assert-throws-shape.ts": 2898, + "1721-assert-throws-regex-class.ts": 3751, + "1722-assert-rejects.ts": 2848, + "1723-assert-does-not-reject.ts": 3358, + "1724-assert-iferror.ts": 1705, + "1725-assert-symbols.ts": 2141, + "1726-promise-with-resolvers.ts": 2575, + "1727-assert-throws-shape-exit.ts": 2905, + "1730-countdown-symbol-keys/main.js": 2273, + "1731-symbol-field-shapes.cjs": 2895, + "1732-symbol-field-cross-module/main.js": 2678, + "1740-stream-extends-readable.ts": 2983, + "1741-stream-extends-writable.ts": 2337, + "1742-stream-extends-duplex-transform.ts": 3417, + "1743-stream-extends-vt-dispatch.ts": 2520, + "1744-stream-set-encoding.ts": 3582, + "1745-stream-encoding-js.cjs": 2993, + "1746-stream-for-await.ts": 4666, + "1747-stream-for-await-js.cjs": 3552, + "1750-http-agent-options.ts": 2667, + "1751-options-record-stance.ts": 3044, + "1760-surplus-args-drop.cjs": 2775, + "1761-emitter-special-event-names.cjs": 2427, + "1770-assert-dyn-strict.ts": 3393, + "1771-assert-dyn-deep.ts": 3639, + "1772-assert-dyn-js.cjs": 2854, + "1773-assert-dyn-exit.ts": 2368, + "1780-http-res-surface.ts": 2318, + "1781-http-server-shapes.cjs": 3339, + "1790-computed-key-folds.ts": 2833, + "1791-searchparams-core.ts": 2212, + "1792-searchparams-encoding.ts": 2305, + "1793-searchparams-iteration.ts": 3412, + "1794-searchparams-url-live.ts": 2492, + "1795-dyn-handle-request.cjs": 3337, + "1796-dyn-handle-body.cjs": 3287, + "1797-dyn-handle-socket.cjs": 2497, + "1798-dyn-handle-typed-box.ts": 2870, + "1800-immediate-basics.ts": 2802, + "1801-immediate-handle.ts": 2655, + "1802-immediate-unref-exit.ts": 2450, + "1803-timeout-refresh.ts": 2797, + "1804-timers-module.ts": 2773, + "1805-timer-callback-args.ts": 2736, + "1806-timer-delay-trunc.ts": 2060, + "1810-stream-options-const-record.ts": 2542, + "1811-stream-option-value-callbacks.cjs": 2462, + "1812-stream-super-options-forwarding.cjs": 3383, + "1813-stream-finished.ts": 2720, + "1814-stream-pipeline.cjs": 3409, + "1815-stream-state-reads.cjs": 2880, + "1820-static-block-basics.ts": 1635, + "1821-static-block-order.ts": 2551, + "1822-static-block-js.js": 2387, + "1823-static-instance-method-names.ts": 1936, + "1824-for-of-destructuring-defaults.ts": 2145, + "1825-exhaustive-typeof-switch.ts": 2973, + "1826-settimeout-arguments-callback.js": 2489, + "1830-enum-numeric-basics.ts": 2207, + "1831-enum-string-const-reverse.ts": 1943, + "1832-enum-modules/main.ts": 2350, + "1835-var-basics.ts": 2804, + "1836-var-loop-capture.ts": 3197, + "1837-var-undefined-hoisting.ts": 2836, + "1838-var-modules/main.ts": 2550, + "1839-var-js/main.cjs": 2492, + "1840-jsdoc-import-type-only/main.js": 1919, + "1850-overload-basics.ts": 2640, + "1851-overload-return-narrowing.ts": 1736, + "1852-overload-class-members.ts": 2774, + "1853-overload-modules/main.ts": 2509, + "1854-ambient-declare-fn.ts": 2603, + "1855-ambient-declare-fn-uncaught.ts": 1999, + "1870-unit-type-values.ts": 2905, + "1871-empty-array-never.ts": 2516, + "1872-template-tostring-composite.ts": 1682, + "1880-json-declared-field-order.ts": 3529, + "1881-default-anon/main.ts": 2084, + "1882-default-cjs-interop/main.ts": 2606, + "1883-default-exports/main.ts": 2612, + "1890-ns-imports/main.ts": 2704, + "1891-ns-reexport/main.ts": 2129, + "1940-class-values-basics.ts": 2668, + "1941-class-values-registry.ts": 2870, + "1942-class-expressions.ts": 2682, + "1943-class-statics-expanded.ts": 2734, + "1944-class-values-modules/main.ts": 2146, + "1950-generic-fn-values.ts": 2755, + "1951-generic-classes-basics.ts": 3235, + "1952-generic-class-statics-values.ts": 2233, + "1953-generic-class-hierarchy.ts": 2990, + "1954-generic-modules/main.ts": 2377, + "1960-namespace-basics.ts": 2728, + "1961-namespace-nested.ts": 2156, + "1962-namespace-classes.ts": 2835, + "1963-namespace-aliases.ts": 2550, + "1964-namespace-type-only.ts": 2471, + "1965-namespace-ambient.ts": 2707, + "1966-namespace-modules/main.ts": 2766, + "1967-namespace-alias-typeonly.ts": 2273, + "1968-namespace-import-eq-snapshot.ts": 2594, + "1970-decorators-basics.ts": 2916, + "1971-decorators-rebinding.ts": 2369, + "1972-decorators-throwing.ts": 2667, + "1973-decorators-ambient.ts": 2709, + "1980-primitive-proto-statics.ts": 3013, + "1981-date-utc.ts": 2644, + "1982-freeze-resolve-passthrough.ts": 3023, + "1983-array-tuple-surfaces.ts": 3232, + "1990-labels-basics.ts": 2990, + "1991-for-in-loops.ts": 3611, + "1992-small-syntax.ts": 3054, + "200-strings.ts": 1903, + "2000-generic-methods-basic.ts": 2832, + "2001-generic-methods-generic-class.ts": 2741, + "2002-generic-methods-inheritance.ts": 2972, + "2003-generic-methods-object-literal.ts": 3023, + "2004-generic-methods-statics.ts": 2292, + "201-templates.ts": 2534, + "2010-generators-basics.ts": 1525, + "2011-generators-forof.ts": 2217, + "2012-generators-return-throw.ts": 3262, + "2013-generators-sent-values.ts": 2117, + "2014-generators-values.ts": 2991, + "2015-generators-yieldstar.ts": 2892, + "2016-generators-rc-stress.ts": 2942, + "2017-generators-async.ts": 1965, + "2018-generators-uncaught.ts": 2403, + "2019-generators-loops.ts": 2116, + "2020-generic-value-bindings.ts": 3355, + "2021-generic-value-binding-modules/main.ts": 2720, + "2022-width-index-capture.ts": 2258, + "2023-width-readonly.ts": 2519, + "2024-width-array-elems.ts": 2776, + "2025-width-union-compose.ts": 3243, + "2026-width-spread.ts": 1625, + "2030-width-nested.ts": 3160, + "2031-width-tuples.ts": 2019, + "2032-cjs-export-assigned-class-expression/main.cjs": 2230, + "2033-property-assigned-class-extends.cjs": 2058, + "2035-ternary-array-retag.cjs": 2602, + "2036-evolving-array-decl.cjs": 2125, + "2037-fn-decl-hoisting.cjs": 1595, + "2038-evolving-array-js.cjs": 2965, + "2040-any-bindings.ts": 3143, + "2040-mixin-heritage.ts": 3206, + "2041-any-params-returns.ts": 2996, + "2041-mixin-values.ts": 3090, + "2042-any-flow-loops.ts": 3104, + "2042-mixin-modules/main.ts": 2762, + "2043-any-dom-values.ts": 3345, + "2043-mixin-rc-stress.ts": 2605, + "2044-vtable-sibling-slots.ts": 3123, + "2045-objlit-accessors-basic.ts": 2774, + "2045-parameter-properties.ts": 3393, + "2046-abstract-classes.ts": 2184, + "2046-objlit-accessors-effects.ts": 2948, + "2047-objlit-accessors-shapes.ts": 1767, + "2047-optional-class-fields.ts": 2566, + "2050-dynamic-import-own-module/main.ts": 2384, + "2051-dynamic-import-then/main.ts": 2679, + "2052-dynamic-import-self.ts": 2722, + "2053-typeof-static-fold.ts": 2817, + "2054-destructuring-island-source.ts": 2995, + "2060-empty-tuple.ts": 2635, + "2070-computed-key-folds.ts": 2872, + "2071-integer-key-enumeration-order.ts": 3125, + "2072-expando-function-members.ts": 2341, + "2073-destructuring-assignment.ts": 2794, + "2074-island-destructuring.ts": 2364, + "2075-index-signature-runtime-keys.ts": 2866, + "2080-destructuring-defaults.ts": 1887, + "2081-destructuring-rest.ts": 3136, + "2082-destructuring-assignment.ts": 2594, + "2085-destructuring-heads-rest-params.ts": 2973, + "2087-destructuring-for-heads.ts": 2753, + "2090-index-signature-number-keys.ts": 2175, + "2091-index-signature-string-intersection.ts": 2763, + "2092-package-imports/main.ts": 2350, + "2093-timers-promises.ts": 2872, + "2094-diagnostics-channel.ts": 2689, + "2095-js-catch-unknown.js": 2633, + "2096-os-type.ts": 1968, + "2097-js-evolving-globals.js": 2880, + "210-string-methods.ts": 2798, + "2100-stream-default-hwm.ts": 2089, + "2101-dyn-param-defaults.ts": 2260, + "2102-empty-pattern-decls.ts": 1677, + "2105-computed-key-static-folds.ts": 2815, + "2106-comma-expressions.ts": 2657, + "211-string-unicode.ts": 2741, + "2110-top-object-types.ts": 2919, + "2111-json-stringify-unknown.ts": 2401, + "2112-array-at-findlast.ts": 1741, + "2113-string-index-methods.js": 1867, + "212-string-aliasing-append.ts": 2513, + "2120-package-self-import/main.ts": 2334, + "2121-esm-cycle-inert-backedge/main.ts": 2266, + "2123-ambient-import-crash/main.ts": 2890, + "2124-imports-field-wildcard/main.ts": 2153, + "2140-uri-component-codecs.ts": 2446, + "2160-dc-tracing-channel.cjs": 2881, + "2161-js-object-literal-identity.cjs": 2928, + "2162-js-dyn-destructure.cjs": 2896, + "2163-js-selfref-const.cjs": 2717, + "2164-js-then-dyn-handler.cjs": 2572, + "2165-js-throw-dyn.cjs": 2672, + "2166-cjs-getter-this/main.cjs": 2899, + "2170-island-array-exits.ts": 2722, + "2171-island-json-stringify.ts": 2071, + "2172-island-regexp-boundary.ts": 2828, + "2190-new-object-and-string-wrappers.ts": 2625, + "2191-uri-encoders.ts": 2849, + "2192-object-default-tostring.ts": 2537, + "2193-discarded-stdlib-reads.ts": 2594, + "2194-ambient-undef-chains.ts": 1718, + "2195-require-missing-package/main.mjs": 2757, + "2196-island-computed-key-chain.ts": 2575, + "2210-dyn-promise-crossing.cjs": 2319, + "2211-dc-trace-promise.cjs": 1935, + "2212-unhandled-rejection-listener.cjs": 2879, + "2213-async-local-storage.cjs": 2883, + "2214-dc-bind-store.cjs": 2240, + "2215-process-emit-warning-exit.cjs": 3330, + "2240-width-class-into-record.ts": 2571, + "2241-width-record-into-class.ts": 2500, + "2242-width-statics-into-record.ts": 1787, + "2243-width-assert-satisfies-shapes.ts": 2738, + "2250-tagged-templates.ts": 2408, + "2252-class-iterators.ts": 3611, + "2253-union-coercions.ts": 2810, + "2260-http2-constants.cjs": 2702, + "2280-builtin-namespace-destructure.cjs": 2594, + "2281-domexception-atob-btoa.cjs": 2615, + "2282-queue-microtask.cjs": 2780, + "2283-structured-clone.cjs": 3105, + "2284-regexp-constructor.cjs": 2648, + "2285-iferror-dyn.cjs": 2717, + "2286-dyn-object-walks.cjs": 3110, + "2300-dyn-record-spread-and-keyed-access.cjs": 2464, + "2301-cjs-export-table-dom-attach.cjs": 2425, + "2310-process-next-tick.ts": 2609, + "2311-next-tick-js-callbacks.js": 2450, + "2312-stream-underscore-assign.ts": 2473, + "2313-stream-underscore-assign-js.cjs": 3017, + "2314-process-introspection.ts": 3479, + "2320-await-unit.ts": 2334, + "2321-emitter-static-setmax.cjs": 2697, + "2322-dyn-array-sort.cjs": 3014, + "2323-timer-callback-returns.ts": 3852, + "2330-tls-server-runtime-options.cjs": 2565, + "2331-tls-server-options-typed.ts": 1980, + "2350-nan-global.ts": 3180, + "2351-async-methods.ts": 2138, + "2352-void-coercions.ts": 2843, + "2353-decorators-member-ambient.ts": 3089, + "2354-decorators-expression-ambient.ts": 1841, + "2360-tuple-to-array.ts": 2335, + "2361-assign-index-record.ts": 3492, + "2362-execsync-inherit.ts": 2484, + "2363-nullish-retag.ts": 2875, + "2364-in-runtime-key.ts": 2156, + "2365-dyn-into-island.ts": 2339, + "2366-string-well-formed.ts": 2760, + "2367-regexp-escape.ts": 2791, + "2368-set-methods.ts": 3237, + "2369-promise-try.ts": 2605, + "2370-group-by.ts": 3569, + "2371-iterator-helpers.ts": 3561, + "2380-buffer-module-named-import.ts": 2746, + "2381-builtin-default-imports.js": 2945, + "2382-cycle-two-decl/main.ts": 2560, + "2383-cycle-assertdoc/main.js": 3011, + "2384-cycle-mixed-bindings/main.ts": 2477, + "2385-builtin-reexport-facade/main.ts": 2948, + "2386-string-to-chars.ts": 2475, + "2387-tonumber-argv.ts": 3071, + "2388-tonumber-grammar-zoo.ts": 3157, + "2389-tonumber-unary-plus.ts": 2176, + "2390-dot-requires/main.cjs": 2329, + "2391-default-builtin-imports/main.ts": 2387, + "2392-block-guard-alias-scope.ts": 2363, + "2393-loop-exit-guard-narrow.ts": 2936, + "2394-loop-narrow-containment.ts": 2244, + "2395-while-cond-guard.ts": 2443, + "2396-born-narrowed-decl.ts": 2276, + "2397-branch-kill-merge.ts": 2681, + "2398-switch-arm-kill.ts": 3027, + "2399-reassign-kill-polarity.ts": 2662, + "240-stdout-write.ts": 1918, + "2400-kill-return-edge.ts": 2414, + "2401-kill-break-staging.ts": 2162, + "2402-labeled-break-kill.ts": 2493, + "2403-kill-continue-backedge.ts": 2457, + "2404-kill-throw-catch.ts": 1792, + "2405-sibling-arm-narrow.ts": 1781, + "2406-switch-clause-sibling-narrow.ts": 2641, + "2407-infinite-loop-seal.ts": 2308, + "2408-loop-terminality-reopen.ts": 2756, + "2409-loop-body-return-not-terminal.ts": 2759, + "2410-stacked-cases-terminality.ts": 2830, + "2411-exhaustive-switch-terminality.ts": 2112, + "2412-dowhile-guard-trailing-test.ts": 2230, + "2413-dowhile-kill-renarrow.ts": 2630, + "2414-dowhile-continue-kill.ts": 2624, + "2415-dowhile-break-trailing-test.ts": 2524, + "2416-spread-ternary-positions.ts": 2956, + "2417-ternary-local-inference.ts": 2300, + "2418-wrapped-ternary-arms.ts": 2768, + "2419-selector-ternary-union.ts": 2727, + "2420-nullish-null-identity.ts": 2533, + "2421-float-lane-inference.ts": 2620, + "2422-ieee-div-rem-corners.ts": 2629, + "2423-param-null-reassign.ts": 2622, + "2424-ternary-miss-first-narrowing.ts": 2228, + "2425-elseif-head-exit-narrow.ts": 2186, + "2426-default-snapshot-mutable/main.ts": 2520, + "2427-perf-hooks-now.ts": 2346, + "2428-field-redeclare-inherited.ts": 2882, + "2429-destructure-class-instance.ts": 2852, + "2430-empty-literal-unknown-field.js": 2190, + "2431-primitive-ctor-values.ts": 2149, + "2432-generic-member-fields-async.ts": 3225, + "2433-as-const-command-tables.ts": 3139, + "2434-deferred-init-fields.ts": 2789, + "2435-loose-same-kind-equality.ts": 2652, + "2440-console-inspect-args.ts": 3314, + "2441-console-process-argv.ts": 2095, + "2442-union-literal-arm-widening.ts": 2062, + "2443-union-literal-shadow-narrowing.ts": 2856, + "2444-union-literal-reducer-spread.ts": 2705, + "2445-math-minmax-nary.ts": 2093, + "2446-performance-global.ts": 2484, + "2447-island-boundary-slots/main.ts": 3456, + "2448-entries-null-arms-regex-arrays.ts": 2911, + "2450-private-instance-methods.ts": 2310, + "2451-private-fields.ts": 2058, + "2452-private-statics.ts": 2844, + "2453-private-accessors.ts": 2851, + "2454-private-generator-methods.ts": 2328, + "2455-private-brand-checks.ts": 2840, + "2456-private-async-methods.ts": 2932, + "2457-private-members.js": 2832, + "2460-qs-parse-grammar.ts": 2844, + "2461-qs-parse-options.ts": 2944, + "2462-qs-stringify.ts": 3219, + "2463-qs-escape-unescape.ts": 2133, + "2464-qs-require-forms.cjs": 2362, + "2470-mockable-module-shape.js": 3020, + "2471-record-keyed-write-hasown.js": 2921, + "2472-string-regexp-union.ts": 1528, + "2473-option-table-widths.js": 2792, + "2474-island-literal-forms.ts": 2730, + "2475-variadic-wrapper-island.js": 2962, + "2476-map-regex-values.ts": 1895, + "2480-recursive-record-tree.ts": 2781, + "2481-mutual-recursive-records.ts": 2829, + "2482-recursive-union-tree.ts": 2626, + "2483-recursive-record-cycles.ts": 2385, + "2484-json-stringify-circular.ts": 1936, + "2485-inspect-circular-refs.ts": 3139, + "2486-recursive-record-boundaries.ts": 3118, + "2487-recursive-deep-equal.ts": 2998, + "2488-ast-walker.ts": 3274, + "2490-find-miss-null-compare.ts": 2608, + "2491-strict-unit-compare-no-arm.ts": 2376, + "2492-loose-null-compare-unions.ts": 2805, + "2493-switch-unit-cases.ts": 2280, + "2494-no-arm-compare-effects.ts": 2159, + "2500-net-autosel-timeout.ts": 2195, + "2510-dyn-evolving-array-map.ts": 1961, + "2511-dyn-evolving-array-filter-foreach.ts": 2859, + "2512-dyn-evolving-array-mixed-push.ts": 1607, + "2520-private-statics-class-name-calls.ts": 2420, + "2521-private-statics-class-expression.ts": 1848, + "2522-private-statics-decorated.ts": 3008, + "2523-private-statics-aliased-class.ts": 2743, + "2530-object-destructuring-decl.ts": 2036, + "2531-array-tuple-destructuring-decl.ts": 2908, + "2532-param-destructuring-options.ts": 2917, + "2533-forof-destructuring.ts": 2821, + "2534-object-rest-decl.ts": 2914, + "2535-destructuring-assign-basics.ts": 2888, + "2536-destructuring-assign-nested.ts": 2697, + "2537-destructuring-assign-member-targets.ts": 1747, + "2538-destructuring-assign-class-source.ts": 2594, + "2539-class-instance-rest.ts": 2144, + "2540-accessor-destructuring-defaults.ts": 2790, + "2541-destructuring-eval-order.ts": 2901, + "2550-generics-keyof-pick.ts": 2724, + "2551-generics-value-aliases.ts": 2899, + "2552-generics-iface-methods.ts": 2924, + "2553-generics-signature-bindings.ts": 1690, + "2554-generics-frontier-mix.ts": 2607, + "2555-generics-keyof-writes.ts": 2074, + "2556-crypto-introspection.ts": 2165, + "2556-width-hybrid-shapes.ts": 1904, + "2557-tls-ca-store.ts": 3159, + "2557-width-field-lifts.ts": 3231, + "2558-index-signature-func-values.ts": 2869, + "2558-rejection-events.cjs": 1923, + "2559-index-signature-container-values.ts": 2319, + "2560-arraybuffer-dataview-set.ts": 3376, + "2561-object-is.ts": 3499, + "2562-intl-numberformat-en-us.ts": 2371, + "2563-stream-promises-pipeline.ts": 3059, + "2564-stream-promises-finished.ts": 1663, + "2565-stream-promises-js.cjs": 2464, + "2566-promise-reject-dyn-reason.js": 2041, + "2567-rest-spread-forward.js": 3238, + "2568-rest-spread-forward-dynamic.js": 2074, + "2569-upcast-identity.ts": 2471, + "2570-buffer-arg-validation.cjs": 4288, + "2571-searchparams-arg-validation.cjs": 2294, + "2572-readable-emitted-readable-flag.cjs": 2792, + "2573-fs-url-arg-ladders.cjs": 3144, + "2574-emitter-max-listeners-ladders.cjs": 2768, + "2575-string-destructuring-decl.ts": 3093, + "2576-string-destructuring-assign.ts": 1948, + "2577-builtin-global-destructuring.js": 1471, + "2578-jsval-into-unknown-rows.ts": 2895, + "2579-jsval-object-param-crossing.js": 2920, + "2580-jsval-routed-keyed-ops.js": 2793, + "2581-jsval-routed-calls.js": 2527, + "2582-jsval-object-statics.js": 3114, + "2582-jsval-routed-keyed-ops.js": 3012, + "2583-dyn-nullish-coalesce.js": 2872, + "2583-jsval-routed-calls.js": 3060, + "2584-jsval-object-statics.js": 3017, + "2584-union-dyn-collapse.ts": 3110, + "2585-dyn-nullish-coalesce.js": 3233, + "2585-unknown-array.ts": 3147, + "2586-object-assign-spread.js": 3063, + "2587-array-entries-forof.ts": 2868, + "2588-array-entries-chains.ts": 2948, + "2589-object-create-null.cjs": 2175, + "2590-object-create-dynamic.js": 2548, + "2591-ambient-generic-traps.ts": 2668, + "2592-ambient-trap-uncaught.ts": 2071, + "2593-generic-inert-bindings.ts": 2582, + "2594-nullish-generic-bindings.ts": 2649, + "2595-fs-arg-ladders.cjs": 3450, + "2596-net-arg-ladders.cjs": 3163, + "2597-dgram-send-ladders.cjs": 3471, + "2598-tls-arg-ladders.cjs": 2644, + "2599-stream-arg-ladders.cjs": 2952, + "2600-dyn-keyed-write-harness.js": 3162, + "2601-dyn-keyed-write-ops.js": 2780, + "2602-dyn-array-destructure.js": 2123, + "2603-island-keyed-write-dyn.js": 2776, + "2604-cycle-classes-mutual/main.ts": 2653, + "2605-cycle-three-module/main.ts": 2386, + "2606-dynamic-import-cycle/main.ts": 2580, + "2608-regex-named-groups.ts": 3189, + "2609-regex-named-replace.ts": 2460, + "2610-regex-named-matchall.ts": 1815, + "2611-regex-named-groups-js.cjs": 3151, + "2613-for-init-uninitialized-let.ts": 2759, + "2614-trap-binding-later-writes.ts": 1833, + "2615-nullish-field-record-binding.ts": 2522, + "2616-js-collect-probe-defers.js": 2932, + "2617-enum-static-field-import/main.ts": 2674, + "2618-ee-emit-override.ts": 2416, + "2619-ee-override-chain.ts": 2759, + "2620-ee-override-once-order.ts": 2863, + "2621-ee-override-error-throw.ts": 2669, + "2622-ee-override-filter.ts": 2972, + "2623-ee-job-queue.ts": 2457, + "2624-ee-override-js.cjs": 2851, + "2625-bytes-views.ts": 1866, + "2626-stream-event-names.ts": 3082, + "2627-stream-ticks-are-nextticks.ts": 2115, + "2628-stream-push-encodings.cjs": 2780, + "2629-stream-consumers.ts": 3333, + "2630-stream-consumers-errors.ts": 2597, + "2631-create-require/main.ts": 3215, + "2632-dyn-jsval-iterate.js": 3094, + "2633-island-promise-crossing.js": 2715, + "2634-stream-pipeline-arg-ladders.cjs": 2970, + "2635-trap-binding-unmappable-written.ts": 2644, + "2636-trap-binding-ambient-rooted-rewrite.ts": 2711, + "2637-create-require-bare/main.ts": 2926, + "2638-http-dyn-res-compat.cjs": 3551, + "2639-http-dyn-req-pause.cjs": 2114, + "2640-net-dyn-socket-compat.cjs": 3221, + "2641-http-agent-surface.cjs": 3393, + "2642-http-agent-maxsockets.cjs": 2445, + "2643-or-default-retag.ts": 2951, + "2644-http-client-url-argument.ts": 3003, + "2645-https-client-url-argument.ts": 1965, + "2646-top-level-await.ts": 1994, + "2647-top-level-await-modules/main.ts": 2883, + "2648-top-level-await-rejection.ts": 2548, + "2649-top-level-await-pending.ts": 2420, + "2650-top-level-await-self-import.ts": 2738, + "2651-top-level-await-pending-unhandled.ts": 1959, + "2652-top-level-await-dynamic/main.ts": 1976, + "2653-top-level-await-rejection-stops-loop.ts": 2530, + "2654-top-level-await-unrelated-rejection.ts": 2557, + "2655-top-level-await-cycle/main.ts": 2575, + "2656-top-level-await-cycle-order/main.ts": 2788, + "2657-top-level-await-cycle-dynamic/main.ts": 1945, + "2658-top-level-await-sync-completion/main.ts": 2486, + "2659-top-level-await-dynamic-cycle/main.ts": 2311, + "2660-top-level-await-cycle-rejection/main.ts": 1648, + "2661-top-level-await-dynamic-runtime-root/main.ts": 2615, + "2662-top-level-await-cycle-external-wait/main.ts": 2307, + "2663-top-level-await-dependency-errors/main.ts": 2145, + "2664-top-level-await-same-checkpoint-rejection.ts": 2652, + "2665-top-level-await-unhandled-listener-liveness.ts": 3003, + "2666-array-to-sorted.ts": 5347, + "2668-stored-number-array-iterator.ts": 2840, + "2669-array-copying-methods.ts": 2792, + "2670-uint8array-copy-iterate.ts": 2664, + "2671-array-copying-js.cjs": 2591, + "2672-http-request-response-callback.ts": 2953, + "2673-top-level-await-implicit-module.ts": 1743, + "2674-top-level-for-await-implicit-module.ts": 2697, + "2675-create-require-nested-esm.js": 2199, + "2675-process-self-reexec.ts": 2588, + "2676-indexed-read-strict-equality.ts": 2188, + "2676-record-clone-overrides.ts": 2426, + "2676-top-level-await-ambiguous/main.ts": 2482, + "2677-runtime-optional-closure.ts": 3477, + "2677-top-level-await-module-scope/main.ts": 2623, + "2678-date-instances.ts": 3208, + "2678-large-string-sparse-index.ts": 2981, + "2678-util-parseargs.ts": 5281, + "2679-util-parseargs-cjs.cjs": 3377, + "2680-util-parseargs-default.ts": 2722, + "2681-util-parseargs-dynamic.js": 1944, + "2682-fs-rename.ts": 3375, + "2683-filter-truthy-predicate.ts": 2838, + "2683-fs-rename-js.cjs": 1913, + "2684-filter-no-predicate-dyn.cjs": 2576, + "2684-fs-rename-abort.ts": 2742, + "2685-array-unshift-reverse.ts": 2654, + "2685-fs-write-sync.ts": 2517, + "2686-fs-file-handle.ts": 3648, + "2687-fsp-write-file-options.ts": 2384, + "2687-process-write-args.ts": 2846, + "2688-fs-stats-disk-fields.ts": 2938, + "2689-http-server-timeout-properties.ts": 3060, + "2690-https-server-timeout-option.ts": 2700, + "2691-retained-lowering-record-order.ts": 4234, + "2692-inline-record-assert-index.ts": 2826, + "2692-string-accumulation.ts": 2691, + "2693-math-constants.ts": 2761, + "2700-array-sort-complexity.ts": 2705, + "2700-http-static-trailers.ts": 2446, + "2700-wasi-core.ts": 2208, + "2701-array-sort-snapshot.ts": 2717, + "2701-http-static-trailer-wire.ts": 2689, + "2701-import-meta/main.mjs": 2846, + "2702-http-static-trailer-end.ts": 2522, + "2702-type-import-link-static/main.ts": 1984, + "2702-uint8array-to-sorted.ts": 2225, + "2703-array-sparse-sort.ts": 5044, + "2703-type-import-link-static-reexport/main.ts": 2359, + "2704-array-sparse-to-sorted.ts": 4461, + "2704-type-import-link-static-success/main.ts": 2324, + "2705-array-sparse-sort-append.ts": 5020, + "2705-type-import-link-dynamic/main.ts": 2074, + "2706-array-search-missing-needle.ts": 1941, + "2706-type-import-link-dynamic-success/main.ts": 2411, + "2707-array-search-huge-sparse.ts": 45551, + "2707-type-import-link-static-default-reexport/main.ts": 2522, + "2708-type-import-link-dynamic/main.ts": 2609, + "2720-array-read-parity.ts": 1979, + "2721-array-nested-missing-receiver.ts": 2483, + "2750-array-sparse-foundation.ts": 2217, + "2751-buffer-concat-sparse-list.ts": 2792, + "2752-array-optional-stores.ts": 2339, + "2753-array-optional-method-values.ts": 2060, + "2754-array-property-undefined.ts": 2275, + "2755-array-optional-literal-forwarding.ts": 2382, + "2780-array-parity-composition.ts": 6446, + "2781-array-missing-value-escape.ts": 1639, + "2782-array-sparse-callbacks.ts": 3365, + "2783-array-defaults-rest.ts": 2775, + "2784-array-reduce-missing-result.ts": 2916, + "2785-array-missing-destructuring.ts": 2952, + "2786-array-sparse-serialization.ts": 3296, + "2787-array-missing-string-arithmetic.ts": 2457, + "2788-array-missing-builtin-conversions.ts": 2610, + "2789-array-missing-optional-tostring.ts": 2734, + "2790-dynamic-import-self-name/main.ts": 2631, + "2791-record-optional-keys.ts": 1771, + "2792-record-optional-spread-entries.ts": 2836, + "2793-union-conversion-identity-capture.ts": 1991, + "2794-array-generic-callback-values.ts": 2454, + "2795-array-optional-typedarray-source.ts": 2778, + "2796-array-sparse-class-value-instanceof.ts": 1902, + "2800-array-expression-consumers.ts": 2537, + "2801-array-switch-consumers.ts": 2609, + "2820-array-missing-method-receivers.ts": 1866, + "2821-array-optional-numeric-comparisons.ts": 2322, + "2830-cjs-require-self-name/main.cjs": 1845, + "2840-finally-completions.ts": 2496, + "2841-using-sync.ts": 2927, + "2842-await-using.ts": 2618, + "2843-using-suppressed-error.ts": 2318, + "2844-node-disposable-resources.ts": 2824, + "2845-for-using-of.ts": 2486, + "2846-generator-using.ts": 2761, + "2850-async-generators-protocol.ts": 3258, + "2851-async-generators-values.ts": 2768, + "2852-timers-promises-interval.ts": 2398, + "2854-leading-bom-literals.ts": 1935, + "2855-searchparams-sort-complexity.ts": 2792, + "2856-dynamic-any-local-operators.ts": 2781, + "2857-branded-primitives.ts": 2351, + "2858-import-meta-resolve/main.mjs": 1967, + "2859-import-meta-resolve-dynamic/main.mjs": 1446, + "2860-require-resolve/main.cjs": 2029, + "2861-readable-iterator-close.ts": 3028, + "2862-web-readable-async-iteration.ts": 3505, + "2863-class-async-iterator.ts": 2866, + "2864-array-class-method-receivers.ts": 2760, + "2865-cjs-process-alias.cjs": 2491, + "2866-dyn-switch.ts": 1865, + "2867-array-shift-length.js": 1558, + "2868-empty-record-promise-presence.js": 2022, + "2869-nullish-mixed-lazy.ts": 2676, + "2870-and-dropped-truthy-arm.ts": 2329, + "2871-optional-promise-to-unknown.ts": 2191, + "2872-unobserved-dynamic-event.ts": 2513, + "2873-optional-receiver-loop-lifetime.js": 1923, + "2874-nullable-callback-field-cycle.js": 2614, + "2875-evolving-let-read-before-write.js": 2456, + "2876-class-unknown-roundtrip.ts": 2982, + "2877-child-unknown-roundtrip.ts": 2124, + "2878-class-private-unknown.cjs": 2900, + "2880-cjs-module-graph/main.cjs": 2229, + "2890-crypto-static-utility.ts": 3535, + "2891-json-record-key-escapes.ts": 3128, + "2892-windows-console-unicode.ts": 2483, + "2893-child-stdin-duplex.ts": 3150, + "2894-child-stdin-backpressure.ts": 2319, + "2895-child-stdin-write-after-end.ts": 3184, + "2896-child-stdin-write-after-finish.ts": 2909, + "2897-child-stdin-destroy.ts": 3007, + "2898-child-stdin-spawn-failure.ts": 2417, + "2899-nested-mutual-recursion.ts": 2782, + "2900-float64array-static.ts": 2797, + "2900-void-conditional-arrow.ts": 2455, + "2901-bigint-core.ts": 2012, + "2902-bigint-bytes.ts": 2175, + "2903-bigint-storage.ts": 2677, + "2904-bigint-errors.ts": 2992, + "2905-bigint-edges.ts": 2250, + "2906-bigint-wasi-width.ts": 2455, + "2910-overloaded-callable-alias.ts": 2480, + "2911-execfile-callback.ts": 2820, + "2912-execfile-callback-options.ts": 2673, + "2912-promisify-fs-readfile.ts": 1599, + "2913-builtin-callable-alias.ts": 2823, + "2914-fixed-tuple-call-spread.ts": 2909, + "2915-path-function-values.ts": 2957, + "2916-path-function-values-cjs.ts": 2512, + "2917-builtin-callable-widths.ts": 3024, + "2918-builtin-callable-widths-cjs.ts": 2656, + "2919-fs-function-values.ts": 3021, + "2920-fs-promises-function-values.ts": 2741, + "2921-zlib-callbacks.ts": 3153, + "2922-dyn-bitwise-not.cjs": 2708, + "2923-cjs-factory-export/main.cjs": 2093, + "2930-union-receiver-calls.ts": 2543, + "2931-union-dynamic-field-call.js": 2484, + "2932-create-require-program/main.ts": 2505, + "2933-static-dynamic-import/main.ts": 2593, + "2934-static-import-stored.ts": 2045, + "2935-module-namespace-values/main.ts": 2788, + "2936-static-loose-equality.ts": 3392, + "2937-bitwise-hot-loop.ts": 2487, + "2938-fs-sync-overloads.cjs": 1878, + "2939-child-shell-text.ts": 3433, + "2940-date-parse.ts": 2705, + "2940-fsp-realpath.ts": 2908, + "2941-fsp-lstat-identity.ts": 3091, + "2941-process-exit-code.ts": 2544, + "2942-fsp-readdir-dirent.ts": 3069, + "2942-process-exit-code-override.ts": 2534, + "2943-process-exit-code-invalid.ts": 2277, + "2944-process-exit-code-wrap.ts": 1815, + "2945-url-origin-username.ts": 2639, + "2946-child-fork-ipc/main.ts": 3716, + "2946-url-port-hash.ts": 1906, + "2947-set-readonly-seeds.ts": 2763, + "2948-child-fork-eof-callback/main.ts": 2163, + "2948-stdio-callback-record.ts": 2566, + "2949-child-fork-default/main.mjs": 3027, + "2949-url-password.ts": 1993, + "2950-fs-descriptor-publication.ts": 2687, + "2951-math-static-analytic.ts": 3185, + "2952-math-static-remaining.ts": 2865, + "2953-http-header-validation.ts": 2969, + "2954-http-outgoing-headers.ts": 3565, + "2955-http-static-state.ts": 2954, + "2956-http-static-informational.ts": 2194, + "2957-http-static-response-controls.ts": 3186, + "2961-emitter-computed-names.cjs": 1565, + "2962-emitter-computed-optional.ts": 2714, + "2963-child-fork-dispatch/main.ts": 3146, + "2964-indexed-compound.ts": 3331, + "2966-numeric-array-read-fusion.ts": 3033, + "2967-numeric-array-read-lifetime.ts": 2835, + "2968-numeric-array-borrow.ts": 2871, + "2969-scalar-record-results.ts": 2889, + "2970-constant-numeric-tables.ts": 3083, + "2971-constant-table-modules/main.ts": 2199, + "2972-http-static-distinct-snapshots.ts": 3234, + "2972-math-receiver-borrow.ts": 3625, + "2973-http-static-agent.ts": 2730, + "2973-integer-bitwise-arithmetic.ts": 2687, + "2974-array-search-from-index.ts": 104135, + "2974-http-static-module-values.ts": 2450, + "2974-numeric-remainder.ts": 3031, + "2975-bigint-default-radix.ts": 2379, + "2975-http-static-client-controls.ts": 2663, + "2976-http-static-incoming-state.ts": 2293, + "2976-json-stringify-no-arguments.js": 2688, + "2977-http-static-incoming-timeout.ts": 2143, + "2977-nested-array-binding-defaults.js": 2455, + "2978-http-static-client-timeout.ts": 2987, + "2978-regexp-optional-subject.js": 2083, + "2979-array-search-mixed-needles.js": 2924, + "2979-http-static-server-timeout.ts": 2502, + "2980-http-static-server-timeout-default.ts": 2655, + "2980-string-position-arguments.js": 2015, + "2981-http-static-events.ts": 2563, + "2981-string-optional-positions.ts": 2841, + "2982-http-static-close-all.ts": 1931, + "2982-string-position-coercion-order.js": 2986, + "2983-http-static-close-idle.ts": 2485, + "2984-http-static-close-upgrade.ts": 2815, + "2985-http-static-message-destroy.ts": 2511, + "2986-http-static-client-socket-finish.ts": 2889, + "2987-http-static-timeout-errors.ts": 2695, + "2988-http-static-client-abort.ts": 2770, + "2989-http-static-response-timeout-handled.ts": 2973, + "2990-http-static-request-timeout-handled.ts": 3045, + "2991-array-indexed-equality.ts": 3039, + "2992-stream-rows.ts": 1990, + "2993-fiber-stack-lifetimes.ts": 3353, + "2994-fromcharcode-scalar.ts": 2251, + "2995-math-hyperbolic.ts": 3028, + "2996-math-near-one.ts": 2750, + "2997-math-integer-float.ts": 2792, + "300-if-else.ts": 2615, + "3001-caught-typeof-object.js": 2565, + "3002-promise-then-two.ts": 3076, + "301-while.ts": 2690, + "302-for.ts": 2617, + "3020-string-last-index-position.ts": 2669, + "3021-buffer-union-narrow-callback.ts": 3133, + "3022-string-affix-positions.ts": 2471, + "3023-string-affix-position-coercion.js": 2793, + "3024-string-number-narrow-for-in.ts": 2773, + "3025-string-search-position-coercion.js": 2152, + "3026-array-last-index-of.js": 2967, + "3027-array-last-index-of-records.ts": 1994, + "3028-string-search-dynamic-needle.js": 2238, + "3029-string-search-union-needle.js": 2519, + "303-break-continue.ts": 2536, + "3030-array-search-no-arg.js": 2653, + "3031-array-relative-index-coercion.js": 3093, + "3031-string-last-index-search-value.js": 1619, + "3032-string-search-value.js": 2450, + "3033-string-search-needle-coercion.js": 2494, + "3034-arguments-with-parameters.js": 3025, + "3035-string-positioned-search-value.js": 3075, + "3036-string-object-search-value.js": 2233, + "3037-number-nullish-conversion.js": 2181, + "3038-number-scalar-unions.ts": 2410, + "3039-string-repeat-count.js": 2478, + "304-compound-incdec.ts": 2719, + "3040-string-prototype-call.js": 3243, + "3041-string-prototype-object-call.js": 2455, + "3042-string-padding-coercion.js": 3099, + "3043-string-split-arguments.js": 2355, + "3044-array-slice-splice-positions.js": 2214, + "3045-array-indexed-mutation.js": 3434, + "3046-array-indexed-ref-identity.ts": 2361, + "3047-object-prototype-tag.js": 3196, + "3048-object-own-prototype.ts": 3472, + "3049-array-flat-depth.ts": 1949, + "305-truthiness.ts": 2568, + "3050-array-splice-insert.ts": 3099, + "3051-array-join-default.ts": 1846, + "3052-array-construction.ts": 3399, + "3053-array-construction-js.js": 1676, + "3054-dynamic-abort-record.ts": 1731, + "3055-default-builtin-nodenext/main.ts": 2687, + "3056-default-builtin-bundler/main.ts": 2789, + "3057-default-builtin-nodenext-dynamic/main.ts": 2579, + "3058-optional-array-chain-join.ts": 2967, + "3059-arguments-property-names.ts": 2947, + "3061-concurrent-fiber-stacks.ts": 2717, + "3062-runtime-optional-record-guards.ts": 3531, + "3063-runtime-optional-class-guards.ts": 3234, + "3064-installed-entry-imports/main.ts": 2104, + "3065-installed-entry-js/main.js": 2454, + "3066-source-debugging/main.ts": 2680, + "3067-cjs-function-export-require/main.cjs": 2781, + "3068-debug-variables/main.ts": 2201, + "3068-url-checked-identity.ts": 3005, + "3069-set-checked-seed.js": 3167, + "3069-tuple-spread.ts": 3057, + "3070-checked-object-accessors.js": 3314, + "3070-collection-views.ts": 2586, + "3071-checked-specialization-narrowing.js": 2429, + "3071-map-contextual-record-seeds.ts": 2886, + "3072-optional-union-receivers.ts": 3001, + "3072-weak-process-streams.js": 2971, + "3073-optional-callable-module.js": 2030, + "3073-union-keyed-reads.ts": 3228, + "3074-discriminated-intersections.ts": 3008, + "3075-recursive-contextual-literals.ts": 3333, + "3076-nullish-record-defaults.ts": 3030, + "3077-optional-union-array-reads.ts": 2968, + "3078-forward-mutable-captures.ts": 1926, + "3079-forward-mutable-tdz.ts": 2889, + "3080-exhaustive-never-bindings.ts": 2787, + "3081-recursive-array-destinations.ts": 2576, + "3082-forward-write-unwind.ts": 2875, + "3083-set-string-seed.ts": 2684, + "3084-record-own-membership.ts": 3102, + "3085-conditional-record-construction.ts": 1925, + "3086-error-constructor-options.ts": 3227, + "3087-error-options-lifetime.ts": 2113, + "3088-array-wide-callbacks.ts": 2993, + "3089-array-find-narrowing.ts": 3128, + "3090-json-discriminated-records.ts": 3480, + "3091-json-recursive-discriminants.ts": 2300, + "3092-number-union-predicates.ts": 2639, + "3093-error-option-data.ts": 2191, + "3094-json-replacer-traversal.ts": 2898, + "3095-json-reviver-traversal.ts": 2824, + "3096-json-callback-nonfinite.ts": 1927, + "3097-json-callback-reentrancy.ts": 3321, + "3098-json-callback-space.ts": 2551, + "3099-json-callback-functions.ts": 3507, + "3100-json-callback-holder.js": 3048, + "3101-json-callback-bytes.ts": 2658, + "3102-json-unknown-fields.ts": 2725, + "3103-scalar-record-nested-control-flow.ts": 3195, + "3104-native-analysis-tables-loops.ts": 1557, + "3105-nullable-collections.ts": 1888, + "3106-mixed-insertion-spreads.ts": 3368, + "3107-nullable-collection-lifetimes.ts": 3149, + "3108-for-await-sync-arrays.js": 4447, + "3108-identity-map-keys.ts": 3401, + "3109-destructuring-unknown-defaults.js": 2735, + "3109-identity-union-collections.ts": 3270, + "3110-builtin-error-families.ts": 2441, + "3110-identity-collection-mutation.ts": 2906, + "3111-identity-collection-cycles.ts": 3069, + "3112-union-switch-control-flow.ts": 2641, + "3113-union-array-removal.ts": 3416, + "3114-union-record-field-write.ts": 3033, + "3115-zlib-static-compression-levels.ts": 2443, + "3116-sequence-expression-lifetimes.ts": 3044, + "3117-unknown-switch-control-flow.ts": 2684, + "3118-recursive-union-spread.ts": 2422, + "3119-runtime-optional-spread.ts": 2447, + "3120-dynamic-property-descriptors.js": 3293, + "3120-generator-method-loop-bindings.ts": 3248, + "3120-ir-nonfinite-numbers.ts": 3000, + "3121-compound-assignment-values.js": 2549, + "3121-dynamic-accessor-descriptors.js": 3250, + "3122-dynamic-delete-descriptors.cjs": 2600, + "3122-dynamic-delete-descriptors.js": 2091, + "3122-js-async-class-methods.js": 2297, + "3123-destructured-global-tdz.js": 2836, + "3124-array-prototype-borrow.js": 3537, + "3125-regex-global-match.ts": 2402, + "3126-js-number-radix/main.ts": 3052, + "3127-spawn-runtime-options.ts": 3285, + "3128-regex-last-index.ts": 3076, + "3129-js-token-union/main.ts": 2700, + "3130-child-generic-streams.ts": 3044, + "3131-child-rest-listeners.js": 2943, + "3132-child-generic-stream-completion.ts": 6235, + "3133-text-decoder-streaming.ts": 2265, + "3134-fs-vectors.ts": 2815, + "3135-fs-file-handle-controls.ts": 2278, + "3136-fs-file-handle-options.ts": 3814, + "3137-fs-vector-callbacks.cjs": 3509, + "3138-array-large-storage.ts": 4245, + "3139-regex-native-deep-alternatives.ts": 27587, + "3140-array-dense-access.ts": 3800, + "3141-map-string-key-hash.ts": 2566, + "3150-integer-remainder.ts": 3289, + "3151-array-push-writes.ts": 3227, + "3170-number-conversion-fast-paths.ts": 2553, + "3171-method-census-data-writes.ts": 3442, + "400-fib.ts": 2589, + "401-mutual-recursion.ts": 2527, + "402-string-functions.ts": 2176, + "403-void-and-params.ts": 2350, + "4030-runtime-object-truthiness.ts": 2749, + "4031-event-emitter-long-tuples.ts": 2083, + "4032-inline-rc-fast-paths.ts": 4192, + "404-rc-stress.ts": 2456, + "4040-adapted-function-identity.ts": 2867, + "4041-adapted-function-properties.ts": 2991, + "4042-object-is-union-subclass.ts": 2310, + "4043-nonnull-missing-element.ts": 2433, + "4044-adapted-callback-modules/main.ts": 2886, + "4045-optional-element-projections.ts": 3138, + "4046-captured-parameter-values.ts": 3423, + "4047-captured-parameter-rebinding.ts": 2500, + "405-params-optional.ts": 2755, + "406-params-defaults.ts": 2105, + "4060-cycle-shared-instance/main.ts": 2837, + "4060-stack-union-reads.ts": 3299, + "4061-cycle-evaluation-order/main.ts": 2712, + "4061-nullable-ref-fields.ts": 4653, + "4062-cycle-tdz-read/main.ts": 1857, + "4063-cycle-hoisted-calls/main.ts": 2616, + "4064-cycle-classes-after-init/main.ts": 2926, + "4065-cycle-init-throws/main.ts": 2592, + "4066-cycle-top-level-tdz/main.ts": 1456, + "4067-dynamic-import-cycle-tdz/main.ts": 2785, + "407-params-rest.ts": 2693, + "408-params-ctors-inheritance.ts": 2837, + "4080-optional-read-presence-tests.ts": 2357, + "4080-string-index-bounds.ts": 2174, + "4081-hoisted-function-tdz.ts": 3131, + "4081-string-index-unproven.ts": 2850, + "4082-hoisted-function-tdz-uncaught.ts": 2634, + "4083-dynamic-import-failure/main.ts": 2355, + "4084-record-optional-field-copies.ts": 2952, + "4085-generator-loop-close.ts": 3078, + "4086-optional-capture-defaults.ts": 2684, + "4088-class-static-tdz.ts": 2183, + "4089-class-wrapper-tdz.js": 2911, + "409-params-async-generics.ts": 1894, + "4090-computed-key-tdz.js": 2483, + "4091-class-evaluation-deferred.ts": 3134, + "410-params-rc-stress.ts": 1591, + "4140-array-callback-split-visit.ts": 4467, + "4141-array-callback-ambient-receiver/main.ts": 2178, + "4142-array-callback-factories.ts": 3521, + "4143-union-refinement-intersection-arms.ts": 3254, + "420-dead-strip-modules/main.ts": 2523, + "4290-acyclic-immutable-trees.ts": 3062, + "4291-acyclic-constructor-escapes.ts": 2390, + "4292-acyclic-readonly-bypass.ts": 1956, + "4293-acyclic-dynamic-writes.ts": 3149, + "4294-console-line-sizes.ts": 5491, + "4295-console-template-parts.ts": 3025, + "4296-console-glued-long-parts.ts": 4102, + "4410-inline-object-allocation.ts": 3371, + "4411-nullable-ref-values.ts": 3446, + "4412-nullable-record-values.ts": 3505, + "4413-cycle-old-late-death.ts": 3210, + "4413-nullable-null-and-undefined.ts": 3960, + "4414-cycle-old-weak-keys.ts": 2210, + "4414-nullable-string-values.ts": 3960, + "4415-identity-borrowed-operands.ts": 2923, + "4415-nullable-container-values.ts": 4078, + "4431-exception-pending-contexts.ts": 3547, + "4432-checked-downcast-failures.ts": 3362, + "4451-int32-field-storage.ts": 3587, + "4452-int32-field-dynamic-writes.ts": 2629, + "4453-int32-closed-locals.ts": 2708, + "4454-int32-field-reflection-reads.ts": 3626, + "4455-live-view-reads-without-stores.ts": 3673, + "4471-unassigned-field-reads.ts": 3063, + "4476-string-ascii-header-fact.ts": 3053, + "4477-buffer-write-ascii-runs.ts": 1845, + "4478-string-large-index-reads.ts": 2385, + "4481-array-optional-push.ts": 2921, + "4482-instanceof-static-class-optional.ts": 2110, + "4483-array-splice-statement.ts": 3260, + "4484-array-length-reset.ts": 2963, + "4485-array-splice-optional-item.ts": 3033, + "4486-array-field-element-borrows.ts": 2099, + "4487-array-literal-optional-values.ts": 2387, + "4520-optional-guard-narrowing.ts": 3290, + "4521-array-callback-element-presence.ts": 4205, + "4522-captured-parameter-lifetimes.ts": 3072, + "4523-array-pop-removal.ts": 2939, + "4524-array-callback-supertype-params.ts": 4250, + "4541-nullable-wrap-borrows.ts": 2850, + "4542-preserving-call-borrows.ts": 3298, + "4543-walk-borrowed-locals.ts": 3324, + "4544-checked-cast-aliases.ts": 2878, + "4545-borrowed-returns.ts": 3935, + "4546-rebound-borrowed-params.ts": 2128, + "4560-field-store-borrowed-receivers.ts": 3268, + "4561-virtual-borrowed-parameters.ts": 2119, + "4562-string-self-concat-move.ts": 2875, + "4563-array-read-projection-receivers.ts": 2961, + "4564-literal-choice-strings.ts": 3091, + "4568-for-of-hole-elements.ts": 3194, + "4569-shorthand-missing-elements.ts": 2799, + "4570-map-lookup-default-record.ts": 2885, + "4591-weak-keys-union-records.ts": 3283, + "4592-cycle-const-from-import/main.ts": 2283, + "4593-weak-keys-empty-objects.ts": 1759, + "4594-union-class-field-mixed-types.ts": 3165, + "4595-union-class-field-optional-receiver.ts": 2742, + "4596-error-subclass-int-fields.ts": 2574, + "4596-tdz-nullable-forward-capture.ts": 3762, + "4597-callback-field-method-name.ts": 3397, + "4598-live-array-ref-element-access.ts": 4852, + "4598-map-set-clear-reuse.ts": 4729, + "4598-os-available-parallelism.ts": 2510, + "4598-publish-constructor-stores.ts": 1852, + "4599-construction-only-field-borrows.ts": 3236, + "4600-construction-only-fields-dynamic-writes.ts": 3072, + "4601-cycle-holders.ts": 2734, + "4602-constructor-escape-order.ts": 2610, + "4610-array-ext-dyn-refresh.ts": 2862, + "4620-optional-chain-borrowed-receivers.ts": 3224, + "4621-edge-preserving-callees/main.ts": 3365, + "4630-contract-int32.ts": 2754, + "4630-reference-write-call-arguments.ts": 3053, + "4631-contract-nothrow.ts": 2070, + "4631-reference-write-aliases.ts": 2695, + "4632-contract-immutable.ts": 2863, + "4632-reference-write-loops-and-walks.ts": 3098, + "4633-contract-program-lifetime.ts": 3689, + "4633-reference-write-callbacks-returns.ts": 3144, + "4634-contract-program-lifetime-publish.ts": 4904, + "4634-optional-element-borrowed-returns.ts": 2709, + "4640-bitwise-identity-ranges.ts": 2778, + "4641-nothrow-try-catch.ts": 2708, + "4642-acyclic-contract.ts": 3288, + "4650-stale-property-narrowing.ts": 3851, + "4651-map-string-get-entry.ts": 3371, + "4652-stale-closure-binding-narrowing.ts": 3495, + "4660-typed-rest-spread-forwarding.ts": 2766, + "4671-scoped-array-read-borrows.ts": 3085, + "4690-cycle-bypass-long-lived.ts": 2735, + "4691-publish-constructor-self-alias.ts": 3219, + "4692-borrowed-result-mutating-callees.ts": 2601, + "4720-cold-throw-paths.ts": 3390, + "4721-integer-induction-numbers.ts": 2467, + "4730-touint32-large-magnitudes.ts": 3097, + "4731-string-mixed-ascii-slices.ts": 2704, + "4732-buffer-write-utf16le-runs.ts": 1998, + "4733-typed-array-read-compares.ts": 3234, + "4750-map-string-absent-filter.ts": 3594, + "4751-string-search-multibyte-needles.ts": 2725, + "4795-published-untyped-member-reads.ts": 3268, + "4806-uint32-loop-accumulators.ts": 3231, + "4810-union-identity-retags.ts": 4620, + "4811-union-retag-checked-cast.ts": 3091, + "4812-int32-wrapping-sums.ts": 3463, + "4813-typed-array-read-equality-bindings.ts": 4674, + "4820-sort-comparator-lent-arguments.ts": 4000, + "4821-callback-lent-arguments.ts": 2333, + "4822-stable-capture-reads.ts": 2409, + "4823-array-store-receivers.ts": 2969, + "4830-typed-teardown-chains.ts": 2905, + "4831-cycle-bypass-probe-windows.ts": 2840, + "4840-array-hole-free-prefix.ts": 2459, + "4860-int32-local-storage.ts": 4170, + "4870-array-pipeline-fusion.ts": 7346, + "4871-array-pipeline-analytics.ts": 4533, + "4872-array-pipeline-temporaries.ts": 7994, + "4875-stream-consumers-array-buffer.ts": 3281, + "4876-array-buffer-inspect.ts": 2814, + "4880-await-call-turn-order.ts": 1921, + "4881-await-call-exceptions.ts": 3225, + "4882-await-call-request-chain.ts": 3022, + "4883-await-values-and-hops.ts": 2825, + "4884-await-call-unhandled-sibling.ts": 2163, + "4885-await-call-checkpoints.ts": 2954, + "4890-regex-literal-sites.ts": 3163, + "4891-regex-plain-text-patterns.ts": 2001, + "4892-regex-exec-read-captures.ts": 3652, + "4900-bigint-division-cross-check.ts": 3357, + "4900-console-instances.ts": 3637, + "4901-bigint-radix-text.ts": 2779, + "4901-console-instance-errors.ts": 3196, + "4902-bigint-compound-assign.ts": 1706, + "4903-bigint-fixed-width.ts": 3128, + "4904-bigint-large-products.ts": 3340, + "4905-bigint-fixed-width-fusion.ts": 3031, + "4906-bigint-small-value-trees.ts": 3759, + "4907-bigint-random-trees.ts": 5188, + "4910-hole-free-prefix-upkeep.ts": 3084, + "4920-string-literal-switch.ts": 3310, + "4930-typed-record-reflection.ts": 4737, + "4931-typed-data-generic-walks.ts": 4118, + "4932-typed-json-unknown.ts": 3475, + "4940-async-return-adoption.ts": 3491, + "4941-async-return-adoption-try.ts": 3096, + "4942-async-return-adoption-values.ts": 2964, + "4943-async-return-adoption-interleaved.ts": 2876, + "4950-regex-compiled-captures.ts": 4852, + "4951-regex-compiled-last-index.ts": 2706, + "4952-regex-compiled-anchors-classes.ts": 2724, + "4953-regex-compiled-backtracking.ts": 4297, + "4954-regex-log-report.ts": 3687, + "4955-regex-compiled-differential.ts": 13757, + "4970-int32-call-abi.ts": 3580, + "4980-generator-early-exit-finally.ts": 3050, + "4981-generator-delegation-iterables.ts": 4127, + "4982-generator-sent-values.ts": 2957, + "4983-generator-reuse-iterables.ts": 3475, + "4984-generator-exceptions.ts": 3390, + "4985-generator-lazy-pipeline.ts": 3419, + "4986-generator-default-channels.ts": 3152, + "4987-generator-closures-methods.ts": 3151, + "4988-generator-async-interplay.ts": 2316, + "4989-generator-step-drives.ts": 3427, + "4990-lone-surrogates.ts": 3491, + "4991-lone-surrogate-halves.ts": 3293, + "4992-lone-surrogate-search.ts": 2456, + "4993-lone-surrogate-json.ts": 3728, + "4994-lone-surrogate-uri.ts": 1777, + "4995-lone-surrogate-regex.ts": 2799, + "4996-lone-surrogate-stdio.ts": 3100, + "4997-lone-surrogate-stdout-patch.js": 1716, + "4998-lone-surrogate-buffers.ts": 3414, + "4999-lone-surrogate-io.ts": 2886, + "500-array-basics.ts": 2955, + "501-array-push-pop.ts": 1902, + "5010-lifetime-region-generations.ts": 3477, + "5011-lifetime-region-outside-references.ts": 2843, + "5012-lifetime-region-shapes.ts": 4150, + "5013-lifetime-region-async.ts": 3814, + "5014-lifetime-region-nesting.ts": 2997, + "5015-lifetime-region-publish.ts": 2741, + "5016-lifetime-region-weak-keys.ts": 3235, + "5017-lifetime-region-cycles.ts": 3057, + "5018-lifetime-region-hierarchies.ts": 4043, + "5019-lifetime-region-values.ts": 2895, + "502-array-for-of.ts": 2808, + "5020-lifetime-region-large.ts": 3808, + "5021-lifetime-region-opaque-holders.ts": 3422, + "5022-lifetime-region-workers.ts": 2531, + "503-array-functions.ts": 2837, + "504-array-rc-stress.ts": 2722, + "5040-promise-all-race-turns.ts": 3860, + "5041-promise-all-turns.js": 3644, + "5042-async-generator-return-promise.ts": 3304, + "5043-async-generator-return-forms.ts": 3190, + "5045-generator-delegation-typed-next.ts": 3751, + "5046-generator-delegation-return-throw.ts": 2749, + "5047-generator-delegation-iterables-typed.ts": 4798, + "5048-generator-delegation-async.ts": 3315, + "5049-generator-delegation-edges.ts": 3539, + "5050-inherited-in-membership.ts": 3427, + "5051-typed-record-prototypes.ts": 2418, + "5052-class-for-in-unknown.ts": 3692, + "5053-json-replacer-arrays.ts": 3781, + "5054-required-field-delete.ts": 2108, + "5055-object-create-record-literal.ts": 2773, + "5056-generator-in-unknown.ts": 2634, + "5060-child-fork-exit-after-messages/main.ts": 2129, + "5061-child-fork-local-disconnect/main.ts": 3136, + "5062-child-fork-message-before-eof/main.ts": 3024, + "5065-global-increment-initializers.ts": 2900, + "5066-global-compound-updates.ts": 3224, + "5067-global-updates-in-functions.ts": 2208, + "5068-global-var-let-const-updates.ts": 2542, + "5069-global-update-modules/main.ts": 1962, + "5070-optional-read-bindings.ts": 2623, + "5071-optional-chain-scalars.ts": 2743, + "5072-optional-nullish-ternary.ts": 2840, + "5073-optional-results.ts": 3242, + "5074-optional-pop-shift.ts": 2144, + "5075-optional-reads-unchecked/main.ts": 3167, + "5076-optional-escapes.ts": 2155, + "5080-boolean-array-storage.ts": 4783, + "5081-boolean-array-dynamic-views.ts": 2550, + "5085-promise-allsettled-turns.ts": 4142, + "5086-promise-any-turns.ts": 3722, + "5087-promise-allsettled-any-dyn.js": 5509, + "5088-promise-combinator-thenables.js": 4706, + "5089-promise-settled-records.ts": 3855, + "5090-generator-finished-result-value.ts": 2787, + "5091-generator-delegation-arrays-strings.ts": 4059, + "5092-generator-delegation-sets-maps.ts": 3822, + "5095-console-count-group.ts": 3219, + "5096-console-assert-dir.ts": 3665, + "5097-console-table.ts": 2407, + "5098-console-time-warnings.ts": 5609, + "5099-console-methods-dynamic.cjs": 3155, + "510-array-map-filter-foreach.ts": 2313, + "511-array-indexof-includes.ts": 2884, + "5110-var-hoisting-early-reads.ts": 2759, + "5111-var-hoisting-closures-classes.ts": 2869, + "5112-var-hoisting-function-scope.ts": 2697, + "5113-tdz-let-const-class.ts": 2402, + "5114-var-hoisting-js.js": 2192, + "5115-regex-replace-compiled.ts": 2826, + "5116-regex-capture-reads.ts": 3329, + "5117-regex-log-report-spans.ts": 3686, + "5118-regex-replace-char-chains.ts": 2917, + "512-array-join-chains.ts": 1729, + "5120-frame-records.ts": 2763, + "5121-frame-objects.ts": 2346, + "5122-frame-result-slots.ts": 3086, + "5123-frame-reassigned.ts": 2807, + "5124-frame-objects-control.ts": 2789, + "5125-frame-mutating-methods.ts": 2122, + "5126-frame-returned-params.ts": 2597, + "5127-frame-loop-bindings.ts": 2498, + "513-array-methods-rc-stress.ts": 3202, + "5130-event-target-dispatch.js": 4435, + "5131-event-target-listener-errors.js": 1856, + "5132-event-target-typed.ts": 2296, + "5133-abort-signal-event-target.ts": 3474, + "5134-events-error-monitor.ts": 2972, + "5135-event-target-warnings.js": 2909, + "5136-events-error-monitor-string-name.ts": 2529, + "5137-events-error-monitor-computed-name.js": 3132, + "5138-events-error-monitor-shared-listener.ts": 2744, + "5139-event-target-listener-throw.ts": 2800, + "514-array-find-some-every.ts": 3281, + "5140-os-host-facts.ts": 3044, + "5141-os-constants.ts": 3300, + "5142-path-parse-format.ts": 2224, + "5145-path-matches-glob-basics.ts": 2906, + "5146-path-matches-glob-braces.ts": 5151, + "5147-path-matches-glob-extglob.ts": 2798, + "5148-path-matches-glob-classes.ts": 2450, + "5149-path-matches-glob-win32.ts": 3351, + "515-array-flatmap.ts": 3014, + "5150-small-array-inline-slots.ts": 3873, + "5155-cycle-header-types.ts": 3715, + "516-array-reduce.ts": 3532, + "5160-field-callback-receiver.ts": 3321, + "5161-field-callback-receiver-escape.ts": 2766, + "5162-field-method-reference-receiver.ts": 2634, + "5163-field-callback-receiver.cjs": 3329, + "5164-worker-field-callback-receiver.ts": 3447, + "5165-interface-method-dispatch.ts": 3406, + "5166-interface-method-values.ts": 4300, + "5167-interface-method-order.ts": 3903, + "5168-interface-method-hierarchy.ts": 5186, + "5169-interface-method-chains.ts": 2434, + "517-array-hof-index-args.ts": 3100, + "5170-string-scan-eviction.ts": 1929, + "5171-lone-surrogate-replace-seams.ts": 2824, + "5175-forin-typed-as-unknown.ts": 2364, + "5176-object-keys-typed-as-unknown.ts": 1967, + "5177-forin-dynamic-objects.ts": 2917, + "5178-forin-keys-js.js": 3039, + "5179-forin-typed-shapes.ts": 3389, + "518-array-sort.ts": 3117, + "518-promise-void-union-callbacks.ts": 2562, + "5180-interface-arrays.ts": 3202, + "5181-interface-array-methods.ts": 6982, + "5182-interface-array-boundaries.ts": 3287, + "5183-interface-property-reads.ts": 3238, + "5184-interface-property-objects.ts": 3177, + "5185-util-inherits.cjs": 3654, + "5186-util-inherits.ts": 3139, + "5187-util-deprecate.cjs": 2383, + "5188-util-deprecate-flags.cjs": 2907, + "5189-util-deprecate.ts": 2180, + "519-array-from-length.ts": 2896, + "519-promise-union-await-values.ts": 2702, + "5190-util-callbackify.cjs": 3059, + "5191-util-callbackify.ts": 3126, + "5192-util-debuglog.cjs": 3809, + "5193-util-debuglog.ts": 2614, + "5194-process-emit-warning-tick.cjs": 2394, + "5195-object-entries-typed-as-unknown.ts": 3883, + "5196-object-values-typed-as-unknown.ts": 3399, + "5197-object-entries-dynamic-objects.ts": 3397, + "5198-object-entries-values-js.js": 2635, + "5199-object-entries-identity.ts": 3121, + "520-map-basics.ts": 2823, + "5200-array-sort-keyed-numbers.ts": 4287, + "5201-array-sort-keyed-records.ts": 4564, + "5202-array-sort-keyed-lookalikes.ts": 3516, + "5203-typed-array-sort-default.ts": 6009, + "5204-typed-array-sort-comparators.ts": 4333, + "521-map-number-keys.ts": 2785, + "5210-process-memory-usage.ts": 2299, + "5211-process-identity.ts": 3103, + "5212-perf-marks-measures.ts": 3829, + "5213-perf-timing-errors.ts": 3477, + "5214-perf-entry-inspect.ts": 4088, + "5215-perf-timing-validation.js": 3386, + "5216-perf-spread-arguments.js": 4128, + "5217-perf-spread-typed.ts": 3454, + "522-map-foreach.ts": 2702, + "5220-url-parse-warnings.ts": 2881, + "5221-url-parse-shapes.ts": 1930, + "5222-url-parse-hosts.ts": 3064, + "5223-url-parse-query.ts": 3104, + "5224-url-format-objects.ts": 3496, + "5225-url-format-whatwg.ts": 2608, + "5226-url-resolve.ts": 2695, + "5227-url-legacy-dependency/main.ts": 2825, + "5228-url-domain-conversion.ts": 2843, + "5229-url-legacy-errors.cjs": 3833, + "523-map-ref-values.ts": 3192, + "5230-inline-union-fields.ts": 2629, + "5231-inline-union-field-kinds.ts": 2513, + "5232-inline-union-fields-dynamic.ts": 3917, + "5233-inline-union-fields-shapes.ts": 3689, + "5234-inline-union-class-fields.ts": 3417, + "5235-inline-union-fields-publish.ts": 2910, + "5236-inline-union-unchecked-reads.ts": 2919, + "5237-inline-union-frame-objects.ts": 2775, + "524-map-cycles.ts": 2820, + "5240-event-target-subclass.ts": 4712, + "5241-event-subclass.ts": 3442, + "5242-event-target-subclass-hierarchy.ts": 3429, + "5243-event-target-subclass-dynamic.ts": 3827, + "5244-event-target-subclass.js": 3772, + "5245-event-target-subclass-signals.ts": 3197, + "5246-event-target-subclass-listener-throw.ts": 1982, + "5247-event-target-subclass-lifetimes.ts": 4315, + "5248-event-target-subclass-warnings.ts": 2798, + "5249-event-target-subclass-unconstructed.ts": 2600, + "525-map-rc-stress.ts": 2751, + "5250-cipher-aes-gcm.ts": 6095, + "5251-cipher-aes-cbc.ts": 3544, + "5252-cipher-aes-ctr.ts": 2536, + "5253-cipher-chacha20-poly1305.ts": 3577, + "5254-cipher-errors.js": 3835, + "5255-cipher-encodings.cjs": 3839, + "5256-cipher-deprecation.cjs": 3149, + "5257-cipher-vectors.ts": 3374, + "5258-cipher-handles.js": 2798, + "5259-cipher-chunked.ts": 3781, + "526-set-basics.ts": 2514, + "5260-record-unknown-identity.ts": 3342, + "5261-optional-field-identity.ts": 2813, + "5262-record-unknown-many.ts": 2768, + "527-set-foreach.ts": 2947, + "5270-url-parse-no-deprecation.cjs": 3204, + "5271-url-parse-throw-deprecation.cjs": 3229, + "5275-http-end-callback-order.ts": 3224, + "5276-style-text-hex-colors.cjs": 2193, + "5277-fs-read-file-buffer-option.cjs": 1864, + "5278-host-null-bytes.cjs": 2972, + "5279-search-params-null-init.cjs": 1662, + "528-set-seeded.ts": 1937, + "5285-blob-construct.ts": 3802, + "5286-blob-readers.ts": 2609, + "5287-blob-inspect.ts": 2930, + "5288-blob-validation.js": 4282, + "5289-blob-read-order.ts": 3276, + "529-map-seeded.ts": 2575, + "5290-blob-dynamic.js": 3409, + "5295-readline-promises-question.ts": 2860, + "5296-readline-lines.ts": 3085, + "5297-readline-callback-events.cjs": 2092, + "5298-readline-abort.cjs": 3384, + "5299-readline-stdin.ts": 2909, + "530-record-arrays.ts": 3090, + "5300-stream-add-abort-signal.ts": 2505, + "5301-stream-add-abort-signal-errors.cjs": 3168, + "5302-stream-promises-options.ts": 2812, + "5303-stream-finished-callback-opts.cjs": 2840, + "5305-json-stringify-typed-arrays.ts": 4425, + "531-record-array-hofs.ts": 3107, + "5315-map-iterate-after-front-deletes.ts": 3372, + "5316-map-lru-eviction.ts": 2980, + "5317-map-iterate-while-mutating.ts": 3025, + "5318-set-iterate-after-deletes.ts": 2325, + "5319-map-iteration-values.ts": 2767, + "532-record-arrays-rc-stress.ts": 2605, + "5320-map-iterate-across-compaction.ts": 3341, + "5321-integer-closed-arithmetic-loops.ts": 2935, + "5321-json-parse-cycles.ts": 2739, + "5322-integer-variable-step-loops.ts": 2732, + "5322-json-stringify-parsed-trees.ts": 3539, + "5323-dyn-numeric-index-reads.ts": 1771, + "5323-int32-nonnegative-slot-facts.ts": 2925, + "5324-int32-initializer-locals.ts": 2126, + "5324-structured-clone-documents.ts": 3093, + "5325-record-boundary-returns.ts": 2952, + "5326-record-boundary-params.ts": 3045, + "5327-record-boundary-identity.ts": 2913, + "5328-record-boundary-open.ts": 2787, + "5329-record-boundary-recursion.ts": 2543, + "533-array-element-cycles.ts": 2595, + "5330-record-boundary-fields.ts": 2690, + "5331-record-boundary-methods.ts": 2941, + "5332-int32-narrowed-slot-facts.ts": 3036, + "5333-integer-guarded-while-counters.ts": 2907, + "5333-record-boundary-nullable-argument.ts": 3066, + "5334-fetch-mentions-without-calls.ts": 2537, + "5335-stream-operators-values.ts": 3463, + "5335-top-level-await-pending-exit-code.ts": 2626, + "5336-stream-operators-promise-timing.ts": 3056, + "5336-top-level-await-pending-exit-listener.ts": 2547, + "5337-dc-subscriber-throw-next-tick.cjs": 2655, + "5337-stream-operators-concurrency.ts": 2539, + "5338-js-tdz-function-element.js": 2247, + "5338-stream-operators-checks.cjs": 3619, + "5339-array-buffer-constructor.js": 3106, + "5339-stream-for-await-hops.ts": 2525, + "534-record-width-subtyping.ts": 2764, + "5340-readable-from-options.ts": 3427, + "5341-compound-any-operand.ts": 3571, + "5341-generator-callback-params.ts": 3696, + "5341-integer-recursion-boundaries.ts": 2410, + "5341-readable-from-dynamic.cjs": 3652, + "5342-compound-any-operand.cjs": 2807, + "5342-generator-scalar-channels.ts": 2386, + "5342-integer-recursion-stack-and-mutual.ts": 2999, + "5342-stream-compose.ts": 3332, + "5343-any-flow-compound.ts": 1598, + "5343-integer-recursion-array-index.ts": 3219, + "5343-iterator-result-records.ts": 2018, + "5343-stream-compose-edges.ts": 3167, + "5344-json-parse-undeclared-keys.ts": 4016, + "5344-stream-pipeline-timing.ts": 3216, + "5345-object-values-for-of-unknown.ts": 2662, + "5346-object-values-length-dynamic.ts": 3253, + "5347-object-values-loop-control.ts": 3534, + "5348-object-values-for-of-js.js": 3133, + "5349-object-entries-values-optional.ts": 3434, + "535-object-statics.ts": 3684, + "5350-object-values-wide-record.ts": 3383, + "5351-object-values-methods-index.ts": 4044, + "5352-final-field-loop-reads.ts": 2982, + "5353-captured-const-values.ts": 3255, + "5354-captured-const-tdz.ts": 1913, + "5355-captured-function-declarations.ts": 2960, + "5356-captured-tdz-ordering.ts": 2164, + "5357-init-only-module-bindings.ts": 3203, + "536-map-seed-array.ts": 2803, + "5360-array-sort-comparator-calls.ts": 2961, + "5361-array-sort-inconsistent-comparators.ts": 2659, + "5362-array-sort-comparator-throws.ts": 2991, + "5363-array-sort-comparator-writes.ts": 5900, + "5364-array-sort-union-and-boolean-elements.ts": 10497, + "5365-array-sort-dynamic-values.js": 3189, + "537-map-iter-drains.ts": 2987, + "5370-zlib-stream-roundtrip.ts": 3454, + "5371-zlib-stream-chunking.cjs": 3925, + "5372-zlib-stream-errors.cjs": 2700, + "5373-zlib-stream-options.cjs": 3872, + "5374-zlib-stream-flush-params.ts": 3102, + "5375-zlib-stream-promises.ts": 2399, + "5376-zlib-constants.cjs": 2483, + "5377-zlib-stream-backpressure.cjs": 3427, + "5378-zlib-sync-options.cjs": 2176, + "5379-zlib-callback-options.ts": 3566, + "538-map-set-for-of.ts": 2976, + "5390-interface-loop-element-lifetimes.ts": 3153, + "5391-interface-dispatch-hierarchies.ts": 3899, + "5392-interface-receiver-bindings.ts": 3131, + "5393-interface-array-holes.ts": 3093, + "5394-interface-implementers.ts": 3579, + "5395-locale-compare-ascii.ts": 2963, + "5396-locale-compare-latin.ts": 1885, + "5397-locale-compare-sorting.ts": 3156, + "540-tuples-basics.ts": 2555, + "5400-json-parse-typed-keys.ts": 3448, + "5405-buffer-arraybuffer-window.ts": 3039, + "5406-util-types-keys.ts": 2823, + "5407-http-header-field-limit.ts": 3316, + "5408-http-unread-request-end.ts": 3667, + "5409-http-held-request-body.ts": 2506, + "541-ref-array-json.ts": 2521, + "5410-inspect-class-values.ts": 2528, + "5411-inspect-class-hierarchies.ts": 3094, + "5412-inspect-dynamic-collections.ts": 3071, + "5413-inspect-class-values.cjs": 3263, + "5415-zlib-dynamic-inputs.cjs": 2520, + "542-union-element-arrays.ts": 2223, + "5420-readable-from-generators.ts": 3661, + "5421-readable-from-generators.cjs": 3036, + "5422-stream-async-push-wakeup.ts": 3138, + "5423-stream-end-and-eos-timing.ts": 3247, + "5424-stream-write-buffer-encoding.ts": 2663, + "5425-pipeline-generator-stage.ts": 2060, + "5426-pipeline-generator-errors.ts": 3490, + "5427-pipeline-generator-backpressure.ts": 2729, + "5428-pipeline-generator-stages.cjs": 3499, + "5429-pipeline-generator-buffers.ts": 3223, + "5430-dyn-number-string-boxes.ts": 3048, + "5435-crypto-hash-algorithms.ts": 2461, + "5436-crypto-hash-names.js": 3064, + "5437-crypto-hmac-algorithms.ts": 3107, + "5438-crypto-kdf-digests.ts": 3109, + "5439-crypto-kdf-callbacks.js": 2368, + "5440-crypto-hash-encodings.js": 4093, + "5441-crypto-hash-output-length.ts": 3652, + "5442-crypto-random-values.ts": 4190, + "5443-crypto-random-arguments.js": 3529, + "5444-crypto-timing-safe-equal.js": 3508, + "5445-crypto-secret-key-objects.ts": 3186, + "5445-stream-buffer-chunks.ts": 3012, + "5446-crypto-secret-key-errors.js": 3785, + "5446-stream-buffer-chunks-dynamic.js": 3127, + "5447-fs-readdir-order.ts": 2143, + "5448-fs-glob-patterns.ts": 3113, + "5449-fs-glob-options.ts": 3649, + "5450-fs-glob-validation.js": 2855, + "5451-fs-promises-glob.ts": 3569, + "5452-fs-glob-callback.ts": 2885, + "5455-power-of-two-remainder.ts": 3093, + "5456-remainder-large-integer-dividends.ts": 2991, + "5457-lcg-modulus.ts": 2871, + "5458-fractional-remainder.ts": 2988, + "5460-locale-compare-contractions.ts": 2881, + "5461-locale-compare-equivalents.ts": 2942, + "5462-locale-compare-probe-sweep.ts": 2752, + "5463-locale-compare-combining-letters.ts": 3006, + "5464-locale-compare-fractions.ts": 2946, + "5465-dyn-index-read-arrays.ts": 3424, + "5466-dyn-index-read-special.ts": 2632, + "5470-strip-vt-osc.cjs": 2376, + "5471-strip-vt-csi.cjs": 2167, + "5472-strip-vt-random.cjs": 3001, + "5473-strip-vt-unterminated.cjs": 3560, + "5474-strip-vt-surrogates.ts": 3301, + "5510-assert-error-properties.js": 3653, + "5511-assert-error-class.ts": 3637, + "5512-assert-error-options.js": 3115, + "5513-assert-deep-equal-loose.js": 3866, + "5514-assert-deep-equal-typed.ts": 3778, + "5515-assert-deep-strict-typed-messages.ts": 1850, + "5516-assert-deep-equal-edges.js": 3662, + "5517-assert-partial-deep-equal.js": 2640, + "5518-assert-partial-deep-typed.ts": 3542, + "5519-assert-partial-deep-typed-edges.ts": 3280, + "5520-assert-record-literal-failures.ts": 3499, + "5520-dyn-property-read-receivers.ts": 3367, + "5521-assert-empty-message.js": 3321, + "5521-dyn-property-read-keys.ts": 2391, + "5522-assert-throws-failure-properties.ts": 3436, + "5523-assert-class-options.js": 3102, + "5524-assert-class-skip-prototype.ts": 3823, + "5530-buffer-pool.ts": 3971, + "5531-buffer-pool-first-slab.ts": 5569, + "5532-buffer-pool-first-slab-untyped.mjs": 40038, + "5540-fs-callback-forms.cjs": 3631, + "5541-fs-stats-fields.cjs": 3800, + "5542-fs-promises-parity.cjs": 3962, + "5543-fs-promises-typed.ts": 2212, + "5544-fs-opendir.cjs": 3332, + "5545-fs-options-encoding.cjs": 4482, + "5546-fs-read-stream.cjs": 4502, + "5547-fs-write-stream.cjs": 5101, + "5548-fs-callback-arguments.cjs": 4306, + "5549-fs-callback-option-checks.cjs": 4187, + "5550-locale-compare-ascii-words.ts": 2669, + "5551-array-search-references.ts": 3663, + "5552-string-appends.ts": 3195, + "5553-string-append-char-code.ts": 2446, + "5554-fs-streams-typed.ts": 3785, + "5555-fs-callback-turns.cjs": 3093, + "5555-http-server-close-keep-alive.ts": 7242, + "5556-http-client-agent-connection.ts": 2788, + "5557-http-outgoing-header-values.ts": 3401, + "5558-http-incoming-duplicate-headers.ts": 2354, + "5559-http-expect-header.ts": 3766, + "5560-http-response-framing.ts": 4849, + "5561-http-max-header-size.ts": 3443, + "5562-https-verify-errors.ts": 3494, + "5563-http-keep-alive-timeout.ts": 11607, + "5564-http-request-signal.ts": 3916, + "5565-fs-dirent-untyped.mjs": 3810, + "5566-fs-dirent-dyn-boundaries/main.mjs": 3533, + "5567-fs-cpsync.ts": 3626, + "5568-fs-cp-errors.js": 3163, + "5569-fs-cp-symlinks.ts": 3704, + "5570-fs-cp-async.ts": 3480, + "5571-fs-cp-deep.ts": 4934, + "5585-record-results-inlined.ts": 3154, + "5595-net-ref-unref.ts": 2641, + "5600-dyn-cycle-self.ts": 2124, + "5601-dyn-cycle-mutual.ts": 3279, + "5602-dyn-cycle-arrays.ts": 2568, + "5603-dyn-cycle-identity.ts": 2702, + "5604-dyn-cycle-checks.ts": 3057, + "5605-dyn-cycle-containers.ts": 3526, + "5606-dyn-cycle-capsules.ts": 1609, + "5610-readable-from-sets-and-views.ts": 3539, + "5611-readable-from-class-iterables.ts": 2637, + "5612-readable-from-iterables.cjs": 4089, + "5613-readable-from-iterable-timing.cjs": 4101, + "5614-readable-from-iterable-errors.cjs": 4082, + "5615-next-tick-callback-phases.ts": 3272, + "5616-next-tick-callback-phases.cjs": 2953, + "5617-pipeline-function-ends.ts": 2551, + "5618-pipeline-function-ends-errors.ts": 3775, + "5619-pipeline-function-ends.cjs": 2549, + "5620-timers-promises-values.ts": 3225, + "5621-util-format-float.ts": 2907, + "5622-events-once.mjs": 3347, + "5623-events-once.ts": 2334, + "5624-timers-promises-unawaited.ts": 3127, + "5625-promisify-exec.ts": 7142, + "5626-promisify-forms.ts": 2175, "5627-exec-callback.ts": 1900, + "5628-promisify-timers.ts": 3185, + "5629-promisify-stream.ts": 3048, + "5630-promisify-zlib.ts": 1934, "5631-promisify-crypto.ts": 2200, "5632-promisify-dns.ts": 1700, - "5644-net-socket-addresses.ts": 2220, - "5645-net-socket-callbacks.ts": 2442, - "5646-net-server-connections.ts": 2389, - "5647-net-is-ip.ts": 2776, - "5648-dns-lookup-forms.ts": 2992, - "5649-dns-service-servers.ts": 2712, - "5650-dns-lookup-errors-untyped.cjs": 2822, - "5681-array-pop-and-length.ts": 3754, - "5800-broadcast-channel.ts": 2899, - "5801-broadcast-channel.cjs": 2727, - "5802-broadcast-channel-workers.ts": 2809, - "5803-worker-environment-data.ts": 2748, - "5804-worker-environment-data.cjs": 2469, - "5805-worker-receive-message-parent-port.ts": 2839, - "5806-worker-resource-limits.ts": 3153, - "5807-worker-error-values.ts": 3304, - "5808-worker-unhandled-rejections.ts": 3430, - "5809-process-exit-and-rejections.cjs": 3294, - "5810-mock-method-records.ts": 3976, - "5811-mock-tracker-restore.ts": 3698, - "5812-dyn-box-async-fields.ts": 3522, - "5813-mock-timers-module.ts": 3766, - "5814-mock-timers-date.ts": 3760, - "5831-util-types-brands.ts": 3347, - "5832-util-types-brands-dynamic.js": 3250, - "5833-url-search-params-iterators.ts": 2678, - "5834-url-search-params-iterators-dynamic.mjs": 2696, - "5835-util-format-integer-specifiers.ts": 2534, - "5836-url-search-params-tuple-pairs.ts": 2118, - "5837-util-format-json-circular.ts": 3117, - "5838-qs-stringify-bigint.ts": 2207, - "5841-json-typed-dyn-members.ts": 5467, - "5842-qs-parse-null-prototype.ts": 1774, - "5843-qs-parse-null-prototype-js.mjs": 1559, - "5844-date-unknown-values.ts": 3969, + "5644-net-socket-addresses.ts": 3275, + "5645-net-socket-callbacks.ts": 3377, + "5646-net-server-connections.ts": 2448, + "5647-net-is-ip.ts": 2731, + "5648-dns-lookup-forms.ts": 3763, + "5649-dns-service-servers.ts": 2892, + "5650-dns-lookup-errors-untyped.cjs": 2811, + "5651-tls-socket-protocol.ts": 3198, + "5652-http-client-trailer-overflow.ts": 2916, + "5653-net-socket-read-ahead.ts": 4816, + "5654-https-empty-servername.ts": 3117, + "5655-dgram-socket-options.ts": 3309, + "5656-dgram-option-states.ts": 3364, + "5657-net-reset-and-address.ts": 2680, + "5658-net-reset-dynamic.cjs": 2474, + "5659-net-blocklist-socketaddress.ts": 4089, + "5664-tls-client-identity.ts": 2704, + "5674-union-instanceof-array-arms.ts": 3663, + "5680-array-growth-after-copy.ts": 3726, + "5681-array-pop-and-length.ts": 4270, + "5682-publish-wide-objects.ts": 3077, + "5700-cycle-release-retained.ts": 2148, + "5701-cycle-release-old-edges.ts": 2696, + "5702-publish-candidate-buffers.ts": 2775, + "5703-lifetime-region-debug.ts": 2224, + "5704-publish-refused-restores-counts.ts": 3329, + "5710-map-number-keys-hashed.ts": 3647, + "5711-map-number-write-after-read.ts": 2210, + "5712-map-number-overwrite-at-growth.ts": 3023, + "5714-cycle-large-candidate-buffers.ts": 2468, + "5715-json-parse-fitted-tables.ts": 3870, + "5717-set-prototype-of-primitives.ts": 2889, + "5719-int32-fields-dynamic-operators.ts": 3112, + "5720-intern-table-basics.ts": 3730, + "5721-intern-table-values.ts": 3508, + "5722-intern-table-workers.ts": 2907, + "5723-intern-table-shared-types.ts": 4686, + "5724-intern-table-array-keys.ts": 3089, + "5725-intern-table-callbacks.ts": 3280, + "5726-intern-table-key-limits.ts": 2828, + "5740-atomics-operation-semantics.ts": 4575, + "5741-atomics-contended-counters.ts": 2574, + "5742-atomics-lock-ordering.ts": 3308, + "5743-atomics-wait-notify.ts": 3213, + "5744-atomics-ring-buffer.ts": 2799, + "5745-atomics-semaphore-stress.ts": 3529, + "5746-shared-bulk-operations.ts": 3548, + "5747-fs-stat-throw-if-no-entry.ts": 2061, + "5748-fs-stat-throw-if-no-entry-js.cjs": 3369, + "5752-string-number-concat.ts": 1990, + "5760-crypto-hash-stream.ts": 3142, + "5761-crypto-hash-stream-states.ts": 3329, + "5762-crypto-hash-stream.cjs": 3414, + "5763-crypto-sha-blocks.ts": 3741, + "5764-class-structural-view-writes.ts": 3376, + "5764-crypto-hmac-edges.cjs": 2142, + "5765-class-structural-view-identity.ts": 3439, + "5766-class-structural-view-callbacks.ts": 2597, + "5767-class-opaque-accessor-view.ts": 3393, + "5776-power-of-two-remainder-integer-path.ts": 2953, + "5780-readline-history-options.ts": 2935, + "5781-readline-history-options.cjs": 2270, + "5782-readline-terminal-editing.ts": 3076, + "5783-readline-terminal-completion.cjs": 5270, + "5784-readline-terminal-promises.ts": 2520, + "5785-readline-terminal-keys.ts": 3009, + "5786-readline-terminal-history.cjs": 2912, + "5787-readline-cursor-helpers.cjs": 1948, + "5788-readline-promises-readline.ts": 3069, + "5789-readline-cursor-pos.cjs": 2494, + "5790-readline-keypress-events.ts": 3064, + "5791-dyn-constant-key-read-sites.ts": 3916, + "5791-readline-keypress-interfaces.cjs": 3122, + "5792-json-parse-repeated-layouts.ts": 3794, + "5792-readline-keypress-listeners.ts": 2820, + "5793-worker-message-channel.ts": 2538, + "5794-worker-message-port-close-order.ts": 2834, + "5795-worker-message-port-batches.ts": 2254, + "5796-worker-message-channel.cjs": 3566, + "5797-worker-message-port-transfer.ts": 3180, + "5800-broadcast-channel.ts": 3206, + "5801-broadcast-channel.cjs": 3035, + "5802-broadcast-channel-workers.ts": 3120, + "5803-worker-environment-data.ts": 3113, + "5804-worker-environment-data.cjs": 3000, + "5805-worker-receive-message-parent-port.ts": 3259, + "5806-worker-resource-limits.ts": 3191, + "5807-worker-error-values.ts": 3239, + "5808-worker-unhandled-rejections.ts": 3439, + "5809-process-exit-and-rejections.cjs": 3393, + "5810-mock-method-records.ts": 3670, + "5811-mock-tracker-restore.ts": 3216, + "5812-dyn-box-async-fields.ts": 2941, + "5813-mock-timers-module.ts": 3052, + "5814-mock-timers-date.ts": 3365, + "5830-timers-promises-signal.ts": 3771, + "5831-util-types-brands.ts": 3300, + "5832-util-types-brands-dynamic.js": 3811, + "5833-url-search-params-iterators.ts": 3578, + "5834-url-search-params-iterators-dynamic.mjs": 3566, + "5835-util-format-integer-specifiers.ts": 2544, + "5836-url-search-params-tuple-pairs.ts": 2830, + "5837-util-format-json-circular.ts": 2387, + "5838-qs-stringify-bigint.ts": 3072, + "5839-timers-promises-scheduler.ts": 2609, + "5840-promise-with-resolvers-js.js": 2922, + "5841-json-typed-dyn-members.ts": 3536, + "5842-qs-parse-null-prototype.ts": 3138, + "5843-qs-parse-null-prototype-js.mjs": 2658, + "5844-date-unknown-values.ts": 3255, + "5845-groupby-null-prototype.ts": 3675, "5846-events-esm-default-max.ts": 2633, "5847-events-cjs-default-max.cjs": 2823, - "5857-regexp-unicode-sets.ts": 3350, - "5858-disposable-stack.ts": 3050, - "5859-disposable-stack-js.js": 3100, - "5870-worker-thread-names.ts": 3106, - "5871-worker-untransferable.cjs": 2786, - "5874-worker-stdio-streams.ts": 2839, - "5875-worker-stdout-pipe.cjs": 2740, - "5879-worker-stdin.ts": 3158, - "5881-inspect-weak-collections.ts": 2615, - "5882-string-decoder-runtime-encoding.ts": 2541, - "5883-os-set-priority.ts": 2380, - "5884-inspect-layout-options.ts": 3108, - "5886-inspect-dates.ts": 2559, - "5887-inspect-typed-arrays.ts": 3448, - "5888-inspect-sorted.ts": 2998, - "5900-float16-array.ts": 3000, - "5901-float16-array-js.js": 2900, - "5904-async-generator-completion.ts": 2950, - "5905-array-from-async-generator.ts": 2750, - "5906-array-from-async-generator-js.js": 2950, + "5849-class-view-observations.ts": 2583, + "5850-using-disposable-values.ts": 3206, + "5851-using-suppressed-error-values.ts": 3035, + "5852-using-disposable-values-js.js": 1792, + "5853-set-methods-map-arguments.ts": 2849, + "5854-array-from-async.ts": 3165, + "5855-array-from-async-js.js": 3186, + "5856-error-is-error.ts": 3631, + "5857-regexp-unicode-sets.ts": 2021, + "5858-disposable-stack.ts": 4753, + "5859-disposable-stack-js.js": 3636, + "5860-url-ipv4-hosts.ts": 3030, + "5870-worker-thread-names.ts": 3457, + "5871-worker-untransferable.cjs": 2368, + "5872-readline-positional-create-interface.mjs": 2993, + "5873-readline-promises-namespace.cjs": 2951, + "5874-worker-stdio-streams.ts": 2974, + "5875-worker-stdout-pipe.cjs": 3115, + "5879-worker-stdin.ts": 3644, + "5880-emitter-leak-warning-delivery.ts": 2660, + "5881-inspect-weak-collections.ts": 2621, + "5882-string-decoder-runtime-encoding.ts": 2742, + "5883-os-set-priority.ts": 2927, + "5884-inspect-layout-options.ts": 3552, + "5885-events-max-listener-helpers.ts": 3645, + "5886-inspect-dates.ts": 2931, + "5887-inspect-typed-arrays.ts": 2476, + "5888-inspect-sorted.ts": 3227, + "5889-timers-scheduler-signal.ts": 2549, + "5890-while-string-length-counters.ts": 3080, + "5892-buffer-write-utf16le-runs.ts": 3098, + "5900-float16-array.ts": 3586, + "5901-float16-array-js.js": 3449, + "5904-async-generator-completion.ts": 5816, + "5905-array-from-async-generator.ts": 2793, + "5906-array-from-async-generator-js.js": 3377, "5907-regex-groups-match-rows.ts": 3150, - "5910-set-prototype-of-primitive-object-kinds.ts": 2719, - "5911-dyn-class-to-primitive.ts": 2850, - "5912-dyn-class-conversion-methods.ts": 3251, - "5913-prototype-type-error-messages.ts": 2484, - "5914-dyn-in-class-prototype-members.ts": 3169, - "5915-dyn-error-string-conversions.ts": 3200, - "5922-matchall-groups-callbacks.ts": 3650, - "5923-matchall-groups-js.js": 3970, + "5910-set-prototype-of-primitive-object-kinds.ts": 2148, + "5911-dyn-class-to-primitive.ts": 6231, + "5912-dyn-class-conversion-methods.ts": 4317, + "5913-prototype-type-error-messages.ts": 2831, + "5914-dyn-in-class-prototype-members.ts": 2811, + "5915-dyn-error-string-conversions.ts": 3158, + "5920-promise-try-args.ts": 3150, + "5921-promise-try-args-js.js": 2112, + "5922-matchall-groups-callbacks.ts": 4259, + "5923-matchall-groups-js.js": 4523, + "5924-js-literal-identity.js": 3064, + "5925-class-view-identity-observers.ts": 2653, + "5926-class-view-switch-js.js": 1690, + "5927-switch-object-identity.ts": 2783, + "5928-groupby-iterables.ts": 3526, + "5929-groupby-js.js": 1756, + "5930-contract-int32-arrays.ts": 3803, + "5930-method-census-asserted-number-keys.ts": 2348, + "5931-asserted-reads-keep-number-parameters.ts": 2715, + "5932-generic-class-observed-methods.ts": 4825, + "5933-class-fields-unknown-object.ts": 3920, + "5934-js-class-fields-property-order.js": 4713, + "5935-js-subclass-fields-and-element-calls.js": 3523, + "5936-checked-js-class-types.js": 2384, + "5937-override-narrowed-union-returns.ts": 3039, "5938-object-literal-computed-keys-keep-methods.ts": 3195, - "5939-js-let-object-reassigned-wider.js": 1945, + "5939-js-let-object-reassigned-wider.js": 2362, + "5940-callback-helper-specialization.ts": 3130, + "5941-callback-specialization-recursion.ts": 3996, + "5942-callback-specialization-throws.ts": 2908, "5943-fields-read-before-assignment.ts": 6856, "5944-js-fields-read-before-assignment.js": 4247, "5945-local-class-observed-methods.ts": 5063, "5946-nested-record-field-optional-writes.ts": 6045, - "5950-tuple-predicate-methods.ts": 5990, - "5951-result-never-widening.ts": 4710, + "5950-tuple-predicate-methods.ts": 3865, + "5951-result-never-widening.ts": 3022, "5952-record-missing-keys.ts": 6090, "5953-nan-coded-method-returns.ts": 4100, - "5955-any-promise-methods.js": 3940, - "5956-erased-generic-members.ts": 6730, - "5958-asserted-union-receiver.ts": 2430, - "5959-date-to-json.ts": 3330, - "5960-generic-mapped-types.ts": 2540, - "5970-net-connect-host-name.ts": 2400, - "5971-buffer-chunks-to-string.ts": 2700, - "5972-net-set-encoding-listeners.ts": 2550, - "5974-typeof-module-exports.cjs": 2000, + "5955-any-promise-methods.js": 3111, + "5956-erased-generic-members.ts": 5669, + "5958-asserted-union-receiver.ts": 1929, + "5959-date-to-json.ts": 2922, + "5960-generic-mapped-types.ts": 3167, + "5970-net-connect-host-name.ts": 1992, + "5971-buffer-chunks-to-string.ts": 3183, + "5972-net-set-encoding-listeners.ts": 2129, + "5974-typeof-module-exports.cjs": 2008, "5975-zlib-class-values.ts": 2800, - "5990-worker-uncloneable.mjs": 3283, - "5991-worker-async-dispose.mjs": 5699, - "5992-worker-thread-name-lifetime.mjs": 2687, - "600-closures-basic.ts": 2349, - "601-closures-loops.ts": 1788, - "602-closures-identity-recursion.ts": 2372, - "6020-class-extends-function-constructor.js": 4300, + "5990-worker-uncloneable.mjs": 3202, + "5991-worker-async-dispose.mjs": 5853, + "5992-worker-thread-name-lifetime.mjs": 2058, + "600-closures-basic.ts": 2637, + "601-closures-loops.ts": 2250, + "602-closures-identity-recursion.ts": 2821, + "6020-class-extends-function-constructor.js": 3026, "6021-asserted-literal-union-arm.ts": 3400, - "603-closures-rc-stress.ts": 1832, - "604-closures-for-of.ts": 2639, - "605-closures-forward-capture-tdz.ts": 3277, - "700-classes-basic.ts": 2530, - "701-classes-composition.ts": 2357, - "702-classes-this-capture.ts": 2140, - "703-classes-rc-stress.ts": 2186, - "710-inheritance-basics.ts": 2728, - "711-inheritance-dispatch.ts": 2360, - "712-inheritance-instanceof.ts": 2715, - "713-inheritance-rc-stress.ts": 2448, - "720-accessors-basics.ts": 2562, - "721-accessors-eval-order.ts": 2406, - "722-accessors-inheritance.ts": 2543, - "723-accessors-rc-stress.ts": 2054, - "750-cycle-closure-box.ts": 2227, - "751-cycle-records-mutual.ts": 2118, - "752-cycle-classes.ts": 2207, - "753-cycle-owned-arrays.ts": 2148, - "754-cycle-external-ref.ts": 2118, - "755-cycle-async-promise.ts": 2303, - "756-cycle-inheritance.ts": 2162, - "757-cycle-cross-generation.ts": 2893, - "762-any-boundary.ts": 2310, - "764-any-async.ts": 2553, - "765-any-optional-chain.ts": 2593, - "766-any-union-boundary.ts": 3292, - "767-string-literal-keys.ts": 2238, - "768-any-uninitialized.ts": 2264, - "800-switch-basics.ts": 2244, - "801-switch-lazy-tests.ts": 2610, - "802-switch-loops.ts": 2329, - "803-switch-rc-stress.ts": 2314, - "804-switch-braced-blocks.ts": 2594, - "810-do-while.ts": 2658, - "820-multi-decl.ts": 2315, - "830-let-uninitialized.ts": 2519, - "900-records-basics.ts": 2736, - "901-records-eval-order.ts": 2544, - "902-records-functions-closures.ts": 2645, - "903-records-rc-stress.ts": 2871, - "904-records-optional-fields.ts": 1801, - "905-records-optional-rc-stress.ts": 2425, - "906-records-utility-types.ts": 2878, - "907-records-utility-generics.ts": 2738, - "908-records-index-signatures.ts": 2545, - "909-records-index-json.ts": 2019, - "910-records-index-rc-stress.ts": 1878, - "911-records-index-dot-access.ts": 3510, - "912-unknown-slots.ts": 2427, - "913-records-index-iteration.ts": 3462, - "914-records-from-entries.ts": 3129, - "915-unknown-tostring-eq.ts": 3072, - "916-unknown-bytes.ts": 2767, - "917-record-array-index-dot.ts": 2445, - "950-modules-basic/main.ts": 2473, - "951-modules-diamond/main.ts": 1969, - "952-modules-cross/main.ts": 2427, - "953-modules-default/main.ts": 2409, - "954-modules-reexport/main.ts": 2586, - "957-builtins-namespace.ts": 2102, - "960-generics-basics.ts": 2487, - "961-generics-recursion.ts": 2589, - "962-generics-closures.ts": 2098, - "963-generics-modules/main.ts": 2726, - "964-generics-rc-stress.ts": 2825, - "965-generics-async.ts": 2802, - "965-unions-retag.ts": 2772, - "966-unions-retag-rc-stress.ts": 2336, - "967-record-field-widening.ts": 2097, - "969-unions-arm-matrix.ts": 2419, - "970-unions-basics.ts": 2692, - "971-unions-switch.ts": 2491, - "972-unions-nested.ts": 3069, - "973-unions-rc-stress.ts": 2478, - "974-unions-modules/main.ts": 2052, - "975-unions-undefined.ts": 2811, - "976-unions-null.ts": 2344, - "977-unions-unit-rc-stress.ts": 2013, - "978-unions-nullish.ts": 2330, - "979-unions-optional-chaining.ts": 2341, - "980-exceptions-basics.ts": 1988, - "981-exceptions-values.ts": 2615, - "982-exceptions-rc-stress.ts": 2259, - "983-exceptions-control-flow.ts": 2004, - "984-exceptions-finally.ts": 2140, - "985-exceptions-call-chains.ts": 2787, - "986-exceptions-uncaught.ts": 2529, - "987-exceptions-result-unions.ts": 2390, - "990-process-basics.ts": 2623, - "991-process-exit.ts": 2155, - "992-fs-roundtrip.ts": 2680, - "993-fs-readdir.ts": 2781, - "994-fs-errors.ts": 2322, - "995-fs-uncaught.ts": 2134, - "996-fs-rc-stress.ts": 2214, - "997-fs-modules/main.ts": 2230, - "998-process-env.ts": 2196, - "abstract-property-dispatch.ts": 2956, - "arguments-arrow-capture.mjs": 2802, - "arguments-reexport/main.ts": 2655, - "array-argument-lifetimes-exits.ts": 2164, - "array-argument-lifetimes-mutation.ts": 2547, - "array-argument-lifetimes-strings.ts": 2738, - "array-argument-lifetimes-values.ts": 3081, - "array-buffer-conversions.js": 1978, - "array-buffer-storage.ts": 3147, - "array-checked-callback-results.mjs": 3053, - "array-checked-constructor.js": 3001, - "array-concat-widening.ts": 2947, - "array-element-compound-updates.ts": 3325, - "array-fill-unit-values.ts": 2281, - "array-from-checked.js": 3228, - "array-from-value.mjs": 2658, - "array-isarray-value/main.js": 2180, - "array-numeric-own-keys.ts": 2770, - "array-optional-number-write-index.ts": 2584, - "array-primitive-ordering.ts": 3806, - "array-read-helper-effects.ts": 3223, - "array-refined-storage.ts": 3132, - "array-sort-dense-effects.ts": 2813, - "array-sort-dense-values.ts": 3705, - "array-sort-holes-published.ts": 6604, - "array-sort-runs.ts": 5713, - "array-sort-runtime-comparator.ts": 5050, - "array-sort-unknown-comparator.ts": 1888, - "array-storage-transitions.ts": 3122, - "array-truncate-reuse.ts": 2475, - "async-backend-factory.mjs": 2638, - "async-local-typed-results.ts": 2579, - "atomics-integer-operations.ts": 3320, - "bigint-checked-casts.ts": 2572, - "bigint-checked-storage.js": 3519, - "bigint-union-conversion.ts": 2774, - "boxed-error-rethrows.mjs": 2034, - "buffer-codec-boundaries.ts": 3206, - "buffer-primitive-predicate.ts": 2712, - "builtin-prototype-method-values.mjs": 3158, - "byte-loop-bounds.ts": 2922, - "byte-number-pipeline.ts": 2738, - "byte-record-windows.ts": 2668, - "call-lifetimes-argument-order.ts": 1933, - "call-lifetimes-control-flow.ts": 2653, - "call-lifetimes-owned-boundaries.ts": 2979, - "call-lifetimes-projections.ts": 3011, - "call-lifetimes-union-values.ts": 2366, - "call-lifetimes-virtual-optionals.ts": 2747, - "callable-module-members.mjs": 2647, - "callable-properties.mjs": 3266, - "callable-property-cycles.js": 2241, - "callable-reexport/main.ts": 2809, - "captured-class-refinement.ts": 2580, - "catch-capture.ts": 2050, - "caught-class-identity.ts": 3173, - "caught-standalone-class.ts": 2858, - "caught-system-error-fields.ts": 2612, + "603-closures-rc-stress.ts": 2800, + "604-closures-for-of.ts": 1980, + "605-closures-forward-capture-tdz.ts": 2765, + "700-classes-basic.ts": 1650, + "701-classes-composition.ts": 2262, + "702-classes-this-capture.ts": 1945, + "703-classes-rc-stress.ts": 2498, + "710-inheritance-basics.ts": 1936, + "711-inheritance-dispatch.ts": 2643, + "712-inheritance-instanceof.ts": 2608, + "713-inheritance-rc-stress.ts": 2855, + "720-accessors-basics.ts": 2703, + "721-accessors-eval-order.ts": 2000, + "722-accessors-inheritance.ts": 2558, + "723-accessors-rc-stress.ts": 2721, + "750-cycle-closure-box.ts": 2521, + "751-cycle-records-mutual.ts": 2024, + "752-cycle-classes.ts": 2646, + "753-cycle-owned-arrays.ts": 2810, + "754-cycle-external-ref.ts": 2655, + "755-cycle-async-promise.ts": 2228, + "756-cycle-inheritance.ts": 2657, + "757-cycle-cross-generation.ts": 2901, + "762-any-boundary.ts": 2854, + "764-any-async.ts": 2890, + "765-any-optional-chain.ts": 2394, + "766-any-union-boundary.ts": 2672, + "767-string-literal-keys.ts": 2479, + "768-any-uninitialized.ts": 2844, + "800-switch-basics.ts": 2758, + "801-switch-lazy-tests.ts": 2588, + "802-switch-loops.ts": 1780, + "803-switch-rc-stress.ts": 2015, + "804-switch-braced-blocks.ts": 2537, + "810-do-while.ts": 1969, + "820-multi-decl.ts": 1629, + "830-let-uninitialized.ts": 2899, + "900-records-basics.ts": 2778, + "901-records-eval-order.ts": 2686, + "902-records-functions-closures.ts": 2628, + "903-records-rc-stress.ts": 2550, + "904-records-optional-fields.ts": 3083, + "905-records-optional-rc-stress.ts": 2791, + "906-records-utility-types.ts": 1783, + "907-records-utility-generics.ts": 2604, + "908-records-index-signatures.ts": 2041, + "909-records-index-json.ts": 3081, + "910-records-index-rc-stress.ts": 2746, + "911-records-index-dot-access.ts": 3174, + "912-unknown-slots.ts": 2915, + "913-records-index-iteration.ts": 3669, + "914-records-from-entries.ts": 3427, + "915-unknown-tostring-eq.ts": 3373, + "916-unknown-bytes.ts": 2791, + "917-record-array-index-dot.ts": 2745, + "950-modules-basic/main.ts": 2721, + "951-modules-diamond/main.ts": 1492, + "952-modules-cross/main.ts": 1431, + "953-modules-default/main.ts": 2552, + "954-modules-reexport/main.ts": 2362, + "957-builtins-namespace.ts": 2216, + "960-generics-basics.ts": 2982, + "961-generics-recursion.ts": 2893, + "962-generics-closures.ts": 2684, + "963-generics-modules/main.ts": 2595, + "964-generics-rc-stress.ts": 3029, + "965-generics-async.ts": 3085, + "965-unions-retag.ts": 2457, + "966-unions-retag-rc-stress.ts": 2098, + "967-record-field-widening.ts": 2939, + "969-unions-arm-matrix.ts": 2998, + "970-unions-basics.ts": 2779, + "971-unions-switch.ts": 2261, + "972-unions-nested.ts": 2825, + "973-unions-rc-stress.ts": 2576, + "974-unions-modules/main.ts": 2186, + "975-unions-undefined.ts": 2396, + "976-unions-null.ts": 2274, + "977-unions-unit-rc-stress.ts": 2486, + "978-unions-nullish.ts": 2487, + "979-unions-optional-chaining.ts": 2987, + "980-exceptions-basics.ts": 2385, + "981-exceptions-values.ts": 2867, + "982-exceptions-rc-stress.ts": 1550, + "983-exceptions-control-flow.ts": 2778, + "984-exceptions-finally.ts": 2144, + "985-exceptions-call-chains.ts": 3115, + "986-exceptions-uncaught.ts": 2615, + "987-exceptions-result-unions.ts": 1576, + "990-process-basics.ts": 2148, + "991-process-exit.ts": 2021, + "992-fs-roundtrip.ts": 2662, + "993-fs-readdir.ts": 2790, + "994-fs-errors.ts": 2954, + "995-fs-uncaught.ts": 2485, + "996-fs-rc-stress.ts": 2801, + "997-fs-modules/main.ts": 1791, + "998-process-env.ts": 2322, + "abstract-property-dispatch.ts": 3676, + "arguments-arrow-capture.mjs": 2969, + "arguments-reexport/main.ts": 2670, + "array-argument-lifetimes-exits.ts": 3229, + "array-argument-lifetimes-mutation.ts": 2355, + "array-argument-lifetimes-strings.ts": 2875, + "array-argument-lifetimes-values.ts": 3135, + "array-buffer-conversions.js": 2768, + "array-buffer-storage.ts": 2184, + "array-checked-callback-results.mjs": 3207, + "array-checked-constructor.js": 2168, + "array-concat-widening.ts": 3084, + "array-deque-unshift.ts": 3209, + "array-element-compound-updates.ts": 4339, + "array-fill-unit-values.ts": 2510, + "array-from-checked.js": 4274, + "array-from-value.mjs": 3224, + "array-isarray-value/main.js": 2742, + "array-numeric-own-keys.ts": 1884, + "array-optional-number-write-index.ts": 2617, + "array-primitive-ordering.ts": 2544, + "array-queue-head-room.ts": 3344, + "array-read-helper-effects.ts": 2217, + "array-refined-storage.ts": 2827, + "array-sort-dense-effects.ts": 3621, + "array-sort-dense-values.ts": 3004, + "array-sort-holes-published.ts": 7729, + "array-sort-runs.ts": 4117, + "array-sort-runtime-comparator.ts": 4714, + "array-sort-unknown-comparator.ts": 2824, + "array-storage-transitions.ts": 3984, + "array-truncate-reuse.ts": 2234, + "async-backend-factory.mjs": 1807, + "async-local-typed-results.ts": 2185, + "atomics-integer-operations.ts": 2603, + "bigint-checked-casts.ts": 2636, + "bigint-checked-storage.js": 3528, + "bigint-union-conversion.ts": 2763, + "boxed-error-rethrows.mjs": 2627, + "buffer-codec-boundaries.ts": 2453, + "buffer-primitive-predicate.ts": 2183, + "builtin-prototype-method-values.mjs": 3361, + "byte-loop-bounds.ts": 3029, + "byte-number-pipeline.ts": 3197, + "byte-record-windows.ts": 2142, + "call-lifetimes-argument-order.ts": 2451, + "call-lifetimes-control-flow.ts": 2879, + "call-lifetimes-owned-boundaries.ts": 3007, + "call-lifetimes-projections.ts": 1722, + "call-lifetimes-union-values.ts": 2751, + "call-lifetimes-virtual-optionals.ts": 3153, + "callable-module-members.mjs": 2485, + "callable-properties.mjs": 3432, + "callable-property-cycles.js": 3096, + "callable-reexport/main.ts": 3039, + "captured-class-refinement.ts": 3032, + "catch-capture.ts": 2928, + "caught-class-identity.ts": 2572, + "caught-standalone-class.ts": 3034, + "caught-system-error-fields.ts": 2540, "checked-addition.js": 2460, - "checked-any-addition.ts": 2551, - "checked-array-assignment.ts": 2273, - "checked-array-flat/main.ts": 2256, - "checked-bitwise/main.js": 2560, - "checked-builder-cycles.js": 3055, - "checked-byte-storage/main.ts": 3171, - "checked-callback-options.ts": 2385, - "checked-class-descriptors.mjs": 3021, - "checked-class-factory.mjs": 2266, - "checked-collection-iterators.ts": 2906, - "checked-collection-symbol-methods.ts": 2575, - "checked-dispatch-input-lifetimes.js": 3038, - "checked-increment/main.js": 2332, - "checked-inherited-fields.ts": 2382, - "checked-iterator-consumption.js": 3603, - "checked-numeric-arithmetic.js": 2783, - "checked-object-module-alias.js": 2898, - "checked-optional-calls.mjs": 2763, - "checked-promise-recovery.ts": 2689, - "checked-proxy-callback/main.ts": 2754, - "checked-record-constructor.ts": 2506, - "checked-renderer-defaults.js": 2308, - "checked-rest-function-adapters.js": 2312, - "checked-storage-transitions.js": 2557, - "checked-symbol-array.ts": 1859, - "checked-value-input-lifetimes.ts": 2728, - "class-accessor-returned-function.js": 2068, - "class-array-optional-return.ts": 2589, - "class-bracket-method-calls.js": 2833, - "class-brand-overload.js": 2700, - "class-callback-replacement.js": 3640, - "class-callback-storage.ts": 3803, - "class-checked-composites.ts": 2846, - "class-checked-upcast.ts": 2625, - "class-collection-insertion.ts": 3901, - "class-computed-presence.ts": 3018, - "class-computed-symbols.js": 3495, - "class-covariant-returns.ts": 3069, - "class-curried-factory.mjs": 3062, - "class-data-descriptors.js": 3732, - "class-factory-inherited-statics.mjs": 2710, - "class-factory-parameter-base.mjs": 2492, - "class-factory-record-base.mjs": 4680, - "class-factory-recursive-statics.mjs": 2820, - "class-factory-static-members.mjs": 2990, - "class-function-base/main.js": 2706, - "class-instance-constructor.js": 2628, - "class-interface-protocols.ts": 3911, - "class-interface-refinements.ts": 2967, - "class-json-checked.ts": 2638, - "class-local-function-base.mjs": 2970, - "class-method-spreads.ts": 3142, - "class-narrowed-views.ts": 2862, - "class-property-call-values.mjs": 3343, - "class-prototype-data.js": 3393, - "class-prototype-descriptor-copy.mjs": 3870, - "class-specialized-computed-base.mjs": 3439, - "class-static-data.js": 2153, - "class-subclass-assertions.ts": 2814, - "class-super-surplus-spread.mjs": 2024, - "class-symbol-accessors.ts": 2458, - "class-symbol-cache.mjs": 2883, - "class-value-constructor-exceptions.ts": 2222, - "closure-nullable-union-return.ts": 2472, - "closure-union-locals.ts": 2465, - "collection-array-cycles.ts": 2552, - "collection-array-maps.ts": 3481, - "collection-array-missing.ts": 2873, - "collection-array-sets.ts": 3383, - "collection-copy-identities.ts": 2585, - "collection-data-unions.ts": 2565, - "collection-ingestion-mappers.ts": 3262, - "collection-ingestion-protocol/main.ts": 3814, - "collection-ingestion-references.ts": 3375, - "collection-ingestion.ts": 3053, - "collection-storage-copies.ts": 3096, - "collection-value-keys.ts": 3176, - "compound-field-receivers.ts": 2272, - "compound-presence-guards.ts": 3094, - "conditional-tuple-destructuring.ts": 2487, - "console-imports.cjs": 2314, - "console-native-value.js": 2165, - "const-enum-module-cycle/main.ts": 2618, - "constant-callback-dispatch.ts": 2539, - "constant-module-globals/main.ts": 2455, - "constant-number-remainders.ts": 2350, - "constructed-class-dispatch.ts": 3014, - "contextual-array-union-write.ts": 5379, - "contextual-return-layouts.ts": 2919, - "counted-loop-numbers.ts": 2515, - "counted-loop-storage.ts": 2556, - "crypto-hash-optional-input.ts": 2860, - "cycle-generations-long-lived.ts": 2691, - "cycle-growth-yield.ts": 2929, - "date-checked-native.js": 2323, - "declared-index-spread.ts": 2660, - "deep-reference-teardown.ts": 3136, - "default-undefined-parameters.ts": 2589, - "deferred-field-updates.ts": 2347, - "deferred-registry-many.ts": 2661, - "derived-numeric-updates.ts": 1907, - "destructure-call-assignment.js": 2267, - "destructure-inferred-row-defaults.js": 2538, - "destructure-union-arrays.ts": 2379, - "dynamic-function-descriptors.js": 2763, - "error-cause-writes.js": 2954, - "error-inherited-message.mjs": 2631, - "error-inherited-name.mjs": 2285, - "error-property-writes.mjs": 2636, - "error-prototype-tostring.js": 3155, - "error-stack-frames.ts": 2206, - "error-stack-limit.ts": 2510, - "error-tostring-overrides.ts": 2305, - "error-values-inspect.ts": 2398, - "exact-index-round-trip.ts": 2801, - "expression-runtime-values.ts": 2027, - "fiber-switch-stress.ts": 2898, - "fiberless-async-ordering.ts": 2908, - "fiberless-async-unhandled.ts": 2133, - "field-assignment-values.ts": 2107, - "file-handle-values.ts": 2357, - "file-read-storage.ts": 2439, - "file-url-percent-decoding.ts": 2222, - "final-field-borrows.ts": 2890, - "for-multiple-bindings.ts": 2286, - "for-multiple-lexical-bindings.ts": 2283, - "for-of-checked-iterator.js": 3511, - "for-of-subclass-elements.ts": 2219, - "forward-generic-signatures.ts": 2294, - "fresh-array-union-layout.js": 2480, - "frozen-checked-dictionaries.mjs": 2629, - "fs-native-realpath.ts": 2351, - "fs-read-encodings.ts": 2505, - "fs-remove-readonly.ts": 2354, - "fs-write-string-bytes-union.ts": 2286, - "function-apply-value.mjs": 2558, - "function-constructor-global.mjs": 1848, - "function-constructor-kinds/main.js": 2532, - "function-custom-prototype.js": 2604, - "function-custom-to-string.mjs": 2607, - "function-object-assign.js": 2509, - "function-own-prototype/main.js": 2423, - "generator-checked-protocol.ts": 2631, - "generator-checked-return.js": 2326, - "generator-custom-delegation/main.ts": 3343, - "generator-default-return-pattern.ts": 2653, - "generator-delegation-values.ts": 2368, - "generator-inferred-date.js": 2465, - "generator-mixed-checked-channels.ts": 2662, - "generator-untyped-consumer/main.ts": 2958, - "generic-base-specializations.ts": 2073, - "generic-binding-ownership.ts": 2817, - "generic-class-js-functions/main.ts": 2051, - "generic-class-recovery.ts": 2415, - "generic-namespace-factories/main.ts": 2073, - "generic-nullable-collections.ts": 2677, - "generic-pattern-bindings.ts": 2698, - "generic-record-index.ts": 2753, - "generic-visitor-void.ts": 2405, - "global-error-subclasses.ts": 1773, - "global-runtime-probes.js": 2288, - "global-stored-probes.js": 2726, - "global-string-cache/main.js": 1889, - "global-symbol-cache/main.js": 3399, - "guarded-native-iterables.ts": 2496, - "heap-input-aliases.ts": 2746, - "heap-input-collections.ts": 2558, - "in-array-runtime-index.ts": 2579, - "indexed-assignment-values.js": 2971, - "indexed-assignment-values.ts": 1852, - "indexed-element-field-reads.ts": 2452, - "inferred-array-assignment-values.mjs": 2352, - "inferred-class-default.mjs": 2460, - "inferred-compound-values.mjs": 2473, - "inferred-conditional-class.mjs": 2635, - "inferred-error-fields.js": 2509, - "inferred-map-patterns.mjs": 2353, - "inferred-method-override.js": 2137, - "inferred-partial-destructuring.mjs": 2205, - "inferred-primitive-properties.mjs": 2135, - "inferred-record-return.mjs": 1793, - "inferred-recursive-record.mjs": 1833, - "inferred-undefined-field.mjs": 1777, - "input-lifetime-intervals.ts": 2714, - "input-lifetimes-modules/main.ts": 3258, - "instanceof-class-record-union.ts": 2400, - "integer-flow-arithmetic.ts": 3652, - "integer-loop-forms.ts": 2368, - "integer-view-control.ts": 1809, - "integer-view-numbers.ts": 2394, - "integer-view-storage.ts": 2439, - "intl-grapheme-conformance/main.ts": 3718, - "intl-grapheme.ts": 2449, - "iterator-typed-returns.ts": 3400, - "js-abort-portable.js": 2829, - "js-array-constructor.js": 3163, - "js-array-default-buffer.js": 2537, - "js-array-iterators.js": 2559, - "js-arrow-bind.cjs": 3343, - "js-buffer-callback-brand.cjs": 2262, - "js-callable-proxy.js": 3516, - "js-chained-native-results.mjs": 2641, - "js-checked-array-iterator.js": 2670, - "js-checked-array-reference.js": 2270, - "js-checked-number-negation.mjs": 1915, - "js-checked-sort-result.js": 2373, - "js-child-error-listener.cjs": 2357, - "js-cjs-callable-snapshots/main.cjs": 1981, - "js-class-added-parameters.js": 2472, - "js-class-checked-overrides.js": 2571, - "js-class-computed-fields.js": 1830, - "js-class-enumeration.js": 3296, - "js-class-field-accessor-override.js": 2567, - "js-class-fluent-overrides.js": 2822, - "js-class-late-method-values.js": 2309, - "js-class-member-dispatch.js": 3016, - "js-class-return-shapes.js": 2231, - "js-class-shadowed-methods.js": 2942, - "js-class-stored-method-receiver.js": 2382, - "js-class-subclass-properties.js": 3695, - "js-class-symbol-spread.cjs": 2704, - "js-computed-prototype-additions.js": 3142, - "js-constructor-returned-callable.js": 2605, - "js-constructor-spread.js": 2289, - "js-dataview-dispatch.js": 2273, - "js-declared-fields.cjs": 3263, - "js-default-listener-arguments.cjs": 2549, - "js-default-options/main.ts": 3044, - "js-deferred-field-initializers.js": 2121, - "js-deferred-registry-effects.js": 2381, - "js-derived-constructor-hoisting.js": 1805, - "js-dormant-array-write.js": 1888, - "js-dormant-overrides.js": 2569, - "js-expando-records.js": 2454, - "js-implicit-call-results.js": 3064, - "js-inferred-callback-exports/main.js": 3830, - "js-inferred-class-array-return.js": 2570, - "js-inferred-object-values.js": 2380, - "js-inherited-field-storage.js": 3121, - "js-inherited-parameter-abi.js": 2210, - "js-iterable-spread.js": 2950, - "js-loose-dynamic-primitives.js": 1960, - "js-map-object-seeds.js": 2610, - "js-member-increment.js": 2926, - "js-module-function-values.js": 2014, - "js-mutable-null-members.js": 2370, - "js-nested-native-descriptors.js": 2412, - "js-normalize-dispatch.js": 2793, - "js-nullish-inherited-fields.mjs": 2710, - "js-object-receiver-storage.js": 2613, - "js-object-returning-constructors.mjs": 2186, - "js-object-shared-arrays.js": 2465, - "js-omitted-typed-arguments.js": 2236, - "js-open-binding-writes.js": 1787, - "js-optional-class-fields.js": 2266, - "js-optional-member-call.js": 1883, - "js-primitive-union-addition.js": 2256, - "js-promise-all-values.js": 3079, - "js-promise-catch-handler.js": 1749, - "js-promise-finally-order.js": 1913, - "js-promise-pending-reactions.js": 2644, - "js-prototype-host-boundary.js": 2224, - "js-reflect-receivers.js": 3119, - "js-regex-record-captures.js": 2010, - "js-scalar-iterables.js": 2477, - "js-shared-method-dispatch.js": 2033, - "js-specialized-field-method.js": 2335, - "js-static-accessors.js": 2520, - "js-static-method-values.js": 2194, - "js-static-registries.cjs": 2703, - "js-super-accessor-initialization.js": 2100, - "js-uninitialized-native-fields.js": 2180, - "json-guarded-map-values.ts": 2374, - "json-output-bulk.ts": 2827, - "json-runtime-options.mjs": 1997, - "json-stringify-value.js": 2563, - "json-typed-parse-direct.ts": 2355, - "literal-switch-dispatch.ts": 2500, - "live-reference-shared-converters.ts": 2552, - "llvm-read-receiver-lifetime.ts": 2343, - "local-class-call-spreads.js": 3208, - "local-class-declaration.ts": 2486, - "local-class-evaluation.ts": 2605, - "local-class-inheritance.ts": 2327, - "local-class-lifetimes.ts": 2376, - "local-class-namespace/main.js": 2940, - "local-class-prototype-data.js": 2781, - "local-class-specialization.js": 2399, - "local-class-unknown.ts": 2443, - "local-class-values.ts": 1784, - "local-union-storage.ts": 2967, - "locale-compare-root-order.ts": 2518, - "logical-assignment-dynamic.js": 2592, - "logical-assignment-values.ts": 2497, - "logical-runtime-optional-record.ts": 2944, - "loop-reference-lifetimes.ts": 2542, - "map-checked-boundary/main.ts": 2629, - "map-checked-seed.js": 3013, - "map-number-keys-dense.ts": 2562, - "map-read-lifetimes-exits.ts": 2227, - "map-read-lifetimes.ts": 2725, - "map-seeds-and-spreads.ts": 2719, - "map-typed-array-values.ts": 2850, - "math-function-values.js": 2367, - "missing-read-lambda-results.ts": 2379, - "missing-read-narrowed-storage.ts": 2498, - "missing-read-number-conversions.ts": 2181, - "module-byte-loops.ts": 2636, - "module-fallback-functions/main.js": 2148, - "narrowed-nullish-values.ts": 2410, - "native-any-timer-callback.ts": 1834, - "native-array-borrowed-find-last.js": 2515, - "native-array-borrowed-slice.js": 2404, - "native-array-copying-methods.js": 2076, - "native-array-fill-copywithin.js": 2636, - "native-array-frozen-noops.js": 2476, - "native-array-index-boundaries.js": 1913, - "native-array-integrity.js": 2429, - "native-array-length.js": 2568, - "native-array-named-properties.js": 2390, - "native-array-prototype/main.js": 2161, - "native-array-read-lifetimes.ts": 2771, - "native-array-reduce-find-last.js": 2375, - "native-array-search-from-index.js": 1823, - "native-array-splice-coercion.js": 2296, - "native-array-splice-flat.js": 1933, - "native-buffer-coercion.js": 2389, - "native-callback-dispatch.ts": 3007, - "native-class-array-boundaries.ts": 2676, - "native-class-cache.js": 3391, - "native-class-properties.cjs": 3541, - "native-class-property-cycles.cjs": 2291, - "native-class-property-order.cjs": 1867, - "native-class-type-predicates.ts": 2386, - "native-factory-records.js": 2851, - "native-method-values.js": 2903, - "native-method-values.ts": 2495, - "native-npm-imports/main.ts": 2716, - "native-object-descriptors.js": 2717, - "native-object-for-in-minimal.js": 2536, - "native-object-property-attributes.js": 3149, - "native-object-prototype.js": 3180, - "native-property-names.ts": 1827, - "native-proxy-env.js": 3519, - "native-worker-arena-reuse.ts": 4699, - "native-worker-bounded-errors.ts": 2268, - "native-worker-buffer-consumers.ts": 2531, - "native-worker-cancel-hot.ts": 2446, - "native-worker-class-fields.ts": 2650, - "native-worker-clone-errors.ts": 2347, - "native-worker-commonjs.cjs": 2188, - "native-worker-delayed-messages.ts": 3114, - "native-worker-discarded-heaps.ts": 4430, - "native-worker-environment.ts": 3538, - "native-worker-error.ts": 2810, - "native-worker-exception-state.ts": 3938, - "native-worker-exit-listeners.ts": 2965, - "native-worker-io.ts": 3018, - "native-worker-loop-cancellation.ts": 2773, - "native-worker-message-graphs.ts": 2440, - "native-worker-messages.ts": 2911, - "native-worker-poll-exceptions.ts": 2706, - "native-worker-port-lifetime.ts": 3175, - "native-worker-process-exit.ts": 2168, - "native-worker-publish-classes.ts": 2797, - "native-worker-publish-refusals.ts": 2330, - "native-worker-published-graphs.ts": 3411, - "native-worker-references.ts": 2156, - "native-worker-roots/main.ts": 2962, - "native-worker-shared-views.ts": 2377, - "native-worker-stack-overflow.ts": 2443, - "native-worker-terminate-exception-state.ts": 3368, - "native-worker-terminate-loop.ts": 1929, - "native-worker-terminate-recursion.ts": 2935, - "native-worker-terminate-suspended.ts": 2843, - "native-worker-terminate-tested-loops.ts": 3082, - "native-worker-terminate-wait.ts": 2267, - "native-worker-typed-arrays.ts": 2361, - "nested-map-cycles.ts": 2306, - "nested-map-values.ts": 2038, - "never-returning-calls.ts": 2680, - "next-tick-commonjs-entry.cjs": 1924, - "node24-buffer-encoding-errors.ts": 2742, - "node24-buffer-encoding.ts": 2822, - "node24-crypto-kdf-errors.ts": 2607, - "node24-crypto-kdf-options.ts": 1925, - "node24-crypto-kdf.ts": 3401, - "node24-crypto-sha2.ts": 2336, - "node24-deep-equality-properties.js": 2551, - "node24-deep-equality.cjs": 2373, - "node24-deep-equality.ts": 3193, - "node24-env-files-errors.ts": 2555, - "node24-env-files.ts": 2556, - "node24-env-imports.cjs": 2518, - "node24-env-parse-errors.ts": 2083, - "node24-env-parse.ts": 2189, - "node24-esm-metadata/main.mjs": 2257, - "node24-file-url-buffer.ts": 1904, - "node24-file-url-errors.js": 2838, - "node24-file-url-options.ts": 2563, - "node24-fs-links-callbacks.cjs": 2964, - "node24-fs-links-errors.cjs": 2795, - "node24-fs-links-options.cjs": 3096, - "node24-fs-links-promise-errors.cjs": 2481, - "node24-fs-links-promises.ts": 2014, - "node24-fs-links.ts": 3060, - "node24-fs-statfs-callbacks.cjs": 2761, - "node24-fs-statfs-errors.cjs": 3068, - "node24-fs-statfs-options.cjs": 2927, - "node24-fs-statfs.ts": 2192, - "node24-fs-timestamps-callbacks.cjs": 2865, - "node24-fs-timestamps-errors.cjs": 2733, - "node24-fs-timestamps-promises.ts": 2476, - "node24-fs-timestamps-symlinks.ts": 2406, - "node24-fs-timestamps.ts": 2758, - "node24-no-error-assertions-coercion.js": 2950, - "node24-no-error-assertions.cjs": 2361, - "node24-no-error-assertions.ts": 2895, - "node24-parseargs.js": 3512, - "node24-string-decoder.ts": 2569, - "node24-style-text-environment.js": 2370, - "node24-style-text-validation.js": 2999, - "node24-style-text.cjs": 1883, - "node24-style-text.ts": 2102, - "node24-system-error-validation.js": 2003, - "node24-system-errors.cjs": 2247, - "node24-system-errors.ts": 2302, - "node24-text-codec-properties.ts": 2178, - "node24-text-encode-into.ts": 2427, - "node24-text-utilities-coercion.js": 2867, - "node24-text-utilities-validation.js": 1874, - "node24-text-utilities.cjs": 2132, - "node24-text-utilities.ts": 2215, - "node24-url-authority-coercion.js": 2529, - "node24-url-authority.ts": 2720, - "node24-url-factories.ts": 2586, - "node24-url-factory-errors.ts": 1931, - "node24-url-mutation-coercion.js": 2518, - "node24-url-mutation.ts": 2194, - "node24-util-types.cjs": 3057, - "node24-util-types.js": 1900, - "node24-util-types.ts": 2935, - "non-null-class-iteration.ts": 2350, - "nonnull-element-arguments.ts": 2545, - "nonnull-forwarded-class-values.ts": 2532, - "nullable-object-extension.mjs": 1922, - "nullish-asserted-class-arms.ts": 2485, - "nullish-assignment-values.ts": 1745, - "nullish-long-chain.ts": 2326, - "number-parse-statics.ts": 2443, - "number-predicates-unknown.ts": 2375, - "numeric-call-specialization.ts": 2588, - "object-enumeration-array-reads.ts": 1967, - "object-from-checked-entries.js": 2542, - "object-inherited-to-string.js": 2670, - "object-key-indexes.js": 2753, - "object-prototype-identity.mjs": 2064, - "object-reexport/main.js": 2482, - "object-spread-computed.ts": 2578, - "opentui-byte-queue.js": 2802, - "optional-callback-arity.ts": 2348, - "optional-class-flows.ts": 2247, - "optional-element-defaults.ts": 2052, - "optional-flag-comparisons.ts": 2527, - "optional-native-callables.js": 2309, - "optional-node-list-iteration.ts": 2316, - "optional-string-index/main.ts": 2950, - "path-to-file-url-options.ts": 2299, - "performance-presence.ts": 2043, - "primitive-and-function-descriptors.js": 2222, - "primitive-union-string.ts": 2856, - "process-builtin-values.js": 2616, - "process-constrained-memory.ts": 2105, - "process-env-computed-keys.js": 2252, - "process-hrtime.js": 2596, - "process-named-signals.cjs": 2604, - "process-uncaught-handler-throws.cjs": 2306, - "process-uncaught-loop.cjs": 2320, - "process-uncaught-module.mjs": 1832, - "process-uncaught-monitor.cjs": 2077, - "process-uncaught-rejection.cjs": 2431, - "process-uncaught-sync.cjs": 2425, - "process-version-pin.ts": 2418, - "process-versions-storage.ts": 2051, - "projected-collection-lifetimes.ts": 2409, - "promise-checked-rejections.ts": 1985, - "promise-resolve-void.ts": 2341, - "prototype-method-overrides.mjs": 4870, - "prototype-named-data-records.ts": 2513, - "record-field-presence.ts": 3025, - "record-key-order.ts": 2807, - "record-optional-json-presence.ts": 2623, - "record-presence-copies.ts": 2693, - "record-presence-delete-json.ts": 2748, - "record-unchecked-read-presence.ts": 2103, - "record-unknown-values.ts": 3450, - "reflect-own-keys.mjs": 2583, - "reflect-record-union-keys.mjs": 2454, - "reflect-typed-record-keys.ts": 1855, - "regex-callback-replacements.ts": 2492, - "regex-callback-values.js": 2733, - "regex-checked-casts.ts": 2350, - "regex-checked-storage.js": 2669, - "regex-exec-long-subject.ts": 4533, - "regex-input-lifetimes.ts": 2535, - "regex-native-matcher.ts": 3683, - "regex-optional-captures.ts": 2606, - "regex-optional-templates.ts": 2338, - "regex-split-captures.ts": 2583, - "regex-text-paths.ts": 2889, - "regexp-constructor-repeat.ts": 2351, - "regexp-optional-constructor.ts": 2315, - "regexp-string-coercion.js": 1897, - "renderer-export-dictionaries.js": 2582, - "renderer-null-state.js": 2185, - "renderer-specializations.js": 2653, - "repeat-and-typed-read-errors.ts": 2751, - "rest-optional-array-arguments.ts": 2671, - "rest-optional-elements.ts": 2289, - "return-void-through-finally.ts": 2486, - "runtime-optional-string-flows.ts": 2406, - "scalar-string-slices.ts": 2175, - "set-checked-methods.js": 2631, - "set-checked-storage.ts": 2064, - "set-iterator-seed-references.ts": 2863, - "set-iterator-seeds.ts": 2896, - "set-optional-seeds.ts": 2121, - "small-collection-transitions.ts": 2645, - "stack-depth-async-bodies.ts": 1910, - "stack-overflow-async.ts": 2447, - "stack-overflow-caught.ts": 2424, - "stack-overflow-finally.ts": 2613, - "stack-overflow-shapes.ts": 2534, - "stack-overflow-uncaught.ts": 2317, - "static-field-updates/main.ts": 2050, - "static-method-receivers.ts": 2243, - "stdio-values.mjs": 2578, - "stdio-write-errors.mjs": 1977, - "stdio-write-overrides.mjs": 2495, - "stored-native-builtins.js": 2831, - "stored-object-helpers.js": 2747, - "string-char-code-integer-loops.ts": 2495, - "string-code-points.ts": 1970, - "string-concat-number-parts.ts": 2044, - "string-construction-order.ts": 2502, - "string-lifetimes-boundaries.ts": 2481, - "string-lifetimes-evaluation.ts": 2486, - "string-lifetimes-iteration.ts": 2043, - "string-lifetimes-operations.ts": 2490, - "string-normalize.ts": 2391, - "string-pattern-replacement.ts": 3527, - "string-scan-fast-paths.ts": 2272, - "string-split-checked-separator.mjs": 2144, - "string-split-traversal.ts": 3038, - "structural-class-properties.ts": 2610, - "structured-text-boundaries.js": 2792, - "structured-text-storage.ts": 2942, - "switch-integer-dispatch.ts": 2290, - "symbol-checked-boundary/main.ts": 2273, - "symbol-class-fields.ts": 2065, - "symbol-class-fields/main.cjs": 2595, - "symbol-class-methods/main.ts": 1855, - "symbol-fields-deferred-factory.ts": 2253, - "symbol-fields-inferred.js": 2329, - "symbol-object-properties/main.js": 2835, - "synchronous-callback-lifetimes.ts": 2768, - "terminal-stream-properties.ts": 2586, - "text-codec-values/main.ts": 2158, - "text-codec-var.ts": 2182, - "text-encode-into-boundaries.ts": 1971, - "timers-clear-many.ts": 2704, - "tuple-and-string-search.ts": 2663, - "tuple-array-union.ts": 2706, - "tuple-callback-visitation.ts": 3464, - "tuple-forof-visitation.ts": 2357, - "typed-array-bulk-conversion.mjs": 3837, - "typed-array-byte-io.js": 2552, - "typed-array-checked-index.js": 2420, - "typed-array-constructor-alias.ts": 2507, - "typed-array-constructor-identity.js": 2453, - "typed-array-constructor-union.ts": 2428, - "typed-array-constructor-values.mjs": 2571, - "typed-array-dynamic-methods.js": 2604, - "typed-array-integer-widths.ts": 2747, - "typed-array-nan-coded-reads.ts": 2921, - "typed-array-numeric-import.ts": 2450, - "typed-array-present-reads.ts": 2582, - "typed-array-reversed-storage.ts": 2168, - "typed-array-unknown.ts": 2500, - "typed-collection-iterator-references.ts": 3186, - "typed-collection-iterators.ts": 2946, - "typed-collection-views/main.ts": 2523, - "typed-index-arguments.ts": 2494, - "typed-prototype-methods.ts": 2527, - "typed-rest-callables.ts": 2391, - "typed-rest-filtered-return.ts": 2578, - "typedarray-native-inputs.js": 3104, - "typeof-checked-comparison.js": 2116, - "uint8array-sort-domains.ts": 2494, - "unicode-case-paths.ts": 2356, - "unicode-process-argv.ts": 2569, - "union-discriminant-width.ts": 2670, - "union-literal-scalar-discriminants.ts": 2869, - "union-literal-slot-conversion.ts": 2792, - "union-nested-layout-discriminant.ts": 2120, - "union-optional-semantic-identity.ts": 2455, - "union-record-clone.ts": 2790, - "union-record-structural-copy.ts": 2905, - "union-reference-comparison.ts": 2401, - "unknown-array-holes.ts": 1853, - "unknown-collections.ts": 3166, - "unknown-object-enumeration.ts": 3783, - "unknown-record-views.ts": 3243, - "url-runtime-base.ts": 2584, - "utf8-span-decoding.ts": 2564, - "util-parseargs-wrapped/main.ts": 2257, - "virtual-runtime-optional-returns.ts": 2981, - "weak-map-array-buffer.ts": 2435, - "weak-map-fresh-array.js": 2341, - "weak-map-native.js": 3068, - "weak-native-class-identity.ts": 2403, - "weak-set-native.js": 2924, - "worker-class-instance-clone.ts": 3052 + "checked-any-addition.ts": 2597, + "checked-array-assignment.ts": 1938, + "checked-array-flat/main.ts": 2376, + "checked-bitwise/main.js": 2931, + "checked-builder-cycles.js": 2124, + "checked-byte-storage/main.ts": 2136, + "checked-callback-options.ts": 2655, + "checked-class-descriptors.mjs": 3730, + "checked-class-factory.mjs": 2259, + "checked-collection-iterators.ts": 3189, + "checked-collection-symbol-methods.ts": 2758, + "checked-dispatch-input-lifetimes.js": 3290, + "checked-increment/main.js": 2209, + "checked-inherited-fields.ts": 1885, + "checked-iterator-consumption.js": 3562, + "checked-numeric-arithmetic.js": 2775, + "checked-object-module-alias.js": 2993, + "checked-optional-calls.mjs": 2857, + "checked-promise-recovery.ts": 2965, + "checked-proxy-callback/main.ts": 2460, + "checked-record-constructor.ts": 2536, + "checked-renderer-defaults.js": 2974, + "checked-rest-function-adapters.js": 2402, + "checked-storage-transitions.js": 3227, + "checked-symbol-array.ts": 2138, + "checked-value-input-lifetimes.ts": 2968, + "class-accessor-returned-function.js": 2548, + "class-array-optional-return.ts": 2505, + "class-bracket-method-calls.js": 3232, + "class-brand-overload.js": 2772, + "class-callback-replacement.js": 4256, + "class-callback-storage.ts": 3103, + "class-checked-composites.ts": 2644, + "class-checked-upcast.ts": 2728, + "class-collection-insertion.ts": 4030, + "class-computed-presence.ts": 3380, + "class-computed-symbols.js": 2436, + "class-covariant-returns.ts": 3091, + "class-curried-factory.mjs": 3427, + "class-data-descriptors.js": 3815, + "class-factory-inherited-statics.mjs": 3016, + "class-factory-parameter-base.mjs": 3162, + "class-factory-record-base.mjs": 5127, + "class-factory-recursive-statics.mjs": 2561, + "class-factory-static-members.mjs": 3200, + "class-function-base/main.js": 3392, + "class-instance-constructor.js": 3735, + "class-interface-protocols.ts": 5264, + "class-interface-refinements.ts": 2054, + "class-json-checked.ts": 2470, + "class-local-function-base.mjs": 3094, + "class-method-spreads.ts": 4098, + "class-narrowed-views.ts": 1811, + "class-property-call-values.mjs": 3042, + "class-prototype-data.js": 2959, + "class-prototype-descriptor-copy.mjs": 3884, + "class-specialized-computed-base.mjs": 3695, + "class-static-data.js": 2083, + "class-subclass-assertions.ts": 2716, + "class-super-surplus-spread.mjs": 3129, + "class-symbol-accessors.ts": 2288, + "class-symbol-cache.mjs": 3599, + "class-value-constructor-exceptions.ts": 2725, + "closed-virtual-dispatch-modules/main.ts": 2752, + "closed-virtual-dispatch.ts": 3200, + "closure-nullable-union-return.ts": 2492, + "closure-union-locals.ts": 2959, + "collection-array-cycles.ts": 3095, + "collection-array-maps.ts": 3559, + "collection-array-missing.ts": 3686, + "collection-array-sets.ts": 3501, + "collection-copy-identities.ts": 2360, + "collection-data-unions.ts": 3003, + "collection-ingestion-mappers.ts": 2535, + "collection-ingestion-protocol/main.ts": 3823, + "collection-ingestion-references.ts": 2342, + "collection-ingestion.ts": 3093, + "collection-storage-copies.ts": 2080, + "collection-value-keys.ts": 2956, + "compound-field-receivers.ts": 1671, + "compound-presence-guards.ts": 3200, + "conditional-tuple-destructuring.ts": 2750, + "console-imports.cjs": 1673, + "console-native-value.js": 2807, + "const-enum-module-cycle/main.ts": 2704, + "constant-callback-dispatch.ts": 1960, + "constant-module-globals/main.ts": 1705, + "constant-number-remainders.ts": 2349, + "constructed-class-dispatch.ts": 3130, + "contextual-array-union-write.ts": 6681, + "contextual-return-layouts.ts": 3422, + "counted-loop-numbers.ts": 2709, + "counted-loop-storage.ts": 2965, + "crypto-hash-optional-input.ts": 2865, + "cycle-generations-long-lived.ts": 2572, + "cycle-growth-yield.ts": 3019, + "date-checked-native.js": 2742, + "declared-index-spread.ts": 3806, + "deep-reference-teardown.ts": 3156, + "default-undefined-parameters.ts": 2963, + "deferred-field-updates.ts": 1865, + "deferred-registry-many.ts": 3051, + "derived-numeric-updates.ts": 1958, + "destructure-call-assignment.js": 2640, + "destructure-inferred-row-defaults.js": 2122, + "destructure-union-arrays.ts": 2784, + "dynamic-function-descriptors.js": 2749, + "error-cause-writes.js": 2022, + "error-inherited-message.mjs": 2684, + "error-inherited-name.mjs": 2378, + "error-property-writes.mjs": 2676, + "error-prototype-tostring.js": 3103, + "error-stack-frames.ts": 2531, + "error-stack-limit.ts": 2338, + "error-tostring-overrides.ts": 2421, + "error-values-inspect.ts": 2394, + "exact-index-round-trip.ts": 2708, + "expression-runtime-values.ts": 2672, + "fiber-switch-stress.ts": 2404, + "fiberless-async-ordering.ts": 2698, + "fiberless-async-unhandled.ts": 2605, + "field-assignment-values.ts": 2753, + "file-handle-values.ts": 2888, + "file-read-storage.ts": 3335, + "file-url-percent-decoding.ts": 1678, + "final-field-borrows.ts": 2810, + "for-multiple-bindings.ts": 2621, + "for-multiple-lexical-bindings.ts": 2696, + "for-of-checked-iterator.js": 2735, + "for-of-subclass-elements.ts": 2538, + "forward-generic-signatures.ts": 1734, + "fresh-array-union-layout.js": 2661, + "frozen-checked-dictionaries.mjs": 2513, + "fs-native-realpath.ts": 2900, + "fs-null-byte-paths-js.cjs": 2166, + "fs-null-byte-paths.ts": 3560, + "fs-read-encodings.ts": 2192, + "fs-read-utf8-edges.ts": 3494, + "fs-read-utf8-handle-forms.ts": 1894, + "fs-remove-readonly.ts": 2005, + "fs-write-string-bytes-union.ts": 2781, + "function-apply-value.mjs": 2795, + "function-constructor-global.mjs": 2338, + "function-constructor-kinds/main.js": 3030, + "function-custom-prototype.js": 2801, + "function-custom-to-string.mjs": 1937, + "function-object-assign.js": 1754, + "function-own-prototype/main.js": 2470, + "generator-checked-protocol.ts": 2909, + "generator-checked-return.js": 3084, + "generator-custom-delegation/main.ts": 5038, + "generator-default-return-pattern.ts": 2685, + "generator-delegation-values.ts": 1962, + "generator-inferred-date.js": 3181, + "generator-mixed-checked-channels.ts": 2887, + "generator-untyped-consumer/main.ts": 2216, + "generic-base-specializations.ts": 2930, + "generic-binding-ownership.ts": 2565, + "generic-class-js-functions/main.ts": 2055, + "generic-class-recovery.ts": 2723, + "generic-namespace-factories/main.ts": 2103, + "generic-nullable-collections.ts": 2282, + "generic-pattern-bindings.ts": 2536, + "generic-record-index.ts": 2488, + "generic-visitor-void.ts": 2848, + "global-accumulator-loops.ts": 2271, + "global-error-subclasses.ts": 1850, + "global-runtime-probes.js": 3085, + "global-stored-probes.js": 3029, + "global-string-cache/main.js": 2487, + "global-symbol-cache/main.js": 2631, + "guarded-native-iterables.ts": 2969, + "heap-input-aliases.ts": 2864, + "heap-input-collections.ts": 2900, + "in-array-runtime-index.ts": 3065, + "indexed-assignment-values.js": 2826, + "indexed-assignment-values.ts": 1639, + "indexed-element-field-reads.ts": 1506, + "inferred-array-assignment-values.mjs": 2520, + "inferred-class-default.mjs": 2339, + "inferred-compound-values.mjs": 2708, + "inferred-conditional-class.mjs": 2429, + "inferred-error-fields.js": 2383, + "inferred-map-patterns.mjs": 2476, + "inferred-method-override.js": 2284, + "inferred-partial-destructuring.mjs": 1972, + "inferred-primitive-properties.mjs": 2268, + "inferred-record-return.mjs": 2543, + "inferred-recursive-record.mjs": 2822, + "inferred-undefined-field.mjs": 2615, + "input-lifetime-intervals.ts": 2188, + "input-lifetimes-modules/main.ts": 2672, + "instanceof-class-record-union.ts": 2441, + "integer-flow-arithmetic.ts": 1990, + "integer-loop-forms.ts": 2426, + "integer-view-control.ts": 2085, + "integer-view-numbers.ts": 2088, + "integer-view-storage.ts": 2560, + "intl-grapheme-conformance/main.ts": 4354, + "intl-grapheme.ts": 1787, + "iterator-typed-returns.ts": 2556, + "js-abort-portable.js": 3289, + "js-array-constructor.js": 3326, + "js-array-default-buffer.js": 2785, + "js-array-iterators.js": 2367, + "js-arrow-bind.cjs": 3832, + "js-buffer-callback-brand.cjs": 2996, + "js-callable-proxy.js": 3619, + "js-chained-native-results.mjs": 2794, + "js-checked-array-iterator.js": 2235, + "js-checked-array-reference.js": 3562, + "js-checked-number-negation.mjs": 2819, + "js-checked-sort-result.js": 2743, + "js-child-error-listener.cjs": 2228, + "js-cjs-callable-snapshots/main.cjs": 2256, + "js-class-added-parameters.js": 2567, + "js-class-checked-overrides.js": 2547, + "js-class-computed-fields.js": 2943, + "js-class-enumeration.js": 3714, + "js-class-field-accessor-override.js": 3000, + "js-class-fluent-overrides.js": 2749, + "js-class-late-method-values.js": 2358, + "js-class-member-dispatch.js": 3594, + "js-class-return-shapes.js": 3435, + "js-class-shadowed-methods.js": 3639, + "js-class-stored-method-receiver.js": 2943, + "js-class-subclass-properties.js": 3662, + "js-class-symbol-spread.cjs": 2503, + "js-computed-prototype-additions.js": 2456, + "js-constructor-returned-callable.js": 2517, + "js-constructor-spread.js": 3593, + "js-dataview-dispatch.js": 2188, + "js-declared-fields.cjs": 4540, + "js-default-listener-arguments.cjs": 2448, + "js-default-options/main.ts": 3104, + "js-deferred-field-initializers.js": 2710, + "js-deferred-registry-effects.js": 2361, + "js-derived-constructor-hoisting.js": 2306, + "js-dormant-array-write.js": 2104, + "js-dormant-overrides.js": 1741, + "js-expando-records.js": 2473, + "js-implicit-call-results.js": 2893, + "js-inferred-callback-exports/main.js": 4125, + "js-inferred-class-array-return.js": 2816, + "js-inferred-object-values.js": 2369, + "js-inherited-field-storage.js": 3308, + "js-inherited-parameter-abi.js": 2238, + "js-iterable-spread.js": 2086, + "js-loose-dynamic-primitives.js": 2810, + "js-map-object-seeds.js": 2592, + "js-member-increment.js": 3352, + "js-module-function-values.js": 2994, + "js-mutable-null-members.js": 2723, + "js-nested-native-descriptors.js": 2548, + "js-normalize-dispatch.js": 2929, + "js-nullish-inherited-fields.mjs": 2189, + "js-object-receiver-storage.js": 2175, + "js-object-returning-constructors.mjs": 2945, + "js-object-shared-arrays.js": 2935, + "js-omitted-typed-arguments.js": 2736, + "js-open-binding-writes.js": 2167, + "js-optional-class-fields.js": 3219, + "js-optional-member-call.js": 3110, + "js-primitive-union-addition.js": 2549, + "js-promise-all-values.js": 3527, + "js-promise-catch-handler.js": 2649, + "js-promise-finally-order.js": 2445, + "js-promise-pending-reactions.js": 2595, + "js-prototype-host-boundary.js": 2723, + "js-reflect-receivers.js": 3391, + "js-regex-record-captures.js": 3115, + "js-scalar-iterables.js": 2746, + "js-shared-method-dispatch.js": 2796, + "js-specialized-field-method.js": 2049, + "js-static-accessors.js": 3053, + "js-static-method-values.js": 2375, + "js-static-registries.cjs": 2790, + "js-super-accessor-initialization.js": 2104, + "js-uninitialized-native-fields.js": 1764, + "json-guarded-map-values.ts": 3144, + "json-output-bulk.ts": 2572, + "json-runtime-options.mjs": 2583, + "json-stringify-value.js": 2182, + "json-typed-parse-direct.ts": 3644, + "json-typed-parse-index-signatures.ts": 4122, + "json-typed-parse-optional-members.ts": 3273, + "json-typed-parse-union-members.ts": 3078, + "literal-switch-dispatch.ts": 2252, + "live-reference-shared-converters.ts": 3470, + "llvm-read-receiver-lifetime.ts": 3118, + "local-class-call-spreads.js": 2490, + "local-class-declaration.ts": 2302, + "local-class-evaluation.ts": 2915, + "local-class-inheritance.ts": 2396, + "local-class-lifetimes.ts": 2780, + "local-class-namespace/main.js": 3248, + "local-class-prototype-data.js": 3273, + "local-class-specialization.js": 2054, + "local-class-unknown.ts": 1964, + "local-class-values.ts": 2059, + "local-union-storage.ts": 2500, + "locale-compare-root-order.ts": 2609, + "logical-assignment-dynamic.js": 2892, + "logical-assignment-values.ts": 2287, + "logical-runtime-optional-record.ts": 2390, + "loop-reference-lifetimes.ts": 2959, + "map-checked-boundary/main.ts": 2651, + "map-checked-seed.js": 1821, + "map-get-set-fusion.ts": 3131, + "map-number-keys-dense.ts": 2480, + "map-read-lifetimes-exits.ts": 2004, + "map-read-lifetimes.ts": 2956, + "map-seeds-and-spreads.ts": 2807, + "map-typed-array-values.ts": 2864, + "math-function-values.js": 2704, + "missing-read-lambda-results.ts": 2964, + "missing-read-narrowed-storage.ts": 2975, + "missing-read-number-conversions.ts": 2247, + "module-byte-loops.ts": 2710, + "module-fallback-functions/main.js": 2953, + "narrowed-nullish-values.ts": 2689, + "native-any-timer-callback.ts": 2256, + "native-array-borrowed-find-last.js": 2331, + "native-array-borrowed-slice.js": 2738, + "native-array-copying-methods.js": 2547, + "native-array-fill-copywithin.js": 2422, + "native-array-frozen-noops.js": 1940, + "native-array-index-boundaries.js": 1855, + "native-array-integrity.js": 3078, + "native-array-length.js": 2779, + "native-array-named-properties.js": 2991, + "native-array-prototype/main.js": 1536, + "native-array-read-lifetimes.ts": 3338, + "native-array-reduce-find-last.js": 2328, + "native-array-search-from-index.js": 2430, + "native-array-splice-coercion.js": 2633, + "native-array-splice-flat.js": 2555, + "native-buffer-coercion.js": 2993, + "native-callback-dispatch.ts": 3551, + "native-class-array-boundaries.ts": 2938, + "native-class-cache.js": 4207, + "native-class-properties.cjs": 3301, + "native-class-property-cycles.cjs": 2085, + "native-class-property-order.cjs": 2417, + "native-class-type-predicates.ts": 2597, + "native-factory-records.js": 2167, + "native-method-values.js": 3675, + "native-method-values.ts": 2504, + "native-npm-imports/main.ts": 3572, + "native-object-descriptors.js": 2795, + "native-object-for-in-minimal.js": 2689, + "native-object-property-attributes.js": 2700, + "native-object-prototype.js": 2600, + "native-property-names.ts": 2409, + "native-proxy-env.js": 3746, + "native-worker-arena-reuse.ts": 4764, + "native-worker-bounded-errors.ts": 3072, + "native-worker-buffer-consumers.ts": 2989, + "native-worker-cancel-hot.ts": 2633, + "native-worker-class-fields.ts": 3458, + "native-worker-clone-errors.ts": 2734, + "native-worker-commonjs.cjs": 2159, + "native-worker-delayed-messages.ts": 2169, + "native-worker-discarded-heaps.ts": 5523, + "native-worker-environment.ts": 3190, + "native-worker-error.ts": 2740, + "native-worker-exception-state.ts": 4140, + "native-worker-exit-listeners.ts": 2056, + "native-worker-io.ts": 2596, + "native-worker-loop-cancellation.ts": 2554, + "native-worker-message-graphs.ts": 3182, + "native-worker-messages.ts": 2651, + "native-worker-poll-exceptions.ts": 3212, + "native-worker-port-lifetime.ts": 3033, + "native-worker-process-exit.ts": 2692, + "native-worker-publish-classes.ts": 4065, + "native-worker-publish-refusals.ts": 3039, + "native-worker-published-graphs.ts": 3663, + "native-worker-references.ts": 2640, + "native-worker-roots/main.ts": 3080, + "native-worker-shared-views.ts": 3041, + "native-worker-stack-overflow.ts": 2862, + "native-worker-terminate-exception-state.ts": 3985, + "native-worker-terminate-loop.ts": 2725, + "native-worker-terminate-recursion.ts": 3128, + "native-worker-terminate-suspended.ts": 2867, + "native-worker-terminate-tested-loops.ts": 3161, + "native-worker-terminate-wait.ts": 1905, + "native-worker-typed-arrays.ts": 2971, + "nested-map-cycles.ts": 2802, + "nested-map-values.ts": 3022, + "never-returning-calls.ts": 2411, + "next-tick-commonjs-entry.cjs": 2251, + "node24-buffer-encoding-errors.ts": 2393, + "node24-buffer-encoding.ts": 2789, + "node24-crypto-kdf-errors.ts": 2833, + "node24-crypto-kdf-options.ts": 2131, + "node24-crypto-kdf.ts": 4066, + "node24-crypto-sha2.ts": 1593, + "node24-deep-equality-properties.js": 2924, + "node24-deep-equality.cjs": 2596, + "node24-deep-equality.ts": 3235, + "node24-env-files-errors.ts": 2781, + "node24-env-files.ts": 2586, + "node24-env-imports.cjs": 1729, + "node24-env-parse-errors.ts": 2642, + "node24-env-parse.ts": 2636, + "node24-esm-metadata/main.mjs": 2627, + "node24-file-url-buffer.ts": 2669, + "node24-file-url-errors.js": 2467, + "node24-file-url-options.ts": 3030, + "node24-fs-links-callbacks.cjs": 3015, + "node24-fs-links-errors.cjs": 2843, + "node24-fs-links-options.cjs": 3229, + "node24-fs-links-promise-errors.cjs": 2844, + "node24-fs-links-promises.ts": 2107, + "node24-fs-links.ts": 1958, + "node24-fs-statfs-callbacks.cjs": 2203, + "node24-fs-statfs-errors.cjs": 2705, + "node24-fs-statfs-options.cjs": 2846, + "node24-fs-statfs.ts": 2174, + "node24-fs-timestamps-callbacks.cjs": 2972, + "node24-fs-timestamps-errors.cjs": 1969, + "node24-fs-timestamps-promises.ts": 2959, + "node24-fs-timestamps-symlinks.ts": 2931, + "node24-fs-timestamps.ts": 1989, + "node24-no-error-assertions-coercion.js": 3207, + "node24-no-error-assertions.cjs": 1972, + "node24-no-error-assertions.ts": 2214, + "node24-parseargs.js": 4158, + "node24-string-decoder.ts": 2635, + "node24-style-text-environment.js": 2062, + "node24-style-text-validation.js": 3237, + "node24-style-text.cjs": 2491, + "node24-style-text.ts": 2829, + "node24-system-error-validation.js": 2660, + "node24-system-errors.cjs": 2361, + "node24-system-errors.ts": 2897, + "node24-text-codec-properties.ts": 2383, + "node24-text-encode-into.ts": 2992, + "node24-text-utilities-coercion.js": 2902, + "node24-text-utilities-validation.js": 2997, + "node24-text-utilities.cjs": 2432, + "node24-text-utilities.ts": 1910, + "node24-url-authority-coercion.js": 2861, + "node24-url-authority.ts": 2689, + "node24-url-factories.ts": 1863, + "node24-url-factory-errors.ts": 1955, + "node24-url-mutation-coercion.js": 2400, + "node24-url-mutation.ts": 2663, + "node24-util-types.cjs": 3712, + "node24-util-types.js": 2869, + "node24-util-types.ts": 3395, + "non-null-class-iteration.ts": 2220, + "nonnull-element-arguments.ts": 2568, + "nonnull-forwarded-class-values.ts": 2603, + "nullable-object-extension.mjs": 2408, + "nullish-asserted-class-arms.ts": 2116, + "nullish-assignment-values.ts": 2517, + "nullish-long-chain.ts": 2430, + "number-parse-statics.ts": 1887, + "number-predicates-unknown.ts": 1974, + "numeric-call-specialization.ts": 2627, + "object-enumeration-array-reads.ts": 2586, + "object-from-checked-entries.js": 2775, + "object-inherited-to-string.js": 2674, + "object-key-indexes.js": 2909, + "object-prototype-identity.mjs": 2317, + "object-reexport/main.js": 2625, + "object-spread-computed.ts": 2429, + "opentui-byte-queue.js": 3139, + "optional-callback-arity.ts": 2294, + "optional-class-flows.ts": 2613, + "optional-element-defaults.ts": 2793, + "optional-flag-comparisons.ts": 2714, + "optional-native-callables.js": 2344, + "optional-node-list-iteration.ts": 2344, + "optional-string-index/main.ts": 2788, + "path-to-file-url-options.ts": 2568, + "performance-presence.ts": 2450, + "primitive-and-function-descriptors.js": 2677, + "primitive-union-string.ts": 1777, + "process-builtin-values.js": 3974, + "process-constrained-memory.ts": 1850, + "process-env-computed-keys.js": 2019, + "process-hrtime.js": 2975, + "process-named-signals.cjs": 2191, + "process-uncaught-handler-throws.cjs": 2460, + "process-uncaught-loop.cjs": 2411, + "process-uncaught-module.mjs": 1942, + "process-uncaught-monitor.cjs": 1718, + "process-uncaught-rejection.cjs": 2645, + "process-uncaught-sync.cjs": 2436, + "process-version-pin.ts": 1717, + "process-versions-storage.ts": 2502, + "projected-collection-lifetimes.ts": 2791, + "promise-checked-rejections.ts": 2434, + "promise-resolve-void.ts": 2330, + "prototype-method-overrides.mjs": 4995, + "prototype-named-data-records.ts": 2858, + "rc-last-use-moves.ts": 2819, + "rc-private-array-writes.ts": 2121, + "record-field-presence.ts": 3356, + "record-key-order.ts": 2943, + "record-optional-json-presence.ts": 2861, + "record-presence-copies.ts": 2372, + "record-presence-delete-json.ts": 3243, + "record-unchecked-read-presence.ts": 2717, + "record-unknown-values.ts": 3976, + "reflect-own-keys.mjs": 2238, + "reflect-record-union-keys.mjs": 2626, + "reflect-typed-record-keys.ts": 2852, + "regex-callback-replacements.ts": 2111, + "regex-callback-values.js": 2464, + "regex-checked-casts.ts": 2160, + "regex-checked-storage.js": 2310, + "regex-exec-long-subject.ts": 4567, + "regex-exec-result-arrays.ts": 3123, + "regex-fs-text-surfaces.ts": 2847, + "regex-input-lifetimes.ts": 2221, + "regex-native-matcher.ts": 4414, + "regex-optional-captures.ts": 3043, + "regex-optional-templates.ts": 2695, + "regex-split-captures.ts": 2413, + "regex-text-paths.ts": 3078, + "regexp-constructor-repeat.ts": 2829, + "regexp-optional-constructor.ts": 2162, + "regexp-string-coercion.js": 2219, + "renderer-export-dictionaries.js": 2331, + "renderer-null-state.js": 1751, + "renderer-specializations.js": 2860, + "repeat-and-typed-read-errors.ts": 2689, + "rest-optional-array-arguments.ts": 2219, + "rest-optional-elements.ts": 2503, + "return-void-through-finally.ts": 2582, + "runtime-optional-string-flows.ts": 2381, + "scalar-string-slices.ts": 2256, + "set-checked-methods.js": 2598, + "set-checked-storage.ts": 2088, + "set-iterator-seed-references.ts": 2454, + "set-iterator-seeds.ts": 3016, + "set-optional-seeds.ts": 2563, + "small-collection-transitions.ts": 2967, + "speculative-integer-globals.ts": 2480, + "speculative-integer-loops.ts": 3219, + "speculative-integer-reads.ts": 2852, + "stack-depth-async-bodies.ts": 2421, + "stack-overflow-async.ts": 1922, + "stack-overflow-caught.ts": 2542, + "stack-overflow-finally.ts": 2607, + "stack-overflow-shapes.ts": 3083, + "stack-overflow-uncaught.ts": 2465, + "stackless-async-concurrency.ts": 2441, + "stackless-async-context.ts": 2934, + "stackless-async-exceptions.ts": 2936, + "stackless-async-ordering.ts": 2618, + "stackless-async-unhandled.ts": 2477, + "static-field-updates/main.ts": 2461, + "static-method-receivers.ts": 1849, + "stdio-values.mjs": 2236, + "stdio-write-errors.mjs": 2342, + "stdio-write-overrides.mjs": 2002, + "stored-native-builtins.js": 2708, + "stored-object-helpers.js": 2808, + "stream-dynamic-entry-kinds.cjs": 3015, + "stream-dynamic-entry-kinds.ts": 1582, + "stream-encoded-from-entries.cjs": 3058, + "stream-encoded-from-entries.ts": 2590, + "string-char-code-integer-loops.ts": 2802, + "string-code-points.ts": 2658, + "string-concat-number-parts.ts": 2339, + "string-construction-order.ts": 2902, + "string-field-append.ts": 3251, + "string-lifetimes-boundaries.ts": 2858, + "string-lifetimes-evaluation.ts": 1805, + "string-lifetimes-iteration.ts": 2235, + "string-lifetimes-operations.ts": 2468, + "string-normalize.ts": 2348, + "string-pattern-replacement.ts": 1662, + "string-scan-fast-paths.ts": 2133, + "string-split-checked-separator.mjs": 2285, + "string-split-traversal.ts": 1939, + "structural-class-properties.ts": 3139, + "structured-text-boundaries.js": 3111, + "structured-text-storage.ts": 2912, + "switch-integer-dispatch.ts": 2264, + "symbol-checked-boundary/main.ts": 2800, + "symbol-class-fields.ts": 2364, + "symbol-class-fields/main.cjs": 2507, + "symbol-class-methods/main.ts": 2255, + "symbol-fields-deferred-factory.ts": 2386, + "symbol-fields-inferred.js": 2386, + "symbol-object-properties/main.js": 3085, + "synchronous-callback-lifetimes.ts": 2296, + "terminal-stream-properties.ts": 2094, + "text-codec-values/main.ts": 2338, + "text-codec-var.ts": 2708, + "text-encode-into-boundaries.ts": 2679, + "timers-clear-many.ts": 2665, + "tuple-and-string-search.ts": 2567, + "tuple-array-union.ts": 2150, + "tuple-callback-visitation.ts": 3321, + "tuple-forof-visitation.ts": 2818, + "typed-array-bulk-conversion.mjs": 4061, + "typed-array-byte-io.js": 3073, + "typed-array-checked-index.js": 2572, + "typed-array-constructor-alias.ts": 2243, + "typed-array-constructor-identity.js": 2693, + "typed-array-constructor-union.ts": 2646, + "typed-array-constructor-values.mjs": 2380, + "typed-array-dynamic-methods.js": 2112, + "typed-array-integer-widths.ts": 2661, + "typed-array-nan-coded-reads.ts": 3761, + "typed-array-numeric-import.ts": 2783, + "typed-array-present-reads.ts": 3074, + "typed-array-reversed-storage.ts": 2650, + "typed-array-unknown.ts": 2830, + "typed-collection-iterator-references.ts": 3315, + "typed-collection-iterators.ts": 3098, + "typed-collection-views/main.ts": 1720, + "typed-index-arguments.ts": 2531, + "typed-prototype-methods.ts": 3386, + "typed-rest-callables.ts": 2393, + "typed-rest-filtered-return.ts": 2745, + "typedarray-native-inputs.js": 3102, + "typeof-checked-comparison.js": 2558, + "uint8array-sort-domains.ts": 2057, + "unicode-case-paths.ts": 2222, + "unicode-process-argv.ts": 2491, + "union-discriminant-width.ts": 2970, + "union-literal-scalar-discriminants.ts": 3053, + "union-literal-slot-conversion.ts": 2820, + "union-nested-layout-discriminant.ts": 1976, + "union-optional-semantic-identity.ts": 3464, + "union-record-clone.ts": 2368, + "union-record-structural-copy.ts": 3130, + "union-reference-comparison.ts": 2882, + "unknown-array-holes.ts": 1889, + "unknown-collections.ts": 3133, + "unknown-object-enumeration.ts": 4341, + "unknown-record-views.ts": 3288, + "url-runtime-base.ts": 2471, + "utf8-span-decoding.ts": 2821, + "util-parseargs-wrapped/main.ts": 2971, + "virtual-runtime-optional-returns.ts": 3001, + "weak-map-array-buffer.ts": 1951, + "weak-map-fresh-array.js": 2498, + "weak-map-native.js": 3238, + "weak-native-class-identity.ts": 2197, + "weak-set-native.js": 2814, + "worker-class-instance-clone.ts": 3421 }, "san": { - "001-hello.ts": 38244, - "002-log-args.ts": 31270, - "100-number-format.ts": 45195, - "1000-json-stringify-basics.ts": 46332, - "1001-json-escapes-unicode.ts": 4513, - "1002-json-parse-cast.ts": 35521, - "1003-json-parse-unions.ts": 3512, - "1004-json-parse-errors.ts": 3903, - "1005-json-nested.ts": 3425, - "1006-json-fs-config.ts": 3347, - "1007-json-rc-stress.ts": 34305, - "1008-json-null-arms.ts": 3422, - "1009-json-optional-fields.ts": 4004, - "101-arithmetic.ts": 4655, - "1010-json-stringify-space.ts": 45417, - "1011-json-unknown-typeof.ts": 4001, - "102-comparisons.ts": 3774, - "1020-async-basics.ts": 3697, - "1021-async-ordering.ts": 3078, - "1022-async-exceptions.ts": 3780, - "1023-async-rc-stress.ts": 3889, - "1024-async-pending-exit.ts": 3389, - "1025-async-promise-capture.ts": 42296, - "1026-throw-promise.ts": 4482, - "1027-async-return-promise.ts": 3534, - "1028-async-return-record-literals.ts": 3843, - "1029-async-eager-chains.ts": 4890, - "103-ternary.ts": 3470, - "104-ternary-empty-arrays.ts": 7056, - "1050-comptime-tables.ts": 4643, - "1051-comptime-strings.ts": 42895, - "1052-comptime-records.ts": 44375, - "1053-comptime-json.ts": 4497, - "1054-comptime-modules/main.ts": 4326, - "110-number-radix.ts": 3100, - "111-record-entries.ts": 7961, - "1110-math-members.ts": 3457, - "1111-math-random.ts": 4321, - "1113-string-methods.ts": 23286, - "1114-string-unicode-island.ts": 45718, - "1115-parse-globals.ts": 3277, - "1116-island-static-mix.ts": 3738, - "1117-typeof-static-union.ts": 4351, - "1118-object-spread-conditional.ts": 3602, - "1119-switch-union.ts": 4833, - "112-class-descriptor-key.js": 4674, - "1121-infinity-number-tostring.ts": 4470, - "1122-any-captures.ts": 7125, - "1124-union-narrowed-retag.ts": 3484, - "113-promise-checked-exits.ts": 4562, - "114-live-record-delete.ts": 3572, - "115-array-compound.js": 6457, - "116-text-decoder-runtime.js": 33483, - "117-weak-cache-cycle.js": 5789, - "118-fs-stored-callbacks.cjs": 52946, - "119-native-patterns.js": 6101, - "1200-regex-test-basics.ts": 47554, - "1201-regex-replace.ts": 3959, - "1202-regex-substitutions.ts": 3855, - "1203-regex-split.ts": 31517, - "1204-regex-empty-unicode.ts": 4662, - "1205-regex-rc-stress.ts": 36658, - "1300-errors-basics.ts": 4354, - "1301-errors-subclass.ts": 4687, - "1302-errors-typed-catch.ts": 4229, - "1303-errors-rc-stress.ts": 3431, - "1304-errors-uncaught.ts": 3763, - "1305-errors-async-rejections.ts": 4254, - "1306-errors-runtime-instances.ts": 4140, - "1350-path-normalize-join.ts": 4224, - "1351-path-parts.ts": 4167, - "1352-path-resolve-relative.ts": 4382, - "1353-os-basics.ts": 4007, - "1354-builtin-bare-specifiers.ts": 3999, - "1355-url-parse.ts": 3346, - "1356-url-file-bridge.ts": 3553, - "1357-fsp-roundtrip.ts": 4325, - "1358-crypto-random.ts": 3398, - "1359-json-module/main.ts": 4414, - "1360-spawn-sync.ts": 4387, - "1361-spawn-events.ts": 4260, - "1362-spawn-timers.ts": 9971, - "1363-spawn-unhandled-error.ts": 3744, - "1364-union-truthiness.ts": 3907, - "1365-union-logical.ts": 4258, - "1366-union-equality.ts": 3058, - "1367-destructuring.ts": 5461, - "1368-constructor-functions.ts": 3781, - "1369-promise-union.ts": 3864, - "1370-spread.ts": 3429, - "1371-union-template-tostring.ts": 3265, - "1372-loose-null-tests.ts": 3885, - "1373-union-array-arms.ts": 3435, - "140-bitwise-operators.ts": 4527, - "1400-typedarray-basics.ts": 5395, - "1401-typedarray-slice-set.ts": 3626, - "1402-buffer-encodings.ts": 4871, - "1403-buffer-fs.ts": 4268, - "1404-zlib-crypto-bytes.ts": 5331, - "1405-bytes-unions-arrays.ts": 3838, - "1406-dataview-mp4.ts": 3661, - "1407-dataview-bounds.ts": 5553, - "1408-string-indexing.ts": 5392, - "1409-typedarray-integer-loops.ts": 4558, - "1420-number-statics.ts": 3886, - "1421-number-parse-strings.ts": 4644, - "1422-date-iso.ts": 4015, - "1423-text-codec.ts": 38476, - "1424-fs-options.ts": 3473, - "1425-stdin-tty.ts": 4093, - "1426-stdin-read.ts": 3982, - "1427-fromcharcode-lastindexof.ts": 2946, - "1428-settled-await-order.ts": 3794, - "1429-promise-catch-finally.ts": 4465, - "1430-promise-race.ts": 4414, - "1431-caught-tostring.ts": 2971, - "1432-destructured-params.ts": 3941, - "1433-filter-narrow.ts": 3907, - "1434-async-never.ts": 3465, - "1435-math-spread.ts": 3652, - "1436-default-undef-param.ts": 3877, - "1437-pad-default.ts": 3475, - "1438-promise-all.ts": 7297, - "1440-interval-basics.ts": 4144, - "1441-interval-clear-cross.ts": 7176, - "1442-interval-throw.ts": 3609, - "1443-signal-handlers.ts": 7600, - "1444-exit-listeners.ts": 4768, - "1445-exit-process-exit.ts": 5403, - "1446-exit-uncaught.ts": 4319, - "1447-stdin-closed-events.ts": 4894, - "1448-stream-columns.ts": 4014, - "1450-incdec-expression.ts": 3639, - "1451-instanceof-uint8array-unknown.ts": 3654, - "1452-return-through-finally.ts": 4057, - "1453-pmap-settled.ts": 4531, - "1454-nonnull-narrow-and-fcc-bytes.ts": 3459, - "1455-lambda-union-return-adoption.ts": 3583, - "1460-console-error-warn.ts": 3484, - "1461-process-pid-getuid-kill.ts": 3345, - "1462-exec-sync.ts": 5307, - "1463-timeout-unref.ts": 3316, - "1464-env-writes.ts": 3946, - "1465-env-value.ts": 3554, - "1466-child-containers.ts": 4064, - "1467-string-match.ts": 3329, - "1468-exec-path.ts": 3588, - "1469-remove-listener.ts": 5747, - "1470-child-lifecycle.ts": 2972, - "1471-child-unref.ts": 8472, - "1472-errno-code.ts": 3388, - "1473-promisify-execfile.ts": 5200, - "1474-string-decoder.ts": 3868, - "1475-readline-closed-stdin.ts": 3587, - "1476-assign-expression.ts": 4319, - "1477-in-expressions.ts": 3951, - "1478-promise-reject.ts": 4331, - "1479-destructuring-assign.ts": 3821, - "1480-os-network-interfaces.ts": 4186, - "1481-string-case-static.ts": 2782, - "1482-spawnsync-error.ts": 2721, - "1483-array-slice.ts": 52661, - "1520-fs-wider-surface.ts": 3691, - "1520-string-split-static.ts": 3432, - "1521-fs-lstat-lock.ts": 3409, - "1521-string-trim-pad-static.ts": 4078, - "1522-parseint-static.ts": 3461, - "1522-spawnsync-options.ts": 5773, - "1523-isnan-floor-static.ts": 3552, - "1523-spawn-options.ts": 5294, - "1524-atomics-sleep-static.ts": 4028, - "1524-catch-narrowing.ts": 2626, - "1525-child-exit-signal.ts": 3477, - "1525-unknown-typeof-validation.ts": 2889, - "1526-set-spread.ts": 3802, - "1527-logical-mixed-operands.ts": 4773, - "1528-delete-records-env.ts": 3621, - "1529-class-with-statics.ts": 3381, - "1530-array-push-variadic.ts": 2970, - "1530-spread-override-completion.ts": 2499, - "1531-delete-optional-fields.ts": 3623, - "1531-process-arch-versions.ts": 2740, - "1532-array-splice-shift.ts": 4204, - "1532-union-shared-field-read.ts": 2834, - "1533-bool-equality.ts": 4076, - "1533-path-platform-namespaces.ts": 3406, - "1534-crypto-hash-chain.ts": 4097, - "1534-union-as-arm-cast.ts": 45787, - "1535-spawn-fd-stdio.ts": 3840, - "1535-union-param-defaults.ts": 4358, - "1536-destructuring-defaults.ts": 3812, - "1536-string-array-sweep.ts": 3859, - "1537-chalk-hybrid/main.ts": 4683, - "1537-os-release-spawnsync-stdio.ts": 2674, - "1538-await-promiselike-return.ts": 2642, - "1538-math-static-scalar.ts": 3735, - "1539-readonly-set-map.ts": 3299, - "1539-unknown-truthiness.ts": 3045, - "1540-os-userinfo.ts": 4119, - "1540-void-statement.ts": 2941, - "1541-fs-readdir-dirent.ts": 5432, - "1541-union-keyed-reads.ts": 4646, - "1542-map-promise-values.ts": 33000, - "1542-record-literal-into-union.ts": 2885, - "1543-rest-destructuring.ts": 3500, - "1543-set-server-handles.ts": 6770, - "1544-dyn-json-reads.ts": 4863, - "1544-string-matchall.ts": 4770, - "1545-spread-order-and-optional.ts": 4536, - "1546-union-element-reads.ts": 4536, - "1547-computed-key-fold.ts": 3960, - "1548-boolean-condition-forms.ts": 4649, - "1549-array-isarray-unions.ts": 4084, - "1550-param-defaults-func-set.ts": 3020, - "1551-dyn-receiver-methods.ts": 3403, - "1552-exec-options-record.ts": 2877, - "1553-truthy-hof-predicates.ts": 3895, - "1554-caught-into-unknown.ts": 3417, - "1555-index-spread-into-declared.ts": 4534, - "1556-union-retag-width-arms.ts": 3587, - "1557-url-host.ts": 2566, - "1558-any-joins-and-dyn-validation.ts": 33883, - "1559-conditional-spread-index-merge.ts": 3282, - "1560-forof-homogeneous-tuples.ts": 3680, - "1561-forof-strings.ts": 2878, - "1561-promise-then.ts": 3851, - "1562-optional-chain-tails.ts": 4618, - "1562-spawn-conditional-spread.ts": 4043, - "1563-forof-iterator-projections.ts": 3930, - "1563-string-raw-fold.ts": 3100, - "1564-fs-watch.ts": 4051, - "1564-string-raw.ts": 3075, - "1565-spawn-pipe-streams.ts": 3895, - "1565-union-element-join.ts": 4167, - "1566-child-duck-interface.ts": 3875, - "1567-server-close-override.ts": 3304, - "1568-x509-fingerprint.ts": 2839, - "1569-fsp-mkdir-unlink-chmod.ts": 3012, - "1570-child-unref-kill-reffed.ts": 9046, - "1571-optional-call-tostring-tail.ts": 26380, - "1571-stdin-set-raw-mode-non-tty.ts": 4151, - "1572-promise-reject-all-tuple.ts": 4201, - "1572-x509-validity-date-gettime.ts": 3944, - "1573-promisify-execfile-env-spread.ts": 4480, - "1573-tdz-scalar-forward-capture.ts": 2862, - "1574-dyn-optional-method-number-keys.ts": 3192, - "1574-promise-all-tuple-literal.ts": 4410, - "1575-unknown-assert-into-record.ts": 3424, - "1576-width-coercions.ts": 4144, - "1577-url-hostname.ts": 4030, - "1578-exec-input-optional.ts": 4028, - "1579-matchall-index.ts": 4108, - "1580-exec-env-conditional-spread.ts": 3516, - "1581-declare-const-read.ts": 3997, - "1582-timer-sleep-resolve.ts": 4177, - "1583-loops-and-stream-captures.ts": 4450, - "1584-union-field-unassigned.ts": 3964, - "1585-union-field-conditional-ctor.ts": 3070, - "1586-derived-field-before-super-init.ts": 4073, - "1590-js-unannotated.js": 4738, - "1591-js-closures.js": 3535, - "1592-js-classes.js": 7400, - "1593-js-jsdoc-records.js": 4695, - "1594-js-async.js": 3836, - "1595-js-island-gap/main.js": 3139, - "1596-cjs-modules/main.js": 3283, - "1597-mjs-graph/main.mjs": 3605, - "1598-cjs-builtin-require/main.js": 2977, - "1599-js-uncaught-throw.js": 3196, - "1600-assert-passing.ts": 4333, - "1601-assert-fail-exit.ts": 3725, - "1602-assert-caught-error.ts": 3373, - "1603-assert-scalar-messages.ts": 5128, - "1604-assert-deep-structures.ts": 4364, - "1605-assert-import-forms.ts": 4371, - "1606-assert-strict-module.ts": 2984, - "1607-assert-throws-match.ts": 4301, - "1608-cjs-assert/main.js": 3820, - "1609-assert-async.ts": 2695, - "1610-path-win32-full.ts": 2757, - "1611-url-file-bridge-neutral.ts": 4375, - "1612-cjs-module-globals.cjs": 3706, - "1613-cjs-esm-proxy-named/main.mjs": 3290, - "1614-js-fence-dodges.cjs": 2861, - "1615-cjs-export-shapes/main.cjs": 4723, - "1616-cjs-esm-lexer-invisible/main.mjs": 2991, - "1617-cjs-esm-lexer-visible/main.mjs": 3860, - "1618-cjs-esm-poisoned-tail/main.mjs": 3236, - "1619-cjs-esm-reexport-invisible/main.mjs": 3244, - "1620-cjs-require-effects-order/main.js": 2604, - "1621-cjs-require-cache-hit/main.js": 3531, - "1622-cjs-require-conditional/main.js": 3501, - "1623-cjs-require-diamond/main.js": 4051, - "1624-cjs-require-dir-mid-file/main.js": 2658, - "1625-cjs-require-lazy-fn/main.js": 3635, - "1626-cjs-require-mjs/main.js": 2942, - "1627-mjs-import-cjs-requires/main.mjs": 3236, - "1628-checked-dynamic-builtin-args.cjs": 2968, - "1629-require-main-filename.cjs": 2826, - "1630-inspect-scalars.ts": 3908, - "1630-rmsync-retry-options.cjs": 3797, - "1631-inspect-arrays.ts": 4065, - "1632-inspect-records.ts": 4843, - "1633-inspect-map-set.ts": 3133, - "1634-inspect-classes.ts": 3805, - "1635-inspect-buffer.ts": 3530, - "1636-util-format.ts": 2945, - "1637-inspect-dyn.ts": 3297, - "1638-inspect-cjs.cjs": 3549, - "1639-versions-openssl-probe.ts": 3544, - "1640-fd-read-decode.ts": 2932, - "1641-string-search.ts": 3476, - "1642-object-fromentries-rows.ts": 3699, - "1643-metadata-dyn-return.cjs": 4074, - "1644-ee-basics.ts": 4205, - "1645-ee-extends.ts": 3512, - "1646-ee-once-remove.ts": 3828, - "1647-ee-meta-events.ts": 3673, - "1648-ee-error-event.ts": 3271, - "1649-ee-names-counts.ts": 3057, - "1650-ee-prepend.ts": 3927, - "1651-ee-max-listeners.ts": 4648, - "1652-ee-snapshot.ts": 4220, - "1653-ee-cjs.cjs": 3230, - "1654-ee-namespace.ts": 3631, - "1655-spawnsync-neutral.ts": 5393, - "1656-execsync-neutral.ts": 3546, - "1657-spawn-async-neutral.ts": 3320, - "1660-buffer-read-write-num.ts": 4303, - "1661-buffer-encodings-full.ts": 3877, - "1662-string-decoder-encodings.ts": 3423, - "1663-buffer-compare-search-fill.ts": 4770, - "1664-dyn-fn-boundary.cjs": 3405, - "1665-dyn-fn-mustcall/main.cjs": 2819, - "1666-dyn-fn-identity.ts": 2740, - "1667-dyn-fn-not-callable.cjs": 3303, - "1668-dyn-fn-throws.cjs": 3745, - "1669-symbol-identity.ts": 3617, - "1670-symbol-registry.ts": 4207, - "1671-symbol-typeof.ts": 3400, - "1672-symbol-containers.ts": 3581, - "1673-symbol-cjs.cjs": 3624, - "1674-symbol-inspect.ts": 2758, - "1676-func-array-surface.ts": 2900, - "1677-emitter-listeners.ts": 4932, - "1678-emitter-dyn-listeners.cjs": 3287, - "1679-console-dyn.js": 3576, - "1680-assert-bytes.ts": 3903, - "1681-assert-funcs.ts": 3918, - "1685-stream-readable-basics.ts": 6503, - "1686-stream-readable-paused.ts": 6965, - "1687-stream-readable-flow-control.ts": 3669, - "1688-stream-writable-basics.ts": 3711, - "1689-stream-writable-async-drain.ts": 6004, - "1690-stream-duplex.ts": 6220, - "1691-stream-transform.ts": 6193, - "1692-stream-pipe.ts": 6662, - "1693-stream-pipe-backpressure.ts": 3700, - "1694-stream-destroy.ts": 3259, - "1695-stream-props.ts": 4843, - "1696-stream-read-inside-read.ts": 3524, - "1697-stream-tick-vs-timer.ts": 3256, - "1698-stream-uncaught-error.ts": 4826, - "1699-stream-callback-shapes.ts": 3791, - "1700-mustcall-common/main.cjs": 4329, - "1701-mustcall-exit-report/main.cjs": 3995, - "1702-dyn-proto-dispatch.cjs": 4694, - "1703-arguments-rest-props.cjs": 3485, - "1710-cjs-export-class/main.js": 2945, - "1711-cjs-export-single-values/main.js": 3527, - "1712-field-incdec.ts": 3301, - "1713-js-dyn-fields.js": 3702, - "1720-assert-throws-shape.ts": 3665, - "1721-assert-throws-regex-class.ts": 3205, - "1722-assert-rejects.ts": 3941, - "1723-assert-does-not-reject.ts": 3991, - "1724-assert-iferror.ts": 2922, - "1725-assert-symbols.ts": 4117, - "1726-promise-with-resolvers.ts": 3773, - "1727-assert-throws-shape-exit.ts": 4180, - "1730-countdown-symbol-keys/main.js": 3717, - "1731-symbol-field-shapes.cjs": 4041, - "1732-symbol-field-cross-module/main.js": 3671, - "1740-stream-extends-readable.ts": 5413, - "1741-stream-extends-writable.ts": 6469, - "1742-stream-extends-duplex-transform.ts": 6437, - "1743-stream-extends-vt-dispatch.ts": 7212, - "1744-stream-set-encoding.ts": 3635, - "1745-stream-encoding-js.cjs": 2973, - "1746-stream-for-await.ts": 4707, - "1747-stream-for-await-js.cjs": 4902, - "1750-http-agent-options.ts": 7371, - "1751-options-record-stance.ts": 4112, - "1760-surplus-args-drop.cjs": 3672, - "1761-emitter-special-event-names.cjs": 5508, - "1770-assert-dyn-strict.ts": 4072, - "1771-assert-dyn-deep.ts": 3521, - "1772-assert-dyn-js.cjs": 3744, - "1773-assert-dyn-exit.ts": 3156, - "1780-http-res-surface.ts": 7173, - "1781-http-server-shapes.cjs": 3500, - "1790-computed-key-folds.ts": 3641, - "1791-searchparams-core.ts": 3206, - "1792-searchparams-encoding.ts": 3500, - "1793-searchparams-iteration.ts": 3620, - "1794-searchparams-url-live.ts": 3114, - "1795-dyn-handle-request.cjs": 6764, - "1796-dyn-handle-body.cjs": 6226, - "1797-dyn-handle-socket.cjs": 3886, - "1798-dyn-handle-typed-box.ts": 6248, - "1800-immediate-basics.ts": 3211, - "1801-immediate-handle.ts": 3455, - "1802-immediate-unref-exit.ts": 3001, - "1803-timeout-refresh.ts": 3714, - "1804-timers-module.ts": 3580, - "1805-timer-callback-args.ts": 3293, - "1806-timer-delay-trunc.ts": 3354, - "1810-stream-options-const-record.ts": 4095, - "1811-stream-option-value-callbacks.cjs": 3113, - "1812-stream-super-options-forwarding.cjs": 3239, - "1813-stream-finished.ts": 3753, - "1814-stream-pipeline.cjs": 3633, - "1815-stream-state-reads.cjs": 3723, - "1820-static-block-basics.ts": 3496, - "1821-static-block-order.ts": 3121, - "1822-static-block-js.js": 2926, - "1823-static-instance-method-names.ts": 2971, - "1824-for-of-destructuring-defaults.ts": 3389, - "1825-exhaustive-typeof-switch.ts": 2558, - "1826-settimeout-arguments-callback.js": 3292, - "1830-enum-numeric-basics.ts": 3721, - "1831-enum-string-const-reverse.ts": 3386, - "1832-enum-modules/main.ts": 3491, - "1835-var-basics.ts": 3090, - "1836-var-loop-capture.ts": 4227, - "1837-var-undefined-hoisting.ts": 3129, - "1838-var-modules/main.ts": 3442, - "1839-var-js/main.cjs": 2943, - "1840-jsdoc-import-type-only/main.js": 3153, - "1850-overload-basics.ts": 3527, - "1851-overload-return-narrowing.ts": 3485, - "1852-overload-class-members.ts": 3165, - "1853-overload-modules/main.ts": 3369, - "1854-ambient-declare-fn.ts": 3339, - "1855-ambient-declare-fn-uncaught.ts": 2825, - "1870-unit-type-values.ts": 3760, - "1871-empty-array-never.ts": 2995, - "1872-template-tostring-composite.ts": 3281, - "1880-json-declared-field-order.ts": 3669, - "1881-default-anon/main.ts": 3229, - "1882-default-cjs-interop/main.ts": 3282, - "1883-default-exports/main.ts": 3775, - "1890-ns-imports/main.ts": 3324, - "1891-ns-reexport/main.ts": 3059, - "1940-class-values-basics.ts": 3481, - "1941-class-values-registry.ts": 3018, - "1942-class-expressions.ts": 2837, - "1943-class-statics-expanded.ts": 3294, - "1944-class-values-modules/main.ts": 3634, - "1950-generic-fn-values.ts": 3713, - "1951-generic-classes-basics.ts": 3449, - "1952-generic-class-statics-values.ts": 3863, - "1953-generic-class-hierarchy.ts": 3771, - "1954-generic-modules/main.ts": 3506, - "1960-namespace-basics.ts": 3039, - "1961-namespace-nested.ts": 2879, - "1962-namespace-classes.ts": 3820, - "1963-namespace-aliases.ts": 2943, - "1964-namespace-type-only.ts": 3637, - "1965-namespace-ambient.ts": 3549, - "1966-namespace-modules/main.ts": 3116, - "1967-namespace-alias-typeonly.ts": 2879, - "1968-namespace-import-eq-snapshot.ts": 3284, - "1970-decorators-basics.ts": 3029, - "1971-decorators-rebinding.ts": 3079, - "1972-decorators-throwing.ts": 2634, - "1973-decorators-ambient.ts": 3508, - "1980-primitive-proto-statics.ts": 3768, - "1981-date-utc.ts": 3681, - "1982-freeze-resolve-passthrough.ts": 3352, - "1983-array-tuple-surfaces.ts": 3130, - "1990-labels-basics.ts": 3662, - "1991-for-in-loops.ts": 4312, - "1992-small-syntax.ts": 3036, - "200-strings.ts": 3188, - "2000-generic-methods-basic.ts": 3233, - "2001-generic-methods-generic-class.ts": 3654, - "2002-generic-methods-inheritance.ts": 3883, - "2003-generic-methods-object-literal.ts": 4002, - "2004-generic-methods-statics.ts": 2781, - "201-templates.ts": 3259, - "2010-generators-basics.ts": 2930, - "2011-generators-forof.ts": 3439, - "2012-generators-return-throw.ts": 3077, - "2013-generators-sent-values.ts": 3157, - "2014-generators-values.ts": 3230, - "2015-generators-yieldstar.ts": 2691, - "2016-generators-rc-stress.ts": 3408, - "2017-generators-async.ts": 3645, - "2018-generators-uncaught.ts": 3372, - "2019-generators-loops.ts": 3684, - "2020-generic-value-bindings.ts": 4814, - "2021-generic-value-binding-modules/main.ts": 2613, - "2022-width-index-capture.ts": 4066, - "2023-width-readonly.ts": 3988, - "2024-width-array-elems.ts": 3088, - "2025-width-union-compose.ts": 3148, - "2026-width-spread.ts": 3721, - "2030-width-nested.ts": 3956, - "2031-width-tuples.ts": 3454, - "2032-cjs-export-assigned-class-expression/main.cjs": 3771, - "2033-property-assigned-class-extends.cjs": 2857, - "2035-ternary-array-retag.cjs": 3742, - "2036-evolving-array-decl.cjs": 3733, - "2037-fn-decl-hoisting.cjs": 3504, - "2038-evolving-array-js.cjs": 4258, - "2040-any-bindings.ts": 3664, - "2040-mixin-heritage.ts": 3192, - "2041-any-params-returns.ts": 3362, - "2041-mixin-values.ts": 3893, - "2042-any-flow-loops.ts": 3770, - "2042-mixin-modules/main.ts": 3144, - "2043-any-dom-values.ts": 3779, - "2043-mixin-rc-stress.ts": 4190, - "2044-vtable-sibling-slots.ts": 4054, - "2045-objlit-accessors-basic.ts": 3443, - "2045-parameter-properties.ts": 3049, - "2046-abstract-classes.ts": 4183, - "2046-objlit-accessors-effects.ts": 3215, - "2047-objlit-accessors-shapes.ts": 3091, - "2047-optional-class-fields.ts": 4146, - "2050-dynamic-import-own-module/main.ts": 3451, - "2051-dynamic-import-then/main.ts": 3601, - "2052-dynamic-import-self.ts": 3591, - "2053-typeof-static-fold.ts": 3479, - "2054-destructuring-island-source.ts": 3225, - "2060-empty-tuple.ts": 3198, - "2070-computed-key-folds.ts": 3432, - "2071-integer-key-enumeration-order.ts": 3897, - "2072-expando-function-members.ts": 3830, - "2073-destructuring-assignment.ts": 3540, - "2074-island-destructuring.ts": 3784, - "2075-index-signature-runtime-keys.ts": 2791, - "2080-destructuring-defaults.ts": 3781, - "2081-destructuring-rest.ts": 3728, - "2082-destructuring-assignment.ts": 3505, - "2085-destructuring-heads-rest-params.ts": 3490, - "2087-destructuring-for-heads.ts": 3190, - "2090-index-signature-number-keys.ts": 2803, - "2091-index-signature-string-intersection.ts": 2723, - "2092-package-imports/main.ts": 2857, - "2093-timers-promises.ts": 4034, - "2094-diagnostics-channel.ts": 3375, - "2095-js-catch-unknown.js": 3448, - "2096-os-type.ts": 3784, - "2097-js-evolving-globals.js": 3531, - "210-string-methods.ts": 3602, - "2100-stream-default-hwm.ts": 3572, - "2101-dyn-param-defaults.ts": 2799, - "2102-empty-pattern-decls.ts": 3305, - "2105-computed-key-static-folds.ts": 3458, - "2106-comma-expressions.ts": 3662, - "211-string-unicode.ts": 2722, - "2110-top-object-types.ts": 2930, - "2111-json-stringify-unknown.ts": 2894, - "2112-array-at-findlast.ts": 3347, - "2113-string-index-methods.js": 2954, - "212-string-aliasing-append.ts": 2936, - "2120-package-self-import/main.ts": 2637, - "2121-esm-cycle-inert-backedge/main.ts": 2688, - "2123-ambient-import-crash/main.ts": 2830, - "2124-imports-field-wildcard/main.ts": 2779, - "2140-uri-component-codecs.ts": 3028, - "2160-dc-tracing-channel.cjs": 3125, - "2161-js-object-literal-identity.cjs": 3710, - "2162-js-dyn-destructure.cjs": 2745, - "2163-js-selfref-const.cjs": 4243, - "2164-js-then-dyn-handler.cjs": 4454, - "2165-js-throw-dyn.cjs": 3859, - "2166-cjs-getter-this/main.cjs": 3481, - "2170-island-array-exits.ts": 5249, - "2171-island-json-stringify.ts": 3408, - "2172-island-regexp-boundary.ts": 4656, - "2190-new-object-and-string-wrappers.ts": 2892, - "2191-uri-encoders.ts": 2460, - "2192-object-default-tostring.ts": 3152, - "2193-discarded-stdlib-reads.ts": 3436, - "2194-ambient-undef-chains.ts": 3329, - "2195-require-missing-package/main.mjs": 3396, - "2196-island-computed-key-chain.ts": 4364, - "2210-dyn-promise-crossing.cjs": 3412, - "2211-dc-trace-promise.cjs": 4496, - "2212-unhandled-rejection-listener.cjs": 3503, - "2213-async-local-storage.cjs": 3304, - "2214-dc-bind-store.cjs": 4372, - "2215-process-emit-warning-exit.cjs": 4385, - "2240-width-class-into-record.ts": 3816, - "2241-width-record-into-class.ts": 3107, - "2242-width-statics-into-record.ts": 3187, - "2243-width-assert-satisfies-shapes.ts": 3725, - "2250-tagged-templates.ts": 2802, - "2252-class-iterators.ts": 4024, - "2253-union-coercions.ts": 2969, - "2260-http2-constants.cjs": 2611, - "2280-builtin-namespace-destructure.cjs": 2964, - "2281-domexception-atob-btoa.cjs": 3116, - "2282-queue-microtask.cjs": 3672, - "2283-structured-clone.cjs": 3661, - "2284-regexp-constructor.cjs": 2921, - "2285-iferror-dyn.cjs": 2815, - "2286-dyn-object-walks.cjs": 2814, - "2300-dyn-record-spread-and-keyed-access.cjs": 3340, - "2301-cjs-export-table-dom-attach.cjs": 2994, - "2310-process-next-tick.ts": 3462, - "2311-next-tick-js-callbacks.js": 3541, - "2312-stream-underscore-assign.ts": 4210, - "2313-stream-underscore-assign-js.cjs": 3281, - "2314-process-introspection.ts": 4007, - "2320-await-unit.ts": 2773, - "2321-emitter-static-setmax.cjs": 3576, - "2322-dyn-array-sort.cjs": 2683, - "2323-timer-callback-returns.ts": 3611, - "2330-tls-server-runtime-options.cjs": 22007, - "2331-tls-server-options-typed.ts": 22550, - "2350-nan-global.ts": 3586, - "2351-async-methods.ts": 3496, - "2352-void-coercions.ts": 2875, - "2353-decorators-member-ambient.ts": 2855, - "2354-decorators-expression-ambient.ts": 2445, - "2360-tuple-to-array.ts": 3725, - "2361-assign-index-record.ts": 3918, - "2362-execsync-inherit.ts": 3204, - "2363-nullish-retag.ts": 3277, - "2364-in-runtime-key.ts": 3653, - "2365-dyn-into-island.ts": 2967, - "2366-string-well-formed.ts": 3530, - "2367-regexp-escape.ts": 3537, - "2368-set-methods.ts": 3321, - "2369-promise-try.ts": 3477, - "2370-group-by.ts": 3834, - "2371-iterator-helpers.ts": 3503, - "2380-buffer-module-named-import.ts": 3337, - "2381-builtin-default-imports.js": 3386, - "2382-cycle-two-decl/main.ts": 2540, - "2383-cycle-assertdoc/main.js": 3635, - "2384-cycle-mixed-bindings/main.ts": 2680, - "2385-builtin-reexport-facade/main.ts": 2415, - "2386-string-to-chars.ts": 3358, - "2387-tonumber-argv.ts": 3189, - "2388-tonumber-grammar-zoo.ts": 2478, - "2389-tonumber-unary-plus.ts": 3505, - "2390-dot-requires/main.cjs": 3502, - "2391-default-builtin-imports/main.ts": 3560, - "2392-block-guard-alias-scope.ts": 2811, - "2393-loop-exit-guard-narrow.ts": 3396, - "2394-loop-narrow-containment.ts": 3368, - "2395-while-cond-guard.ts": 2736, - "2396-born-narrowed-decl.ts": 3324, - "2397-branch-kill-merge.ts": 2593, - "2398-switch-arm-kill.ts": 3348, - "2399-reassign-kill-polarity.ts": 3637, - "240-stdout-write.ts": 3882, - "2400-kill-return-edge.ts": 3195, - "2401-kill-break-staging.ts": 3449, - "2402-labeled-break-kill.ts": 2813, - "2403-kill-continue-backedge.ts": 3428, - "2404-kill-throw-catch.ts": 2824, - "2405-sibling-arm-narrow.ts": 2442, - "2406-switch-clause-sibling-narrow.ts": 2665, - "2407-infinite-loop-seal.ts": 3312, - "2408-loop-terminality-reopen.ts": 3281, - "2409-loop-body-return-not-terminal.ts": 3145, - "2410-stacked-cases-terminality.ts": 3627, - "2411-exhaustive-switch-terminality.ts": 3158, - "2412-dowhile-guard-trailing-test.ts": 3265, - "2413-dowhile-kill-renarrow.ts": 2701, - "2414-dowhile-continue-kill.ts": 3317, - "2415-dowhile-break-trailing-test.ts": 3362, - "2416-spread-ternary-positions.ts": 3467, - "2417-ternary-local-inference.ts": 3368, - "2418-wrapped-ternary-arms.ts": 3310, - "2419-selector-ternary-union.ts": 3702, - "2420-nullish-null-identity.ts": 2553, - "2421-float-lane-inference.ts": 3344, - "2422-ieee-div-rem-corners.ts": 3186, - "2423-param-null-reassign.ts": 3025, - "2424-ternary-miss-first-narrowing.ts": 3552, - "2425-elseif-head-exit-narrow.ts": 3257, - "2426-default-snapshot-mutable/main.ts": 3423, - "2427-perf-hooks-now.ts": 3049, - "2428-field-redeclare-inherited.ts": 3585, - "2429-destructure-class-instance.ts": 2694, - "2430-empty-literal-unknown-field.js": 3401, - "2431-primitive-ctor-values.ts": 2884, - "2432-generic-member-fields-async.ts": 5845, - "2433-as-const-command-tables.ts": 3180, - "2434-deferred-init-fields.ts": 3249, - "2435-loose-same-kind-equality.ts": 3363, - "2440-console-inspect-args.ts": 5418, - "2441-console-process-argv.ts": 3041, - "2442-union-literal-arm-widening.ts": 2555, - "2443-union-literal-shadow-narrowing.ts": 3302, - "2444-union-literal-reducer-spread.ts": 3618, - "2445-math-minmax-nary.ts": 2645, - "2446-performance-global.ts": 3980, - "2447-island-boundary-slots/main.ts": 6217, - "2448-entries-null-arms-regex-arrays.ts": 3545, - "2450-private-instance-methods.ts": 2931, - "2451-private-fields.ts": 3694, - "2452-private-statics.ts": 2965, - "2453-private-accessors.ts": 3478, - "2454-private-generator-methods.ts": 3697, - "2455-private-brand-checks.ts": 3515, - "2456-private-async-methods.ts": 3535, - "2457-private-members.js": 2780, - "2460-qs-parse-grammar.ts": 4534, - "2461-qs-parse-options.ts": 4115, - "2462-qs-stringify.ts": 3434, - "2463-qs-escape-unescape.ts": 3311, - "2464-qs-require-forms.cjs": 2821, - "2470-mockable-module-shape.js": 2978, - "2471-record-keyed-write-hasown.js": 2970, - "2472-string-regexp-union.ts": 3393, - "2473-option-table-widths.js": 3653, - "2474-island-literal-forms.ts": 3643, - "2475-variadic-wrapper-island.js": 3606, - "2476-map-regex-values.ts": 3711, - "2480-recursive-record-tree.ts": 3376, - "2481-mutual-recursive-records.ts": 3699, - "2482-recursive-union-tree.ts": 3347, - "2483-recursive-record-cycles.ts": 2764, - "2484-json-stringify-circular.ts": 3845, - "2485-inspect-circular-refs.ts": 3694, - "2486-recursive-record-boundaries.ts": 3988, - "2487-recursive-deep-equal.ts": 3416, - "2488-ast-walker.ts": 3100, - "2490-find-miss-null-compare.ts": 3107, - "2491-strict-unit-compare-no-arm.ts": 2820, - "2492-loose-null-compare-unions.ts": 3683, - "2493-switch-unit-cases.ts": 3703, - "2494-no-arm-compare-effects.ts": 3089, - "2500-net-autosel-timeout.ts": 3775, - "2510-dyn-evolving-array-map.ts": 3265, - "2511-dyn-evolving-array-filter-foreach.ts": 2885, - "2512-dyn-evolving-array-mixed-push.ts": 3639, - "2520-private-statics-class-name-calls.ts": 3155, - "2521-private-statics-class-expression.ts": 3520, - "2522-private-statics-decorated.ts": 3673, - "2523-private-statics-aliased-class.ts": 3795, - "2530-object-destructuring-decl.ts": 2869, - "2531-array-tuple-destructuring-decl.ts": 3168, - "2532-param-destructuring-options.ts": 2906, - "2533-forof-destructuring.ts": 2840, - "2534-object-rest-decl.ts": 3199, - "2535-destructuring-assign-basics.ts": 3816, - "2536-destructuring-assign-nested.ts": 3047, - "2537-destructuring-assign-member-targets.ts": 3590, - "2538-destructuring-assign-class-source.ts": 3544, - "2539-class-instance-rest.ts": 3764, - "2540-accessor-destructuring-defaults.ts": 3201, - "2541-destructuring-eval-order.ts": 2670, - "2550-generics-keyof-pick.ts": 3947, - "2551-generics-value-aliases.ts": 3227, - "2552-generics-iface-methods.ts": 3318, - "2553-generics-signature-bindings.ts": 3442, - "2554-generics-frontier-mix.ts": 3344, - "2555-generics-keyof-writes.ts": 3448, - "2556-crypto-introspection.ts": 3351, - "2556-width-hybrid-shapes.ts": 3462, - "2557-tls-ca-store.ts": 4438, - "2557-width-field-lifts.ts": 4453, - "2558-index-signature-func-values.ts": 3590, - "2558-rejection-events.cjs": 3641, - "2559-index-signature-container-values.ts": 4066, - "2560-arraybuffer-dataview-set.ts": 3614, - "2561-object-is.ts": 3391, - "2562-intl-numberformat-en-us.ts": 3241, - "2563-stream-promises-pipeline.ts": 3490, - "2564-stream-promises-finished.ts": 2994, - "2565-stream-promises-js.cjs": 2616, - "2566-promise-reject-dyn-reason.js": 3548, - "2567-rest-spread-forward.js": 3292, - "2568-rest-spread-forward-dynamic.js": 3367, - "2569-upcast-identity.ts": 2553, - "2570-buffer-arg-validation.cjs": 5779, - "2571-searchparams-arg-validation.cjs": 3913, - "2572-readable-emitted-readable-flag.cjs": 3556, - "2573-fs-url-arg-ladders.cjs": 3502, - "2574-emitter-max-listeners-ladders.cjs": 2895, - "2575-string-destructuring-decl.ts": 3433, - "2576-string-destructuring-assign.ts": 2984, - "2577-builtin-global-destructuring.js": 3466, - "2578-jsval-into-unknown-rows.ts": 3398, - "2579-jsval-object-param-crossing.js": 3294, - "2580-jsval-routed-keyed-ops.js": 3298, - "2581-jsval-routed-calls.js": 3542, - "2582-jsval-object-statics.js": 3509, - "2582-jsval-routed-keyed-ops.js": 3136, - "2583-dyn-nullish-coalesce.js": 2976, - "2583-jsval-routed-calls.js": 2950, - "2584-jsval-object-statics.js": 3305, - "2584-union-dyn-collapse.ts": 2970, - "2585-dyn-nullish-coalesce.js": 3632, - "2585-unknown-array.ts": 3809, - "2586-object-assign-spread.js": 4084, - "2587-array-entries-forof.ts": 2633, - "2588-array-entries-chains.ts": 4097, - "2589-object-create-null.cjs": 3112, - "2590-object-create-dynamic.js": 4279, - "2591-ambient-generic-traps.ts": 3216, - "2592-ambient-trap-uncaught.ts": 3198, - "2593-generic-inert-bindings.ts": 3007, - "2594-nullish-generic-bindings.ts": 3321, - "2595-fs-arg-ladders.cjs": 3930, - "2596-net-arg-ladders.cjs": 3528, - "2597-dgram-send-ladders.cjs": 4536, - "2598-tls-arg-ladders.cjs": 4142, - "2599-stream-arg-ladders.cjs": 5465, - "2600-dyn-keyed-write-harness.js": 2800, - "2601-dyn-keyed-write-ops.js": 3269, - "2602-dyn-array-destructure.js": 3207, - "2603-island-keyed-write-dyn.js": 3608, - "2604-cycle-classes-mutual/main.ts": 3410, - "2605-cycle-three-module/main.ts": 2592, - "2606-dynamic-import-cycle/main.ts": 2445, - "2608-regex-named-groups.ts": 3896, - "2609-regex-named-replace.ts": 3215, - "2610-regex-named-matchall.ts": 3887, - "2611-regex-named-groups-js.cjs": 3523, - "2613-for-init-uninitialized-let.ts": 3167, - "2614-trap-binding-later-writes.ts": 3345, - "2615-nullish-field-record-binding.ts": 2720, - "2616-js-collect-probe-defers.js": 3534, - "2617-enum-static-field-import/main.ts": 3068, - "2618-ee-emit-override.ts": 3915, - "2619-ee-override-chain.ts": 2567, - "2620-ee-override-once-order.ts": 3439, - "2621-ee-override-error-throw.ts": 3265, - "2622-ee-override-filter.ts": 3339, - "2623-ee-job-queue.ts": 3586, - "2624-ee-override-js.cjs": 2637, - "2625-bytes-views.ts": 2847, - "2626-stream-event-names.ts": 3436, - "2627-stream-ticks-are-nextticks.ts": 4048, - "2628-stream-push-encodings.cjs": 3219, - "2629-stream-consumers.ts": 4523, - "2630-stream-consumers-errors.ts": 3353, - "2631-create-require/main.ts": 2869, - "2632-dyn-jsval-iterate.js": 3938, - "2633-island-promise-crossing.js": 3898, - "2634-stream-pipeline-arg-ladders.cjs": 2829, - "2635-trap-binding-unmappable-written.ts": 3493, - "2636-trap-binding-ambient-rooted-rewrite.ts": 3155, - "2637-create-require-bare/main.ts": 3093, - "2638-http-dyn-res-compat.cjs": 7897, - "2639-http-dyn-req-pause.cjs": 4028, - "2640-net-dyn-socket-compat.cjs": 3877, - "2641-http-agent-surface.cjs": 6286, - "2642-http-agent-maxsockets.cjs": 4681, - "2643-or-default-retag.ts": 3292, - "2644-http-client-url-argument.ts": 3256, - "2645-https-client-url-argument.ts": 24258, - "2646-top-level-await.ts": 3392, - "2647-top-level-await-modules/main.ts": 3047, - "2648-top-level-await-rejection.ts": 3150, - "2649-top-level-await-pending.ts": 3160, - "2650-top-level-await-self-import.ts": 2440, - "2651-top-level-await-pending-unhandled.ts": 2762, - "2652-top-level-await-dynamic/main.ts": 3760, - "2653-top-level-await-rejection-stops-loop.ts": 2631, - "2654-top-level-await-unrelated-rejection.ts": 2643, - "2655-top-level-await-cycle/main.ts": 3098, - "2656-top-level-await-cycle-order/main.ts": 3167, - "2657-top-level-await-cycle-dynamic/main.ts": 2957, - "2658-top-level-await-sync-completion/main.ts": 3318, - "2659-top-level-await-dynamic-cycle/main.ts": 2585, - "2660-top-level-await-cycle-rejection/main.ts": 3210, - "2661-top-level-await-dynamic-runtime-root/main.ts": 3366, - "2662-top-level-await-cycle-external-wait/main.ts": 3005, - "2663-top-level-await-dependency-errors/main.ts": 2847, - "2664-top-level-await-same-checkpoint-rejection.ts": 3116, - "2665-top-level-await-unhandled-listener-liveness.ts": 2875, - "2666-array-to-sorted.ts": 7633, - "2668-stored-number-array-iterator.ts": 3253, - "2669-array-copying-methods.ts": 3549, - "2670-uint8array-copy-iterate.ts": 3853, - "2671-array-copying-js.cjs": 3682, - "2672-http-request-response-callback.ts": 4143, - "2673-top-level-await-implicit-module.ts": 3247, - "2674-top-level-for-await-implicit-module.ts": 3134, - "2675-create-require-nested-esm.js": 2364, - "2675-process-self-reexec.ts": 2727, - "2676-indexed-read-strict-equality.ts": 2731, - "2676-record-clone-overrides.ts": 2957, - "2676-top-level-await-ambiguous/main.ts": 2732, - "2677-runtime-optional-closure.ts": 4013, - "2677-top-level-await-module-scope/main.ts": 3413, - "2678-date-instances.ts": 2682, - "2678-large-string-sparse-index.ts": 3695, - "2678-util-parseargs.ts": 6509, - "2679-util-parseargs-cjs.cjs": 4674, - "2680-util-parseargs-default.ts": 2968, - "2681-util-parseargs-dynamic.js": 4805, - "2682-fs-rename.ts": 3870, - "2683-filter-truthy-predicate.ts": 3057, - "2683-fs-rename-js.cjs": 3194, - "2684-filter-no-predicate-dyn.cjs": 2886, - "2684-fs-rename-abort.ts": 4187, - "2685-array-unshift-reverse.ts": 3336, - "2685-fs-write-sync.ts": 3018, - "2686-fs-file-handle.ts": 4533, - "2687-fsp-write-file-options.ts": 3468, - "2687-process-write-args.ts": 4056, - "2688-fs-stats-disk-fields.ts": 3885, - "2689-http-server-timeout-properties.ts": 3928, - "2690-https-server-timeout-option.ts": 21635, - "2691-retained-lowering-record-order.ts": 4394, - "2692-inline-record-assert-index.ts": 4260, - "2692-string-accumulation.ts": 2769, - "2693-math-constants.ts": 2825, - "2700-array-sort-complexity.ts": 3067, - "2700-http-static-trailers.ts": 3428, - "2700-wasi-core.ts": 3839, - "2701-array-sort-snapshot.ts": 3995, - "2701-http-static-trailer-wire.ts": 3237, - "2701-import-meta/main.mjs": 2794, - "2702-http-static-trailer-end.ts": 3525, - "2702-type-import-link-static/main.ts": 3217, - "2702-uint8array-to-sorted.ts": 3838, - "2703-array-sparse-sort.ts": 7138, - "2703-type-import-link-static-reexport/main.ts": 2989, - "2704-array-sparse-to-sorted.ts": 7251, - "2704-type-import-link-static-success/main.ts": 3249, - "2705-array-sparse-sort-append.ts": 6240, - "2705-type-import-link-dynamic/main.ts": 2760, - "2706-array-search-missing-needle.ts": 3091, - "2706-type-import-link-dynamic-success/main.ts": 3330, - "2707-array-search-huge-sparse.ts": 45179, - "2707-type-import-link-static-default-reexport/main.ts": 2758, - "2708-type-import-link-dynamic/main.ts": 4132, - "2720-array-read-parity.ts": 3456, - "2721-array-nested-missing-receiver.ts": 3322, - "2750-array-sparse-foundation.ts": 3816, - "2751-buffer-concat-sparse-list.ts": 3043, - "2752-array-optional-stores.ts": 3548, - "2753-array-optional-method-values.ts": 3422, - "2754-array-property-undefined.ts": 3456, - "2755-array-optional-literal-forwarding.ts": 3507, - "2780-array-parity-composition.ts": 9748, - "2781-array-missing-value-escape.ts": 2984, - "2782-array-sparse-callbacks.ts": 3368, - "2783-array-defaults-rest.ts": 3426, - "2784-array-reduce-missing-result.ts": 2920, - "2785-array-missing-destructuring.ts": 4220, - "2786-array-sparse-serialization.ts": 3688, - "2787-array-missing-string-arithmetic.ts": 2565, - "2788-array-missing-builtin-conversions.ts": 2767, - "2789-array-missing-optional-tostring.ts": 3009, - "2790-dynamic-import-self-name/main.ts": 3621, - "2791-record-optional-keys.ts": 3660, - "2792-record-optional-spread-entries.ts": 3741, - "2793-union-conversion-identity-capture.ts": 3519, - "2794-array-generic-callback-values.ts": 2842, - "2795-array-optional-typedarray-source.ts": 29642, - "2796-array-sparse-class-value-instanceof.ts": 4014, - "2800-array-expression-consumers.ts": 2964, - "2801-array-switch-consumers.ts": 3634, - "2820-array-missing-method-receivers.ts": 3219, - "2821-array-optional-numeric-comparisons.ts": 3648, - "2830-cjs-require-self-name/main.cjs": 2817, - "2840-finally-completions.ts": 2484, - "2841-using-sync.ts": 3654, - "2842-await-using.ts": 3139, - "2843-using-suppressed-error.ts": 3369, - "2844-node-disposable-resources.ts": 3909, - "2845-for-using-of.ts": 3562, - "2846-generator-using.ts": 3676, - "2850-async-generators-protocol.ts": 4224, - "2851-async-generators-values.ts": 3418, - "2852-timers-promises-interval.ts": 3999, - "2854-leading-bom-literals.ts": 3644, - "2855-searchparams-sort-complexity.ts": 2896, - "2856-dynamic-any-local-operators.ts": 3122, - "2857-branded-primitives.ts": 2535, - "2858-import-meta-resolve/main.mjs": 2803, - "2859-import-meta-resolve-dynamic/main.mjs": 2791, - "2860-require-resolve/main.cjs": 3416, - "2861-readable-iterator-close.ts": 3965, - "2862-web-readable-async-iteration.ts": 48807, - "2863-class-async-iterator.ts": 3227, - "2864-array-class-method-receivers.ts": 2404, - "2865-cjs-process-alias.cjs": 3403, - "2866-dyn-switch.ts": 2311, - "2867-array-shift-length.js": 3507, - "2868-empty-record-promise-presence.js": 2925, - "2869-nullish-mixed-lazy.ts": 2958, - "2870-and-dropped-truthy-arm.ts": 2834, - "2871-optional-promise-to-unknown.ts": 3267, - "2872-unobserved-dynamic-event.ts": 3355, - "2873-optional-receiver-loop-lifetime.js": 3047, - "2874-nullable-callback-field-cycle.js": 3534, - "2875-evolving-let-read-before-write.js": 2810, - "2876-class-unknown-roundtrip.ts": 3764, - "2877-child-unknown-roundtrip.ts": 2785, - "2878-class-private-unknown.cjs": 3352, - "2880-cjs-module-graph/main.cjs": 3782, - "2890-crypto-static-utility.ts": 2826, - "2891-json-record-key-escapes.ts": 3816, - "2892-windows-console-unicode.ts": 3563, - "2893-child-stdin-duplex.ts": 3578, - "2894-child-stdin-backpressure.ts": 3536, - "2895-child-stdin-write-after-end.ts": 3038, - "2896-child-stdin-write-after-finish.ts": 3391, - "2897-child-stdin-destroy.ts": 3563, - "2898-child-stdin-spawn-failure.ts": 3036, - "2899-nested-mutual-recursion.ts": 3350, - "2900-float64array-static.ts": 3865, - "2900-void-conditional-arrow.ts": 2828, - "2901-bigint-core.ts": 3440, - "2902-bigint-bytes.ts": 2684, - "2903-bigint-storage.ts": 3029, - "2904-bigint-errors.ts": 3660, - "2905-bigint-edges.ts": 3424, - "2906-bigint-wasi-width.ts": 3017, - "2910-overloaded-callable-alias.ts": 3175, - "2911-execfile-callback.ts": 3152, - "2912-execfile-callback-options.ts": 3514, - "2912-promisify-fs-readfile.ts": 3307, - "2913-builtin-callable-alias.ts": 4333, - "2914-fixed-tuple-call-spread.ts": 3657, - "2915-path-function-values.ts": 2684, - "2916-path-function-values-cjs.ts": 3544, - "2917-builtin-callable-widths.ts": 3312, - "2918-builtin-callable-widths-cjs.ts": 4040, - "2919-fs-function-values.ts": 4214, - "2920-fs-promises-function-values.ts": 2447, - "2921-zlib-callbacks.ts": 4192, - "2922-dyn-bitwise-not.cjs": 2704, - "2923-cjs-factory-export/main.cjs": 3106, - "2930-union-receiver-calls.ts": 3700, - "2931-union-dynamic-field-call.js": 3466, - "2932-create-require-program/main.ts": 3686, - "2933-static-dynamic-import/main.ts": 3405, - "2934-static-import-stored.ts": 2381, - "2935-module-namespace-values/main.ts": 3289, - "2936-static-loose-equality.ts": 3642, - "2937-bitwise-hot-loop.ts": 3298, - "2938-fs-sync-overloads.cjs": 2598, - "2939-child-shell-text.ts": 2919, - "2940-date-parse.ts": 3171, - "2940-fsp-realpath.ts": 3497, - "2941-fsp-lstat-identity.ts": 3608, - "2941-process-exit-code.ts": 3007, - "2942-fsp-readdir-dirent.ts": 3744, - "2942-process-exit-code-override.ts": 2479, - "2943-process-exit-code-invalid.ts": 3225, - "2944-process-exit-code-wrap.ts": 3249, - "2945-url-origin-username.ts": 2371, - "2946-child-fork-ipc/main.ts": 4191, - "2946-url-port-hash.ts": 2720, - "2947-set-readonly-seeds.ts": 3363, - "2948-child-fork-eof-callback/main.ts": 3691, - "2948-stdio-callback-record.ts": 3021, - "2949-child-fork-default/main.mjs": 3752, - "2949-url-password.ts": 3268, - "2950-fs-descriptor-publication.ts": 3039, - "2951-math-static-analytic.ts": 2897, - "2952-math-static-remaining.ts": 3708, - "2953-http-header-validation.ts": 2926, - "2954-http-outgoing-headers.ts": 3568, - "2955-http-static-state.ts": 3392, - "2956-http-static-informational.ts": 3156, - "2957-http-static-response-controls.ts": 3011, - "2961-emitter-computed-names.cjs": 3061, - "2962-emitter-computed-optional.ts": 3117, - "2963-child-fork-dispatch/main.ts": 3069, - "2964-indexed-compound.ts": 4283, - "2966-numeric-array-read-fusion.ts": 2881, - "2967-numeric-array-read-lifetime.ts": 3327, - "2968-numeric-array-borrow.ts": 3624, - "2969-scalar-record-results.ts": 3705, - "2970-constant-numeric-tables.ts": 3396, - "2971-constant-table-modules/main.ts": 2786, - "2972-http-static-distinct-snapshots.ts": 3464, - "2972-math-receiver-borrow.ts": 4257, - "2973-http-static-agent.ts": 3844, - "2973-integer-bitwise-arithmetic.ts": 3703, - "2974-array-search-from-index.ts": 120829, - "2974-http-static-module-values.ts": 5733, - "2974-numeric-remainder.ts": 3749, - "2975-bigint-default-radix.ts": 2671, - "2975-http-static-client-controls.ts": 3229, - "2976-http-static-incoming-state.ts": 3560, - "2976-json-stringify-no-arguments.js": 3221, - "2977-http-static-incoming-timeout.ts": 3554, - "2977-nested-array-binding-defaults.js": 3145, - "2978-http-static-client-timeout.ts": 3607, - "2978-regexp-optional-subject.js": 3504, - "2979-array-search-mixed-needles.js": 2692, - "2979-http-static-server-timeout.ts": 3769, - "2980-http-static-server-timeout-default.ts": 3050, - "2980-string-position-arguments.js": 3269, - "2981-http-static-events.ts": 2644, - "2981-string-optional-positions.ts": 2494, - "2982-http-static-close-all.ts": 2737, - "2982-string-position-coercion-order.js": 3410, - "2983-http-static-close-idle.ts": 3031, - "2984-http-static-close-upgrade.ts": 3101, - "2985-http-static-message-destroy.ts": 3632, - "2986-http-static-client-socket-finish.ts": 2911, - "2987-http-static-timeout-errors.ts": 3301, - "2988-http-static-client-abort.ts": 2940, - "2989-http-static-response-timeout-handled.ts": 3640, - "2990-http-static-request-timeout-handled.ts": 3597, - "2991-array-indexed-equality.ts": 3696, - "2992-stream-rows.ts": 3357, - "2993-fiber-stack-lifetimes.ts": 3545, - "2994-fromcharcode-scalar.ts": 3381, - "2995-math-hyperbolic.ts": 3225, - "2996-math-near-one.ts": 2714, - "2997-math-integer-float.ts": 3635, - "300-if-else.ts": 2510, - "3001-caught-typeof-object.js": 3444, - "3002-promise-then-two.ts": 3645, - "301-while.ts": 3200, - "302-for.ts": 2865, - "3020-string-last-index-position.ts": 3627, - "3021-buffer-union-narrow-callback.ts": 3829, - "3022-string-affix-positions.ts": 3463, - "3023-string-affix-position-coercion.js": 3644, - "3024-string-number-narrow-for-in.ts": 3394, - "3025-string-search-position-coercion.js": 3367, - "3026-array-last-index-of.js": 2868, - "3027-array-last-index-of-records.ts": 3472, - "3028-string-search-dynamic-needle.js": 2934, - "3029-string-search-union-needle.js": 3701, - "303-break-continue.ts": 2701, - "3030-array-search-no-arg.js": 3806, - "3031-array-relative-index-coercion.js": 3498, - "3031-string-last-index-search-value.js": 2610, - "3032-string-search-value.js": 3067, - "3033-string-search-needle-coercion.js": 3292, - "3034-arguments-with-parameters.js": 2687, - "3035-string-positioned-search-value.js": 3575, - "3036-string-object-search-value.js": 2688, - "3037-number-nullish-conversion.js": 3018, - "3038-number-scalar-unions.ts": 2381, - "3039-string-repeat-count.js": 2336, - "304-compound-incdec.ts": 3307, - "3040-string-prototype-call.js": 3584, - "3041-string-prototype-object-call.js": 3163, - "3042-string-padding-coercion.js": 3486, - "3043-string-split-arguments.js": 3038, - "3044-array-slice-splice-positions.js": 3582, - "3045-array-indexed-mutation.js": 4003, - "3046-array-indexed-ref-identity.ts": 2594, - "3047-object-prototype-tag.js": 5012, - "3048-object-own-prototype.ts": 4080, - "3049-array-flat-depth.ts": 3414, - "305-truthiness.ts": 2664, - "3050-array-splice-insert.ts": 2966, - "3051-array-join-default.ts": 3468, - "3052-array-construction.ts": 4201, - "3053-array-construction-js.js": 2937, - "3054-dynamic-abort-record.ts": 25141, - "3055-default-builtin-nodenext/main.ts": 2702, - "3056-default-builtin-bundler/main.ts": 3487, - "3057-default-builtin-nodenext-dynamic/main.ts": 2447, - "3058-optional-array-chain-join.ts": 3991, - "3059-arguments-property-names.ts": 2550, - "3061-concurrent-fiber-stacks.ts": 3788, - "3062-runtime-optional-record-guards.ts": 3181, - "3063-runtime-optional-class-guards.ts": 3568, - "3064-installed-entry-imports/main.ts": 2606, - "3065-installed-entry-js/main.js": 3045, - "3066-source-debugging/main.ts": 3383, - "3067-cjs-function-export-require/main.cjs": 2939, - "3068-debug-variables/main.ts": 2618, - "3068-url-checked-identity.ts": 3006, - "3069-set-checked-seed.js": 3140, - "3069-tuple-spread.ts": 3376, - "3070-checked-object-accessors.js": 3573, - "3070-collection-views.ts": 3175, - "3071-checked-specialization-narrowing.js": 3321, - "3071-map-contextual-record-seeds.ts": 4329, - "3072-optional-union-receivers.ts": 3610, - "3072-weak-process-streams.js": 2918, - "3073-optional-callable-module.js": 3300, - "3073-union-keyed-reads.ts": 3869, - "3074-discriminated-intersections.ts": 3384, - "3075-recursive-contextual-literals.ts": 4502, - "3076-nullish-record-defaults.ts": 3009, - "3077-optional-union-array-reads.ts": 3992, - "3078-forward-mutable-captures.ts": 3466, - "3079-forward-mutable-tdz.ts": 3489, - "3080-exhaustive-never-bindings.ts": 3664, - "3081-recursive-array-destinations.ts": 3893, - "3082-forward-write-unwind.ts": 3471, - "3083-set-string-seed.ts": 3139, - "3084-record-own-membership.ts": 2971, - "3085-conditional-record-construction.ts": 3822, - "3086-error-constructor-options.ts": 3660, - "3087-error-options-lifetime.ts": 2905, - "3088-array-wide-callbacks.ts": 3195, - "3089-array-find-narrowing.ts": 4220, - "3090-json-discriminated-records.ts": 3463, - "3091-json-recursive-discriminants.ts": 3555, - "3092-number-union-predicates.ts": 2884, - "3093-error-option-data.ts": 2574, - "3094-json-replacer-traversal.ts": 3823, - "3095-json-reviver-traversal.ts": 3825, - "3096-json-callback-nonfinite.ts": 3620, - "3097-json-callback-reentrancy.ts": 2760, - "3098-json-callback-space.ts": 3696, - "3099-json-callback-functions.ts": 4108, - "3100-json-callback-holder.js": 3675, - "3101-json-callback-bytes.ts": 3250, - "3102-json-unknown-fields.ts": 2925, - "3103-scalar-record-nested-control-flow.ts": 3592, - "3104-native-analysis-tables-loops.ts": 3494, - "3105-nullable-collections.ts": 3244, - "3106-mixed-insertion-spreads.ts": 4146, - "3107-nullable-collection-lifetimes.ts": 3486, - "3108-for-await-sync-arrays.js": 4312, - "3108-identity-map-keys.ts": 3894, - "3109-destructuring-unknown-defaults.js": 3234, - "3109-identity-union-collections.ts": 3977, - "3110-builtin-error-families.ts": 3250, - "3110-identity-collection-mutation.ts": 3825, - "3111-identity-collection-cycles.ts": 3640, - "3112-union-switch-control-flow.ts": 2681, - "3113-union-array-removal.ts": 3778, - "3114-union-record-field-write.ts": 3884, - "3115-zlib-static-compression-levels.ts": 4085, - "3116-sequence-expression-lifetimes.ts": 3245, - "3117-unknown-switch-control-flow.ts": 3706, - "3118-recursive-union-spread.ts": 3476, - "3119-runtime-optional-spread.ts": 4508, - "3120-dynamic-property-descriptors.js": 3228, - "3120-generator-method-loop-bindings.ts": 3222, - "3120-ir-nonfinite-numbers.ts": 3251, - "3121-compound-assignment-values.js": 3525, - "3121-dynamic-accessor-descriptors.js": 4470, - "3122-dynamic-delete-descriptors.cjs": 3353, - "3122-dynamic-delete-descriptors.js": 3300, - "3122-js-async-class-methods.js": 3524, - "3123-destructured-global-tdz.js": 3896, - "3124-array-prototype-borrow.js": 4000, - "3125-regex-global-match.ts": 2889, - "3126-js-number-radix/main.ts": 3491, - "3127-spawn-runtime-options.ts": 3338, - "3128-regex-last-index.ts": 3768, - "3129-js-token-union/main.ts": 3461, - "3130-child-generic-streams.ts": 3435, - "3131-child-rest-listeners.js": 3280, - "3132-child-generic-stream-completion.ts": 6821, - "3133-text-decoder-streaming.ts": 32031, - "3134-fs-vectors.ts": 3621, - "3135-fs-file-handle-controls.ts": 3152, - "3136-fs-file-handle-options.ts": 4992, - "3137-fs-vector-callbacks.cjs": 3636, - "3138-array-large-storage.ts": 5104, - "3139-regex-native-deep-alternatives.ts": 38096, - "3140-array-dense-access.ts": 4712, - "3141-map-string-key-hash.ts": 3358, - "3150-integer-remainder.ts": 3568, - "3151-array-push-writes.ts": 3892, - "3170-number-conversion-fast-paths.ts": 2663, - "3171-method-census-data-writes.ts": 4253, - "400-fib.ts": 3919, - "401-mutual-recursion.ts": 2844, - "402-string-functions.ts": 3081, - "403-void-and-params.ts": 3112, - "4030-runtime-object-truthiness.ts": 3275, - "4031-event-emitter-long-tuples.ts": 3646, - "4032-inline-rc-fast-paths.ts": 4866, - "404-rc-stress.ts": 2781, - "4040-adapted-function-identity.ts": 3610, - "4041-adapted-function-properties.ts": 3413, - "4042-object-is-union-subclass.ts": 2746, - "4043-nonnull-missing-element.ts": 3815, - "4044-adapted-callback-modules/main.ts": 2918, - "4045-optional-element-projections.ts": 4182, - "4046-captured-parameter-values.ts": 4191, - "4047-captured-parameter-rebinding.ts": 2867, - "405-params-optional.ts": 2408, - "406-params-defaults.ts": 2614, - "4060-cycle-shared-instance/main.ts": 2758, - "4060-stack-union-reads.ts": 4386, - "4061-cycle-evaluation-order/main.ts": 3229, - "4061-nullable-ref-fields.ts": 6151, - "4062-cycle-tdz-read/main.ts": 3056, - "4063-cycle-hoisted-calls/main.ts": 3238, - "4064-cycle-classes-after-init/main.ts": 2548, - "4065-cycle-init-throws/main.ts": 2955, - "4066-cycle-top-level-tdz/main.ts": 3040, - "4067-dynamic-import-cycle-tdz/main.ts": 3004, - "407-params-rest.ts": 3335, - "408-params-ctors-inheritance.ts": 3021, - "4080-optional-read-presence-tests.ts": 3095, - "4080-string-index-bounds.ts": 3083, - "4081-hoisted-function-tdz.ts": 3193, - "4081-string-index-unproven.ts": 3273, - "4082-hoisted-function-tdz-uncaught.ts": 2845, - "4083-dynamic-import-failure/main.ts": 3748, - "4084-record-optional-field-copies.ts": 4118, - "4085-generator-loop-close.ts": 3638, - "4086-optional-capture-defaults.ts": 3227, - "4088-class-static-tdz.ts": 3234, - "4089-class-wrapper-tdz.js": 3393, - "409-params-async-generics.ts": 2742, - "4090-computed-key-tdz.js": 2796, - "4091-class-evaluation-deferred.ts": 3464, - "410-params-rc-stress.ts": 3461, - "4140-array-callback-split-visit.ts": 7289, - "4141-array-callback-ambient-receiver/main.ts": 3100, - "4142-array-callback-factories.ts": 4541, - "4143-union-refinement-intersection-arms.ts": 3822, - "420-dead-strip-modules/main.ts": 3118, - "4290-acyclic-immutable-trees.ts": 3580, - "4291-acyclic-constructor-escapes.ts": 3039, - "4292-acyclic-readonly-bypass.ts": 4316, - "4293-acyclic-dynamic-writes.ts": 3268, - "4294-console-line-sizes.ts": 6986, - "4295-console-template-parts.ts": 3358, - "4296-console-glued-long-parts.ts": 3290, - "4410-inline-object-allocation.ts": 3305, - "4411-nullable-ref-values.ts": 5301, - "4412-nullable-record-values.ts": 5088, - "4413-cycle-old-late-death.ts": 4012, - "4413-nullable-null-and-undefined.ts": 4328, - "4414-cycle-old-weak-keys.ts": 4005, - "4414-nullable-string-values.ts": 5044, - "4415-identity-borrowed-operands.ts": 3101, - "4415-nullable-container-values.ts": 4932, - "4431-exception-pending-contexts.ts": 3487, - "4432-checked-downcast-failures.ts": 3971, - "4451-int32-field-storage.ts": 3668, - "4452-int32-field-dynamic-writes.ts": 4531, - "4453-int32-closed-locals.ts": 2786, - "4471-unassigned-field-reads.ts": 3896, - "4476-string-ascii-header-fact.ts": 3522, - "4477-buffer-write-ascii-runs.ts": 3321, - "4478-string-large-index-reads.ts": 4146, - "4481-array-optional-push.ts": 3259, - "4482-instanceof-static-class-optional.ts": 3786, - "4483-array-splice-statement.ts": 4036, - "4484-array-length-reset.ts": 2849, - "4485-array-splice-optional-item.ts": 3817, - "4486-array-field-element-borrows.ts": 2903, - "4487-array-literal-optional-values.ts": 3145, - "4520-optional-guard-narrowing.ts": 2774, - "4521-array-callback-element-presence.ts": 5601, - "4522-captured-parameter-lifetimes.ts": 3907, - "4523-array-pop-removal.ts": 3769, - "4524-array-callback-supertype-params.ts": 4594, - "4541-nullable-wrap-borrows.ts": 3939, - "4542-preserving-call-borrows.ts": 3361, - "4543-walk-borrowed-locals.ts": 3633, - "4544-checked-cast-aliases.ts": 3723, - "4545-borrowed-returns.ts": 4116, - "4546-rebound-borrowed-params.ts": 2930, - "4560-field-store-borrowed-receivers.ts": 4438, - "4561-virtual-borrowed-parameters.ts": 3634, - "4562-string-self-concat-move.ts": 2703, - "4563-array-read-projection-receivers.ts": 3601, - "4564-literal-choice-strings.ts": 3137, - "4568-for-of-hole-elements.ts": 3387, - "4569-shorthand-missing-elements.ts": 3958, - "4570-map-lookup-default-record.ts": 3112, - "4591-weak-keys-union-records.ts": 3556, - "4592-cycle-const-from-import/main.ts": 3467, - "4593-weak-keys-empty-objects.ts": 2938, - "4594-union-class-field-mixed-types.ts": 4040, - "4595-union-class-field-optional-receiver.ts": 3379, - "4596-error-subclass-int-fields.ts": 3559, - "4596-tdz-nullable-forward-capture.ts": 4676, - "4597-callback-field-method-name.ts": 4014, - "4598-live-array-ref-element-access.ts": 8384, - "4598-map-set-clear-reuse.ts": 4224, - "4598-os-available-parallelism.ts": 3815, - "4598-publish-constructor-stores.ts": 3618, - "4599-construction-only-field-borrows.ts": 3619, - "4600-construction-only-fields-dynamic-writes.ts": 3184, - "4601-cycle-holders.ts": 3348, - "4602-constructor-escape-order.ts": 3674, - "4610-array-ext-dyn-refresh.ts": 4598, - "4620-optional-chain-borrowed-receivers.ts": 3411, - "4621-edge-preserving-callees/main.ts": 3288, - "4630-contract-int32.ts": 2810, - "4630-reference-write-call-arguments.ts": 3333, - "4631-contract-nothrow.ts": 3196, - "4631-reference-write-aliases.ts": 4264, - "4632-contract-immutable.ts": 3449, - "4632-reference-write-loops-and-walks.ts": 3791, - "4633-contract-program-lifetime.ts": 4644, - "4633-reference-write-callbacks-returns.ts": 4024, - "4634-contract-program-lifetime-publish.ts": 42618, - "4634-optional-element-borrowed-returns.ts": 3411, - "4640-bitwise-identity-ranges.ts": 3713, - "4641-nothrow-try-catch.ts": 3056, - "4642-acyclic-contract.ts": 4040, - "4650-stale-property-narrowing.ts": 3665, - "4651-map-string-get-entry.ts": 3369, - "4652-stale-closure-binding-narrowing.ts": 3504, - "4660-typed-rest-spread-forwarding.ts": 3148, - "4671-scoped-array-read-borrows.ts": 3020, - "4690-cycle-bypass-long-lived.ts": 5374, - "4691-publish-constructor-self-alias.ts": 38620, - "4692-borrowed-result-mutating-callees.ts": 3592, - "4720-cold-throw-paths.ts": 4339, - "4721-integer-induction-numbers.ts": 3854, - "4730-touint32-large-magnitudes.ts": 3431, - "4731-string-mixed-ascii-slices.ts": 4436, - "4732-buffer-write-utf16le-runs.ts": 4084, - "4733-typed-array-read-compares.ts": 3240, - "4750-map-string-absent-filter.ts": 3584, - "4751-string-search-multibyte-needles.ts": 3227, - "4795-published-untyped-member-reads.ts": 3450, - "4806-uint32-loop-accumulators.ts": 3543, - "4810-union-identity-retags.ts": 34911, - "4811-union-retag-checked-cast.ts": 3044, - "4812-int32-wrapping-sums.ts": 3457, - "4813-typed-array-read-equality-bindings.ts": 4853, - "4820-sort-comparator-lent-arguments.ts": 3579, - "4821-callback-lent-arguments.ts": 4210, - "4822-stable-capture-reads.ts": 3094, - "4823-array-store-receivers.ts": 3774, - "4830-typed-teardown-chains.ts": 3908, - "4831-cycle-bypass-probe-windows.ts": 6157, - "4840-array-hole-free-prefix.ts": 3932, - "4860-int32-local-storage.ts": 5136, - "4870-array-pipeline-fusion.ts": 6645, - "4871-array-pipeline-analytics.ts": 4575, - "4872-array-pipeline-temporaries.ts": 10635, - "4875-stream-consumers-array-buffer.ts": 4120, - "4876-array-buffer-inspect.ts": 2819, - "4880-await-call-turn-order.ts": 3872, - "4881-await-call-exceptions.ts": 3027, - "4882-await-call-request-chain.ts": 2730, - "4883-await-values-and-hops.ts": 3412, - "4884-await-call-unhandled-sibling.ts": 3410, - "4885-await-call-checkpoints.ts": 2703, - "4890-regex-literal-sites.ts": 3712, - "4891-regex-plain-text-patterns.ts": 3018, - "4892-regex-exec-read-captures.ts": 4130, - "4900-bigint-division-cross-check.ts": 3763, - "4900-console-instances.ts": 4286, - "4901-bigint-radix-text.ts": 3099, - "4901-console-instance-errors.ts": 3171, - "4902-bigint-compound-assign.ts": 3431, - "4903-bigint-fixed-width.ts": 3707, - "4904-bigint-large-products.ts": 3972, - "4905-bigint-fixed-width-fusion.ts": 3443, - "4906-bigint-small-value-trees.ts": 4875, - "4907-bigint-random-trees.ts": 5277, - "4910-hole-free-prefix-upkeep.ts": 4073, - "4920-string-literal-switch.ts": 3607, - "4930-typed-record-reflection.ts": 4869, - "4931-typed-data-generic-walks.ts": 5228, - "4932-typed-json-unknown.ts": 3250, - "4940-async-return-adoption.ts": 4405, - "4941-async-return-adoption-try.ts": 3533, - "4942-async-return-adoption-values.ts": 4824, - "4943-async-return-adoption-interleaved.ts": 3851, - "4950-regex-compiled-captures.ts": 5146, - "4951-regex-compiled-last-index.ts": 4316, - "4952-regex-compiled-anchors-classes.ts": 3149, - "4953-regex-compiled-backtracking.ts": 3822, - "4954-regex-log-report.ts": 4449, - "4955-regex-compiled-differential.ts": 20102, - "4970-int32-call-abi.ts": 3029, - "4980-generator-early-exit-finally.ts": 3262, - "4981-generator-delegation-iterables.ts": 5306, - "4982-generator-sent-values.ts": 3649, - "4983-generator-reuse-iterables.ts": 4023, - "4984-generator-exceptions.ts": 4220, - "4985-generator-lazy-pipeline.ts": 3164, - "4986-generator-default-channels.ts": 3434, - "4987-generator-closures-methods.ts": 3505, - "4988-generator-async-interplay.ts": 2790, - "4989-generator-step-drives.ts": 3509, - "4990-lone-surrogates.ts": 3213, - "4991-lone-surrogate-halves.ts": 4020, - "4992-lone-surrogate-search.ts": 3375, - "4993-lone-surrogate-json.ts": 3473, - "4994-lone-surrogate-uri.ts": 3848, - "4995-lone-surrogate-regex.ts": 4302, - "4996-lone-surrogate-stdio.ts": 2592, - "4997-lone-surrogate-stdout-patch.js": 3072, - "4998-lone-surrogate-buffers.ts": 3134, - "4999-lone-surrogate-io.ts": 3225, - "500-array-basics.ts": 2886, - "501-array-push-pop.ts": 2682, - "5010-lifetime-region-generations.ts": 4147, - "5011-lifetime-region-outside-references.ts": 3407, - "5012-lifetime-region-shapes.ts": 4861, - "5013-lifetime-region-async.ts": 3124, - "5014-lifetime-region-nesting.ts": 3259, - "5015-lifetime-region-publish.ts": 27669, - "5016-lifetime-region-weak-keys.ts": 2554, - "5017-lifetime-region-cycles.ts": 3105, - "5018-lifetime-region-hierarchies.ts": 4007, - "5019-lifetime-region-values.ts": 2888, - "502-array-for-of.ts": 3621, - "5020-lifetime-region-large.ts": 4812, - "5021-lifetime-region-opaque-holders.ts": 3957, - "5022-lifetime-region-workers.ts": 38841, - "503-array-functions.ts": 2982, - "504-array-rc-stress.ts": 3289, - "5040-promise-all-race-turns.ts": 4439, - "5041-promise-all-turns.js": 3708, - "5042-async-generator-return-promise.ts": 3292, - "5043-async-generator-return-forms.ts": 3922, - "5045-generator-delegation-typed-next.ts": 4740, - "5046-generator-delegation-return-throw.ts": 3192, - "5047-generator-delegation-iterables-typed.ts": 4558, - "5048-generator-delegation-async.ts": 3457, - "5049-generator-delegation-edges.ts": 3057, - "5050-inherited-in-membership.ts": 4297, - "5051-typed-record-prototypes.ts": 3534, - "5052-class-for-in-unknown.ts": 3663, - "5053-json-replacer-arrays.ts": 4093, - "5054-required-field-delete.ts": 3619, - "5055-object-create-record-literal.ts": 3237, - "5056-generator-in-unknown.ts": 3060, - "5060-child-fork-exit-after-messages/main.ts": 3584, - "5061-child-fork-local-disconnect/main.ts": 4277, - "5062-child-fork-message-before-eof/main.ts": 3570, - "5065-global-increment-initializers.ts": 2946, - "5066-global-compound-updates.ts": 3425, - "5067-global-updates-in-functions.ts": 3465, - "5068-global-var-let-const-updates.ts": 3395, - "5069-global-update-modules/main.ts": 3167, - "5070-optional-read-bindings.ts": 3316, - "5071-optional-chain-scalars.ts": 3214, - "5072-optional-nullish-ternary.ts": 2900, - "5073-optional-results.ts": 3751, - "5074-optional-pop-shift.ts": 3099, - "5075-optional-reads-unchecked/main.ts": 3754, - "5076-optional-escapes.ts": 3593, - "5080-boolean-array-storage.ts": 7564, - "5081-boolean-array-dynamic-views.ts": 3915, - "5085-promise-allsettled-turns.ts": 4557, - "5086-promise-any-turns.ts": 3994, - "5087-promise-allsettled-any-dyn.js": 5205, - "5088-promise-combinator-thenables.js": 5007, - "5089-promise-settled-records.ts": 4859, - "5090-generator-finished-result-value.ts": 3648, - "5091-generator-delegation-arrays-strings.ts": 3362, - "5092-generator-delegation-sets-maps.ts": 4496, - "5095-console-count-group.ts": 3356, - "5096-console-assert-dir.ts": 3645, - "5097-console-table.ts": 3255, - "5098-console-time-warnings.ts": 7324, - "5099-console-methods-dynamic.cjs": 3314, - "510-array-map-filter-foreach.ts": 3232, - "511-array-indexof-includes.ts": 3286, - "5110-var-hoisting-early-reads.ts": 4048, - "5111-var-hoisting-closures-classes.ts": 2474, - "5112-var-hoisting-function-scope.ts": 3383, - "5113-tdz-let-const-class.ts": 3628, - "5114-var-hoisting-js.js": 3550, - "5115-regex-replace-compiled.ts": 3344, - "5116-regex-capture-reads.ts": 3874, - "5117-regex-log-report-spans.ts": 3719, - "5118-regex-replace-char-chains.ts": 3632, - "512-array-join-chains.ts": 3268, - "5120-frame-records.ts": 3221, - "5121-frame-objects.ts": 3861, - "5122-frame-result-slots.ts": 3008, - "5123-frame-reassigned.ts": 3589, - "5124-frame-objects-control.ts": 3184, - "5125-frame-mutating-methods.ts": 3607, - "5126-frame-returned-params.ts": 3362, - "5127-frame-loop-bindings.ts": 4392, - "513-array-methods-rc-stress.ts": 3208, - "5130-event-target-dispatch.js": 4958, - "5131-event-target-listener-errors.js": 4558, - "5132-event-target-typed.ts": 5171, - "5133-abort-signal-event-target.ts": 22917, - "5134-events-error-monitor.ts": 3499, - "5135-event-target-warnings.js": 9058, - "5136-events-error-monitor-string-name.ts": 3057, - "5137-events-error-monitor-computed-name.js": 4052, - "5138-events-error-monitor-shared-listener.ts": 2466, - "5139-event-target-listener-throw.ts": 2925, - "514-array-find-some-every.ts": 3925, - "5140-os-host-facts.ts": 3438, - "5141-os-constants.ts": 2815, - "5142-path-parse-format.ts": 3808, - "5145-path-matches-glob-basics.ts": 3287, - "5146-path-matches-glob-braces.ts": 4987, - "5147-path-matches-glob-extglob.ts": 3938, - "5148-path-matches-glob-classes.ts": 3973, - "5149-path-matches-glob-win32.ts": 3835, - "515-array-flatmap.ts": 3688, - "5150-small-array-inline-slots.ts": 4419, - "5155-cycle-header-types.ts": 38708, - "516-array-reduce.ts": 4017, - "5160-field-callback-receiver.ts": 3678, - "5161-field-callback-receiver-escape.ts": 2857, - "5162-field-method-reference-receiver.ts": 2944, - "5163-field-callback-receiver.cjs": 3655, - "5164-worker-field-callback-receiver.ts": 30046, - "5165-interface-method-dispatch.ts": 2969, - "5166-interface-method-values.ts": 4129, - "5167-interface-method-order.ts": 3988, - "5168-interface-method-hierarchy.ts": 4483, - "5169-interface-method-chains.ts": 3336, - "517-array-hof-index-args.ts": 3024, - "5170-string-scan-eviction.ts": 3285, - "5171-lone-surrogate-replace-seams.ts": 3558, - "5175-forin-typed-as-unknown.ts": 4230, - "5176-object-keys-typed-as-unknown.ts": 3721, - "5177-forin-dynamic-objects.ts": 2893, - "5178-forin-keys-js.js": 2555, - "5179-forin-typed-shapes.ts": 4446, - "518-array-sort.ts": 3134, - "518-promise-void-union-callbacks.ts": 2401, - "5180-interface-arrays.ts": 3230, - "5181-interface-array-methods.ts": 11973, - "5182-interface-array-boundaries.ts": 3847, - "5183-interface-property-reads.ts": 3799, - "5184-interface-property-objects.ts": 3828, - "5185-util-inherits.cjs": 5041, - "5186-util-inherits.ts": 4542, - "5187-util-deprecate.cjs": 5818, - "5188-util-deprecate-flags.cjs": 4078, - "5189-util-deprecate.ts": 3798, - "519-array-from-length.ts": 2988, - "519-promise-union-await-values.ts": 3664, - "5190-util-callbackify.cjs": 5115, - "5191-util-callbackify.ts": 4367, - "5192-util-debuglog.cjs": 5096, - "5193-util-debuglog.ts": 4056, - "5194-process-emit-warning-tick.cjs": 2761, - "5195-object-entries-typed-as-unknown.ts": 3177, - "5196-object-values-typed-as-unknown.ts": 4077, - "5197-object-entries-dynamic-objects.ts": 4742, - "5198-object-entries-values-js.js": 3089, - "5199-object-entries-identity.ts": 3679, - "520-map-basics.ts": 3767, - "5200-array-sort-keyed-numbers.ts": 4618, - "5201-array-sort-keyed-records.ts": 5422, - "5202-array-sort-keyed-lookalikes.ts": 4034, - "5203-typed-array-sort-default.ts": 7941, - "5204-typed-array-sort-comparators.ts": 4085, - "521-map-number-keys.ts": 3317, - "5210-process-memory-usage.ts": 3262, - "5211-process-identity.ts": 3448, - "5212-perf-marks-measures.ts": 4026, - "5213-perf-timing-errors.ts": 4151, - "5214-perf-entry-inspect.ts": 4315, - "5215-perf-timing-validation.js": 2982, - "5216-perf-spread-arguments.js": 3745, - "5217-perf-spread-typed.ts": 4057, - "522-map-foreach.ts": 2964, - "5220-url-parse-warnings.ts": 4859, - "5221-url-parse-shapes.ts": 3814, - "5222-url-parse-hosts.ts": 3398, - "5223-url-parse-query.ts": 2653, - "5224-url-format-objects.ts": 5550, - "5225-url-format-whatwg.ts": 5213, - "5226-url-resolve.ts": 2600, - "5227-url-legacy-dependency/main.ts": 5803, - "5228-url-domain-conversion.ts": 4876, - "5229-url-legacy-errors.cjs": 5195, - "523-map-ref-values.ts": 4321, - "5230-inline-union-fields.ts": 3644, - "5231-inline-union-field-kinds.ts": 4871, - "5232-inline-union-fields-dynamic.ts": 3887, - "5233-inline-union-fields-shapes.ts": 4145, - "5234-inline-union-class-fields.ts": 3244, - "5235-inline-union-fields-publish.ts": 3360, - "5236-inline-union-unchecked-reads.ts": 3108, - "5237-inline-union-frame-objects.ts": 2533, - "524-map-cycles.ts": 3943, - "5240-event-target-subclass.ts": 5571, - "5241-event-subclass.ts": 4311, - "5242-event-target-subclass-hierarchy.ts": 4079, - "5243-event-target-subclass-dynamic.ts": 3528, - "5244-event-target-subclass.js": 4645, - "5245-event-target-subclass-signals.ts": 9410, - "5246-event-target-subclass-listener-throw.ts": 3995, - "5247-event-target-subclass-lifetimes.ts": 5991, - "5248-event-target-subclass-warnings.ts": 4513, - "5249-event-target-subclass-unconstructed.ts": 2679, - "525-map-rc-stress.ts": 2764, - "526-set-basics.ts": 2480, - "5260-record-unknown-identity.ts": 3505, - "5261-optional-field-identity.ts": 3914, - "5262-record-unknown-many.ts": 3839, - "527-set-foreach.ts": 3683, - "5270-url-parse-no-deprecation.cjs": 4076, - "5271-url-parse-throw-deprecation.cjs": 3487, - "5275-http-end-callback-order.ts": 3028, - "5276-style-text-hex-colors.cjs": 4502, - "5277-fs-read-file-buffer-option.cjs": 2635, - "5278-host-null-bytes.cjs": 16385, - "5279-search-params-null-init.cjs": 2915, - "528-set-seeded.ts": 3643, - "5285-blob-construct.ts": 3124, - "5286-blob-readers.ts": 3309, - "5287-blob-inspect.ts": 2504, - "5288-blob-validation.js": 3775, - "5289-blob-read-order.ts": 3614, - "529-map-seeded.ts": 3331, - "5290-blob-dynamic.js": 2674, - "5295-readline-promises-question.ts": 2401, - "5296-readline-lines.ts": 3088, - "5297-readline-callback-events.cjs": 2975, - "5298-readline-abort.cjs": 6980, - "5299-readline-stdin.ts": 3836, - "530-record-arrays.ts": 3125, - "5300-stream-add-abort-signal.ts": 7154, - "5301-stream-add-abort-signal-errors.cjs": 7763, - "5302-stream-promises-options.ts": 8927, - "5303-stream-finished-callback-opts.cjs": 7119, - "5305-json-stringify-typed-arrays.ts": 4254, - "531-record-array-hofs.ts": 3609, - "5315-map-iterate-after-front-deletes.ts": 2759, - "5316-map-lru-eviction.ts": 3688, - "5317-map-iterate-while-mutating.ts": 3035, - "5318-set-iterate-after-deletes.ts": 2543, - "5319-map-iteration-values.ts": 4062, - "532-record-arrays-rc-stress.ts": 2708, - "5320-map-iterate-across-compaction.ts": 2736, - "5325-record-boundary-returns.ts": 3046, - "5326-record-boundary-params.ts": 2989, - "5327-record-boundary-identity.ts": 3529, - "5328-record-boundary-open.ts": 3718, - "5329-record-boundary-recursion.ts": 3361, - "533-array-element-cycles.ts": 3118, - "5330-record-boundary-fields.ts": 3048, - "5331-record-boundary-methods.ts": 2560, - "5333-record-boundary-nullable-argument.ts": 3100, - "5334-fetch-mentions-without-calls.ts": 4032, - "5335-top-level-await-pending-exit-code.ts": 2383, - "5336-top-level-await-pending-exit-listener.ts": 2814, - "5337-dc-subscriber-throw-next-tick.cjs": 3273, - "5338-js-tdz-function-element.js": 3733, - "5339-array-buffer-constructor.js": 2884, - "534-record-width-subtyping.ts": 3530, - "5345-object-values-for-of-unknown.ts": 4013, - "5346-object-values-length-dynamic.ts": 3930, - "5347-object-values-loop-control.ts": 3598, - "5348-object-values-for-of-js.js": 2760, - "5349-object-entries-values-optional.ts": 3370, - "535-object-statics.ts": 2862, - "5350-object-values-wide-record.ts": 3272, - "5351-object-values-methods-index.ts": 3637, - "536-map-seed-array.ts": 3237, - "5360-array-sort-comparator-calls.ts": 4265, - "5361-array-sort-inconsistent-comparators.ts": 4181, - "5362-array-sort-comparator-throws.ts": 2826, - "5363-array-sort-comparator-writes.ts": 10362, - "5364-array-sort-union-and-boolean-elements.ts": 14300, - "5365-array-sort-dynamic-values.js": 2919, - "537-map-iter-drains.ts": 3050, - "538-map-set-for-of.ts": 3029, - "5390-interface-loop-element-lifetimes.ts": 3566, - "5391-interface-dispatch-hierarchies.ts": 3731, - "5392-interface-receiver-bindings.ts": 3061, - "5393-interface-array-holes.ts": 2702, - "5394-interface-implementers.ts": 3603, - "5395-locale-compare-ascii.ts": 3587, - "5396-locale-compare-latin.ts": 4291, - "5397-locale-compare-sorting.ts": 3576, - "540-tuples-basics.ts": 3420, - "5400-json-parse-typed-keys.ts": 3141, - "5405-buffer-arraybuffer-window.ts": 3036, - "5406-util-types-keys.ts": 2954, - "5407-http-header-field-limit.ts": 3052, - "5408-http-unread-request-end.ts": 3992, - "5409-http-held-request-body.ts": 3771, - "541-ref-array-json.ts": 3761, - "5410-inspect-class-values.ts": 3124, - "5411-inspect-class-hierarchies.ts": 2423, - "5412-inspect-dynamic-collections.ts": 3042, - "5413-inspect-class-values.cjs": 3217, - "542-union-element-arrays.ts": 2812, - "5430-dyn-number-string-boxes.ts": 3930, - "5435-crypto-hash-algorithms.ts": 3451, - "5436-crypto-hash-names.js": 3185, - "5437-crypto-hmac-algorithms.ts": 3269, - "5438-crypto-kdf-digests.ts": 3099, - "5439-crypto-kdf-callbacks.js": 4398, - "5440-crypto-hash-encodings.js": 4908, - "5441-crypto-hash-output-length.ts": 3959, - "5442-crypto-random-values.ts": 4791, - "5443-crypto-random-arguments.js": 3724, - "5444-crypto-timing-safe-equal.js": 4074, - "5445-crypto-secret-key-objects.ts": 4784, - "5445-stream-buffer-chunks.ts": 5661, - "5446-crypto-secret-key-errors.js": 3275, - "5446-stream-buffer-chunks-dynamic.js": 5780, - "5447-fs-readdir-order.ts": 3355, - "5448-fs-glob-patterns.ts": 3298, - "5449-fs-glob-options.ts": 3827, - "5450-fs-glob-validation.js": 4321, - "5451-fs-promises-glob.ts": 3074, - "5452-fs-glob-callback.ts": 3887, - "5455-power-of-two-remainder.ts": 4228, - "5456-remainder-large-integer-dividends.ts": 3551, - "5457-lcg-modulus.ts": 2909, - "5458-fractional-remainder.ts": 2650, - "5460-locale-compare-contractions.ts": 3201, - "5461-locale-compare-equivalents.ts": 3410, - "5462-locale-compare-probe-sweep.ts": 4164, - "5463-locale-compare-combining-letters.ts": 3755, - "5464-locale-compare-fractions.ts": 3312, - "5470-strip-vt-osc.cjs": 2708, - "5471-strip-vt-csi.cjs": 3038, - "5472-strip-vt-random.cjs": 2850, - "5473-strip-vt-unterminated.cjs": 4462, - "5474-strip-vt-surrogates.ts": 3554, - "5540-fs-callback-forms.cjs": 3079, - "5541-fs-stats-fields.cjs": 4039, - "5542-fs-promises-parity.cjs": 3312, - "5543-fs-promises-typed.ts": 2944, - "5544-fs-opendir.cjs": 3622, - "5545-fs-options-encoding.cjs": 3497, - "5548-fs-callback-arguments.cjs": 3905, - "5549-fs-callback-option-checks.cjs": 3471, - "5550-locale-compare-ascii-words.ts": 2824, - "5551-array-search-references.ts": 3964, - "5552-string-appends.ts": 3653, - "5553-string-append-char-code.ts": 3292, - "5565-fs-dirent-untyped.mjs": 2898, - "5566-fs-dirent-dyn-boundaries/main.mjs": 3333, - "5585-record-results-inlined.ts": 3681, - "5595-net-ref-unref.ts": 3036, + "001-hello.ts": 47467, + "002-log-args.ts": 4723, + "100-number-format.ts": 49913, + "1000-json-stringify-basics.ts": 49071, + "1001-json-escapes-unicode.ts": 5167, + "1002-json-parse-cast.ts": 48226, + "1003-json-parse-unions.ts": 5247, + "1004-json-parse-errors.ts": 4196, + "1005-json-nested.ts": 8262, + "1006-json-fs-config.ts": 36095, + "1007-json-rc-stress.ts": 30487, + "1008-json-null-arms.ts": 48758, + "1009-json-optional-fields.ts": 3469, + "101-arithmetic.ts": 49638, + "1010-json-stringify-space.ts": 48585, + "1011-json-unknown-typeof.ts": 52058, + "102-comparisons.ts": 47851, + "1020-async-basics.ts": 4722, + "1021-async-ordering.ts": 4973, + "1022-async-exceptions.ts": 49732, + "1023-async-rc-stress.ts": 6131, + "1024-async-pending-exit.ts": 48202, + "1025-async-promise-capture.ts": 3959, + "1026-throw-promise.ts": 4948, + "1027-async-return-promise.ts": 4908, + "1028-async-return-record-literals.ts": 4271, + "1029-async-eager-chains.ts": 3619, + "103-ternary.ts": 5182, + "104-ternary-empty-arrays.ts": 7669, + "1050-comptime-tables.ts": 4897, + "1051-comptime-strings.ts": 47107, + "1052-comptime-records.ts": 39735, + "1053-comptime-json.ts": 5104, + "1054-comptime-modules/main.ts": 48253, + "110-number-radix.ts": 3792, + "111-record-entries.ts": 7069, + "1110-math-members.ts": 5365, + "1111-math-random.ts": 4260, + "1113-string-methods.ts": 54370, + "1114-string-unicode-island.ts": 52372, + "1115-parse-globals.ts": 3948, + "1116-island-static-mix.ts": 42223, + "1117-typeof-static-union.ts": 4732, + "1118-object-spread-conditional.ts": 39126, + "1119-switch-union.ts": 28754, + "112-class-descriptor-key.js": 39424, + "1121-infinity-number-tostring.ts": 4725, + "1122-any-captures.ts": 7404, + "1124-union-narrowed-retag.ts": 6000, + "113-promise-checked-exits.ts": 3453, + "114-live-record-delete.ts": 4924, + "115-array-compound.js": 5191, + "116-text-decoder-runtime.js": 46050, + "117-weak-cache-cycle.js": 5083, + "118-fs-stored-callbacks.cjs": 56960, + "119-native-patterns.js": 8396, + "1200-regex-test-basics.ts": 52932, + "1201-regex-replace.ts": 57037, + "1202-regex-substitutions.ts": 57467, + "1203-regex-split.ts": 3335, + "1204-regex-empty-unicode.ts": 42721, + "1205-regex-rc-stress.ts": 4531, + "1300-errors-basics.ts": 4518, + "1301-errors-subclass.ts": 4955, + "1302-errors-typed-catch.ts": 4560, + "1303-errors-rc-stress.ts": 3938, + "1304-errors-uncaught.ts": 4101, + "1305-errors-async-rejections.ts": 3614, + "1306-errors-runtime-instances.ts": 4054, + "1350-path-normalize-join.ts": 3568, + "1351-path-parts.ts": 4963, + "1352-path-resolve-relative.ts": 4503, + "1353-os-basics.ts": 4704, + "1354-builtin-bare-specifiers.ts": 4189, + "1355-url-parse.ts": 3863, + "1356-url-file-bridge.ts": 4207, + "1357-fsp-roundtrip.ts": 4886, + "1358-crypto-random.ts": 4050, + "1359-json-module/main.ts": 3853, + "1360-spawn-sync.ts": 4896, + "1361-spawn-events.ts": 3844, + "1362-spawn-timers.ts": 9749, + "1363-spawn-unhandled-error.ts": 5302, + "1364-union-truthiness.ts": 4307, + "1365-union-logical.ts": 4482, + "1366-union-equality.ts": 4253, + "1367-destructuring.ts": 5033, + "1368-constructor-functions.ts": 4831, + "1369-promise-union.ts": 3513, + "1370-spread.ts": 3969, + "1371-union-template-tostring.ts": 4126, + "1372-loose-null-tests.ts": 4513, + "1373-union-array-arms.ts": 3764, + "140-bitwise-operators.ts": 5173, + "1400-typedarray-basics.ts": 5411, + "1401-typedarray-slice-set.ts": 6335, + "1402-buffer-encodings.ts": 3500, + "1403-buffer-fs.ts": 7777, + "1404-zlib-crypto-bytes.ts": 6742, + "1405-bytes-unions-arrays.ts": 3762, + "1406-dataview-mp4.ts": 4549, + "1407-dataview-bounds.ts": 3820, + "1408-string-indexing.ts": 4530, + "1409-typedarray-integer-loops.ts": 4694, + "1420-number-statics.ts": 2928, + "1421-number-parse-strings.ts": 4454, + "1422-date-iso.ts": 3607, + "1423-text-codec.ts": 45738, + "1424-fs-options.ts": 3565, + "1425-stdin-tty.ts": 3853, + "1426-stdin-read.ts": 4250, + "1427-fromcharcode-lastindexof.ts": 3449, + "1428-settled-await-order.ts": 3904, + "1429-promise-catch-finally.ts": 6712, + "1430-promise-race.ts": 5576, + "1431-caught-tostring.ts": 4594, + "1432-destructured-params.ts": 5133, + "1433-filter-narrow.ts": 5015, + "1434-async-never.ts": 4402, + "1435-math-spread.ts": 4605, + "1436-default-undef-param.ts": 3807, + "1437-pad-default.ts": 3436, + "1438-promise-all.ts": 7568, + "1440-interval-basics.ts": 4290, + "1441-interval-clear-cross.ts": 7227, + "1442-interval-throw.ts": 4291, + "1443-signal-handlers.ts": 9442, + "1444-exit-listeners.ts": 5858, + "1445-exit-process-exit.ts": 5492, + "1446-exit-uncaught.ts": 4521, + "1447-stdin-closed-events.ts": 5005, + "1448-stream-columns.ts": 4280, + "1450-incdec-expression.ts": 3444, + "1451-instanceof-uint8array-unknown.ts": 4098, + "1452-return-through-finally.ts": 4660, + "1453-pmap-settled.ts": 7068, + "1454-nonnull-narrow-and-fcc-bytes.ts": 4716, + "1455-lambda-union-return-adoption.ts": 4826, + "1460-console-error-warn.ts": 4457, + "1461-process-pid-getuid-kill.ts": 4447, + "1462-exec-sync.ts": 4723, + "1463-timeout-unref.ts": 3720, + "1464-env-writes.ts": 4414, + "1465-env-value.ts": 4722, + "1466-child-containers.ts": 3465, + "1467-string-match.ts": 3798, + "1468-exec-path.ts": 4492, + "1469-remove-listener.ts": 6954, + "1470-child-lifecycle.ts": 4162, + "1471-child-unref.ts": 8772, + "1472-errno-code.ts": 5205, + "1473-promisify-execfile.ts": 5324, + "1474-string-decoder.ts": 4470, + "1475-readline-closed-stdin.ts": 55374, + "1476-assign-expression.ts": 4697, + "1477-in-expressions.ts": 3393, + "1478-promise-reject.ts": 4340, + "1479-destructuring-assign.ts": 4907, + "1480-os-network-interfaces.ts": 5202, + "1481-string-case-static.ts": 5232, + "1482-spawnsync-error.ts": 4518, + "1483-array-slice.ts": 47847, + "1520-fs-wider-surface.ts": 4261, + "1520-string-split-static.ts": 3932, + "1521-fs-lstat-lock.ts": 4472, + "1521-string-trim-pad-static.ts": 3262, + "1522-parseint-static.ts": 4734, + "1522-spawnsync-options.ts": 5888, + "1523-isnan-floor-static.ts": 4375, + "1523-spawn-options.ts": 4320, + "1524-atomics-sleep-static.ts": 4175, + "1524-catch-narrowing.ts": 4322, + "1525-child-exit-signal.ts": 4107, + "1525-unknown-typeof-validation.ts": 4804, + "1526-set-spread.ts": 5272, + "1527-logical-mixed-operands.ts": 3380, + "1528-delete-records-env.ts": 26816, + "1529-class-with-statics.ts": 3554, + "1530-array-push-variadic.ts": 4410, + "1530-spread-override-completion.ts": 4642, + "1531-delete-optional-fields.ts": 4468, + "1531-process-arch-versions.ts": 4294, + "1532-array-splice-shift.ts": 4135, + "1532-union-shared-field-read.ts": 3539, + "1533-bool-equality.ts": 3797, + "1533-path-platform-namespaces.ts": 4105, + "1534-crypto-hash-chain.ts": 4243, + "1534-union-as-arm-cast.ts": 3852, + "1535-spawn-fd-stdio.ts": 3827, + "1535-union-param-defaults.ts": 3756, + "1536-destructuring-defaults.ts": 4441, + "1536-string-array-sweep.ts": 4773, + "1537-chalk-hybrid/main.ts": 4555, + "1537-os-release-spawnsync-stdio.ts": 3030, + "1538-await-promiselike-return.ts": 4081, + "1538-math-static-scalar.ts": 2688, + "1539-readonly-set-map.ts": 4386, + "1539-unknown-truthiness.ts": 4573, + "1540-os-userinfo.ts": 4277, + "1540-void-statement.ts": 3770, + "1541-fs-readdir-dirent.ts": 5970, + "1541-union-keyed-reads.ts": 5137, + "1542-map-promise-values.ts": 3680, + "1542-record-literal-into-union.ts": 4161, + "1543-rest-destructuring.ts": 5386, + "1543-set-server-handles.ts": 8749, + "1544-dyn-json-reads.ts": 5370, + "1544-string-matchall.ts": 4375, + "1545-spread-order-and-optional.ts": 4546, + "1546-union-element-reads.ts": 50679, + "1547-computed-key-fold.ts": 5436, + "1548-boolean-condition-forms.ts": 3960, + "1549-array-isarray-unions.ts": 3329, + "1550-param-defaults-func-set.ts": 3161, + "1551-dyn-receiver-methods.ts": 6009, + "1552-exec-options-record.ts": 3255, + "1553-truthy-hof-predicates.ts": 4287, + "1554-caught-into-unknown.ts": 3533, + "1555-index-spread-into-declared.ts": 4772, + "1556-union-retag-width-arms.ts": 4319, + "1557-url-host.ts": 4070, + "1558-any-joins-and-dyn-validation.ts": 54305, + "1559-conditional-spread-index-merge.ts": 2926, + "1560-forof-homogeneous-tuples.ts": 32566, + "1561-forof-strings.ts": 3862, + "1561-promise-then.ts": 4850, + "1562-optional-chain-tails.ts": 4960, + "1562-spawn-conditional-spread.ts": 3616, + "1563-forof-iterator-projections.ts": 4225, + "1563-string-raw-fold.ts": 4244, + "1564-fs-watch.ts": 5142, + "1564-string-raw.ts": 4078, + "1565-spawn-pipe-streams.ts": 4189, + "1565-union-element-join.ts": 3622, + "1566-child-duck-interface.ts": 4142, + "1567-server-close-override.ts": 8728, + "1568-x509-fingerprint.ts": 3542, + "1569-fsp-mkdir-unlink-chmod.ts": 4083, + "1570-child-unref-kill-reffed.ts": 9583, + "1571-optional-call-tostring-tail.ts": 28217, + "1571-stdin-set-raw-mode-non-tty.ts": 3839, + "1572-promise-reject-all-tuple.ts": 4539, + "1572-x509-validity-date-gettime.ts": 4354, + "1573-promisify-execfile-env-spread.ts": 5359, + "1573-tdz-scalar-forward-capture.ts": 4394, + "1574-dyn-optional-method-number-keys.ts": 4461, + "1574-promise-all-tuple-literal.ts": 5082, + "1575-unknown-assert-into-record.ts": 4680, + "1576-width-coercions.ts": 4595, + "1577-url-hostname.ts": 3199, + "1578-exec-input-optional.ts": 3688, + "1579-matchall-index.ts": 4163, + "1580-exec-env-conditional-spread.ts": 3992, + "1581-declare-const-read.ts": 3904, + "1582-timer-sleep-resolve.ts": 5122, + "1583-loops-and-stream-captures.ts": 2955, + "1584-union-field-unassigned.ts": 4202, + "1585-union-field-conditional-ctor.ts": 4837, + "1586-derived-field-before-super-init.ts": 3740, + "1590-js-unannotated.js": 5105, + "1591-js-closures.js": 4745, + "1592-js-classes.js": 5879, + "1593-js-jsdoc-records.js": 4650, + "1594-js-async.js": 4426, + "1595-js-island-gap/main.js": 26477, + "1596-cjs-modules/main.js": 3160, + "1597-mjs-graph/main.mjs": 4960, + "1598-cjs-builtin-require/main.js": 3030, + "1599-js-uncaught-throw.js": 4259, + "1600-assert-passing.ts": 4325, + "1601-assert-fail-exit.ts": 4804, + "1602-assert-caught-error.ts": 5361, + "1603-assert-scalar-messages.ts": 4806, + "1604-assert-deep-structures.ts": 6023, + "1605-assert-import-forms.ts": 5339, + "1606-assert-strict-module.ts": 4600, + "1607-assert-throws-match.ts": 4414, + "1608-cjs-assert/main.js": 5188, + "1609-assert-async.ts": 4729, + "1610-path-win32-full.ts": 2755, + "1611-url-file-bridge-neutral.ts": 3733, + "1612-cjs-module-globals.cjs": 4516, + "1613-cjs-esm-proxy-named/main.mjs": 4105, + "1614-js-fence-dodges.cjs": 5207, + "1615-cjs-export-shapes/main.cjs": 5553, + "1616-cjs-esm-lexer-invisible/main.mjs": 3099, + "1617-cjs-esm-lexer-visible/main.mjs": 4087, + "1618-cjs-esm-poisoned-tail/main.mjs": 2476, + "1619-cjs-esm-reexport-invisible/main.mjs": 3415, + "1620-cjs-require-effects-order/main.js": 2713, + "1621-cjs-require-cache-hit/main.js": 3783, + "1622-cjs-require-conditional/main.js": 3828, + "1623-cjs-require-diamond/main.js": 3626, + "1624-cjs-require-dir-mid-file/main.js": 2336, + "1625-cjs-require-lazy-fn/main.js": 3015, + "1626-cjs-require-mjs/main.js": 2250, + "1627-mjs-import-cjs-requires/main.mjs": 2873, + "1628-checked-dynamic-builtin-args.cjs": 3077, + "1629-require-main-filename.cjs": 3479, + "1630-inspect-scalars.ts": 3977, + "1630-rmsync-retry-options.cjs": 3932, + "1631-inspect-arrays.ts": 5457, + "1632-inspect-records.ts": 4882, + "1633-inspect-map-set.ts": 4086, + "1634-inspect-classes.ts": 5725, + "1635-inspect-buffer.ts": 5155, + "1636-util-format.ts": 5015, + "1637-inspect-dyn.ts": 4071, + "1638-inspect-cjs.cjs": 3892, + "1639-versions-openssl-probe.ts": 4020, + "1640-fd-read-decode.ts": 4014, + "1641-string-search.ts": 21121, + "1642-object-fromentries-rows.ts": 4097, + "1643-metadata-dyn-return.cjs": 56433, + "1644-ee-basics.ts": 3623, + "1645-ee-extends.ts": 5009, + "1646-ee-once-remove.ts": 3768, + "1647-ee-meta-events.ts": 3840, + "1648-ee-error-event.ts": 2892, + "1649-ee-names-counts.ts": 4454, + "1650-ee-prepend.ts": 2707, + "1651-ee-max-listeners.ts": 4174, + "1652-ee-snapshot.ts": 5505, + "1653-ee-cjs.cjs": 4390, + "1654-ee-namespace.ts": 4636, + "1655-spawnsync-neutral.ts": 6342, + "1656-execsync-neutral.ts": 4702, + "1657-spawn-async-neutral.ts": 4011, + "1660-buffer-read-write-num.ts": 4936, + "1661-buffer-encodings-full.ts": 4916, + "1662-string-decoder-encodings.ts": 4639, + "1663-buffer-compare-search-fill.ts": 4818, + "1664-dyn-fn-boundary.cjs": 3636, + "1665-dyn-fn-mustcall/main.cjs": 4145, + "1666-dyn-fn-identity.ts": 3840, + "1667-dyn-fn-not-callable.cjs": 2882, + "1668-dyn-fn-throws.cjs": 3462, + "1669-symbol-identity.ts": 4719, + "1670-symbol-registry.ts": 4117, + "1671-symbol-typeof.ts": 5887, + "1672-symbol-containers.ts": 4625, + "1673-symbol-cjs.cjs": 6028, + "1674-symbol-inspect.ts": 4649, + "1676-func-array-surface.ts": 3616, + "1677-emitter-listeners.ts": 5664, + "1678-emitter-dyn-listeners.cjs": 6093, + "1679-console-dyn.js": 4398, + "1680-assert-bytes.ts": 3589, + "1681-assert-funcs.ts": 4450, + "1685-stream-readable-basics.ts": 8176, + "1686-stream-readable-paused.ts": 8142, + "1687-stream-readable-flow-control.ts": 6069, + "1688-stream-writable-basics.ts": 9377, + "1689-stream-writable-async-drain.ts": 7873, + "1690-stream-duplex.ts": 8422, + "1691-stream-transform.ts": 6383, + "1692-stream-pipe.ts": 5114, + "1693-stream-pipe-backpressure.ts": 3801, + "1694-stream-destroy.ts": 3612, + "1695-stream-props.ts": 8560, + "1696-stream-read-inside-read.ts": 4132, + "1697-stream-tick-vs-timer.ts": 7129, + "1698-stream-uncaught-error.ts": 4025, + "1699-stream-callback-shapes.ts": 4137, + "1700-mustcall-common/main.cjs": 4739, + "1701-mustcall-exit-report/main.cjs": 4788, + "1702-dyn-proto-dispatch.cjs": 4406, + "1703-arguments-rest-props.cjs": 3234, + "1710-cjs-export-class/main.js": 4152, + "1711-cjs-export-single-values/main.js": 3547, + "1712-field-incdec.ts": 3906, + "1713-js-dyn-fields.js": 5278, + "1720-assert-throws-shape.ts": 4205, + "1721-assert-throws-regex-class.ts": 3161, + "1722-assert-rejects.ts": 4021, + "1723-assert-does-not-reject.ts": 4049, + "1724-assert-iferror.ts": 3854, + "1725-assert-symbols.ts": 3165, + "1726-promise-with-resolvers.ts": 2792, + "1727-assert-throws-shape-exit.ts": 4670, + "1730-countdown-symbol-keys/main.js": 3893, + "1731-symbol-field-shapes.cjs": 4357, + "1732-symbol-field-cross-module/main.js": 4117, + "1740-stream-extends-readable.ts": 5412, + "1741-stream-extends-writable.ts": 7703, + "1742-stream-extends-duplex-transform.ts": 8664, + "1743-stream-extends-vt-dispatch.ts": 7746, + "1744-stream-set-encoding.ts": 3694, + "1745-stream-encoding-js.cjs": 3919, + "1746-stream-for-await.ts": 6732, + "1747-stream-for-await-js.cjs": 11913, + "1750-http-agent-options.ts": 7010, + "1751-options-record-stance.ts": 4331, + "1760-surplus-args-drop.cjs": 3419, + "1761-emitter-special-event-names.cjs": 3326, + "1770-assert-dyn-strict.ts": 4129, + "1771-assert-dyn-deep.ts": 4621, + "1772-assert-dyn-js.cjs": 3690, + "1773-assert-dyn-exit.ts": 3870, + "1780-http-res-surface.ts": 7391, + "1781-http-server-shapes.cjs": 11204, + "1790-computed-key-folds.ts": 3769, + "1791-searchparams-core.ts": 2566, + "1792-searchparams-encoding.ts": 3926, + "1793-searchparams-iteration.ts": 3839, + "1794-searchparams-url-live.ts": 3667, + "1795-dyn-handle-request.cjs": 7469, + "1796-dyn-handle-body.cjs": 4708, + "1797-dyn-handle-socket.cjs": 6317, + "1798-dyn-handle-typed-box.ts": 12433, + "1800-immediate-basics.ts": 3461, + "1801-immediate-handle.ts": 2828, + "1802-immediate-unref-exit.ts": 3773, + "1803-timeout-refresh.ts": 2890, + "1804-timers-module.ts": 4324, + "1805-timer-callback-args.ts": 4084, + "1806-timer-delay-trunc.ts": 3166, + "1810-stream-options-const-record.ts": 3962, + "1811-stream-option-value-callbacks.cjs": 3964, + "1812-stream-super-options-forwarding.cjs": 8384, + "1813-stream-finished.ts": 5772, + "1814-stream-pipeline.cjs": 8091, + "1815-stream-state-reads.cjs": 7977, + "1820-static-block-basics.ts": 3028, + "1821-static-block-order.ts": 2726, + "1822-static-block-js.js": 4178, + "1823-static-instance-method-names.ts": 2438, + "1824-for-of-destructuring-defaults.ts": 3053, + "1825-exhaustive-typeof-switch.ts": 3216, + "1826-settimeout-arguments-callback.js": 2649, + "1830-enum-numeric-basics.ts": 3631, + "1831-enum-string-const-reverse.ts": 3353, + "1832-enum-modules/main.ts": 3697, + "1835-var-basics.ts": 3553, + "1836-var-loop-capture.ts": 3991, + "1837-var-undefined-hoisting.ts": 3692, + "1838-var-modules/main.ts": 2987, + "1839-var-js/main.cjs": 3074, + "1840-jsdoc-import-type-only/main.js": 3723, + "1850-overload-basics.ts": 3730, + "1851-overload-return-narrowing.ts": 3097, + "1852-overload-class-members.ts": 4001, + "1853-overload-modules/main.ts": 4277, + "1854-ambient-declare-fn.ts": 2860, + "1855-ambient-declare-fn-uncaught.ts": 4252, + "1870-unit-type-values.ts": 3913, + "1871-empty-array-never.ts": 2656, + "1872-template-tostring-composite.ts": 3669, + "1880-json-declared-field-order.ts": 5166, + "1881-default-anon/main.ts": 3155, + "1882-default-cjs-interop/main.ts": 4152, + "1883-default-exports/main.ts": 4005, + "1890-ns-imports/main.ts": 4423, + "1891-ns-reexport/main.ts": 2975, + "1940-class-values-basics.ts": 2991, + "1941-class-values-registry.ts": 4395, + "1942-class-expressions.ts": 4086, + "1943-class-statics-expanded.ts": 3500, + "1944-class-values-modules/main.ts": 3932, + "1950-generic-fn-values.ts": 4360, + "1951-generic-classes-basics.ts": 4948, + "1952-generic-class-statics-values.ts": 4310, + "1953-generic-class-hierarchy.ts": 3171, + "1954-generic-modules/main.ts": 3610, + "1960-namespace-basics.ts": 3656, + "1961-namespace-nested.ts": 4076, + "1962-namespace-classes.ts": 3740, + "1963-namespace-aliases.ts": 3282, + "1964-namespace-type-only.ts": 3064, + "1965-namespace-ambient.ts": 3659, + "1966-namespace-modules/main.ts": 4077, + "1967-namespace-alias-typeonly.ts": 2697, + "1968-namespace-import-eq-snapshot.ts": 2527, + "1970-decorators-basics.ts": 4151, + "1971-decorators-rebinding.ts": 2897, + "1972-decorators-throwing.ts": 2556, + "1973-decorators-ambient.ts": 3932, + "1980-primitive-proto-statics.ts": 4096, + "1981-date-utc.ts": 3463, + "1982-freeze-resolve-passthrough.ts": 4042, + "1983-array-tuple-surfaces.ts": 4356, + "1990-labels-basics.ts": 3887, + "1991-for-in-loops.ts": 5008, + "1992-small-syntax.ts": 3829, + "200-strings.ts": 3521, + "2000-generic-methods-basic.ts": 4027, + "2001-generic-methods-generic-class.ts": 3431, + "2002-generic-methods-inheritance.ts": 3737, + "2003-generic-methods-object-literal.ts": 4544, + "2004-generic-methods-statics.ts": 3642, + "201-templates.ts": 2558, + "2010-generators-basics.ts": 3652, + "2011-generators-forof.ts": 3852, + "2012-generators-return-throw.ts": 3950, + "2013-generators-sent-values.ts": 4017, + "2014-generators-values.ts": 4246, + "2015-generators-yieldstar.ts": 3908, + "2016-generators-rc-stress.ts": 4275, + "2017-generators-async.ts": 2845, + "2018-generators-uncaught.ts": 3328, + "2019-generators-loops.ts": 3191, + "2020-generic-value-bindings.ts": 5274, + "2021-generic-value-binding-modules/main.ts": 3546, + "2022-width-index-capture.ts": 4336, + "2023-width-readonly.ts": 3104, + "2024-width-array-elems.ts": 3482, + "2025-width-union-compose.ts": 4076, + "2026-width-spread.ts": 3943, + "2030-width-nested.ts": 4567, + "2031-width-tuples.ts": 2753, + "2032-cjs-export-assigned-class-expression/main.cjs": 4056, + "2033-property-assigned-class-extends.cjs": 3174, + "2035-ternary-array-retag.cjs": 4091, + "2036-evolving-array-decl.cjs": 3778, + "2037-fn-decl-hoisting.cjs": 2776, + "2038-evolving-array-js.cjs": 4351, + "2040-any-bindings.ts": 3377, + "2040-mixin-heritage.ts": 3511, + "2041-any-params-returns.ts": 3626, + "2041-mixin-values.ts": 4380, + "2042-any-flow-loops.ts": 3135, + "2042-mixin-modules/main.ts": 4398, + "2043-any-dom-values.ts": 3973, + "2043-mixin-rc-stress.ts": 3648, + "2044-vtable-sibling-slots.ts": 3788, + "2045-objlit-accessors-basic.ts": 3867, + "2045-parameter-properties.ts": 4798, + "2046-abstract-classes.ts": 5738, + "2046-objlit-accessors-effects.ts": 3922, + "2047-objlit-accessors-shapes.ts": 3974, + "2047-optional-class-fields.ts": 5957, + "2050-dynamic-import-own-module/main.ts": 4276, + "2051-dynamic-import-then/main.ts": 3569, + "2052-dynamic-import-self.ts": 2505, + "2053-typeof-static-fold.ts": 3591, + "2054-destructuring-island-source.ts": 4039, + "2060-empty-tuple.ts": 3547, + "2070-computed-key-folds.ts": 5392, + "2071-integer-key-enumeration-order.ts": 4114, + "2072-expando-function-members.ts": 3911, + "2073-destructuring-assignment.ts": 3331, + "2074-island-destructuring.ts": 2722, + "2075-index-signature-runtime-keys.ts": 2808, + "2080-destructuring-defaults.ts": 4723, + "2081-destructuring-rest.ts": 3815, + "2082-destructuring-assignment.ts": 4463, + "2085-destructuring-heads-rest-params.ts": 3370, + "2087-destructuring-for-heads.ts": 3817, + "2090-index-signature-number-keys.ts": 3307, + "2091-index-signature-string-intersection.ts": 4503, + "2092-package-imports/main.ts": 3209, + "2093-timers-promises.ts": 4576, + "2094-diagnostics-channel.ts": 5184, + "2095-js-catch-unknown.js": 3505, + "2096-os-type.ts": 3468, + "2097-js-evolving-globals.js": 3426, + "210-string-methods.ts": 3239, + "2100-stream-default-hwm.ts": 4068, + "2101-dyn-param-defaults.ts": 4169, + "2102-empty-pattern-decls.ts": 3916, + "2105-computed-key-static-folds.ts": 3626, + "2106-comma-expressions.ts": 4728, + "211-string-unicode.ts": 3897, + "2110-top-object-types.ts": 3438, + "2111-json-stringify-unknown.ts": 3888, + "2112-array-at-findlast.ts": 3424, + "2113-string-index-methods.js": 3570, + "212-string-aliasing-append.ts": 3570, + "2120-package-self-import/main.ts": 3971, + "2121-esm-cycle-inert-backedge/main.ts": 2650, + "2123-ambient-import-crash/main.ts": 3746, + "2124-imports-field-wildcard/main.ts": 2731, + "2140-uri-component-codecs.ts": 3381, + "2160-dc-tracing-channel.cjs": 4690, + "2161-js-object-literal-identity.cjs": 4257, + "2162-js-dyn-destructure.cjs": 3551, + "2163-js-selfref-const.cjs": 4654, + "2164-js-then-dyn-handler.cjs": 5156, + "2165-js-throw-dyn.cjs": 3523, + "2166-cjs-getter-this/main.cjs": 3882, + "2170-island-array-exits.ts": 3858, + "2171-island-json-stringify.ts": 3712, + "2172-island-regexp-boundary.ts": 3327, + "2190-new-object-and-string-wrappers.ts": 2850, + "2191-uri-encoders.ts": 2942, + "2192-object-default-tostring.ts": 3177, + "2193-discarded-stdlib-reads.ts": 3355, + "2194-ambient-undef-chains.ts": 3563, + "2195-require-missing-package/main.mjs": 4117, + "2196-island-computed-key-chain.ts": 3932, + "2210-dyn-promise-crossing.cjs": 5102, + "2211-dc-trace-promise.cjs": 4621, + "2212-unhandled-rejection-listener.cjs": 4270, + "2213-async-local-storage.cjs": 4068, + "2214-dc-bind-store.cjs": 5707, + "2215-process-emit-warning-exit.cjs": 4386, + "2240-width-class-into-record.ts": 3665, + "2241-width-record-into-class.ts": 3361, + "2242-width-statics-into-record.ts": 3708, + "2243-width-assert-satisfies-shapes.ts": 3967, + "2250-tagged-templates.ts": 3434, + "2252-class-iterators.ts": 4459, + "2253-union-coercions.ts": 2359, + "2260-http2-constants.cjs": 3538, + "2280-builtin-namespace-destructure.cjs": 3057, + "2281-domexception-atob-btoa.cjs": 3389, + "2282-queue-microtask.cjs": 5820, + "2283-structured-clone.cjs": 4600, + "2284-regexp-constructor.cjs": 3741, + "2285-iferror-dyn.cjs": 2861, + "2286-dyn-object-walks.cjs": 3243, + "2300-dyn-record-spread-and-keyed-access.cjs": 2809, + "2301-cjs-export-table-dom-attach.cjs": 2887, + "2310-process-next-tick.ts": 4130, + "2311-next-tick-js-callbacks.js": 4068, + "2312-stream-underscore-assign.ts": 6594, + "2313-stream-underscore-assign-js.cjs": 4269, + "2314-process-introspection.ts": 3297, + "2320-await-unit.ts": 3657, + "2321-emitter-static-setmax.cjs": 4316, + "2322-dyn-array-sort.cjs": 3658, + "2323-timer-callback-returns.ts": 4288, + "2330-tls-server-runtime-options.cjs": 57265, + "2331-tls-server-options-typed.ts": 24831, + "2350-nan-global.ts": 3780, + "2351-async-methods.ts": 4037, + "2352-void-coercions.ts": 4230, + "2353-decorators-member-ambient.ts": 3783, + "2354-decorators-expression-ambient.ts": 3425, + "2360-tuple-to-array.ts": 4066, + "2361-assign-index-record.ts": 3954, + "2362-execsync-inherit.ts": 3811, + "2363-nullish-retag.ts": 4019, + "2364-in-runtime-key.ts": 3905, + "2365-dyn-into-island.ts": 4006, + "2366-string-well-formed.ts": 2861, + "2367-regexp-escape.ts": 3081, + "2368-set-methods.ts": 3869, + "2369-promise-try.ts": 4228, + "2370-group-by.ts": 4759, + "2371-iterator-helpers.ts": 4028, + "2380-buffer-module-named-import.ts": 3715, + "2381-builtin-default-imports.js": 3602, + "2382-cycle-two-decl/main.ts": 2942, + "2383-cycle-assertdoc/main.js": 2814, + "2384-cycle-mixed-bindings/main.ts": 2985, + "2385-builtin-reexport-facade/main.ts": 2368, + "2386-string-to-chars.ts": 3688, + "2387-tonumber-argv.ts": 4524, + "2388-tonumber-grammar-zoo.ts": 3447, + "2389-tonumber-unary-plus.ts": 3631, + "2390-dot-requires/main.cjs": 3823, + "2391-default-builtin-imports/main.ts": 4261, + "2392-block-guard-alias-scope.ts": 3432, + "2393-loop-exit-guard-narrow.ts": 4204, + "2394-loop-narrow-containment.ts": 3545, + "2395-while-cond-guard.ts": 3342, + "2396-born-narrowed-decl.ts": 3204, + "2397-branch-kill-merge.ts": 2872, + "2398-switch-arm-kill.ts": 2478, + "2399-reassign-kill-polarity.ts": 3975, + "240-stdout-write.ts": 3714, + "2400-kill-return-edge.ts": 2788, + "2401-kill-break-staging.ts": 3266, + "2402-labeled-break-kill.ts": 3546, + "2403-kill-continue-backedge.ts": 3341, + "2404-kill-throw-catch.ts": 3390, + "2405-sibling-arm-narrow.ts": 3636, + "2406-switch-clause-sibling-narrow.ts": 3321, + "2407-infinite-loop-seal.ts": 3706, + "2408-loop-terminality-reopen.ts": 3556, + "2409-loop-body-return-not-terminal.ts": 2952, + "2410-stacked-cases-terminality.ts": 2785, + "2411-exhaustive-switch-terminality.ts": 2898, + "2412-dowhile-guard-trailing-test.ts": 3018, + "2413-dowhile-kill-renarrow.ts": 3619, + "2414-dowhile-continue-kill.ts": 3030, + "2415-dowhile-break-trailing-test.ts": 3541, + "2416-spread-ternary-positions.ts": 3398, + "2417-ternary-local-inference.ts": 2779, + "2418-wrapped-ternary-arms.ts": 3414, + "2419-selector-ternary-union.ts": 2916, + "2420-nullish-null-identity.ts": 2738, + "2421-float-lane-inference.ts": 3483, + "2422-ieee-div-rem-corners.ts": 3493, + "2423-param-null-reassign.ts": 2469, + "2424-ternary-miss-first-narrowing.ts": 2704, + "2425-elseif-head-exit-narrow.ts": 3239, + "2426-default-snapshot-mutable/main.ts": 3047, + "2427-perf-hooks-now.ts": 3594, + "2428-field-redeclare-inherited.ts": 3306, + "2429-destructure-class-instance.ts": 3925, + "2430-empty-literal-unknown-field.js": 3247, + "2431-primitive-ctor-values.ts": 4135, + "2432-generic-member-fields-async.ts": 4525, + "2433-as-const-command-tables.ts": 4328, + "2434-deferred-init-fields.ts": 3024, + "2435-loose-same-kind-equality.ts": 3478, + "2440-console-inspect-args.ts": 5890, + "2441-console-process-argv.ts": 3753, + "2442-union-literal-arm-widening.ts": 3136, + "2443-union-literal-shadow-narrowing.ts": 3135, + "2444-union-literal-reducer-spread.ts": 2966, + "2445-math-minmax-nary.ts": 3844, + "2446-performance-global.ts": 3708, + "2447-island-boundary-slots/main.ts": 4610, + "2448-entries-null-arms-regex-arrays.ts": 4797, + "2450-private-instance-methods.ts": 4126, + "2451-private-fields.ts": 3682, + "2452-private-statics.ts": 3833, + "2453-private-accessors.ts": 3714, + "2454-private-generator-methods.ts": 4326, + "2455-private-brand-checks.ts": 2955, + "2456-private-async-methods.ts": 4273, + "2457-private-members.js": 3893, + "2460-qs-parse-grammar.ts": 5096, + "2461-qs-parse-options.ts": 3628, + "2462-qs-stringify.ts": 4992, + "2463-qs-escape-unescape.ts": 3734, + "2464-qs-require-forms.cjs": 4220, + "2470-mockable-module-shape.js": 2876, + "2471-record-keyed-write-hasown.js": 4081, + "2472-string-regexp-union.ts": 2606, + "2473-option-table-widths.js": 4586, + "2474-island-literal-forms.ts": 4522, + "2475-variadic-wrapper-island.js": 3845, + "2476-map-regex-values.ts": 3182, + "2480-recursive-record-tree.ts": 3879, + "2481-mutual-recursive-records.ts": 3675, + "2482-recursive-union-tree.ts": 3577, + "2483-recursive-record-cycles.ts": 3205, + "2484-json-stringify-circular.ts": 3643, + "2485-inspect-circular-refs.ts": 3845, + "2486-recursive-record-boundaries.ts": 2991, + "2487-recursive-deep-equal.ts": 4100, + "2488-ast-walker.ts": 4477, + "2490-find-miss-null-compare.ts": 3671, + "2491-strict-unit-compare-no-arm.ts": 3227, + "2492-loose-null-compare-unions.ts": 3901, + "2493-switch-unit-cases.ts": 3674, + "2494-no-arm-compare-effects.ts": 3403, + "2500-net-autosel-timeout.ts": 3482, + "2510-dyn-evolving-array-map.ts": 3667, + "2511-dyn-evolving-array-filter-foreach.ts": 4096, + "2512-dyn-evolving-array-mixed-push.ts": 4423, + "2520-private-statics-class-name-calls.ts": 3265, + "2521-private-statics-class-expression.ts": 3750, + "2522-private-statics-decorated.ts": 3195, + "2523-private-statics-aliased-class.ts": 3584, + "2530-object-destructuring-decl.ts": 3283, + "2531-array-tuple-destructuring-decl.ts": 4032, + "2532-param-destructuring-options.ts": 4645, + "2533-forof-destructuring.ts": 4187, + "2534-object-rest-decl.ts": 4358, + "2535-destructuring-assign-basics.ts": 3621, + "2536-destructuring-assign-nested.ts": 3573, + "2537-destructuring-assign-member-targets.ts": 3272, + "2538-destructuring-assign-class-source.ts": 3962, + "2539-class-instance-rest.ts": 4142, + "2540-accessor-destructuring-defaults.ts": 3446, + "2541-destructuring-eval-order.ts": 3928, + "2550-generics-keyof-pick.ts": 3409, + "2551-generics-value-aliases.ts": 3346, + "2552-generics-iface-methods.ts": 3488, + "2553-generics-signature-bindings.ts": 3749, + "2554-generics-frontier-mix.ts": 3794, + "2555-generics-keyof-writes.ts": 3364, + "2556-crypto-introspection.ts": 3435, + "2556-width-hybrid-shapes.ts": 4079, + "2557-tls-ca-store.ts": 3530, + "2557-width-field-lifts.ts": 4176, + "2558-index-signature-func-values.ts": 4225, + "2558-rejection-events.cjs": 3844, + "2559-index-signature-container-values.ts": 4449, + "2560-arraybuffer-dataview-set.ts": 3087, + "2561-object-is.ts": 4355, + "2562-intl-numberformat-en-us.ts": 3901, + "2563-stream-promises-pipeline.ts": 3564, + "2564-stream-promises-finished.ts": 6034, + "2565-stream-promises-js.cjs": 4473, + "2566-promise-reject-dyn-reason.js": 3377, + "2567-rest-spread-forward.js": 3534, + "2568-rest-spread-forward-dynamic.js": 4104, + "2569-upcast-identity.ts": 3496, + "2570-buffer-arg-validation.cjs": 5910, + "2571-searchparams-arg-validation.cjs": 4428, + "2572-readable-emitted-readable-flag.cjs": 3512, + "2573-fs-url-arg-ladders.cjs": 3763, + "2574-emitter-max-listeners-ladders.cjs": 3689, + "2575-string-destructuring-decl.ts": 4712, + "2576-string-destructuring-assign.ts": 3735, + "2577-builtin-global-destructuring.js": 4445, + "2578-jsval-into-unknown-rows.ts": 3828, + "2579-jsval-object-param-crossing.js": 3036, + "2580-jsval-routed-keyed-ops.js": 3956, + "2581-jsval-routed-calls.js": 3809, + "2582-jsval-object-statics.js": 3967, + "2582-jsval-routed-keyed-ops.js": 2714, + "2583-dyn-nullish-coalesce.js": 3955, + "2583-jsval-routed-calls.js": 4033, + "2584-jsval-object-statics.js": 3852, + "2584-union-dyn-collapse.ts": 3199, + "2585-dyn-nullish-coalesce.js": 4086, + "2585-unknown-array.ts": 3037, + "2586-object-assign-spread.js": 4129, + "2587-array-entries-forof.ts": 3963, + "2588-array-entries-chains.ts": 4778, + "2589-object-create-null.cjs": 3994, + "2590-object-create-dynamic.js": 3840, + "2591-ambient-generic-traps.ts": 3572, + "2592-ambient-trap-uncaught.ts": 3517, + "2593-generic-inert-bindings.ts": 3984, + "2594-nullish-generic-bindings.ts": 3028, + "2595-fs-arg-ladders.cjs": 6103, + "2596-net-arg-ladders.cjs": 3811, + "2597-dgram-send-ladders.cjs": 4888, + "2598-tls-arg-ladders.cjs": 26930, + "2599-stream-arg-ladders.cjs": 6141, + "2600-dyn-keyed-write-harness.js": 2931, + "2601-dyn-keyed-write-ops.js": 2148, + "2602-dyn-array-destructure.js": 2954, + "2603-island-keyed-write-dyn.js": 2848, + "2604-cycle-classes-mutual/main.ts": 3417, + "2605-cycle-three-module/main.ts": 3678, + "2606-dynamic-import-cycle/main.ts": 3530, + "2608-regex-named-groups.ts": 4497, + "2609-regex-named-replace.ts": 3665, + "2610-regex-named-matchall.ts": 3003, + "2611-regex-named-groups-js.cjs": 4787, + "2613-for-init-uninitialized-let.ts": 3768, + "2614-trap-binding-later-writes.ts": 2989, + "2615-nullish-field-record-binding.ts": 3529, + "2616-js-collect-probe-defers.js": 3466, + "2617-enum-static-field-import/main.ts": 3293, + "2618-ee-emit-override.ts": 3565, + "2619-ee-override-chain.ts": 3727, + "2620-ee-override-once-order.ts": 4249, + "2621-ee-override-error-throw.ts": 3855, + "2622-ee-override-filter.ts": 3910, + "2623-ee-job-queue.ts": 3743, + "2624-ee-override-js.cjs": 3084, + "2625-bytes-views.ts": 3970, + "2626-stream-event-names.ts": 4359, + "2627-stream-ticks-are-nextticks.ts": 7617, + "2628-stream-push-encodings.cjs": 3343, + "2629-stream-consumers.ts": 4441, + "2630-stream-consumers-errors.ts": 5041, + "2631-create-require/main.ts": 3703, + "2632-dyn-jsval-iterate.js": 3831, + "2633-island-promise-crossing.js": 5160, + "2634-stream-pipeline-arg-ladders.cjs": 3923, + "2635-trap-binding-unmappable-written.ts": 3043, + "2636-trap-binding-ambient-rooted-rewrite.ts": 3569, + "2637-create-require-bare/main.ts": 2767, + "2638-http-dyn-res-compat.cjs": 8125, + "2639-http-dyn-req-pause.cjs": 8808, + "2640-net-dyn-socket-compat.cjs": 4119, + "2641-http-agent-surface.cjs": 8974, + "2642-http-agent-maxsockets.cjs": 7586, + "2643-or-default-retag.ts": 3938, + "2644-http-client-url-argument.ts": 8788, + "2645-https-client-url-argument.ts": 5188, + "2646-top-level-await.ts": 3543, + "2647-top-level-await-modules/main.ts": 3228, + "2648-top-level-await-rejection.ts": 3718, + "2649-top-level-await-pending.ts": 3680, + "2650-top-level-await-self-import.ts": 3580, + "2651-top-level-await-pending-unhandled.ts": 3616, + "2652-top-level-await-dynamic/main.ts": 3624, + "2653-top-level-await-rejection-stops-loop.ts": 3405, + "2654-top-level-await-unrelated-rejection.ts": 3746, + "2655-top-level-await-cycle/main.ts": 3633, + "2656-top-level-await-cycle-order/main.ts": 3581, + "2657-top-level-await-cycle-dynamic/main.ts": 3334, + "2658-top-level-await-sync-completion/main.ts": 3454, + "2659-top-level-await-dynamic-cycle/main.ts": 2695, + "2660-top-level-await-cycle-rejection/main.ts": 3883, + "2661-top-level-await-dynamic-runtime-root/main.ts": 3717, + "2662-top-level-await-cycle-external-wait/main.ts": 3322, + "2663-top-level-await-dependency-errors/main.ts": 4049, + "2664-top-level-await-same-checkpoint-rejection.ts": 4075, + "2665-top-level-await-unhandled-listener-liveness.ts": 3625, + "2666-array-to-sorted.ts": 8369, + "2668-stored-number-array-iterator.ts": 3915, + "2669-array-copying-methods.ts": 4422, + "2670-uint8array-copy-iterate.ts": 4692, + "2671-array-copying-js.cjs": 3615, + "2672-http-request-response-callback.ts": 3326, + "2673-top-level-await-implicit-module.ts": 2622, + "2674-top-level-for-await-implicit-module.ts": 3487, + "2675-create-require-nested-esm.js": 3107, + "2675-process-self-reexec.ts": 3537, + "2676-indexed-read-strict-equality.ts": 3497, + "2676-record-clone-overrides.ts": 3652, + "2676-top-level-await-ambiguous/main.ts": 3641, + "2677-runtime-optional-closure.ts": 4530, + "2677-top-level-await-module-scope/main.ts": 3142, + "2678-date-instances.ts": 4477, + "2678-large-string-sparse-index.ts": 3931, + "2678-util-parseargs.ts": 7627, + "2679-util-parseargs-cjs.cjs": 4984, + "2680-util-parseargs-default.ts": 2670, + "2681-util-parseargs-dynamic.js": 3233, + "2682-fs-rename.ts": 4087, + "2683-filter-truthy-predicate.ts": 4348, + "2683-fs-rename-js.cjs": 2621, + "2684-filter-no-predicate-dyn.cjs": 3942, + "2684-fs-rename-abort.ts": 3403, + "2685-array-unshift-reverse.ts": 3942, + "2685-fs-write-sync.ts": 4263, + "2686-fs-file-handle.ts": 6233, + "2687-fsp-write-file-options.ts": 3951, + "2687-process-write-args.ts": 2844, + "2688-fs-stats-disk-fields.ts": 4789, + "2689-http-server-timeout-properties.ts": 3279, + "2690-https-server-timeout-option.ts": 56311, + "2691-retained-lowering-record-order.ts": 5946, + "2692-inline-record-assert-index.ts": 3857, + "2692-string-accumulation.ts": 3602, + "2693-math-constants.ts": 3816, + "2700-array-sort-complexity.ts": 3912, + "2700-http-static-trailers.ts": 6657, + "2700-wasi-core.ts": 3863, + "2701-array-sort-snapshot.ts": 3906, + "2701-http-static-trailer-wire.ts": 3412, + "2701-import-meta/main.mjs": 4097, + "2702-http-static-trailer-end.ts": 8433, + "2702-type-import-link-static/main.ts": 2947, + "2702-uint8array-to-sorted.ts": 3549, + "2703-array-sparse-sort.ts": 8716, + "2703-type-import-link-static-reexport/main.ts": 3510, + "2704-array-sparse-to-sorted.ts": 8447, + "2704-type-import-link-static-success/main.ts": 3172, + "2705-array-sparse-sort-append.ts": 7740, + "2705-type-import-link-dynamic/main.ts": 3687, + "2706-array-search-missing-needle.ts": 3192, + "2706-type-import-link-dynamic-success/main.ts": 4191, + "2707-array-search-huge-sparse.ts": 48438, + "2707-type-import-link-static-default-reexport/main.ts": 3502, + "2708-type-import-link-dynamic/main.ts": 3358, + "2720-array-read-parity.ts": 3686, + "2721-array-nested-missing-receiver.ts": 2904, + "2750-array-sparse-foundation.ts": 3895, + "2751-buffer-concat-sparse-list.ts": 3589, + "2752-array-optional-stores.ts": 3503, + "2753-array-optional-method-values.ts": 2814, + "2754-array-property-undefined.ts": 2681, + "2755-array-optional-literal-forwarding.ts": 3614, + "2780-array-parity-composition.ts": 12116, + "2781-array-missing-value-escape.ts": 3458, + "2782-array-sparse-callbacks.ts": 3870, + "2783-array-defaults-rest.ts": 3473, + "2784-array-reduce-missing-result.ts": 3973, + "2785-array-missing-destructuring.ts": 4123, + "2786-array-sparse-serialization.ts": 4457, + "2787-array-missing-string-arithmetic.ts": 3381, + "2788-array-missing-builtin-conversions.ts": 3415, + "2789-array-missing-optional-tostring.ts": 2621, + "2790-dynamic-import-self-name/main.ts": 3399, + "2791-record-optional-keys.ts": 3271, + "2792-record-optional-spread-entries.ts": 4055, + "2793-union-conversion-identity-capture.ts": 4295, + "2794-array-generic-callback-values.ts": 3662, + "2795-array-optional-typedarray-source.ts": 38684, + "2796-array-sparse-class-value-instanceof.ts": 3585, + "2800-array-expression-consumers.ts": 3265, + "2801-array-switch-consumers.ts": 4057, + "2820-array-missing-method-receivers.ts": 3301, + "2821-array-optional-numeric-comparisons.ts": 2316, + "2830-cjs-require-self-name/main.cjs": 3030, + "2840-finally-completions.ts": 3523, + "2841-using-sync.ts": 3234, + "2842-await-using.ts": 3418, + "2843-using-suppressed-error.ts": 3352, + "2844-node-disposable-resources.ts": 5430, + "2845-for-using-of.ts": 3355, + "2846-generator-using.ts": 3702, + "2850-async-generators-protocol.ts": 4747, + "2851-async-generators-values.ts": 4111, + "2852-timers-promises-interval.ts": 3376, + "2854-leading-bom-literals.ts": 2675, + "2855-searchparams-sort-complexity.ts": 2462, + "2856-dynamic-any-local-operators.ts": 3959, + "2857-branded-primitives.ts": 3738, + "2858-import-meta-resolve/main.mjs": 2597, + "2859-import-meta-resolve-dynamic/main.mjs": 2565, + "2860-require-resolve/main.cjs": 3076, + "2861-readable-iterator-close.ts": 3422, + "2862-web-readable-async-iteration.ts": 55094, + "2863-class-async-iterator.ts": 3586, + "2864-array-class-method-receivers.ts": 4152, + "2865-cjs-process-alias.cjs": 3499, + "2866-dyn-switch.ts": 3318, + "2867-array-shift-length.js": 3797, + "2868-empty-record-promise-presence.js": 3592, + "2869-nullish-mixed-lazy.ts": 3886, + "2870-and-dropped-truthy-arm.ts": 3748, + "2871-optional-promise-to-unknown.ts": 3966, + "2872-unobserved-dynamic-event.ts": 3095, + "2873-optional-receiver-loop-lifetime.js": 3310, + "2874-nullable-callback-field-cycle.js": 4239, + "2875-evolving-let-read-before-write.js": 2007, + "2876-class-unknown-roundtrip.ts": 3485, + "2877-child-unknown-roundtrip.ts": 3462, + "2878-class-private-unknown.cjs": 3481, + "2880-cjs-module-graph/main.cjs": 4418, + "2890-crypto-static-utility.ts": 3693, + "2891-json-record-key-escapes.ts": 3227, + "2892-windows-console-unicode.ts": 3154, + "2893-child-stdin-duplex.ts": 3517, + "2894-child-stdin-backpressure.ts": 4232, + "2895-child-stdin-write-after-end.ts": 3755, + "2896-child-stdin-write-after-finish.ts": 4128, + "2897-child-stdin-destroy.ts": 2592, + "2898-child-stdin-spawn-failure.ts": 3984, + "2899-nested-mutual-recursion.ts": 3524, + "2900-float64array-static.ts": 2647, + "2900-void-conditional-arrow.ts": 3544, + "2901-bigint-core.ts": 3085, + "2902-bigint-bytes.ts": 3574, + "2903-bigint-storage.ts": 4190, + "2904-bigint-errors.ts": 3820, + "2905-bigint-edges.ts": 3695, + "2906-bigint-wasi-width.ts": 3566, + "2910-overloaded-callable-alias.ts": 2729, + "2911-execfile-callback.ts": 3798, + "2912-execfile-callback-options.ts": 3803, + "2912-promisify-fs-readfile.ts": 3648, + "2913-builtin-callable-alias.ts": 5737, + "2914-fixed-tuple-call-spread.ts": 3851, + "2915-path-function-values.ts": 4013, + "2916-path-function-values-cjs.ts": 3957, + "2917-builtin-callable-widths.ts": 3640, + "2918-builtin-callable-widths-cjs.ts": 3701, + "2919-fs-function-values.ts": 3810, + "2920-fs-promises-function-values.ts": 3724, + "2921-zlib-callbacks.ts": 5492, + "2922-dyn-bitwise-not.cjs": 3645, + "2923-cjs-factory-export/main.cjs": 3645, + "2930-union-receiver-calls.ts": 4841, + "2931-union-dynamic-field-call.js": 3975, + "2932-create-require-program/main.ts": 4060, + "2933-static-dynamic-import/main.ts": 3736, + "2934-static-import-stored.ts": 3490, + "2935-module-namespace-values/main.ts": 3371, + "2936-static-loose-equality.ts": 4954, + "2937-bitwise-hot-loop.ts": 3448, + "2938-fs-sync-overloads.cjs": 3181, + "2939-child-shell-text.ts": 4371, + "2940-date-parse.ts": 3212, + "2940-fsp-realpath.ts": 3484, + "2941-fsp-lstat-identity.ts": 3903, + "2941-process-exit-code.ts": 3406, + "2942-fsp-readdir-dirent.ts": 4202, + "2942-process-exit-code-override.ts": 3082, + "2943-process-exit-code-invalid.ts": 3479, + "2944-process-exit-code-wrap.ts": 3266, + "2945-url-origin-username.ts": 2899, + "2946-child-fork-ipc/main.ts": 4761, + "2946-url-port-hash.ts": 2865, + "2947-set-readonly-seeds.ts": 3446, + "2948-child-fork-eof-callback/main.ts": 3476, + "2948-stdio-callback-record.ts": 3365, + "2949-child-fork-default/main.mjs": 3332, + "2949-url-password.ts": 3628, + "2950-fs-descriptor-publication.ts": 3569, + "2951-math-static-analytic.ts": 3919, + "2952-math-static-remaining.ts": 3652, + "2953-http-header-validation.ts": 7274, + "2954-http-outgoing-headers.ts": 9450, + "2955-http-static-state.ts": 6516, + "2956-http-static-informational.ts": 6092, + "2957-http-static-response-controls.ts": 6929, + "2961-emitter-computed-names.cjs": 4004, + "2962-emitter-computed-optional.ts": 2860, + "2963-child-fork-dispatch/main.ts": 3483, + "2964-indexed-compound.ts": 4204, + "2966-numeric-array-read-fusion.ts": 4381, + "2967-numeric-array-read-lifetime.ts": 3892, + "2968-numeric-array-borrow.ts": 3610, + "2969-scalar-record-results.ts": 4035, + "2970-constant-numeric-tables.ts": 2720, + "2971-constant-table-modules/main.ts": 3311, + "2972-http-static-distinct-snapshots.ts": 4474, + "2972-math-receiver-borrow.ts": 4401, + "2973-http-static-agent.ts": 3997, + "2973-integer-bitwise-arithmetic.ts": 3629, + "2974-array-search-from-index.ts": 116997, + "2974-http-static-module-values.ts": 7598, + "2974-numeric-remainder.ts": 3511, + "2975-bigint-default-radix.ts": 3179, + "2975-http-static-client-controls.ts": 3852, + "2976-http-static-incoming-state.ts": 8478, + "2976-json-stringify-no-arguments.js": 3354, + "2977-http-static-incoming-timeout.ts": 3463, + "2977-nested-array-binding-defaults.js": 2952, + "2978-http-static-client-timeout.ts": 4066, + "2978-regexp-optional-subject.js": 2771, + "2979-array-search-mixed-needles.js": 3599, + "2979-http-static-server-timeout.ts": 3821, + "2980-http-static-server-timeout-default.ts": 3238, + "2980-string-position-arguments.js": 3754, + "2981-http-static-events.ts": 3579, + "2981-string-optional-positions.ts": 3623, + "2982-http-static-close-all.ts": 2800, + "2982-string-position-coercion-order.js": 4005, + "2983-http-static-close-idle.ts": 3208, + "2984-http-static-close-upgrade.ts": 3773, + "2985-http-static-message-destroy.ts": 3787, + "2986-http-static-client-socket-finish.ts": 3574, + "2987-http-static-timeout-errors.ts": 3533, + "2988-http-static-client-abort.ts": 4341, + "2989-http-static-response-timeout-handled.ts": 3444, + "2990-http-static-request-timeout-handled.ts": 3719, + "2991-array-indexed-equality.ts": 3650, + "2992-stream-rows.ts": 3551, + "2993-fiber-stack-lifetimes.ts": 3792, + "2994-fromcharcode-scalar.ts": 4459, + "2995-math-hyperbolic.ts": 3860, + "2996-math-near-one.ts": 3086, + "2997-math-integer-float.ts": 3955, + "300-if-else.ts": 3194, + "3001-caught-typeof-object.js": 4263, + "3002-promise-then-two.ts": 4357, + "301-while.ts": 3525, + "302-for.ts": 3433, + "3020-string-last-index-position.ts": 3282, + "3021-buffer-union-narrow-callback.ts": 3951, + "3022-string-affix-positions.ts": 2990, + "3023-string-affix-position-coercion.js": 3327, + "3024-string-number-narrow-for-in.ts": 3695, + "3025-string-search-position-coercion.js": 3055, + "3026-array-last-index-of.js": 3971, + "3027-array-last-index-of-records.ts": 3174, + "3028-string-search-dynamic-needle.js": 3488, + "3029-string-search-union-needle.js": 2317, + "303-break-continue.ts": 3497, + "3030-array-search-no-arg.js": 3148, + "3031-array-relative-index-coercion.js": 4248, + "3031-string-last-index-search-value.js": 2998, + "3032-string-search-value.js": 3484, + "3033-string-search-needle-coercion.js": 3256, + "3034-arguments-with-parameters.js": 3316, + "3035-string-positioned-search-value.js": 3436, + "3036-string-object-search-value.js": 3562, + "3037-number-nullish-conversion.js": 3657, + "3038-number-scalar-unions.ts": 2371, + "3039-string-repeat-count.js": 3353, + "304-compound-incdec.ts": 3802, + "3040-string-prototype-call.js": 4850, + "3041-string-prototype-object-call.js": 3234, + "3042-string-padding-coercion.js": 3916, + "3043-string-split-arguments.js": 3976, + "3044-array-slice-splice-positions.js": 4465, + "3045-array-indexed-mutation.js": 3477, + "3046-array-indexed-ref-identity.ts": 3717, + "3047-object-prototype-tag.js": 7241, + "3048-object-own-prototype.ts": 2902, + "3049-array-flat-depth.ts": 4100, + "305-truthiness.ts": 3370, + "3050-array-splice-insert.ts": 4056, + "3051-array-join-default.ts": 3538, + "3052-array-construction.ts": 4542, + "3053-array-construction-js.js": 3392, + "3054-dynamic-abort-record.ts": 30732, + "3055-default-builtin-nodenext/main.ts": 3399, + "3056-default-builtin-bundler/main.ts": 3748, + "3057-default-builtin-nodenext-dynamic/main.ts": 3727, + "3058-optional-array-chain-join.ts": 3025, + "3059-arguments-property-names.ts": 3619, + "3061-concurrent-fiber-stacks.ts": 4083, + "3062-runtime-optional-record-guards.ts": 4619, + "3063-runtime-optional-class-guards.ts": 4458, + "3064-installed-entry-imports/main.ts": 2755, + "3065-installed-entry-js/main.js": 2496, + "3066-source-debugging/main.ts": 3345, + "3067-cjs-function-export-require/main.cjs": 3584, + "3068-debug-variables/main.ts": 2803, + "3068-url-checked-identity.ts": 3525, + "3069-set-checked-seed.js": 3730, + "3069-tuple-spread.ts": 3638, + "3070-checked-object-accessors.js": 3937, + "3070-collection-views.ts": 3112, + "3071-checked-specialization-narrowing.js": 4666, + "3071-map-contextual-record-seeds.ts": 3637, + "3072-optional-union-receivers.ts": 4348, + "3072-weak-process-streams.js": 3937, + "3073-optional-callable-module.js": 3783, + "3073-union-keyed-reads.ts": 3349, + "3074-discriminated-intersections.ts": 3833, + "3075-recursive-contextual-literals.ts": 4956, + "3076-nullish-record-defaults.ts": 3537, + "3077-optional-union-array-reads.ts": 4192, + "3078-forward-mutable-captures.ts": 4709, + "3079-forward-mutable-tdz.ts": 4069, + "3080-exhaustive-never-bindings.ts": 3678, + "3081-recursive-array-destinations.ts": 3824, + "3082-forward-write-unwind.ts": 3698, + "3083-set-string-seed.ts": 3916, + "3084-record-own-membership.ts": 4502, + "3085-conditional-record-construction.ts": 4272, + "3086-error-constructor-options.ts": 2549, + "3087-error-options-lifetime.ts": 3996, + "3088-array-wide-callbacks.ts": 4379, + "3089-array-find-narrowing.ts": 4095, + "3090-json-discriminated-records.ts": 4621, + "3091-json-recursive-discriminants.ts": 4799, + "3092-number-union-predicates.ts": 3661, + "3093-error-option-data.ts": 3834, + "3094-json-replacer-traversal.ts": 3366, + "3095-json-reviver-traversal.ts": 3492, + "3096-json-callback-nonfinite.ts": 3652, + "3097-json-callback-reentrancy.ts": 4051, + "3098-json-callback-space.ts": 4000, + "3099-json-callback-functions.ts": 4355, + "3100-json-callback-holder.js": 4131, + "3101-json-callback-bytes.ts": 4053, + "3102-json-unknown-fields.ts": 3096, + "3103-scalar-record-nested-control-flow.ts": 3773, + "3104-native-analysis-tables-loops.ts": 3270, + "3105-nullable-collections.ts": 3945, + "3106-mixed-insertion-spreads.ts": 4363, + "3107-nullable-collection-lifetimes.ts": 4026, + "3108-for-await-sync-arrays.js": 5613, + "3108-identity-map-keys.ts": 3552, + "3109-destructuring-unknown-defaults.js": 3464, + "3109-identity-union-collections.ts": 4940, + "3110-builtin-error-families.ts": 3056, + "3110-identity-collection-mutation.ts": 4022, + "3111-identity-collection-cycles.ts": 4287, + "3112-union-switch-control-flow.ts": 3956, + "3113-union-array-removal.ts": 4360, + "3114-union-record-field-write.ts": 3442, + "3115-zlib-static-compression-levels.ts": 5168, + "3116-sequence-expression-lifetimes.ts": 4189, + "3117-unknown-switch-control-flow.ts": 4180, + "3118-recursive-union-spread.ts": 3041, + "3119-runtime-optional-spread.ts": 3381, + "3120-dynamic-property-descriptors.js": 2965, + "3120-generator-method-loop-bindings.ts": 4201, + "3120-ir-nonfinite-numbers.ts": 4055, + "3121-compound-assignment-values.js": 3508, + "3121-dynamic-accessor-descriptors.js": 5206, + "3122-dynamic-delete-descriptors.cjs": 3618, + "3122-dynamic-delete-descriptors.js": 3463, + "3122-js-async-class-methods.js": 3826, + "3123-destructured-global-tdz.js": 3445, + "3124-array-prototype-borrow.js": 4427, + "3125-regex-global-match.ts": 2948, + "3126-js-number-radix/main.ts": 3569, + "3127-spawn-runtime-options.ts": 3489, + "3128-regex-last-index.ts": 4225, + "3129-js-token-union/main.ts": 4007, + "3130-child-generic-streams.ts": 4070, + "3131-child-rest-listeners.js": 3532, + "3132-child-generic-stream-completion.ts": 11386, + "3133-text-decoder-streaming.ts": 19582, + "3134-fs-vectors.ts": 4100, + "3135-fs-file-handle-controls.ts": 5084, + "3136-fs-file-handle-options.ts": 5319, + "3137-fs-vector-callbacks.cjs": 4121, + "3138-array-large-storage.ts": 5662, + "3139-regex-native-deep-alternatives.ts": 37923, + "3140-array-dense-access.ts": 5683, + "3141-map-string-key-hash.ts": 3292, + "3150-integer-remainder.ts": 4041, + "3151-array-push-writes.ts": 4409, + "3170-number-conversion-fast-paths.ts": 3918, + "3171-method-census-data-writes.ts": 4678, + "400-fib.ts": 3649, + "401-mutual-recursion.ts": 2468, + "402-string-functions.ts": 3526, + "403-void-and-params.ts": 3277, + "4030-runtime-object-truthiness.ts": 4681, + "4031-event-emitter-long-tuples.ts": 3970, + "4032-inline-rc-fast-paths.ts": 6135, + "404-rc-stress.ts": 3734, + "4040-adapted-function-identity.ts": 4226, + "4041-adapted-function-properties.ts": 3785, + "4042-object-is-union-subclass.ts": 3204, + "4043-nonnull-missing-element.ts": 4658, + "4044-adapted-callback-modules/main.ts": 3502, + "4045-optional-element-projections.ts": 4551, + "4046-captured-parameter-values.ts": 4678, + "4047-captured-parameter-rebinding.ts": 3804, + "405-params-optional.ts": 3480, + "406-params-defaults.ts": 3673, + "4060-cycle-shared-instance/main.ts": 2973, + "4060-stack-union-reads.ts": 3684, + "4061-cycle-evaluation-order/main.ts": 3762, + "4061-nullable-ref-fields.ts": 5610, + "4062-cycle-tdz-read/main.ts": 3351, + "4063-cycle-hoisted-calls/main.ts": 3608, + "4064-cycle-classes-after-init/main.ts": 3570, + "4065-cycle-init-throws/main.ts": 3220, + "4066-cycle-top-level-tdz/main.ts": 2340, + "4067-dynamic-import-cycle-tdz/main.ts": 3378, + "407-params-rest.ts": 3809, + "408-params-ctors-inheritance.ts": 4026, + "4080-optional-read-presence-tests.ts": 3072, + "4080-string-index-bounds.ts": 2694, + "4081-hoisted-function-tdz.ts": 4427, + "4081-string-index-unproven.ts": 3902, + "4082-hoisted-function-tdz-uncaught.ts": 2748, + "4083-dynamic-import-failure/main.ts": 3742, + "4084-record-optional-field-copies.ts": 4621, + "4085-generator-loop-close.ts": 4491, + "4086-optional-capture-defaults.ts": 2947, + "4088-class-static-tdz.ts": 3366, + "4089-class-wrapper-tdz.js": 2781, + "409-params-async-generics.ts": 4252, + "4090-computed-key-tdz.js": 3408, + "4091-class-evaluation-deferred.ts": 2828, + "410-params-rc-stress.ts": 2917, + "4140-array-callback-split-visit.ts": 6798, + "4141-array-callback-ambient-receiver/main.ts": 3870, + "4142-array-callback-factories.ts": 4472, + "4143-union-refinement-intersection-arms.ts": 4107, + "420-dead-strip-modules/main.ts": 2681, + "4290-acyclic-immutable-trees.ts": 3286, + "4291-acyclic-constructor-escapes.ts": 3619, + "4292-acyclic-readonly-bypass.ts": 4006, + "4293-acyclic-dynamic-writes.ts": 3787, + "4294-console-line-sizes.ts": 5430, + "4295-console-template-parts.ts": 3102, + "4296-console-glued-long-parts.ts": 4254, + "4410-inline-object-allocation.ts": 4263, + "4411-nullable-ref-values.ts": 5324, + "4412-nullable-record-values.ts": 4337, + "4413-cycle-old-late-death.ts": 3017, + "4413-nullable-null-and-undefined.ts": 4035, + "4414-cycle-old-weak-keys.ts": 3820, + "4414-nullable-string-values.ts": 5821, + "4415-identity-borrowed-operands.ts": 4327, + "4415-nullable-container-values.ts": 5953, + "4431-exception-pending-contexts.ts": 5399, + "4432-checked-downcast-failures.ts": 4507, + "4451-int32-field-storage.ts": 5079, + "4452-int32-field-dynamic-writes.ts": 4478, + "4453-int32-closed-locals.ts": 3221, + "4454-int32-field-reflection-reads.ts": 4583, + "4455-live-view-reads-without-stores.ts": 4961, + "4471-unassigned-field-reads.ts": 4391, + "4476-string-ascii-header-fact.ts": 4538, + "4477-buffer-write-ascii-runs.ts": 4115, + "4478-string-large-index-reads.ts": 4211, + "4481-array-optional-push.ts": 3640, + "4482-instanceof-static-class-optional.ts": 2991, + "4483-array-splice-statement.ts": 5079, + "4484-array-length-reset.ts": 3655, + "4485-array-splice-optional-item.ts": 4264, + "4486-array-field-element-borrows.ts": 3950, + "4487-array-literal-optional-values.ts": 5139, + "4520-optional-guard-narrowing.ts": 4441, + "4521-array-callback-element-presence.ts": 6451, + "4522-captured-parameter-lifetimes.ts": 3198, + "4523-array-pop-removal.ts": 4334, + "4524-array-callback-supertype-params.ts": 5586, + "4541-nullable-wrap-borrows.ts": 4310, + "4542-preserving-call-borrows.ts": 4231, + "4543-walk-borrowed-locals.ts": 3976, + "4544-checked-cast-aliases.ts": 4280, + "4545-borrowed-returns.ts": 4524, + "4546-rebound-borrowed-params.ts": 4010, + "4560-field-store-borrowed-receivers.ts": 3877, + "4561-virtual-borrowed-parameters.ts": 4633, + "4562-string-self-concat-move.ts": 3881, + "4563-array-read-projection-receivers.ts": 4188, + "4564-literal-choice-strings.ts": 4026, + "4568-for-of-hole-elements.ts": 4432, + "4569-shorthand-missing-elements.ts": 4672, + "4570-map-lookup-default-record.ts": 3777, + "4591-weak-keys-union-records.ts": 3889, + "4592-cycle-const-from-import/main.ts": 2581, + "4593-weak-keys-empty-objects.ts": 3813, + "4594-union-class-field-mixed-types.ts": 7147, + "4595-union-class-field-optional-receiver.ts": 3827, + "4596-error-subclass-int-fields.ts": 3477, + "4596-tdz-nullable-forward-capture.ts": 3990, + "4597-callback-field-method-name.ts": 4176, + "4598-live-array-ref-element-access.ts": 9941, + "4598-map-set-clear-reuse.ts": 5807, + "4598-os-available-parallelism.ts": 3624, + "4598-publish-constructor-stores.ts": 3208, + "4599-construction-only-field-borrows.ts": 5064, + "4600-construction-only-fields-dynamic-writes.ts": 3234, + "4601-cycle-holders.ts": 3389, + "4602-constructor-escape-order.ts": 3798, + "4610-array-ext-dyn-refresh.ts": 4533, + "4620-optional-chain-borrowed-receivers.ts": 4161, + "4621-edge-preserving-callees/main.ts": 4709, + "4630-contract-int32.ts": 4369, + "4630-reference-write-call-arguments.ts": 4010, + "4631-contract-nothrow.ts": 4027, + "4631-reference-write-aliases.ts": 4138, + "4632-contract-immutable.ts": 3925, + "4632-reference-write-loops-and-walks.ts": 4126, + "4633-contract-program-lifetime.ts": 5198, + "4633-reference-write-callbacks-returns.ts": 4361, + "4634-contract-program-lifetime-publish.ts": 51728, + "4634-optional-element-borrowed-returns.ts": 3758, + "4640-bitwise-identity-ranges.ts": 4521, + "4641-nothrow-try-catch.ts": 3856, + "4642-acyclic-contract.ts": 4836, + "4650-stale-property-narrowing.ts": 5065, + "4651-map-string-get-entry.ts": 3204, + "4652-stale-closure-binding-narrowing.ts": 4161, + "4660-typed-rest-spread-forwarding.ts": 2965, + "4671-scoped-array-read-borrows.ts": 4639, + "4690-cycle-bypass-long-lived.ts": 6384, + "4691-publish-constructor-self-alias.ts": 43679, + "4692-borrowed-result-mutating-callees.ts": 4134, + "4720-cold-throw-paths.ts": 3925, + "4721-integer-induction-numbers.ts": 3986, + "4730-touint32-large-magnitudes.ts": 3378, + "4731-string-mixed-ascii-slices.ts": 3992, + "4732-buffer-write-utf16le-runs.ts": 4419, + "4733-typed-array-read-compares.ts": 3723, + "4750-map-string-absent-filter.ts": 4339, + "4751-string-search-multibyte-needles.ts": 2934, + "4795-published-untyped-member-reads.ts": 4864, + "4806-uint32-loop-accumulators.ts": 4131, + "4810-union-identity-retags.ts": 45852, + "4811-union-retag-checked-cast.ts": 3777, + "4812-int32-wrapping-sums.ts": 4491, + "4813-typed-array-read-equality-bindings.ts": 5104, + "4820-sort-comparator-lent-arguments.ts": 4547, + "4821-callback-lent-arguments.ts": 4044, + "4822-stable-capture-reads.ts": 3520, + "4823-array-store-receivers.ts": 3708, + "4830-typed-teardown-chains.ts": 5155, + "4831-cycle-bypass-probe-windows.ts": 6539, + "4840-array-hole-free-prefix.ts": 5312, + "4860-int32-local-storage.ts": 5193, + "4870-array-pipeline-fusion.ts": 9277, + "4871-array-pipeline-analytics.ts": 4466, + "4872-array-pipeline-temporaries.ts": 8037, + "4875-stream-consumers-array-buffer.ts": 4195, + "4876-array-buffer-inspect.ts": 3460, + "4880-await-call-turn-order.ts": 3196, + "4881-await-call-exceptions.ts": 3913, + "4882-await-call-request-chain.ts": 3966, + "4883-await-values-and-hops.ts": 3305, + "4884-await-call-unhandled-sibling.ts": 3775, + "4885-await-call-checkpoints.ts": 3389, + "4890-regex-literal-sites.ts": 4481, + "4891-regex-plain-text-patterns.ts": 4954, + "4892-regex-exec-read-captures.ts": 5836, + "4900-bigint-division-cross-check.ts": 4132, + "4900-console-instances.ts": 3398, + "4901-bigint-radix-text.ts": 4240, + "4901-console-instance-errors.ts": 4118, + "4902-bigint-compound-assign.ts": 3348, + "4903-bigint-fixed-width.ts": 4053, + "4904-bigint-large-products.ts": 4084, + "4905-bigint-fixed-width-fusion.ts": 4866, + "4906-bigint-small-value-trees.ts": 4495, + "4907-bigint-random-trees.ts": 6985, + "4910-hole-free-prefix-upkeep.ts": 3869, + "4920-string-literal-switch.ts": 3948, + "4930-typed-record-reflection.ts": 6446, + "4931-typed-data-generic-walks.ts": 6005, + "4932-typed-json-unknown.ts": 4690, + "4940-async-return-adoption.ts": 4747, + "4941-async-return-adoption-try.ts": 4808, + "4942-async-return-adoption-values.ts": 4525, + "4943-async-return-adoption-interleaved.ts": 4076, + "4950-regex-compiled-captures.ts": 5853, + "4951-regex-compiled-last-index.ts": 4237, + "4952-regex-compiled-anchors-classes.ts": 2970, + "4953-regex-compiled-backtracking.ts": 4881, + "4954-regex-log-report.ts": 4017, + "4955-regex-compiled-differential.ts": 17656, + "4970-int32-call-abi.ts": 4034, + "4980-generator-early-exit-finally.ts": 4293, + "4981-generator-delegation-iterables.ts": 4701, + "4982-generator-sent-values.ts": 3850, + "4983-generator-reuse-iterables.ts": 4013, + "4984-generator-exceptions.ts": 3941, + "4985-generator-lazy-pipeline.ts": 5191, + "4986-generator-default-channels.ts": 4218, + "4987-generator-closures-methods.ts": 3564, + "4988-generator-async-interplay.ts": 4129, + "4989-generator-step-drives.ts": 3945, + "4990-lone-surrogates.ts": 4283, + "4991-lone-surrogate-halves.ts": 3965, + "4992-lone-surrogate-search.ts": 4450, + "4993-lone-surrogate-json.ts": 4533, + "4994-lone-surrogate-uri.ts": 3275, + "4995-lone-surrogate-regex.ts": 4305, + "4996-lone-surrogate-stdio.ts": 3980, + "4997-lone-surrogate-stdout-patch.js": 3708, + "4998-lone-surrogate-buffers.ts": 3397, + "4999-lone-surrogate-io.ts": 4183, + "500-array-basics.ts": 3681, + "501-array-push-pop.ts": 3744, + "5010-lifetime-region-generations.ts": 4361, + "5011-lifetime-region-outside-references.ts": 3723, + "5012-lifetime-region-shapes.ts": 5352, + "5013-lifetime-region-async.ts": 4836, + "5014-lifetime-region-nesting.ts": 4098, + "5015-lifetime-region-publish.ts": 44284, + "5016-lifetime-region-weak-keys.ts": 4090, + "5017-lifetime-region-cycles.ts": 2993, + "5018-lifetime-region-hierarchies.ts": 4448, + "5019-lifetime-region-values.ts": 4593, + "502-array-for-of.ts": 3697, + "5020-lifetime-region-large.ts": 6810, + "5021-lifetime-region-opaque-holders.ts": 3221, + "5022-lifetime-region-workers.ts": 43902, + "503-array-functions.ts": 3221, + "504-array-rc-stress.ts": 3902, + "5040-promise-all-race-turns.ts": 3963, + "5041-promise-all-turns.js": 3961, + "5042-async-generator-return-promise.ts": 4464, + "5043-async-generator-return-forms.ts": 3956, + "5045-generator-delegation-typed-next.ts": 4940, + "5046-generator-delegation-return-throw.ts": 4744, + "5047-generator-delegation-iterables-typed.ts": 5495, + "5048-generator-delegation-async.ts": 4004, + "5049-generator-delegation-edges.ts": 3818, + "5050-inherited-in-membership.ts": 2952, + "5051-typed-record-prototypes.ts": 4128, + "5052-class-for-in-unknown.ts": 4437, + "5053-json-replacer-arrays.ts": 4585, + "5054-required-field-delete.ts": 3565, + "5055-object-create-record-literal.ts": 3433, + "5056-generator-in-unknown.ts": 3552, + "5060-child-fork-exit-after-messages/main.ts": 4059, + "5061-child-fork-local-disconnect/main.ts": 3921, + "5062-child-fork-message-before-eof/main.ts": 5311, + "5065-global-increment-initializers.ts": 3409, + "5066-global-compound-updates.ts": 3878, + "5067-global-updates-in-functions.ts": 3060, + "5068-global-var-let-const-updates.ts": 3099, + "5069-global-update-modules/main.ts": 3105, + "5070-optional-read-bindings.ts": 3986, + "5071-optional-chain-scalars.ts": 4053, + "5072-optional-nullish-ternary.ts": 3786, + "5073-optional-results.ts": 3653, + "5074-optional-pop-shift.ts": 3809, + "5075-optional-reads-unchecked/main.ts": 4486, + "5076-optional-escapes.ts": 3781, + "5080-boolean-array-storage.ts": 9389, + "5081-boolean-array-dynamic-views.ts": 5005, + "5085-promise-allsettled-turns.ts": 5227, + "5086-promise-any-turns.ts": 4926, + "5087-promise-allsettled-any-dyn.js": 5648, + "5088-promise-combinator-thenables.js": 6097, + "5089-promise-settled-records.ts": 4902, + "5090-generator-finished-result-value.ts": 3980, + "5091-generator-delegation-arrays-strings.ts": 4920, + "5092-generator-delegation-sets-maps.ts": 5655, + "5095-console-count-group.ts": 4543, + "5096-console-assert-dir.ts": 3659, + "5097-console-table.ts": 4019, + "5098-console-time-warnings.ts": 7779, + "5099-console-methods-dynamic.cjs": 4211, + "510-array-map-filter-foreach.ts": 3693, + "511-array-indexof-includes.ts": 2587, + "5110-var-hoisting-early-reads.ts": 3722, + "5111-var-hoisting-closures-classes.ts": 3558, + "5112-var-hoisting-function-scope.ts": 3736, + "5113-tdz-let-const-class.ts": 3427, + "5114-var-hoisting-js.js": 2426, + "5115-regex-replace-compiled.ts": 4045, + "5116-regex-capture-reads.ts": 3563, + "5117-regex-log-report-spans.ts": 3810, + "5118-regex-replace-char-chains.ts": 3242, + "512-array-join-chains.ts": 3887, + "5120-frame-records.ts": 4007, + "5121-frame-objects.ts": 3950, + "5122-frame-result-slots.ts": 3225, + "5123-frame-reassigned.ts": 3642, + "5124-frame-objects-control.ts": 2980, + "5125-frame-mutating-methods.ts": 3316, + "5126-frame-returned-params.ts": 3759, + "5127-frame-loop-bindings.ts": 4535, + "513-array-methods-rc-stress.ts": 3991, + "5130-event-target-dispatch.js": 5194, + "5131-event-target-listener-errors.js": 5170, + "5132-event-target-typed.ts": 5485, + "5133-abort-signal-event-target.ts": 30480, + "5134-events-error-monitor.ts": 3910, + "5135-event-target-warnings.js": 38892, + "5136-events-error-monitor-string-name.ts": 3923, + "5137-events-error-monitor-computed-name.js": 4432, + "5138-events-error-monitor-shared-listener.ts": 3642, + "5139-event-target-listener-throw.ts": 4714, + "514-array-find-some-every.ts": 3747, + "5140-os-host-facts.ts": 4713, + "5141-os-constants.ts": 3991, + "5142-path-parse-format.ts": 3463, + "5145-path-matches-glob-basics.ts": 4364, + "5146-path-matches-glob-braces.ts": 5382, + "5147-path-matches-glob-extglob.ts": 3804, + "5148-path-matches-glob-classes.ts": 3686, + "5149-path-matches-glob-win32.ts": 4358, + "515-array-flatmap.ts": 4323, + "5150-small-array-inline-slots.ts": 4485, + "5155-cycle-header-types.ts": 32161, + "516-array-reduce.ts": 4410, + "5160-field-callback-receiver.ts": 4515, + "5161-field-callback-receiver-escape.ts": 3931, + "5162-field-method-reference-receiver.ts": 3961, + "5163-field-callback-receiver.cjs": 4008, + "5164-worker-field-callback-receiver.ts": 43587, + "5165-interface-method-dispatch.ts": 4146, + "5166-interface-method-values.ts": 5178, + "5167-interface-method-order.ts": 4344, + "5168-interface-method-hierarchy.ts": 5405, + "5169-interface-method-chains.ts": 5047, + "517-array-hof-index-args.ts": 3899, + "5170-string-scan-eviction.ts": 2657, + "5171-lone-surrogate-replace-seams.ts": 3047, + "5175-forin-typed-as-unknown.ts": 3918, + "5176-object-keys-typed-as-unknown.ts": 2645, + "5177-forin-dynamic-objects.ts": 3654, + "5178-forin-keys-js.js": 2761, + "5179-forin-typed-shapes.ts": 3622, + "518-array-sort.ts": 4004, + "518-promise-void-union-callbacks.ts": 3964, + "5180-interface-arrays.ts": 4400, + "5181-interface-array-methods.ts": 13672, + "5182-interface-array-boundaries.ts": 3272, + "5183-interface-property-reads.ts": 4146, + "5184-interface-property-objects.ts": 3495, + "5185-util-inherits.cjs": 6043, + "5186-util-inherits.ts": 6829, + "5187-util-deprecate.cjs": 6304, + "5188-util-deprecate-flags.cjs": 4852, + "5189-util-deprecate.ts": 5176, + "519-array-from-length.ts": 4670, + "519-promise-union-await-values.ts": 3522, + "5190-util-callbackify.cjs": 4881, + "5191-util-callbackify.ts": 5163, + "5192-util-debuglog.cjs": 5490, + "5193-util-debuglog.ts": 3737, + "5194-process-emit-warning-tick.cjs": 4043, + "5195-object-entries-typed-as-unknown.ts": 3294, + "5196-object-values-typed-as-unknown.ts": 4153, + "5197-object-entries-dynamic-objects.ts": 4163, + "5198-object-entries-values-js.js": 3223, + "5199-object-entries-identity.ts": 4287, + "520-map-basics.ts": 3177, + "5200-array-sort-keyed-numbers.ts": 5498, + "5201-array-sort-keyed-records.ts": 6386, + "5202-array-sort-keyed-lookalikes.ts": 3643, + "5203-typed-array-sort-default.ts": 7538, + "5204-typed-array-sort-comparators.ts": 5252, + "521-map-number-keys.ts": 3394, + "5210-process-memory-usage.ts": 2806, + "5211-process-identity.ts": 3698, + "5212-perf-marks-measures.ts": 4803, + "5213-perf-timing-errors.ts": 4464, + "5214-perf-entry-inspect.ts": 4525, + "5215-perf-timing-validation.js": 4263, + "5216-perf-spread-arguments.js": 4935, + "5217-perf-spread-typed.ts": 3571, + "522-map-foreach.ts": 2998, + "5220-url-parse-warnings.ts": 5276, + "5221-url-parse-shapes.ts": 5152, + "5222-url-parse-hosts.ts": 5614, + "5223-url-parse-query.ts": 5852, + "5224-url-format-objects.ts": 5092, + "5225-url-format-whatwg.ts": 5939, + "5226-url-resolve.ts": 4968, + "5227-url-legacy-dependency/main.ts": 5444, + "5228-url-domain-conversion.ts": 2782, + "5229-url-legacy-errors.cjs": 6339, + "523-map-ref-values.ts": 3549, + "5230-inline-union-fields.ts": 4686, + "5231-inline-union-field-kinds.ts": 4192, + "5232-inline-union-fields-dynamic.ts": 4074, + "5233-inline-union-fields-shapes.ts": 4531, + "5234-inline-union-class-fields.ts": 4699, + "5235-inline-union-fields-publish.ts": 3783, + "5236-inline-union-unchecked-reads.ts": 3109, + "5237-inline-union-frame-objects.ts": 2338, + "524-map-cycles.ts": 3268, + "5240-event-target-subclass.ts": 5177, + "5241-event-subclass.ts": 5478, + "5242-event-target-subclass-hierarchy.ts": 4631, + "5243-event-target-subclass-dynamic.ts": 4520, + "5244-event-target-subclass.js": 5329, + "5245-event-target-subclass-signals.ts": 33048, + "5246-event-target-subclass-listener-throw.ts": 3829, + "5247-event-target-subclass-lifetimes.ts": 6504, + "5248-event-target-subclass-warnings.ts": 4300, + "5249-event-target-subclass-unconstructed.ts": 4427, + "525-map-rc-stress.ts": 3704, + "5250-cipher-aes-gcm.ts": 7929, + "5251-cipher-aes-cbc.ts": 15678, + "5252-cipher-aes-ctr.ts": 26018, + "5253-cipher-chacha20-poly1305.ts": 7999, + "5254-cipher-errors.js": 26643, + "5255-cipher-encodings.cjs": 20470, + "5256-cipher-deprecation.cjs": 48818, + "5257-cipher-vectors.ts": 18839, + "5258-cipher-handles.js": 21996, + "5259-cipher-chunked.ts": 21780, + "526-set-basics.ts": 3497, + "5260-record-unknown-identity.ts": 3759, + "5261-optional-field-identity.ts": 3633, + "5262-record-unknown-many.ts": 4065, + "527-set-foreach.ts": 3282, + "5270-url-parse-no-deprecation.cjs": 4123, + "5271-url-parse-throw-deprecation.cjs": 5457, + "5275-http-end-callback-order.ts": 4317, + "5276-style-text-hex-colors.cjs": 4489, + "5277-fs-read-file-buffer-option.cjs": 3576, + "5278-host-null-bytes.cjs": 8285, + "5279-search-params-null-init.cjs": 3511, + "528-set-seeded.ts": 3372, + "5285-blob-construct.ts": 4331, + "5286-blob-readers.ts": 3684, + "5287-blob-inspect.ts": 4285, + "5288-blob-validation.js": 4292, + "5289-blob-read-order.ts": 3682, + "529-map-seeded.ts": 3677, + "5290-blob-dynamic.js": 4399, + "5295-readline-promises-question.ts": 3697, + "5296-readline-lines.ts": 3534, + "5297-readline-callback-events.cjs": 3926, + "5298-readline-abort.cjs": 12732, + "5299-readline-stdin.ts": 4774, + "530-record-arrays.ts": 3665, + "5300-stream-add-abort-signal.ts": 34654, + "5301-stream-add-abort-signal-errors.cjs": 12589, + "5302-stream-promises-options.ts": 13246, + "5303-stream-finished-callback-opts.cjs": 9506, + "5305-json-stringify-typed-arrays.ts": 5926, + "531-record-array-hofs.ts": 3761, + "5315-map-iterate-after-front-deletes.ts": 3399, + "5316-map-lru-eviction.ts": 4060, + "5317-map-iterate-while-mutating.ts": 3994, + "5318-set-iterate-after-deletes.ts": 3956, + "5319-map-iteration-values.ts": 4002, + "532-record-arrays-rc-stress.ts": 3024, + "5320-map-iterate-across-compaction.ts": 4445, + "5321-integer-closed-arithmetic-loops.ts": 3363, + "5321-json-parse-cycles.ts": 3162, + "5322-integer-variable-step-loops.ts": 3747, + "5322-json-stringify-parsed-trees.ts": 4167, + "5323-dyn-numeric-index-reads.ts": 3375, + "5323-int32-nonnegative-slot-facts.ts": 3657, + "5324-int32-initializer-locals.ts": 2946, + "5324-structured-clone-documents.ts": 4653, + "5325-record-boundary-returns.ts": 3627, + "5326-record-boundary-params.ts": 3878, + "5327-record-boundary-identity.ts": 2625, + "5328-record-boundary-open.ts": 3032, + "5329-record-boundary-recursion.ts": 3600, + "533-array-element-cycles.ts": 3019, + "5330-record-boundary-fields.ts": 3682, + "5331-record-boundary-methods.ts": 3949, + "5332-int32-narrowed-slot-facts.ts": 3391, + "5333-integer-guarded-while-counters.ts": 3537, + "5333-record-boundary-nullable-argument.ts": 4003, + "5334-fetch-mentions-without-calls.ts": 3134, + "5335-stream-operators-values.ts": 5552, + "5335-top-level-await-pending-exit-code.ts": 3309, + "5336-stream-operators-promise-timing.ts": 3761, + "5336-top-level-await-pending-exit-listener.ts": 4072, + "5337-dc-subscriber-throw-next-tick.cjs": 4314, + "5337-stream-operators-concurrency.ts": 9296, + "5338-js-tdz-function-element.js": 2718, + "5338-stream-operators-checks.cjs": 4825, + "5339-array-buffer-constructor.js": 3399, + "5339-stream-for-await-hops.ts": 5761, + "534-record-width-subtyping.ts": 3917, + "5340-readable-from-options.ts": 4100, + "5341-compound-any-operand.ts": 4139, + "5341-generator-callback-params.ts": 4032, + "5341-integer-recursion-boundaries.ts": 3324, + "5341-readable-from-dynamic.cjs": 5054, + "5342-compound-any-operand.cjs": 3210, + "5342-generator-scalar-channels.ts": 3572, + "5342-integer-recursion-stack-and-mutual.ts": 4091, + "5342-stream-compose.ts": 8635, + "5343-any-flow-compound.ts": 3298, + "5343-integer-recursion-array-index.ts": 4086, + "5343-iterator-result-records.ts": 3462, + "5343-stream-compose-edges.ts": 8761, + "5344-json-parse-undeclared-keys.ts": 4683, + "5344-stream-pipeline-timing.ts": 3627, + "5345-object-values-for-of-unknown.ts": 3893, + "5346-object-values-length-dynamic.ts": 4302, + "5347-object-values-loop-control.ts": 3777, + "5348-object-values-for-of-js.js": 3584, + "5349-object-entries-values-optional.ts": 3677, + "535-object-statics.ts": 4668, + "5350-object-values-wide-record.ts": 4386, + "5351-object-values-methods-index.ts": 3615, + "5352-final-field-loop-reads.ts": 3880, + "5353-captured-const-values.ts": 4470, + "5354-captured-const-tdz.ts": 3331, + "5355-captured-function-declarations.ts": 3574, + "5356-captured-tdz-ordering.ts": 3626, + "5357-init-only-module-bindings.ts": 3698, + "536-map-seed-array.ts": 3057, + "5360-array-sort-comparator-calls.ts": 4503, + "5361-array-sort-inconsistent-comparators.ts": 4396, + "5362-array-sort-comparator-throws.ts": 3173, + "5363-array-sort-comparator-writes.ts": 12179, + "5364-array-sort-union-and-boolean-elements.ts": 14770, + "5365-array-sort-dynamic-values.js": 4175, + "537-map-iter-drains.ts": 3108, + "5370-zlib-stream-roundtrip.ts": 6069, + "5371-zlib-stream-chunking.cjs": 3999, + "5372-zlib-stream-errors.cjs": 4377, + "5373-zlib-stream-options.cjs": 4901, + "5374-zlib-stream-flush-params.ts": 4306, + "5375-zlib-stream-promises.ts": 5322, + "5376-zlib-constants.cjs": 3332, + "5377-zlib-stream-backpressure.cjs": 5428, + "5378-zlib-sync-options.cjs": 5415, + "5379-zlib-callback-options.ts": 5768, + "538-map-set-for-of.ts": 3575, + "5390-interface-loop-element-lifetimes.ts": 4065, + "5391-interface-dispatch-hierarchies.ts": 4925, + "5392-interface-receiver-bindings.ts": 3293, + "5393-interface-array-holes.ts": 3549, + "5394-interface-implementers.ts": 4320, + "5395-locale-compare-ascii.ts": 4299, + "5396-locale-compare-latin.ts": 3694, + "5397-locale-compare-sorting.ts": 4218, + "540-tuples-basics.ts": 3768, + "5400-json-parse-typed-keys.ts": 4494, + "5405-buffer-arraybuffer-window.ts": 3875, + "5406-util-types-keys.ts": 4065, + "5407-http-header-field-limit.ts": 2684, + "5408-http-unread-request-end.ts": 4832, + "5409-http-held-request-body.ts": 4395, + "541-ref-array-json.ts": 4658, + "5410-inspect-class-values.ts": 4013, + "5411-inspect-class-hierarchies.ts": 3695, + "5412-inspect-dynamic-collections.ts": 2565, + "5413-inspect-class-values.cjs": 4189, + "5415-zlib-dynamic-inputs.cjs": 3913, + "542-union-element-arrays.ts": 4031, + "5420-readable-from-generators.ts": 5476, + "5421-readable-from-generators.cjs": 3700, + "5422-stream-async-push-wakeup.ts": 4528, + "5423-stream-end-and-eos-timing.ts": 3712, + "5424-stream-write-buffer-encoding.ts": 3446, + "5425-pipeline-generator-stage.ts": 3465, + "5426-pipeline-generator-errors.ts": 4156, + "5427-pipeline-generator-backpressure.ts": 3689, + "5428-pipeline-generator-stages.cjs": 5519, + "5429-pipeline-generator-buffers.ts": 4449, + "5430-dyn-number-string-boxes.ts": 3851, + "5435-crypto-hash-algorithms.ts": 4090, + "5436-crypto-hash-names.js": 3513, + "5437-crypto-hmac-algorithms.ts": 3873, + "5438-crypto-kdf-digests.ts": 4076, + "5439-crypto-kdf-callbacks.js": 3741, + "5440-crypto-hash-encodings.js": 5108, + "5441-crypto-hash-output-length.ts": 5257, + "5442-crypto-random-values.ts": 4596, + "5443-crypto-random-arguments.js": 4093, + "5444-crypto-timing-safe-equal.js": 3904, + "5445-crypto-secret-key-objects.ts": 3885, + "5445-stream-buffer-chunks.ts": 4371, + "5446-crypto-secret-key-errors.js": 3542, + "5446-stream-buffer-chunks-dynamic.js": 5530, + "5447-fs-readdir-order.ts": 3865, + "5448-fs-glob-patterns.ts": 3617, + "5449-fs-glob-options.ts": 4047, + "5450-fs-glob-validation.js": 4514, + "5451-fs-promises-glob.ts": 4041, + "5452-fs-glob-callback.ts": 3311, + "5455-power-of-two-remainder.ts": 3496, + "5456-remainder-large-integer-dividends.ts": 3106, + "5457-lcg-modulus.ts": 3217, + "5458-fractional-remainder.ts": 3231, + "5460-locale-compare-contractions.ts": 4279, + "5461-locale-compare-equivalents.ts": 4168, + "5462-locale-compare-probe-sweep.ts": 5118, + "5463-locale-compare-combining-letters.ts": 4089, + "5464-locale-compare-fractions.ts": 3465, + "5465-dyn-index-read-arrays.ts": 2910, + "5466-dyn-index-read-special.ts": 3472, + "5470-strip-vt-osc.cjs": 2950, + "5471-strip-vt-csi.cjs": 3252, + "5472-strip-vt-random.cjs": 3939, + "5473-strip-vt-unterminated.cjs": 4153, + "5474-strip-vt-surrogates.ts": 3689, + "5510-assert-error-properties.js": 3848, + "5511-assert-error-class.ts": 3354, + "5512-assert-error-options.js": 3961, + "5513-assert-deep-equal-loose.js": 4575, + "5514-assert-deep-equal-typed.ts": 4346, + "5515-assert-deep-strict-typed-messages.ts": 3857, + "5516-assert-deep-equal-edges.js": 4060, + "5517-assert-partial-deep-equal.js": 4428, + "5518-assert-partial-deep-typed.ts": 4540, + "5519-assert-partial-deep-typed-edges.ts": 4298, + "5520-assert-record-literal-failures.ts": 4043, + "5520-dyn-property-read-receivers.ts": 3946, + "5521-assert-empty-message.js": 4460, + "5521-dyn-property-read-keys.ts": 3510, + "5522-assert-throws-failure-properties.ts": 3814, + "5523-assert-class-options.js": 4920, + "5524-assert-class-skip-prototype.ts": 3993, + "5530-buffer-pool.ts": 4954, + "5531-buffer-pool-first-slab.ts": 4419, + "5532-buffer-pool-first-slab-untyped.mjs": 156958, + "5540-fs-callback-forms.cjs": 5033, + "5541-fs-stats-fields.cjs": 5031, + "5542-fs-promises-parity.cjs": 3782, + "5543-fs-promises-typed.ts": 4425, + "5544-fs-opendir.cjs": 4598, + "5545-fs-options-encoding.cjs": 3812, + "5546-fs-read-stream.cjs": 4053, + "5547-fs-write-stream.cjs": 5026, + "5548-fs-callback-arguments.cjs": 3447, + "5549-fs-callback-option-checks.cjs": 4220, + "5550-locale-compare-ascii-words.ts": 3391, + "5551-array-search-references.ts": 4559, + "5552-string-appends.ts": 3836, + "5553-string-append-char-code.ts": 3220, + "5554-fs-streams-typed.ts": 4826, + "5555-fs-callback-turns.cjs": 4160, + "5555-http-server-close-keep-alive.ts": 16562, + "5556-http-client-agent-connection.ts": 7869, + "5557-http-outgoing-header-values.ts": 4486, + "5558-http-incoming-duplicate-headers.ts": 3277, + "5559-http-expect-header.ts": 13540, + "5560-http-response-framing.ts": 11999, + "5561-http-max-header-size.ts": 4546, + "5562-https-verify-errors.ts": 5339, + "5563-http-keep-alive-timeout.ts": 18223, + "5564-http-request-signal.ts": 6038, + "5565-fs-dirent-untyped.mjs": 4190, + "5566-fs-dirent-dyn-boundaries/main.mjs": 4370, + "5567-fs-cpsync.ts": 4231, + "5568-fs-cp-errors.js": 4710, + "5569-fs-cp-symlinks.ts": 3975, + "5570-fs-cp-async.ts": 4871, + "5571-fs-cp-deep.ts": 4651, + "5585-record-results-inlined.ts": 3799, + "5595-net-ref-unref.ts": 2930, + "5600-dyn-cycle-self.ts": 2377, + "5601-dyn-cycle-mutual.ts": 3087, + "5602-dyn-cycle-arrays.ts": 3074, + "5603-dyn-cycle-identity.ts": 3151, + "5604-dyn-cycle-checks.ts": 4016, + "5605-dyn-cycle-containers.ts": 4827, + "5606-dyn-cycle-capsules.ts": 3409, + "5610-readable-from-sets-and-views.ts": 6055, + "5611-readable-from-class-iterables.ts": 4787, + "5612-readable-from-iterables.cjs": 4888, + "5613-readable-from-iterable-timing.cjs": 4572, + "5614-readable-from-iterable-errors.cjs": 4862, + "5615-next-tick-callback-phases.ts": 4035, + "5616-next-tick-callback-phases.cjs": 3650, + "5617-pipeline-function-ends.ts": 55330, + "5618-pipeline-function-ends-errors.ts": 9347, + "5619-pipeline-function-ends.cjs": 5502, + "5620-timers-promises-values.ts": 3441, + "5621-util-format-float.ts": 4023, + "5622-events-once.mjs": 2752, + "5623-events-once.ts": 3430, + "5624-timers-promises-unawaited.ts": 3337, + "5625-promisify-exec.ts": 7797, + "5626-promisify-forms.ts": 2892, "5627-exec-callback.ts": 2500, + "5628-promisify-timers.ts": 4069, + "5629-promisify-stream.ts": 4133, + "5630-promisify-zlib.ts": 3777, "5631-promisify-crypto.ts": 2600, "5632-promisify-dns.ts": 2000, - "5644-net-socket-addresses.ts": 2393, - "5645-net-socket-callbacks.ts": 2060, - "5646-net-server-connections.ts": 2755, - "5647-net-is-ip.ts": 2560, - "5648-dns-lookup-forms.ts": 3416, - "5649-dns-service-servers.ts": 4916, - "5650-dns-lookup-errors-untyped.cjs": 3889, - "5681-array-pop-and-length.ts": 3216, - "5800-broadcast-channel.ts": 28374, - "5801-broadcast-channel.cjs": 27251, - "5802-broadcast-channel-workers.ts": 27251, - "5803-worker-environment-data.ts": 29298, - "5804-worker-environment-data.cjs": 26404, - "5805-worker-receive-message-parent-port.ts": 30268, - "5806-worker-resource-limits.ts": 29711, - "5807-worker-error-values.ts": 35248, - "5808-worker-unhandled-rejections.ts": 33209, - "5809-process-exit-and-rejections.cjs": 30261, - "5810-mock-method-records.ts": 6363, - "5811-mock-tracker-restore.ts": 4503, - "5812-dyn-box-async-fields.ts": 5278, - "5813-mock-timers-module.ts": 4227, - "5814-mock-timers-date.ts": 17708, - "5831-util-types-brands.ts": 4380, - "5832-util-types-brands-dynamic.js": 3658, - "5833-url-search-params-iterators.ts": 5339, - "5834-url-search-params-iterators-dynamic.mjs": 3797, - "5835-util-format-integer-specifiers.ts": 2768, - "5836-url-search-params-tuple-pairs.ts": 3193, - "5837-util-format-json-circular.ts": 3408, - "5838-qs-stringify-bigint.ts": 3519, - "5841-json-typed-dyn-members.ts": 3238, - "5842-qs-parse-null-prototype.ts": 7077, - "5843-qs-parse-null-prototype-js.mjs": 5395, - "5844-date-unknown-values.ts": 4543, + "5644-net-socket-addresses.ts": 3299, + "5645-net-socket-callbacks.ts": 4363, + "5646-net-server-connections.ts": 4089, + "5647-net-is-ip.ts": 3406, + "5648-dns-lookup-forms.ts": 4891, + "5649-dns-service-servers.ts": 4574, + "5650-dns-lookup-errors-untyped.cjs": 4634, + "5651-tls-socket-protocol.ts": 4232, + "5652-http-client-trailer-overflow.ts": 3846, + "5653-net-socket-read-ahead.ts": 5725, + "5654-https-empty-servername.ts": 5753, + "5655-dgram-socket-options.ts": 5148, + "5656-dgram-option-states.ts": 4307, + "5657-net-reset-and-address.ts": 3700, + "5658-net-reset-dynamic.cjs": 3925, + "5659-net-blocklist-socketaddress.ts": 4339, + "5664-tls-client-identity.ts": 5675, + "5674-union-instanceof-array-arms.ts": 4342, + "5680-array-growth-after-copy.ts": 5326, + "5681-array-pop-and-length.ts": 4603, + "5682-publish-wide-objects.ts": 2847, + "5700-cycle-release-retained.ts": 2881, + "5701-cycle-release-old-edges.ts": 2910, + "5702-publish-candidate-buffers.ts": 3240, + "5703-lifetime-region-debug.ts": 2720, + "5704-publish-refused-restores-counts.ts": 3978, + "5710-map-number-keys-hashed.ts": 4622, + "5711-map-number-write-after-read.ts": 4051, + "5712-map-number-overwrite-at-growth.ts": 3797, + "5714-cycle-large-candidate-buffers.ts": 5014, + "5715-json-parse-fitted-tables.ts": 4538, + "5717-set-prototype-of-primitives.ts": 3446, + "5719-int32-fields-dynamic-operators.ts": 3704, + "5720-intern-table-basics.ts": 4156, + "5721-intern-table-values.ts": 4709, + "5722-intern-table-workers.ts": 39327, + "5723-intern-table-shared-types.ts": 5477, + "5724-intern-table-array-keys.ts": 5614, + "5725-intern-table-callbacks.ts": 3793, + "5726-intern-table-key-limits.ts": 4034, + "5740-atomics-operation-semantics.ts": 3727, + "5741-atomics-contended-counters.ts": 24517, + "5742-atomics-lock-ordering.ts": 5553, + "5743-atomics-wait-notify.ts": 29359, + "5744-atomics-ring-buffer.ts": 32353, + "5745-atomics-semaphore-stress.ts": 39374, + "5746-shared-bulk-operations.ts": 4179, + "5747-fs-stat-throw-if-no-entry.ts": 3952, + "5748-fs-stat-throw-if-no-entry-js.cjs": 4210, + "5752-string-number-concat.ts": 2959, + "5760-crypto-hash-stream.ts": 3973, + "5761-crypto-hash-stream-states.ts": 3637, + "5762-crypto-hash-stream.cjs": 3895, + "5763-crypto-sha-blocks.ts": 3916, + "5764-class-structural-view-writes.ts": 4447, + "5764-crypto-hmac-edges.cjs": 3134, + "5765-class-structural-view-identity.ts": 3804, + "5766-class-structural-view-callbacks.ts": 3899, + "5767-class-opaque-accessor-view.ts": 3629, + "5776-power-of-two-remainder-integer-path.ts": 4355, + "5780-readline-history-options.ts": 2574, + "5781-readline-history-options.cjs": 2685, + "5782-readline-terminal-editing.ts": 7458, + "5783-readline-terminal-completion.cjs": 9987, + "5784-readline-terminal-promises.ts": 7899, + "5785-readline-terminal-keys.ts": 8463, + "5786-readline-terminal-history.cjs": 4186, + "5787-readline-cursor-helpers.cjs": 4616, + "5788-readline-promises-readline.ts": 4151, + "5789-readline-cursor-pos.cjs": 8106, + "5790-readline-keypress-events.ts": 4768, + "5791-dyn-constant-key-read-sites.ts": 3912, + "5791-readline-keypress-interfaces.cjs": 4765, + "5792-json-parse-repeated-layouts.ts": 4527, + "5792-readline-keypress-listeners.ts": 5406, + "5793-worker-message-channel.ts": 5212, + "5794-worker-message-port-close-order.ts": 4655, + "5795-worker-message-port-batches.ts": 3502, + "5796-worker-message-channel.cjs": 4995, + "5797-worker-message-port-transfer.ts": 23371, + "5800-broadcast-channel.ts": 4829, + "5801-broadcast-channel.cjs": 36650, + "5802-broadcast-channel-workers.ts": 3203, + "5803-worker-environment-data.ts": 6261, + "5804-worker-environment-data.cjs": 3356, + "5805-worker-receive-message-parent-port.ts": 3933, + "5806-worker-resource-limits.ts": 22085, + "5807-worker-error-values.ts": 5689, + "5808-worker-unhandled-rejections.ts": 6775, + "5809-process-exit-and-rejections.cjs": 38724, + "5810-mock-method-records.ts": 6060, + "5811-mock-tracker-restore.ts": 5297, + "5812-dyn-box-async-fields.ts": 4153, + "5813-mock-timers-module.ts": 3845, + "5814-mock-timers-date.ts": 10489, + "5830-timers-promises-signal.ts": 5868, + "5831-util-types-brands.ts": 3846, + "5832-util-types-brands-dynamic.js": 3912, + "5833-url-search-params-iterators.ts": 3034, + "5834-url-search-params-iterators-dynamic.mjs": 3877, + "5835-util-format-integer-specifiers.ts": 2899, + "5836-url-search-params-tuple-pairs.ts": 2897, + "5837-util-format-json-circular.ts": 2745, + "5838-qs-stringify-bigint.ts": 2868, + "5839-timers-promises-scheduler.ts": 3136, + "5840-promise-with-resolvers-js.js": 2701, + "5841-json-typed-dyn-members.ts": 4508, + "5842-qs-parse-null-prototype.ts": 3749, + "5843-qs-parse-null-prototype-js.mjs": 3308, + "5844-date-unknown-values.ts": 3966, + "5845-groupby-null-prototype.ts": 3946, "5846-events-esm-default-max.ts": 3102, "5847-events-cjs-default-max.cjs": 3039, - "5857-regexp-unicode-sets.ts": 3900, - "5858-disposable-stack.ts": 3750, - "5859-disposable-stack-js.js": 3600, - "5870-worker-thread-names.ts": 31697, - "5871-worker-untransferable.cjs": 27481, - "5874-worker-stdio-streams.ts": 27801, - "5875-worker-stdout-pipe.cjs": 31391, - "5879-worker-stdin.ts": 33232, - "5881-inspect-weak-collections.ts": 2915, - "5882-string-decoder-runtime-encoding.ts": 3854, - "5883-os-set-priority.ts": 3417, - "5884-inspect-layout-options.ts": 3596, - "5886-inspect-dates.ts": 2736, - "5887-inspect-typed-arrays.ts": 2997, - "5888-inspect-sorted.ts": 2861, - "5900-float16-array.ts": 3750, - "5901-float16-array-js.js": 3700, - "5904-async-generator-completion.ts": 3800, - "5905-array-from-async-generator.ts": 3500, - "5906-array-from-async-generator-js.js": 3750, + "5849-class-view-observations.ts": 3234, + "5850-using-disposable-values.ts": 3491, + "5851-using-suppressed-error-values.ts": 4335, + "5852-using-disposable-values-js.js": 3438, + "5853-set-methods-map-arguments.ts": 3861, + "5854-array-from-async.ts": 4644, + "5855-array-from-async-js.js": 3880, + "5856-error-is-error.ts": 3947, + "5857-regexp-unicode-sets.ts": 3156, + "5858-disposable-stack.ts": 4000, + "5859-disposable-stack-js.js": 4197, + "5860-url-ipv4-hosts.ts": 3379, + "5870-worker-thread-names.ts": 5388, + "5871-worker-untransferable.cjs": 38904, + "5872-readline-positional-create-interface.mjs": 4683, + "5873-readline-promises-namespace.cjs": 3786, + "5874-worker-stdio-streams.ts": 8408, + "5875-worker-stdout-pipe.cjs": 36125, + "5879-worker-stdin.ts": 56815, + "5880-emitter-leak-warning-delivery.ts": 3928, + "5881-inspect-weak-collections.ts": 3161, + "5882-string-decoder-runtime-encoding.ts": 3686, + "5883-os-set-priority.ts": 2593, + "5884-inspect-layout-options.ts": 3958, + "5885-events-max-listener-helpers.ts": 3524, + "5886-inspect-dates.ts": 3606, + "5887-inspect-typed-arrays.ts": 3660, + "5888-inspect-sorted.ts": 2960, + "5889-timers-scheduler-signal.ts": 3671, + "5890-while-string-length-counters.ts": 3347, + "5892-buffer-write-utf16le-runs.ts": 3722, + "5900-float16-array.ts": 3748, + "5901-float16-array-js.js": 3979, + "5904-async-generator-completion.ts": 6741, + "5905-array-from-async-generator.ts": 4080, + "5906-array-from-async-generator-js.js": 3999, "5907-regex-groups-match-rows.ts": 3750, - "5910-set-prototype-of-primitive-object-kinds.ts": 5033, - "5911-dyn-class-to-primitive.ts": 4732, - "5912-dyn-class-conversion-methods.ts": 4424, - "5913-prototype-type-error-messages.ts": 4068, - "5914-dyn-in-class-prototype-members.ts": 4327, - "5915-dyn-error-string-conversions.ts": 4247, - "5922-matchall-groups-callbacks.ts": 5960, - "5923-matchall-groups-js.js": 6650, + "5910-set-prototype-of-primitive-object-kinds.ts": 4285, + "5911-dyn-class-to-primitive.ts": 6260, + "5912-dyn-class-conversion-methods.ts": 4623, + "5913-prototype-type-error-messages.ts": 3542, + "5914-dyn-in-class-prototype-members.ts": 2963, + "5915-dyn-error-string-conversions.ts": 2860, + "5920-promise-try-args.ts": 2731, + "5921-promise-try-args-js.js": 2533, + "5922-matchall-groups-callbacks.ts": 4812, + "5923-matchall-groups-js.js": 4191, + "5924-js-literal-identity.js": 2661, + "5925-class-view-identity-observers.ts": 2640, + "5926-class-view-switch-js.js": 2843, + "5927-switch-object-identity.ts": 3333, + "5928-groupby-iterables.ts": 4581, + "5929-groupby-js.js": 3288, + "5930-contract-int32-arrays.ts": 4209, + "5930-method-census-asserted-number-keys.ts": 3405, + "5931-asserted-reads-keep-number-parameters.ts": 3441, + "5932-generic-class-observed-methods.ts": 4594, + "5933-class-fields-unknown-object.ts": 4036, + "5934-js-class-fields-property-order.js": 4840, + "5935-js-subclass-fields-and-element-calls.js": 4505, + "5936-checked-js-class-types.js": 3902, + "5937-override-narrowed-union-returns.ts": 3617, "5938-object-literal-computed-keys-keep-methods.ts": 7194, - "5939-js-let-object-reassigned-wider.js": 4436, + "5939-js-let-object-reassigned-wider.js": 3070, + "5940-callback-helper-specialization.ts": 5355, + "5941-callback-specialization-recursion.ts": 4385, + "5942-callback-specialization-throws.ts": 3535, "5943-fields-read-before-assignment.ts": 72293, "5944-js-fields-read-before-assignment.js": 40310, "5945-local-class-observed-methods.ts": 6212, "5946-nested-record-field-optional-writes.ts": 68117, - "5950-tuple-predicate-methods.ts": 7790, - "5951-result-never-widening.ts": 6120, + "5950-tuple-predicate-methods.ts": 5999, + "5951-result-never-widening.ts": 3370, "5952-record-missing-keys.ts": 20400, "5953-nan-coded-method-returns.ts": 15600, - "5955-any-promise-methods.js": 5120, - "5956-erased-generic-members.ts": 8750, - "5958-asserted-union-receiver.ts": 3160, - "5959-date-to-json.ts": 4330, - "5960-generic-mapped-types.ts": 3300, - "5970-net-connect-host-name.ts": 2800, - "5971-buffer-chunks-to-string.ts": 3100, - "5972-net-set-encoding-listeners.ts": 3000, - "5974-typeof-module-exports.cjs": 2500, + "5955-any-promise-methods.js": 3616, + "5956-erased-generic-members.ts": 6191, + "5958-asserted-union-receiver.ts": 2929, + "5959-date-to-json.ts": 2856, + "5960-generic-mapped-types.ts": 3526, + "5970-net-connect-host-name.ts": 2998, + "5971-buffer-chunks-to-string.ts": 3483, + "5972-net-set-encoding-listeners.ts": 7935, + "5974-typeof-module-exports.cjs": 2121, "5975-zlib-class-values.ts": 4200, - "5990-worker-uncloneable.mjs": 22432, - "5991-worker-async-dispose.mjs": 25768, - "5992-worker-thread-name-lifetime.mjs": 28932, - "600-closures-basic.ts": 2534, - "601-closures-loops.ts": 2297, - "602-closures-identity-recursion.ts": 2427, - "6020-class-extends-function-constructor.js": 7500, + "5990-worker-uncloneable.mjs": 37308, + "5991-worker-async-dispose.mjs": 7506, + "5992-worker-thread-name-lifetime.mjs": 44550, + "600-closures-basic.ts": 3477, + "601-closures-loops.ts": 2866, + "602-closures-identity-recursion.ts": 3704, + "6020-class-extends-function-constructor.js": 3671, "6021-asserted-literal-union-arm.ts": 7200, - "603-closures-rc-stress.ts": 2589, - "604-closures-for-of.ts": 3514, - "605-closures-forward-capture-tdz.ts": 4638, - "700-classes-basic.ts": 2674, - "701-classes-composition.ts": 2606, - "702-classes-this-capture.ts": 2403, - "703-classes-rc-stress.ts": 3477, - "710-inheritance-basics.ts": 2972, - "711-inheritance-dispatch.ts": 2507, - "712-inheritance-instanceof.ts": 2847, - "713-inheritance-rc-stress.ts": 3484, - "720-accessors-basics.ts": 3144, - "721-accessors-eval-order.ts": 3241, - "722-accessors-inheritance.ts": 3694, - "723-accessors-rc-stress.ts": 2838, - "750-cycle-closure-box.ts": 3262, - "751-cycle-records-mutual.ts": 3163, - "752-cycle-classes.ts": 2239, - "753-cycle-owned-arrays.ts": 2204, - "754-cycle-external-ref.ts": 2593, - "755-cycle-async-promise.ts": 3154, - "756-cycle-inheritance.ts": 2213, - "757-cycle-cross-generation.ts": 3118, - "762-any-boundary.ts": 3063, - "764-any-async.ts": 3129, - "765-any-optional-chain.ts": 3899, - "766-any-union-boundary.ts": 3346, - "767-string-literal-keys.ts": 2340, - "768-any-uninitialized.ts": 2983, - "800-switch-basics.ts": 3128, - "801-switch-lazy-tests.ts": 2842, - "802-switch-loops.ts": 3486, - "803-switch-rc-stress.ts": 2321, - "804-switch-braced-blocks.ts": 3234, - "810-do-while.ts": 3326, - "820-multi-decl.ts": 2338, - "830-let-uninitialized.ts": 2579, - "900-records-basics.ts": 3473, - "901-records-eval-order.ts": 2890, - "902-records-functions-closures.ts": 3085, - "903-records-rc-stress.ts": 3146, - "904-records-optional-fields.ts": 2930, - "905-records-optional-rc-stress.ts": 2986, - "906-records-utility-types.ts": 2822, - "907-records-utility-generics.ts": 3048, - "908-records-index-signatures.ts": 2695, - "909-records-index-json.ts": 3037, - "910-records-index-rc-stress.ts": 2958, - "911-records-index-dot-access.ts": 4686, - "912-unknown-slots.ts": 3359, - "913-records-index-iteration.ts": 3265, - "914-records-from-entries.ts": 3414, - "915-unknown-tostring-eq.ts": 3349, - "916-unknown-bytes.ts": 3729, - "917-record-array-index-dot.ts": 3331, - "950-modules-basic/main.ts": 2717, - "951-modules-diamond/main.ts": 2315, - "952-modules-cross/main.ts": 2751, - "953-modules-default/main.ts": 3300, - "954-modules-reexport/main.ts": 2770, - "957-builtins-namespace.ts": 2759, - "960-generics-basics.ts": 3631, - "961-generics-recursion.ts": 3262, - "962-generics-closures.ts": 2245, - "963-generics-modules/main.ts": 2769, - "964-generics-rc-stress.ts": 3123, - "965-generics-async.ts": 3925, - "965-unions-retag.ts": 3882, - "966-unions-retag-rc-stress.ts": 3167, - "967-record-field-widening.ts": 2827, - "969-unions-arm-matrix.ts": 3297, - "970-unions-basics.ts": 3439, - "971-unions-switch.ts": 3593, - "972-unions-nested.ts": 2812, - "973-unions-rc-stress.ts": 2567, - "974-unions-modules/main.ts": 2485, - "975-unions-undefined.ts": 2505, - "976-unions-null.ts": 3528, - "977-unions-unit-rc-stress.ts": 2503, - "978-unions-nullish.ts": 2591, - "979-unions-optional-chaining.ts": 2499, - "980-exceptions-basics.ts": 2297, - "981-exceptions-values.ts": 3503, - "982-exceptions-rc-stress.ts": 3146, - "983-exceptions-control-flow.ts": 2518, - "984-exceptions-finally.ts": 2504, - "985-exceptions-call-chains.ts": 3540, - "986-exceptions-uncaught.ts": 3473, - "987-exceptions-result-unions.ts": 3527, - "990-process-basics.ts": 3510, - "991-process-exit.ts": 2297, - "992-fs-roundtrip.ts": 2694, - "993-fs-readdir.ts": 3781, - "994-fs-errors.ts": 2370, - "995-fs-uncaught.ts": 2239, - "996-fs-rc-stress.ts": 2822, - "997-fs-modules/main.ts": 2578, - "998-process-env.ts": 2181, - "abstract-property-dispatch.ts": 2739, - "arguments-arrow-capture.mjs": 3039, - "arguments-reexport/main.ts": 2635, - "array-argument-lifetimes-exits.ts": 3136, - "array-argument-lifetimes-mutation.ts": 3333, - "array-argument-lifetimes-strings.ts": 3015, - "array-argument-lifetimes-values.ts": 3223, - "array-buffer-conversions.js": 2594, - "array-buffer-storage.ts": 3699, - "array-checked-callback-results.mjs": 3402, - "array-checked-constructor.js": 3477, - "array-concat-widening.ts": 3858, - "array-element-compound-updates.ts": 3591, - "array-fill-unit-values.ts": 2572, - "array-from-checked.js": 3097, - "array-from-value.mjs": 3428, - "array-isarray-value/main.js": 3143, - "array-numeric-own-keys.ts": 3632, - "array-optional-number-write-index.ts": 3380, - "array-primitive-ordering.ts": 3925, - "array-read-helper-effects.ts": 3425, - "array-refined-storage.ts": 3909, - "array-sort-dense-effects.ts": 2917, - "array-sort-dense-values.ts": 5261, - "array-sort-holes-published.ts": 13040, - "array-sort-runs.ts": 10059, - "array-sort-runtime-comparator.ts": 5498, - "array-sort-unknown-comparator.ts": 2858, - "array-storage-transitions.ts": 2799, - "array-truncate-reuse.ts": 2407, - "async-backend-factory.mjs": 3609, - "async-local-typed-results.ts": 2487, - "atomics-integer-operations.ts": 3832, - "bigint-checked-casts.ts": 3603, - "bigint-checked-storage.js": 3992, - "bigint-union-conversion.ts": 3125, - "boxed-error-rethrows.mjs": 2646, - "buffer-codec-boundaries.ts": 3139, - "buffer-primitive-predicate.ts": 3495, - "builtin-prototype-method-values.mjs": 4297, - "byte-loop-bounds.ts": 3001, - "byte-number-pipeline.ts": 3966, - "byte-record-windows.ts": 3749, - "call-lifetimes-argument-order.ts": 2794, - "call-lifetimes-control-flow.ts": 3894, - "call-lifetimes-owned-boundaries.ts": 3881, - "call-lifetimes-projections.ts": 3082, - "call-lifetimes-union-values.ts": 3090, + "603-closures-rc-stress.ts": 3096, + "604-closures-for-of.ts": 3045, + "605-closures-forward-capture-tdz.ts": 3323, + "700-classes-basic.ts": 2577, + "701-classes-composition.ts": 3154, + "702-classes-this-capture.ts": 2733, + "703-classes-rc-stress.ts": 3485, + "710-inheritance-basics.ts": 3238, + "711-inheritance-dispatch.ts": 3078, + "712-inheritance-instanceof.ts": 3534, + "713-inheritance-rc-stress.ts": 3301, + "720-accessors-basics.ts": 3158, + "721-accessors-eval-order.ts": 2971, + "722-accessors-inheritance.ts": 3316, + "723-accessors-rc-stress.ts": 3170, + "750-cycle-closure-box.ts": 2126, + "751-cycle-records-mutual.ts": 2363, + "752-cycle-classes.ts": 1960, + "753-cycle-owned-arrays.ts": 2692, + "754-cycle-external-ref.ts": 2903, + "755-cycle-async-promise.ts": 3043, + "756-cycle-inheritance.ts": 2972, + "757-cycle-cross-generation.ts": 2984, + "762-any-boundary.ts": 2786, + "764-any-async.ts": 3084, + "765-any-optional-chain.ts": 3008, + "766-any-union-boundary.ts": 3499, + "767-string-literal-keys.ts": 3514, + "768-any-uninitialized.ts": 3560, + "800-switch-basics.ts": 2767, + "801-switch-lazy-tests.ts": 2686, + "802-switch-loops.ts": 3125, + "803-switch-rc-stress.ts": 3547, + "804-switch-braced-blocks.ts": 2839, + "810-do-while.ts": 2218, + "820-multi-decl.ts": 3261, + "830-let-uninitialized.ts": 3097, + "900-records-basics.ts": 3422, + "901-records-eval-order.ts": 2695, + "902-records-functions-closures.ts": 3207, + "903-records-rc-stress.ts": 2631, + "904-records-optional-fields.ts": 2009, + "905-records-optional-rc-stress.ts": 2569, + "906-records-utility-types.ts": 3252, + "907-records-utility-generics.ts": 3311, + "908-records-index-signatures.ts": 3591, + "909-records-index-json.ts": 3947, + "910-records-index-rc-stress.ts": 3536, + "911-records-index-dot-access.ts": 3503, + "912-unknown-slots.ts": 3313, + "913-records-index-iteration.ts": 4350, + "914-records-from-entries.ts": 3768, + "915-unknown-tostring-eq.ts": 2630, + "916-unknown-bytes.ts": 3440, + "917-record-array-index-dot.ts": 3157, + "950-modules-basic/main.ts": 2848, + "951-modules-diamond/main.ts": 3198, + "952-modules-cross/main.ts": 3183, + "953-modules-default/main.ts": 3167, + "954-modules-reexport/main.ts": 2018, + "957-builtins-namespace.ts": 3430, + "960-generics-basics.ts": 3705, + "961-generics-recursion.ts": 2537, + "962-generics-closures.ts": 3548, + "963-generics-modules/main.ts": 2784, + "964-generics-rc-stress.ts": 3384, + "965-generics-async.ts": 2822, + "965-unions-retag.ts": 3386, + "966-unions-retag-rc-stress.ts": 2717, + "967-record-field-widening.ts": 2715, + "969-unions-arm-matrix.ts": 3012, + "970-unions-basics.ts": 2986, + "971-unions-switch.ts": 3685, + "972-unions-nested.ts": 3090, + "973-unions-rc-stress.ts": 3424, + "974-unions-modules/main.ts": 3121, + "975-unions-undefined.ts": 2840, + "976-unions-null.ts": 2783, + "977-unions-unit-rc-stress.ts": 3216, + "978-unions-nullish.ts": 3540, + "979-unions-optional-chaining.ts": 3197, + "980-exceptions-basics.ts": 3555, + "981-exceptions-values.ts": 3193, + "982-exceptions-rc-stress.ts": 2933, + "983-exceptions-control-flow.ts": 3085, + "984-exceptions-finally.ts": 3513, + "985-exceptions-call-chains.ts": 2381, + "986-exceptions-uncaught.ts": 2898, + "987-exceptions-result-unions.ts": 2879, + "990-process-basics.ts": 3199, + "991-process-exit.ts": 3081, + "992-fs-roundtrip.ts": 2369, + "993-fs-readdir.ts": 3082, + "994-fs-errors.ts": 3422, + "995-fs-uncaught.ts": 3294, + "996-fs-rc-stress.ts": 3471, + "997-fs-modules/main.ts": 2673, + "998-process-env.ts": 3051, + "abstract-property-dispatch.ts": 3176, + "arguments-arrow-capture.mjs": 3073, + "arguments-reexport/main.ts": 2672, + "array-argument-lifetimes-exits.ts": 3589, + "array-argument-lifetimes-mutation.ts": 3438, + "array-argument-lifetimes-strings.ts": 3059, + "array-argument-lifetimes-values.ts": 3883, + "array-buffer-conversions.js": 2989, + "array-buffer-storage.ts": 3822, + "array-checked-callback-results.mjs": 3408, + "array-checked-constructor.js": 3489, + "array-concat-widening.ts": 3866, + "array-deque-unshift.ts": 2667, + "array-element-compound-updates.ts": 5084, + "array-fill-unit-values.ts": 3524, + "array-from-checked.js": 4344, + "array-from-value.mjs": 3171, + "array-isarray-value/main.js": 2914, + "array-numeric-own-keys.ts": 3622, + "array-optional-number-write-index.ts": 2652, + "array-primitive-ordering.ts": 4006, + "array-queue-head-room.ts": 3597, + "array-read-helper-effects.ts": 3562, + "array-refined-storage.ts": 4149, + "array-sort-dense-effects.ts": 4479, + "array-sort-dense-values.ts": 4819, + "array-sort-holes-published.ts": 7708, + "array-sort-runs.ts": 7566, + "array-sort-runtime-comparator.ts": 6150, + "array-sort-unknown-comparator.ts": 2544, + "array-storage-transitions.ts": 3926, + "array-truncate-reuse.ts": 3660, + "async-backend-factory.mjs": 3134, + "async-local-typed-results.ts": 3527, + "atomics-integer-operations.ts": 4356, + "bigint-checked-casts.ts": 2554, + "bigint-checked-storage.js": 3784, + "bigint-union-conversion.ts": 3322, + "boxed-error-rethrows.mjs": 2897, + "buffer-codec-boundaries.ts": 3387, + "buffer-primitive-predicate.ts": 3237, + "builtin-prototype-method-values.mjs": 3628, + "byte-loop-bounds.ts": 3700, + "byte-number-pipeline.ts": 3420, + "byte-record-windows.ts": 3513, + "call-lifetimes-argument-order.ts": 3157, + "call-lifetimes-control-flow.ts": 3596, + "call-lifetimes-owned-boundaries.ts": 3515, + "call-lifetimes-projections.ts": 2258, + "call-lifetimes-union-values.ts": 3157, "call-lifetimes-virtual-optionals.ts": 3774, - "callable-module-members.mjs": 2996, - "callable-properties.mjs": 3737, - "callable-property-cycles.js": 2394, - "callable-reexport/main.ts": 2995, - "captured-class-refinement.ts": 3815, - "catch-capture.ts": 2295, - "caught-class-identity.ts": 3893, - "caught-standalone-class.ts": 3591, - "caught-system-error-fields.ts": 3373, - "checked-addition.js": 3059, - "checked-any-addition.ts": 2638, - "checked-array-assignment.ts": 2861, - "checked-array-flat/main.ts": 2441, - "checked-bitwise/main.js": 3177, - "checked-builder-cycles.js": 3284, - "checked-byte-storage/main.ts": 3985, - "checked-callback-options.ts": 3034, - "checked-class-descriptors.mjs": 2786, - "checked-class-factory.mjs": 2348, - "checked-collection-iterators.ts": 3731, - "checked-collection-symbol-methods.ts": 3019, - "checked-dispatch-input-lifetimes.js": 3481, - "checked-increment/main.js": 2884, - "checked-inherited-fields.ts": 2756, - "checked-iterator-consumption.js": 4074, - "checked-numeric-arithmetic.js": 2874, - "checked-object-module-alias.js": 3204, - "checked-optional-calls.mjs": 2897, - "checked-promise-recovery.ts": 2819, - "checked-proxy-callback/main.ts": 3009, - "checked-record-constructor.ts": 3034, - "checked-renderer-defaults.js": 2935, - "checked-rest-function-adapters.js": 2965, - "checked-storage-transitions.js": 2510, - "checked-symbol-array.ts": 2504, - "checked-value-input-lifetimes.ts": 3033, - "class-accessor-returned-function.js": 2287, - "class-array-optional-return.ts": 3498, - "class-bracket-method-calls.js": 3071, - "class-brand-overload.js": 3526, - "class-callback-replacement.js": 3460, - "class-callback-storage.ts": 4585, - "class-checked-composites.ts": 3187, - "class-checked-upcast.ts": 3072, - "class-collection-insertion.ts": 4235, - "class-computed-presence.ts": 2974, - "class-computed-symbols.js": 3740, - "class-covariant-returns.ts": 3957, - "class-curried-factory.mjs": 4128, - "class-data-descriptors.js": 3270, - "class-factory-inherited-statics.mjs": 2538, - "class-factory-parameter-base.mjs": 2587, - "class-factory-record-base.mjs": 5836, - "class-factory-recursive-statics.mjs": 3651, - "class-factory-static-members.mjs": 3672, - "class-function-base/main.js": 2657, - "class-instance-constructor.js": 2942, - "class-interface-protocols.ts": 3713, - "class-interface-refinements.ts": 4567, - "class-json-checked.ts": 2571, - "class-local-function-base.mjs": 3643, - "class-method-spreads.ts": 3220, - "class-narrowed-views.ts": 3766, - "class-property-call-values.mjs": 3125, - "class-prototype-data.js": 4251, - "class-prototype-descriptor-copy.mjs": 3998, - "class-specialized-computed-base.mjs": 3397, - "class-static-data.js": 2157, - "class-subclass-assertions.ts": 3733, - "class-super-surplus-spread.mjs": 2301, - "class-symbol-accessors.ts": 2479, - "class-symbol-cache.mjs": 3721, - "class-value-constructor-exceptions.ts": 3210, - "closure-nullable-union-return.ts": 2727, - "closure-union-locals.ts": 2878, - "collection-array-cycles.ts": 3240, - "collection-array-maps.ts": 4497, - "collection-array-missing.ts": 3865, - "collection-array-sets.ts": 3087, - "collection-copy-identities.ts": 2655, - "collection-data-unions.ts": 2993, - "collection-ingestion-mappers.ts": 3305, - "collection-ingestion-protocol/main.ts": 5059, - "collection-ingestion-references.ts": 4238, - "collection-ingestion.ts": 3626, - "collection-storage-copies.ts": 4163, - "collection-value-keys.ts": 4167, - "compound-field-receivers.ts": 2877, - "compound-presence-guards.ts": 3145, - "conditional-tuple-destructuring.ts": 3213, - "console-imports.cjs": 2893, - "console-native-value.js": 2516, - "const-enum-module-cycle/main.ts": 3456, - "constant-callback-dispatch.ts": 2916, - "constant-module-globals/main.ts": 2911, - "constant-number-remainders.ts": 2372, - "constructed-class-dispatch.ts": 3382, - "contextual-array-union-write.ts": 6417, - "contextual-return-layouts.ts": 3746, - "counted-loop-numbers.ts": 2724, - "counted-loop-storage.ts": 2302, - "crypto-hash-optional-input.ts": 3311, - "cycle-generations-long-lived.ts": 3514, - "cycle-growth-yield.ts": 3352, - "date-checked-native.js": 2676, - "declared-index-spread.ts": 2941, - "deep-reference-teardown.ts": 4427, - "default-undefined-parameters.ts": 3232, - "deferred-field-updates.ts": 3345, - "deferred-registry-many.ts": 3072, - "derived-numeric-updates.ts": 2702, - "destructure-call-assignment.js": 2978, - "destructure-inferred-row-defaults.js": 3175, - "destructure-union-arrays.ts": 3248, - "dynamic-function-descriptors.js": 2750, - "error-cause-writes.js": 3104, - "error-inherited-message.mjs": 3024, - "error-inherited-name.mjs": 2500, - "error-property-writes.mjs": 3373, - "error-prototype-tostring.js": 3874, - "error-stack-frames.ts": 2418, - "error-stack-limit.ts": 2675, - "error-tostring-overrides.ts": 3246, - "error-values-inspect.ts": 3043, - "exact-index-round-trip.ts": 3701, - "expression-runtime-values.ts": 2154, - "fiber-switch-stress.ts": 5012, - "fiberless-async-ordering.ts": 3413, - "fiberless-async-unhandled.ts": 2739, - "field-assignment-values.ts": 2662, - "file-handle-values.ts": 3133, - "file-read-storage.ts": 3685, - "file-url-percent-decoding.ts": 2659, - "final-field-borrows.ts": 3350, - "for-multiple-bindings.ts": 3223, - "for-multiple-lexical-bindings.ts": 3021, - "for-of-checked-iterator.js": 3541, - "for-of-subclass-elements.ts": 3037, - "forward-generic-signatures.ts": 2999, - "fresh-array-union-layout.js": 2679, - "frozen-checked-dictionaries.mjs": 3220, - "fs-native-realpath.ts": 2477, - "fs-read-encodings.ts": 3111, - "fs-remove-readonly.ts": 2708, - "fs-write-string-bytes-union.ts": 2772, - "function-apply-value.mjs": 2976, - "function-constructor-global.mjs": 2229, - "function-constructor-kinds/main.js": 3064, - "function-custom-prototype.js": 3165, - "function-custom-to-string.mjs": 3379, - "function-object-assign.js": 3235, - "function-own-prototype/main.js": 2539, - "generator-checked-protocol.ts": 3197, - "generator-checked-return.js": 3544, - "generator-custom-delegation/main.ts": 3611, - "generator-default-return-pattern.ts": 3352, - "generator-delegation-values.ts": 3047, - "generator-inferred-date.js": 3314, - "generator-mixed-checked-channels.ts": 3576, - "generator-untyped-consumer/main.ts": 3225, - "generic-base-specializations.ts": 2247, - "generic-binding-ownership.ts": 3517, - "generic-class-js-functions/main.ts": 2300, - "generic-class-recovery.ts": 2961, - "generic-namespace-factories/main.ts": 3104, - "generic-nullable-collections.ts": 2983, - "generic-pattern-bindings.ts": 3518, - "generic-record-index.ts": 3239, - "generic-visitor-void.ts": 3402, - "global-error-subclasses.ts": 2754, - "global-runtime-probes.js": 2804, - "global-stored-probes.js": 3113, - "global-string-cache/main.js": 2090, - "global-symbol-cache/main.js": 3628, - "guarded-native-iterables.ts": 3327, - "heap-input-aliases.ts": 3457, - "heap-input-collections.ts": 3653, - "in-array-runtime-index.ts": 3275, - "indexed-assignment-values.js": 3011, - "indexed-assignment-values.ts": 2182, - "indexed-element-field-reads.ts": 3247, - "inferred-array-assignment-values.mjs": 2906, - "inferred-class-default.mjs": 2977, - "inferred-compound-values.mjs": 2759, - "inferred-conditional-class.mjs": 3292, - "inferred-error-fields.js": 3405, - "inferred-map-patterns.mjs": 2764, - "inferred-method-override.js": 2696, - "inferred-partial-destructuring.mjs": 2539, - "inferred-primitive-properties.mjs": 2255, - "inferred-record-return.mjs": 2589, - "inferred-recursive-record.mjs": 2186, - "inferred-undefined-field.mjs": 2551, - "input-lifetime-intervals.ts": 3191, - "input-lifetimes-modules/main.ts": 3221, - "instanceof-class-record-union.ts": 3279, - "integer-flow-arithmetic.ts": 3347, - "integer-loop-forms.ts": 2940, - "integer-view-control.ts": 2093, - "integer-view-numbers.ts": 2680, - "integer-view-storage.ts": 3947, - "intl-grapheme-conformance/main.ts": 5064, - "intl-grapheme.ts": 2412, - "iterator-typed-returns.ts": 3466, - "js-abort-portable.js": 4587, - "js-array-constructor.js": 3296, - "js-array-default-buffer.js": 3604, - "js-array-iterators.js": 3215, - "js-arrow-bind.cjs": 3596, - "js-buffer-callback-brand.cjs": 3526, - "js-callable-proxy.js": 3865, - "js-chained-native-results.mjs": 3076, - "js-checked-array-iterator.js": 2790, - "js-checked-array-reference.js": 2884, - "js-checked-number-negation.mjs": 2418, - "js-checked-sort-result.js": 2906, - "js-child-error-listener.cjs": 2538, - "js-cjs-callable-snapshots/main.cjs": 2461, - "js-class-added-parameters.js": 2522, - "js-class-checked-overrides.js": 2542, - "js-class-computed-fields.js": 2281, - "js-class-enumeration.js": 3084, - "js-class-field-accessor-override.js": 3865, - "js-class-fluent-overrides.js": 3368, - "js-class-late-method-values.js": 2526, - "js-class-member-dispatch.js": 3846, - "js-class-return-shapes.js": 2639, - "js-class-shadowed-methods.js": 2891, - "js-class-stored-method-receiver.js": 2685, - "js-class-subclass-properties.js": 3775, - "js-class-symbol-spread.cjs": 3550, - "js-computed-prototype-additions.js": 3462, - "js-constructor-returned-callable.js": 3346, + "callable-module-members.mjs": 3196, + "callable-properties.mjs": 3885, + "callable-property-cycles.js": 3532, + "callable-reexport/main.ts": 3427, + "captured-class-refinement.ts": 3597, + "catch-capture.ts": 2987, + "caught-class-identity.ts": 4072, + "caught-standalone-class.ts": 2672, + "caught-system-error-fields.ts": 3700, + "checked-addition.js": 3105, + "checked-any-addition.ts": 2239, + "checked-array-assignment.ts": 3049, + "checked-array-flat/main.ts": 3431, + "checked-bitwise/main.js": 3320, + "checked-builder-cycles.js": 2792, + "checked-byte-storage/main.ts": 3747, + "checked-callback-options.ts": 2687, + "checked-class-descriptors.mjs": 3712, + "checked-class-factory.mjs": 2771, + "checked-collection-iterators.ts": 3380, + "checked-collection-symbol-methods.ts": 2530, + "checked-dispatch-input-lifetimes.js": 3328, + "checked-increment/main.js": 3104, + "checked-inherited-fields.ts": 2621, + "checked-iterator-consumption.js": 4294, + "checked-numeric-arithmetic.js": 3111, + "checked-object-module-alias.js": 3420, + "checked-optional-calls.mjs": 3475, + "checked-promise-recovery.ts": 3214, + "checked-proxy-callback/main.ts": 2353, + "checked-record-constructor.ts": 3432, + "checked-renderer-defaults.js": 3283, + "checked-rest-function-adapters.js": 3083, + "checked-storage-transitions.js": 3622, + "checked-symbol-array.ts": 3310, + "checked-value-input-lifetimes.ts": 3545, + "class-accessor-returned-function.js": 3128, + "class-array-optional-return.ts": 2098, + "class-bracket-method-calls.js": 3772, + "class-brand-overload.js": 2492, + "class-callback-replacement.js": 4751, + "class-callback-storage.ts": 4435, + "class-checked-composites.ts": 2988, + "class-checked-upcast.ts": 3528, + "class-collection-insertion.ts": 3819, + "class-computed-presence.ts": 3069, + "class-computed-symbols.js": 4319, + "class-covariant-returns.ts": 2381, + "class-curried-factory.mjs": 4502, + "class-data-descriptors.js": 3422, + "class-factory-inherited-statics.mjs": 3137, + "class-factory-parameter-base.mjs": 3744, + "class-factory-record-base.mjs": 4712, + "class-factory-recursive-statics.mjs": 3419, + "class-factory-static-members.mjs": 3588, + "class-function-base/main.js": 3762, + "class-instance-constructor.js": 3074, + "class-interface-protocols.ts": 5102, + "class-interface-refinements.ts": 3720, + "class-json-checked.ts": 2934, + "class-local-function-base.mjs": 3255, + "class-method-spreads.ts": 4902, + "class-narrowed-views.ts": 3371, + "class-property-call-values.mjs": 4011, + "class-prototype-data.js": 3004, + "class-prototype-descriptor-copy.mjs": 3813, + "class-specialized-computed-base.mjs": 4267, + "class-static-data.js": 3151, + "class-subclass-assertions.ts": 3297, + "class-super-surplus-spread.mjs": 3182, + "class-symbol-accessors.ts": 3548, + "class-symbol-cache.mjs": 4032, + "class-value-constructor-exceptions.ts": 2673, + "closed-virtual-dispatch-modules/main.ts": 2555, + "closed-virtual-dispatch.ts": 3659, + "closure-nullable-union-return.ts": 3544, + "closure-union-locals.ts": 3476, + "collection-array-cycles.ts": 3864, + "collection-array-maps.ts": 4225, + "collection-array-missing.ts": 4159, + "collection-array-sets.ts": 4385, + "collection-copy-identities.ts": 2778, + "collection-data-unions.ts": 3634, + "collection-ingestion-mappers.ts": 3206, + "collection-ingestion-protocol/main.ts": 3833, + "collection-ingestion-references.ts": 3449, + "collection-ingestion.ts": 3258, + "collection-storage-copies.ts": 3108, + "collection-value-keys.ts": 4397, + "compound-field-receivers.ts": 3249, + "compound-presence-guards.ts": 2877, + "conditional-tuple-destructuring.ts": 2382, + "console-imports.cjs": 3167, + "console-native-value.js": 3394, + "const-enum-module-cycle/main.ts": 2006, + "constant-callback-dispatch.ts": 2991, + "constant-module-globals/main.ts": 2958, + "constant-number-remainders.ts": 3341, + "constructed-class-dispatch.ts": 2784, + "contextual-array-union-write.ts": 7276, + "contextual-return-layouts.ts": 3888, + "counted-loop-numbers.ts": 3637, + "counted-loop-storage.ts": 2691, + "crypto-hash-optional-input.ts": 3463, + "cycle-generations-long-lived.ts": 3441, + "cycle-growth-yield.ts": 3944, + "date-checked-native.js": 2845, + "declared-index-spread.ts": 4567, + "deep-reference-teardown.ts": 3926, + "default-undefined-parameters.ts": 3319, + "deferred-field-updates.ts": 3102, + "deferred-registry-many.ts": 3953, + "derived-numeric-updates.ts": 3389, + "destructure-call-assignment.js": 2983, + "destructure-inferred-row-defaults.js": 3512, + "destructure-union-arrays.ts": 2816, + "dynamic-function-descriptors.js": 3146, + "error-cause-writes.js": 3354, + "error-inherited-message.mjs": 3845, + "error-inherited-name.mjs": 2619, + "error-property-writes.mjs": 3158, + "error-prototype-tostring.js": 3672, + "error-stack-frames.ts": 3288, + "error-stack-limit.ts": 2624, + "error-tostring-overrides.ts": 3434, + "error-values-inspect.ts": 2196, + "exact-index-round-trip.ts": 3473, + "expression-runtime-values.ts": 3088, + "fiber-switch-stress.ts": 4040, + "fiberless-async-ordering.ts": 3692, + "fiberless-async-unhandled.ts": 2796, + "field-assignment-values.ts": 3175, + "file-handle-values.ts": 4245, + "file-read-storage.ts": 3850, + "file-url-percent-decoding.ts": 3346, + "final-field-borrows.ts": 4200, + "for-multiple-bindings.ts": 3350, + "for-multiple-lexical-bindings.ts": 2400, + "for-of-checked-iterator.js": 2766, + "for-of-subclass-elements.ts": 3269, + "forward-generic-signatures.ts": 3369, + "fresh-array-union-layout.js": 2566, + "frozen-checked-dictionaries.mjs": 3872, + "fs-native-realpath.ts": 3355, + "fs-null-byte-paths-js.cjs": 2643, + "fs-null-byte-paths.ts": 5975, + "fs-read-encodings.ts": 3730, + "fs-read-utf8-edges.ts": 4190, + "fs-read-utf8-handle-forms.ts": 3943, + "fs-remove-readonly.ts": 3417, + "fs-write-string-bytes-union.ts": 3274, + "function-apply-value.mjs": 3476, + "function-constructor-global.mjs": 3249, + "function-constructor-kinds/main.js": 3769, + "function-custom-prototype.js": 3876, + "function-custom-to-string.mjs": 3155, + "function-object-assign.js": 3527, + "function-own-prototype/main.js": 3460, + "generator-checked-protocol.ts": 2621, + "generator-checked-return.js": 3221, + "generator-custom-delegation/main.ts": 5126, + "generator-default-return-pattern.ts": 3182, + "generator-delegation-values.ts": 3197, + "generator-inferred-date.js": 3585, + "generator-mixed-checked-channels.ts": 3199, + "generator-untyped-consumer/main.ts": 3049, + "generic-base-specializations.ts": 3459, + "generic-binding-ownership.ts": 3288, + "generic-class-js-functions/main.ts": 2834, + "generic-class-recovery.ts": 3640, + "generic-namespace-factories/main.ts": 2618, + "generic-nullable-collections.ts": 3599, + "generic-pattern-bindings.ts": 3103, + "generic-record-index.ts": 3516, + "generic-visitor-void.ts": 3557, + "global-accumulator-loops.ts": 3302, + "global-error-subclasses.ts": 2292, + "global-runtime-probes.js": 3435, + "global-stored-probes.js": 2946, + "global-string-cache/main.js": 2368, + "global-symbol-cache/main.js": 2737, + "guarded-native-iterables.ts": 3541, + "heap-input-aliases.ts": 3756, + "heap-input-collections.ts": 4265, + "in-array-runtime-index.ts": 3804, + "indexed-assignment-values.js": 3469, + "indexed-assignment-values.ts": 2742, + "indexed-element-field-reads.ts": 3016, + "inferred-array-assignment-values.mjs": 2506, + "inferred-class-default.mjs": 2376, + "inferred-compound-values.mjs": 2280, + "inferred-conditional-class.mjs": 3032, + "inferred-error-fields.js": 3161, + "inferred-map-patterns.mjs": 3075, + "inferred-method-override.js": 3123, + "inferred-partial-destructuring.mjs": 3133, + "inferred-primitive-properties.mjs": 2211, + "inferred-record-return.mjs": 3298, + "inferred-recursive-record.mjs": 3328, + "inferred-undefined-field.mjs": 2721, + "input-lifetime-intervals.ts": 3442, + "input-lifetimes-modules/main.ts": 3449, + "instanceof-class-record-union.ts": 3488, + "integer-flow-arithmetic.ts": 3827, + "integer-loop-forms.ts": 3201, + "integer-view-control.ts": 3231, + "integer-view-numbers.ts": 3409, + "integer-view-storage.ts": 3994, + "intl-grapheme-conformance/main.ts": 3445, + "intl-grapheme.ts": 2906, + "iterator-typed-returns.ts": 4729, + "js-abort-portable.js": 27919, + "js-array-constructor.js": 3813, + "js-array-default-buffer.js": 2697, + "js-array-iterators.js": 3607, + "js-arrow-bind.cjs": 4009, + "js-buffer-callback-brand.cjs": 3617, + "js-callable-proxy.js": 4304, + "js-chained-native-results.mjs": 2822, + "js-checked-array-iterator.js": 3340, + "js-checked-array-reference.js": 3923, + "js-checked-number-negation.mjs": 2222, + "js-checked-sort-result.js": 3358, + "js-child-error-listener.cjs": 3277, + "js-cjs-callable-snapshots/main.cjs": 2133, + "js-class-added-parameters.js": 4197, + "js-class-checked-overrides.js": 3307, + "js-class-computed-fields.js": 2995, + "js-class-enumeration.js": 4227, + "js-class-field-accessor-override.js": 3739, + "js-class-fluent-overrides.js": 3694, + "js-class-late-method-values.js": 3823, + "js-class-member-dispatch.js": 2888, + "js-class-return-shapes.js": 4179, + "js-class-shadowed-methods.js": 3019, + "js-class-stored-method-receiver.js": 3182, + "js-class-subclass-properties.js": 4548, + "js-class-symbol-spread.cjs": 3271, + "js-computed-prototype-additions.js": 3652, + "js-constructor-returned-callable.js": 3080, "js-constructor-spread.js": 3311, - "js-dataview-dispatch.js": 2423, - "js-declared-fields.cjs": 3098, - "js-default-listener-arguments.cjs": 2941, - "js-default-options/main.ts": 3442, - "js-deferred-field-initializers.js": 2409, - "js-deferred-registry-effects.js": 2980, - "js-derived-constructor-hoisting.js": 2695, - "js-dormant-array-write.js": 2014, - "js-dormant-overrides.js": 3783, - "js-expando-records.js": 2526, - "js-implicit-call-results.js": 2892, - "js-inferred-callback-exports/main.js": 3776, - "js-inferred-class-array-return.js": 3477, - "js-inferred-object-values.js": 3358, - "js-inherited-field-storage.js": 3527, - "js-inherited-parameter-abi.js": 3324, - "js-iterable-spread.js": 3504, - "js-loose-dynamic-primitives.js": 2079, - "js-map-object-seeds.js": 3322, - "js-member-increment.js": 4257, - "js-module-function-values.js": 3135, - "js-mutable-null-members.js": 2750, - "js-nested-native-descriptors.js": 2725, - "js-normalize-dispatch.js": 3264, - "js-nullish-inherited-fields.mjs": 3080, - "js-object-receiver-storage.js": 3515, - "js-object-returning-constructors.mjs": 3015, - "js-object-shared-arrays.js": 2539, - "js-omitted-typed-arguments.js": 2295, - "js-open-binding-writes.js": 1944, - "js-optional-class-fields.js": 3252, - "js-optional-member-call.js": 3095, - "js-primitive-union-addition.js": 2779, - "js-promise-all-values.js": 3443, - "js-promise-catch-handler.js": 2034, - "js-promise-finally-order.js": 2084, - "js-promise-pending-reactions.js": 3602, - "js-prototype-host-boundary.js": 4779, - "js-reflect-receivers.js": 3486, - "js-regex-record-captures.js": 2214, - "js-scalar-iterables.js": 3719, - "js-shared-method-dispatch.js": 2114, - "js-specialized-field-method.js": 3011, - "js-static-accessors.js": 3435, - "js-static-method-values.js": 3174, - "js-static-registries.cjs": 3047, - "js-super-accessor-initialization.js": 2998, - "js-uninitialized-native-fields.js": 2354, - "json-guarded-map-values.ts": 2502, - "json-output-bulk.ts": 3214, - "json-runtime-options.mjs": 2794, - "json-stringify-value.js": 2833, - "json-typed-parse-direct.ts": 3580, - "literal-switch-dispatch.ts": 2951, - "live-reference-shared-converters.ts": 19276, - "llvm-read-receiver-lifetime.ts": 3803, - "local-class-call-spreads.js": 3495, - "local-class-declaration.ts": 2661, - "local-class-evaluation.ts": 3104, - "local-class-inheritance.ts": 2552, - "local-class-lifetimes.ts": 3344, - "local-class-namespace/main.js": 3630, - "local-class-prototype-data.js": 3990, - "local-class-specialization.js": 2812, - "local-class-unknown.ts": 3002, - "local-class-values.ts": 2009, - "local-union-storage.ts": 3026, - "locale-compare-root-order.ts": 3444, - "logical-assignment-dynamic.js": 3230, - "logical-assignment-values.ts": 3566, - "logical-runtime-optional-record.ts": 3322, - "loop-reference-lifetimes.ts": 3339, - "map-checked-boundary/main.ts": 2843, - "map-checked-seed.js": 2966, - "map-number-keys-dense.ts": 2773, - "map-read-lifetimes-exits.ts": 2761, - "map-read-lifetimes.ts": 3024, - "map-seeds-and-spreads.ts": 3502, - "map-typed-array-values.ts": 3300, - "math-function-values.js": 2815, - "missing-read-lambda-results.ts": 3370, - "missing-read-narrowed-storage.ts": 2854, - "missing-read-number-conversions.ts": 2326, - "module-byte-loops.ts": 2961, - "module-fallback-functions/main.js": 2737, - "narrowed-nullish-values.ts": 3160, - "native-any-timer-callback.ts": 2388, - "native-array-borrowed-find-last.js": 2571, - "native-array-borrowed-slice.js": 3010, - "native-array-copying-methods.js": 3608, - "native-array-fill-copywithin.js": 2996, - "native-array-frozen-noops.js": 3132, - "native-array-index-boundaries.js": 2225, - "native-array-integrity.js": 3091, - "native-array-length.js": 2365, - "native-array-named-properties.js": 2772, - "native-array-prototype/main.js": 3257, - "native-array-read-lifetimes.ts": 3805, - "native-array-reduce-find-last.js": 2524, - "native-array-search-from-index.js": 2027, - "native-array-splice-coercion.js": 2902, - "native-array-splice-flat.js": 2702, - "native-buffer-coercion.js": 2533, - "native-callback-dispatch.ts": 3850, - "native-class-array-boundaries.ts": 3272, - "native-class-cache.js": 3290, - "native-class-properties.cjs": 4583, - "native-class-property-cycles.cjs": 2888, - "native-class-property-order.cjs": 2105, - "native-class-type-predicates.ts": 2960, - "native-factory-records.js": 3080, - "native-method-values.js": 3222, - "native-method-values.ts": 2808, - "native-npm-imports/main.ts": 2750, - "native-object-descriptors.js": 2979, - "native-object-for-in-minimal.js": 2411, - "native-object-property-attributes.js": 3057, - "native-object-prototype.js": 3409, - "native-property-names.ts": 2077, - "native-proxy-env.js": 4372, - "native-worker-arena-reuse.ts": 33854, - "native-worker-bounded-errors.ts": 2556, - "native-worker-buffer-consumers.ts": 38253, - "native-worker-cancel-hot.ts": 28908, - "native-worker-class-fields.ts": 3286, - "native-worker-clone-errors.ts": 3629, - "native-worker-commonjs.cjs": 3085, - "native-worker-delayed-messages.ts": 28752, - "native-worker-discarded-heaps.ts": 39440, - "native-worker-environment.ts": 27133, - "native-worker-error.ts": 2958, - "native-worker-exception-state.ts": 3945, - "native-worker-exit-listeners.ts": 4052, - "native-worker-io.ts": 3361, - "native-worker-loop-cancellation.ts": 2798, - "native-worker-message-graphs.ts": 2738, - "native-worker-messages.ts": 3079, - "native-worker-poll-exceptions.ts": 2575, - "native-worker-port-lifetime.ts": 3213, - "native-worker-process-exit.ts": 4104, - "native-worker-publish-classes.ts": 24713, - "native-worker-publish-refusals.ts": 2820, - "native-worker-published-graphs.ts": 3534, - "native-worker-references.ts": 3358, - "native-worker-roots/main.ts": 2808, - "native-worker-shared-views.ts": 3012, - "native-worker-stack-overflow.ts": 2597, - "native-worker-terminate-exception-state.ts": 3340, - "native-worker-terminate-loop.ts": 2222, - "native-worker-terminate-recursion.ts": 2829, - "native-worker-terminate-suspended.ts": 4348, - "native-worker-terminate-tested-loops.ts": 3576, - "native-worker-terminate-wait.ts": 3222, - "native-worker-typed-arrays.ts": 2653, - "nested-map-cycles.ts": 3041, - "nested-map-values.ts": 2382, - "never-returning-calls.ts": 2642, - "next-tick-commonjs-entry.cjs": 2624, - "node24-buffer-encoding-errors.ts": 2695, - "node24-buffer-encoding.ts": 3038, - "node24-crypto-kdf-errors.ts": 2745, - "node24-crypto-kdf-options.ts": 2029, - "node24-crypto-kdf.ts": 3632, - "node24-crypto-sha2.ts": 2849, - "node24-deep-equality-properties.js": 3355, - "node24-deep-equality.cjs": 2682, - "node24-deep-equality.ts": 4058, - "node24-env-files-errors.ts": 3202, - "node24-env-files.ts": 3044, - "node24-env-imports.cjs": 2529, - "node24-env-parse-errors.ts": 2062, - "node24-env-parse.ts": 3684, - "node24-esm-metadata/main.mjs": 2492, - "node24-file-url-buffer.ts": 2158, - "node24-file-url-errors.js": 3331, - "node24-file-url-options.ts": 2772, - "node24-fs-links-callbacks.cjs": 3549, - "node24-fs-links-errors.cjs": 2633, - "node24-fs-links-options.cjs": 3571, - "node24-fs-links-promise-errors.cjs": 2445, - "node24-fs-links-promises.ts": 2105, - "node24-fs-links.ts": 2967, - "node24-fs-statfs-callbacks.cjs": 3035, - "node24-fs-statfs-errors.cjs": 2969, - "node24-fs-statfs-options.cjs": 3557, - "node24-fs-statfs.ts": 3067, - "node24-fs-timestamps-callbacks.cjs": 3095, - "node24-fs-timestamps-errors.cjs": 3110, - "node24-fs-timestamps-promises.ts": 3573, - "node24-fs-timestamps-symlinks.ts": 3390, - "node24-fs-timestamps.ts": 3032, - "node24-no-error-assertions-coercion.js": 2850, - "node24-no-error-assertions.cjs": 2814, - "node24-no-error-assertions.ts": 4358, - "node24-parseargs.js": 5971, - "node24-string-decoder.ts": 3185, - "node24-style-text-environment.js": 4225, - "node24-style-text-validation.js": 3673, - "node24-style-text.cjs": 3476, - "node24-style-text.ts": 3037, - "node24-system-error-validation.js": 3005, - "node24-system-errors.cjs": 3631, - "node24-system-errors.ts": 2849, - "node24-text-codec-properties.ts": 30185, - "node24-text-encode-into.ts": 3601, - "node24-text-utilities-coercion.js": 3094, - "node24-text-utilities-validation.js": 2330, - "node24-text-utilities.cjs": 2768, - "node24-text-utilities.ts": 3312, - "node24-url-authority-coercion.js": 3307, - "node24-url-authority.ts": 2639, - "node24-url-factories.ts": 3240, - "node24-url-factory-errors.ts": 2819, - "node24-url-mutation-coercion.js": 2399, - "node24-url-mutation.ts": 3257, - "node24-util-types.cjs": 3263, - "node24-util-types.js": 2199, - "node24-util-types.ts": 3506, - "non-null-class-iteration.ts": 3295, - "nonnull-element-arguments.ts": 2857, - "nonnull-forwarded-class-values.ts": 3303, - "nullable-object-extension.mjs": 2652, - "nullish-asserted-class-arms.ts": 2669, - "nullish-assignment-values.ts": 2125, - "nullish-long-chain.ts": 2641, - "number-parse-statics.ts": 2471, - "number-predicates-unknown.ts": 2568, - "numeric-call-specialization.ts": 2498, - "object-enumeration-array-reads.ts": 2246, - "object-from-checked-entries.js": 3478, - "object-inherited-to-string.js": 2987, - "object-key-indexes.js": 3206, - "object-prototype-identity.mjs": 3083, - "object-reexport/main.js": 2466, - "object-spread-computed.ts": 2806, - "opentui-byte-queue.js": 3532, - "optional-callback-arity.ts": 2417, - "optional-class-flows.ts": 2497, - "optional-element-defaults.ts": 2632, - "optional-flag-comparisons.ts": 2536, - "optional-native-callables.js": 2751, - "optional-node-list-iteration.ts": 2564, - "optional-string-index/main.ts": 3419, - "path-to-file-url-options.ts": 2301, - "performance-presence.ts": 2913, - "primitive-and-function-descriptors.js": 3070, - "primitive-union-string.ts": 3434, - "process-builtin-values.js": 2781, - "process-constrained-memory.ts": 2857, - "process-env-computed-keys.js": 3185, - "process-hrtime.js": 2662, - "process-named-signals.cjs": 3171, - "process-uncaught-handler-throws.cjs": 2344, - "process-uncaught-loop.cjs": 3141, - "process-uncaught-module.mjs": 2646, - "process-uncaught-monitor.cjs": 2837, - "process-uncaught-rejection.cjs": 2664, - "process-uncaught-sync.cjs": 2858, - "process-version-pin.ts": 3005, - "process-versions-storage.ts": 2055, - "projected-collection-lifetimes.ts": 3232, - "promise-checked-rejections.ts": 2914, - "promise-resolve-void.ts": 2846, - "prototype-method-overrides.mjs": 4119, - "prototype-named-data-records.ts": 3179, - "record-field-presence.ts": 3698, - "record-key-order.ts": 2706, - "record-optional-json-presence.ts": 3216, - "record-presence-copies.ts": 3381, - "record-presence-delete-json.ts": 3160, - "record-unchecked-read-presence.ts": 2953, - "record-unknown-values.ts": 4095, - "reflect-own-keys.mjs": 2705, - "reflect-record-union-keys.mjs": 2815, - "reflect-typed-record-keys.ts": 2683, - "regex-callback-replacements.ts": 2631, - "regex-callback-values.js": 3741, - "regex-checked-casts.ts": 2405, - "regex-checked-storage.js": 3560, - "regex-exec-long-subject.ts": 5584, - "regex-input-lifetimes.ts": 3241, - "regex-native-matcher.ts": 3652, - "regex-optional-captures.ts": 2740, - "regex-optional-templates.ts": 2802, - "regex-split-captures.ts": 3590, - "regex-text-paths.ts": 2840, - "regexp-constructor-repeat.ts": 2602, - "regexp-optional-constructor.ts": 2950, - "regexp-string-coercion.js": 2621, - "renderer-export-dictionaries.js": 3415, - "renderer-null-state.js": 2259, - "renderer-specializations.js": 2837, - "repeat-and-typed-read-errors.ts": 3220, - "rest-optional-array-arguments.ts": 2860, - "rest-optional-elements.ts": 2445, - "return-void-through-finally.ts": 2861, - "runtime-optional-string-flows.ts": 2977, - "scalar-string-slices.ts": 2840, - "set-checked-methods.js": 3072, - "set-checked-storage.ts": 2667, - "set-iterator-seed-references.ts": 3159, - "set-iterator-seeds.ts": 3269, - "set-optional-seeds.ts": 2164, - "small-collection-transitions.ts": 3586, - "stack-depth-async-bodies.ts": 2727, - "stack-overflow-async.ts": 2942, - "stack-overflow-caught.ts": 3056, - "stack-overflow-finally.ts": 3694, - "stack-overflow-shapes.ts": 3565, - "stack-overflow-uncaught.ts": 2532, - "static-field-updates/main.ts": 2914, - "static-method-receivers.ts": 2350, - "stdio-values.mjs": 2761, - "stdio-write-errors.mjs": 2672, - "stdio-write-overrides.mjs": 3205, - "stored-native-builtins.js": 3341, - "stored-object-helpers.js": 2959, - "string-char-code-integer-loops.ts": 2575, - "string-code-points.ts": 2460, - "string-concat-number-parts.ts": 2155, - "string-construction-order.ts": 3307, - "string-lifetimes-boundaries.ts": 3304, - "string-lifetimes-evaluation.ts": 2835, - "string-lifetimes-iteration.ts": 2037, - "string-lifetimes-operations.ts": 2789, - "string-normalize.ts": 2348, - "string-pattern-replacement.ts": 3823, - "string-scan-fast-paths.ts": 3224, - "string-split-checked-separator.mjs": 2349, - "string-split-traversal.ts": 3258, - "structural-class-properties.ts": 2627, - "structured-text-boundaries.js": 3452, - "structured-text-storage.ts": 3201, - "switch-integer-dispatch.ts": 2387, - "symbol-checked-boundary/main.ts": 2796, - "symbol-class-fields.ts": 2814, - "symbol-class-fields/main.cjs": 2659, - "symbol-class-methods/main.ts": 1948, - "symbol-fields-deferred-factory.ts": 2721, - "symbol-fields-inferred.js": 2792, - "symbol-object-properties/main.js": 3376, - "synchronous-callback-lifetimes.ts": 2872, - "terminal-stream-properties.ts": 2946, - "text-codec-values/main.ts": 18964, - "text-codec-var.ts": 3480, - "text-encode-into-boundaries.ts": 2224, - "timers-clear-many.ts": 3073, - "tuple-and-string-search.ts": 2595, - "tuple-array-union.ts": 3305, - "tuple-callback-visitation.ts": 3801, - "tuple-forof-visitation.ts": 3276, - "typed-array-bulk-conversion.mjs": 5346, - "typed-array-byte-io.js": 41314, - "typed-array-checked-index.js": 2607, - "typed-array-constructor-alias.ts": 2778, - "typed-array-constructor-identity.js": 2769, - "typed-array-constructor-union.ts": 2366, - "typed-array-constructor-values.mjs": 3448, - "typed-array-dynamic-methods.js": 3373, - "typed-array-integer-widths.ts": 3014, - "typed-array-nan-coded-reads.ts": 4239, - "typed-array-numeric-import.ts": 3499, - "typed-array-present-reads.ts": 3561, - "typed-array-reversed-storage.ts": 2954, - "typed-array-unknown.ts": 3453, - "typed-collection-iterator-references.ts": 3531, - "typed-collection-iterators.ts": 3385, - "typed-collection-views/main.ts": 2577, - "typed-index-arguments.ts": 3036, - "typed-prototype-methods.ts": 2475, - "typed-rest-callables.ts": 2463, - "typed-rest-filtered-return.ts": 2800, - "typedarray-native-inputs.js": 3164, - "typeof-checked-comparison.js": 2913, - "uint8array-sort-domains.ts": 2505, - "unicode-case-paths.ts": 2924, - "unicode-process-argv.ts": 2793, - "union-discriminant-width.ts": 3726, - "union-literal-scalar-discriminants.ts": 3704, - "union-literal-slot-conversion.ts": 2972, - "union-nested-layout-discriminant.ts": 2841, - "union-optional-semantic-identity.ts": 3100, - "union-record-clone.ts": 3480, - "union-record-structural-copy.ts": 3563, - "union-reference-comparison.ts": 3338, - "unknown-array-holes.ts": 2088, - "unknown-collections.ts": 3765, - "unknown-object-enumeration.ts": 4219, - "unknown-record-views.ts": 3040, - "url-runtime-base.ts": 2778, - "utf8-span-decoding.ts": 2655, - "util-parseargs-wrapped/main.ts": 2482, - "virtual-runtime-optional-returns.ts": 3876, - "weak-map-array-buffer.ts": 2826, - "weak-map-fresh-array.js": 2495, - "weak-map-native.js": 3627, - "weak-native-class-identity.ts": 2943, - "weak-set-native.js": 3056, - "worker-class-instance-clone.ts": 35222 + "js-dataview-dispatch.js": 2584, + "js-declared-fields.cjs": 4858, + "js-default-listener-arguments.cjs": 2246, + "js-default-options/main.ts": 2763, + "js-deferred-field-initializers.js": 3209, + "js-deferred-registry-effects.js": 3112, + "js-derived-constructor-hoisting.js": 2435, + "js-dormant-array-write.js": 2504, + "js-dormant-overrides.js": 2426, + "js-expando-records.js": 2649, + "js-implicit-call-results.js": 2821, + "js-inferred-callback-exports/main.js": 4081, + "js-inferred-class-array-return.js": 3706, + "js-inferred-object-values.js": 2559, + "js-inherited-field-storage.js": 3955, + "js-inherited-parameter-abi.js": 2394, + "js-iterable-spread.js": 3349, + "js-loose-dynamic-primitives.js": 3110, + "js-map-object-seeds.js": 3942, + "js-member-increment.js": 4274, + "js-module-function-values.js": 3403, + "js-mutable-null-members.js": 2899, + "js-nested-native-descriptors.js": 3202, + "js-normalize-dispatch.js": 3282, + "js-nullish-inherited-fields.mjs": 2655, + "js-object-receiver-storage.js": 3904, + "js-object-returning-constructors.mjs": 2279, + "js-object-shared-arrays.js": 3613, + "js-omitted-typed-arguments.js": 2937, + "js-open-binding-writes.js": 2903, + "js-optional-class-fields.js": 3536, + "js-optional-member-call.js": 2325, + "js-primitive-union-addition.js": 3324, + "js-promise-all-values.js": 3699, + "js-promise-catch-handler.js": 3309, + "js-promise-finally-order.js": 3229, + "js-promise-pending-reactions.js": 3312, + "js-prototype-host-boundary.js": 3876, + "js-reflect-receivers.js": 2676, + "js-regex-record-captures.js": 3109, + "js-scalar-iterables.js": 3335, + "js-shared-method-dispatch.js": 3207, + "js-specialized-field-method.js": 3320, + "js-static-accessors.js": 3426, + "js-static-method-values.js": 3661, + "js-static-registries.cjs": 3718, + "js-super-accessor-initialization.js": 2555, + "js-uninitialized-native-fields.js": 3260, + "json-guarded-map-values.ts": 2760, + "json-output-bulk.ts": 3183, + "json-runtime-options.mjs": 3276, + "json-stringify-value.js": 3464, + "json-typed-parse-direct.ts": 4317, + "json-typed-parse-index-signatures.ts": 4012, + "json-typed-parse-optional-members.ts": 4377, + "json-typed-parse-union-members.ts": 4357, + "literal-switch-dispatch.ts": 2642, + "live-reference-shared-converters.ts": 5581, + "llvm-read-receiver-lifetime.ts": 3426, + "local-class-call-spreads.js": 3773, + "local-class-declaration.ts": 3293, + "local-class-evaluation.ts": 2921, + "local-class-inheritance.ts": 3273, + "local-class-lifetimes.ts": 3403, + "local-class-namespace/main.js": 4002, + "local-class-prototype-data.js": 3135, + "local-class-specialization.js": 3358, + "local-class-unknown.ts": 3386, + "local-class-values.ts": 3003, + "local-union-storage.ts": 3264, + "locale-compare-root-order.ts": 2579, + "logical-assignment-dynamic.js": 3596, + "logical-assignment-values.ts": 2685, + "logical-runtime-optional-record.ts": 3575, + "loop-reference-lifetimes.ts": 2726, + "map-checked-boundary/main.ts": 3371, + "map-checked-seed.js": 2974, + "map-get-set-fusion.ts": 3516, + "map-number-keys-dense.ts": 3426, + "map-read-lifetimes-exits.ts": 2870, + "map-read-lifetimes.ts": 2755, + "map-seeds-and-spreads.ts": 3696, + "map-typed-array-values.ts": 3121, + "math-function-values.js": 3080, + "missing-read-lambda-results.ts": 2590, + "missing-read-narrowed-storage.ts": 3503, + "missing-read-number-conversions.ts": 3648, + "module-byte-loops.ts": 3462, + "module-fallback-functions/main.js": 3043, + "narrowed-nullish-values.ts": 2912, + "native-any-timer-callback.ts": 1952, + "native-array-borrowed-find-last.js": 2795, + "native-array-borrowed-slice.js": 3711, + "native-array-copying-methods.js": 3069, + "native-array-fill-copywithin.js": 3430, + "native-array-frozen-noops.js": 3638, + "native-array-index-boundaries.js": 2630, + "native-array-integrity.js": 3935, + "native-array-length.js": 3375, + "native-array-named-properties.js": 3404, + "native-array-prototype/main.js": 3369, + "native-array-read-lifetimes.ts": 3688, + "native-array-reduce-find-last.js": 3264, + "native-array-search-from-index.js": 3220, + "native-array-splice-coercion.js": 3281, + "native-array-splice-flat.js": 3336, + "native-buffer-coercion.js": 2766, + "native-callback-dispatch.ts": 3779, + "native-class-array-boundaries.ts": 3630, + "native-class-cache.js": 3925, + "native-class-properties.cjs": 3940, + "native-class-property-cycles.cjs": 2802, + "native-class-property-order.cjs": 3298, + "native-class-type-predicates.ts": 3174, + "native-factory-records.js": 3338, + "native-method-values.js": 4444, + "native-method-values.ts": 3470, + "native-npm-imports/main.ts": 4028, + "native-object-descriptors.js": 2892, + "native-object-for-in-minimal.js": 2799, + "native-object-property-attributes.js": 3744, + "native-object-prototype.js": 2121, + "native-property-names.ts": 2951, + "native-proxy-env.js": 4417, + "native-worker-arena-reuse.ts": 38589, + "native-worker-bounded-errors.ts": 3955, + "native-worker-buffer-consumers.ts": 3076, + "native-worker-cancel-hot.ts": 3811, + "native-worker-class-fields.ts": 3737, + "native-worker-clone-errors.ts": 3557, + "native-worker-commonjs.cjs": 3258, + "native-worker-delayed-messages.ts": 3234, + "native-worker-discarded-heaps.ts": 8633, + "native-worker-environment.ts": 2690, + "native-worker-error.ts": 2115, + "native-worker-exception-state.ts": 37223, + "native-worker-exit-listeners.ts": 4215, + "native-worker-io.ts": 4024, + "native-worker-loop-cancellation.ts": 3683, + "native-worker-message-graphs.ts": 4038, + "native-worker-messages.ts": 2850, + "native-worker-poll-exceptions.ts": 3386, + "native-worker-port-lifetime.ts": 3672, + "native-worker-process-exit.ts": 4483, + "native-worker-publish-classes.ts": 43586, + "native-worker-publish-refusals.ts": 3568, + "native-worker-published-graphs.ts": 4341, + "native-worker-references.ts": 3658, + "native-worker-roots/main.ts": 3661, + "native-worker-shared-views.ts": 3873, + "native-worker-stack-overflow.ts": 3498, + "native-worker-terminate-exception-state.ts": 4768, + "native-worker-terminate-loop.ts": 3671, + "native-worker-terminate-recursion.ts": 2944, + "native-worker-terminate-suspended.ts": 4867, + "native-worker-terminate-tested-loops.ts": 3737, + "native-worker-terminate-wait.ts": 3200, + "native-worker-typed-arrays.ts": 2972, + "nested-map-cycles.ts": 3092, + "nested-map-values.ts": 3902, + "never-returning-calls.ts": 3512, + "next-tick-commonjs-entry.cjs": 3497, + "node24-buffer-encoding-errors.ts": 2874, + "node24-buffer-encoding.ts": 2697, + "node24-crypto-kdf-errors.ts": 3771, + "node24-crypto-kdf-options.ts": 2897, + "node24-crypto-kdf.ts": 3236, + "node24-crypto-sha2.ts": 3082, + "node24-deep-equality-properties.js": 3692, + "node24-deep-equality.cjs": 4490, + "node24-deep-equality.ts": 2856, + "node24-env-files-errors.ts": 2870, + "node24-env-files.ts": 3392, + "node24-env-imports.cjs": 2365, + "node24-env-parse-errors.ts": 3439, + "node24-env-parse.ts": 3033, + "node24-esm-metadata/main.mjs": 3209, + "node24-file-url-buffer.ts": 3465, + "node24-file-url-errors.js": 3937, + "node24-file-url-options.ts": 3735, + "node24-fs-links-callbacks.cjs": 3621, + "node24-fs-links-errors.cjs": 3404, + "node24-fs-links-options.cjs": 6459, + "node24-fs-links-promise-errors.cjs": 3319, + "node24-fs-links-promises.ts": 2636, + "node24-fs-links.ts": 3567, + "node24-fs-statfs-callbacks.cjs": 2515, + "node24-fs-statfs-errors.cjs": 2787, + "node24-fs-statfs-options.cjs": 3945, + "node24-fs-statfs.ts": 3105, + "node24-fs-timestamps-callbacks.cjs": 3550, + "node24-fs-timestamps-errors.cjs": 2070, + "node24-fs-timestamps-promises.ts": 3342, + "node24-fs-timestamps-symlinks.ts": 3375, + "node24-fs-timestamps.ts": 3308, + "node24-no-error-assertions-coercion.js": 3613, + "node24-no-error-assertions.cjs": 2851, + "node24-no-error-assertions.ts": 4400, + "node24-parseargs.js": 5202, + "node24-string-decoder.ts": 3402, + "node24-style-text-environment.js": 3896, + "node24-style-text-validation.js": 3092, + "node24-style-text.cjs": 3244, + "node24-style-text.ts": 2726, + "node24-system-error-validation.js": 3065, + "node24-system-errors.cjs": 2955, + "node24-system-errors.ts": 3258, + "node24-text-codec-properties.ts": 31240, + "node24-text-encode-into.ts": 2827, + "node24-text-utilities-coercion.js": 3019, + "node24-text-utilities-validation.js": 3576, + "node24-text-utilities.cjs": 3204, + "node24-text-utilities.ts": 2533, + "node24-url-authority-coercion.js": 3364, + "node24-url-authority.ts": 3386, + "node24-url-factories.ts": 3341, + "node24-url-factory-errors.ts": 3442, + "node24-url-mutation-coercion.js": 3344, + "node24-url-mutation.ts": 3264, + "node24-util-types.cjs": 3872, + "node24-util-types.js": 3533, + "node24-util-types.ts": 2848, + "non-null-class-iteration.ts": 2837, + "nonnull-element-arguments.ts": 3131, + "nonnull-forwarded-class-values.ts": 2449, + "nullable-object-extension.mjs": 3515, + "nullish-asserted-class-arms.ts": 3564, + "nullish-assignment-values.ts": 3337, + "nullish-long-chain.ts": 4149, + "number-parse-statics.ts": 2899, + "number-predicates-unknown.ts": 2922, + "numeric-call-specialization.ts": 2677, + "object-enumeration-array-reads.ts": 3480, + "object-from-checked-entries.js": 4289, + "object-inherited-to-string.js": 3243, + "object-key-indexes.js": 3558, + "object-prototype-identity.mjs": 3385, + "object-reexport/main.js": 2771, + "object-spread-computed.ts": 3307, + "opentui-byte-queue.js": 3572, + "optional-callback-arity.ts": 3027, + "optional-class-flows.ts": 3557, + "optional-element-defaults.ts": 3575, + "optional-flag-comparisons.ts": 3414, + "optional-native-callables.js": 3002, + "optional-node-list-iteration.ts": 2230, + "optional-string-index/main.ts": 3788, + "path-to-file-url-options.ts": 2444, + "performance-presence.ts": 2497, + "primitive-and-function-descriptors.js": 3169, + "primitive-union-string.ts": 2622, + "process-builtin-values.js": 3706, + "process-constrained-memory.ts": 2749, + "process-env-computed-keys.js": 3550, + "process-hrtime.js": 2677, + "process-named-signals.cjs": 3293, + "process-uncaught-handler-throws.cjs": 2718, + "process-uncaught-loop.cjs": 2801, + "process-uncaught-module.mjs": 3158, + "process-uncaught-monitor.cjs": 3031, + "process-uncaught-rejection.cjs": 3327, + "process-uncaught-sync.cjs": 2443, + "process-version-pin.ts": 2957, + "process-versions-storage.ts": 3651, + "projected-collection-lifetimes.ts": 3241, + "promise-checked-rejections.ts": 3404, + "promise-resolve-void.ts": 3343, + "prototype-method-overrides.mjs": 4289, + "prototype-named-data-records.ts": 3466, + "rc-last-use-moves.ts": 4113, + "rc-private-array-writes.ts": 4261, + "record-field-presence.ts": 4642, + "record-key-order.ts": 3034, + "record-optional-json-presence.ts": 3355, + "record-presence-copies.ts": 2764, + "record-presence-delete-json.ts": 2807, + "record-unchecked-read-presence.ts": 3073, + "record-unknown-values.ts": 4519, + "reflect-own-keys.mjs": 3709, + "reflect-record-union-keys.mjs": 2498, + "reflect-typed-record-keys.ts": 2697, + "regex-callback-replacements.ts": 3004, + "regex-callback-values.js": 2710, + "regex-checked-casts.ts": 3352, + "regex-checked-storage.js": 3330, + "regex-exec-long-subject.ts": 6176, + "regex-exec-result-arrays.ts": 3812, + "regex-fs-text-surfaces.ts": 4280, + "regex-input-lifetimes.ts": 3127, + "regex-native-matcher.ts": 5535, + "regex-optional-captures.ts": 3580, + "regex-optional-templates.ts": 3221, + "regex-split-captures.ts": 2939, + "regex-text-paths.ts": 3596, + "regexp-constructor-repeat.ts": 3069, + "regexp-optional-constructor.ts": 2996, + "regexp-string-coercion.js": 3263, + "renderer-export-dictionaries.js": 3616, + "renderer-null-state.js": 3037, + "renderer-specializations.js": 3634, + "repeat-and-typed-read-errors.ts": 2617, + "rest-optional-array-arguments.ts": 3777, + "rest-optional-elements.ts": 3195, + "return-void-through-finally.ts": 2410, + "runtime-optional-string-flows.ts": 3467, + "scalar-string-slices.ts": 3659, + "set-checked-methods.js": 2038, + "set-checked-storage.ts": 3153, + "set-iterator-seed-references.ts": 3637, + "set-iterator-seeds.ts": 3641, + "set-optional-seeds.ts": 3312, + "small-collection-transitions.ts": 3749, + "speculative-integer-globals.ts": 3132, + "speculative-integer-loops.ts": 3533, + "speculative-integer-reads.ts": 3953, + "stack-depth-async-bodies.ts": 3272, + "stack-overflow-async.ts": 2638, + "stack-overflow-caught.ts": 2219, + "stack-overflow-finally.ts": 3033, + "stack-overflow-shapes.ts": 4491, + "stack-overflow-uncaught.ts": 2225, + "stackless-async-concurrency.ts": 4361, + "stackless-async-context.ts": 2699, + "stackless-async-exceptions.ts": 3282, + "stackless-async-ordering.ts": 3335, + "stackless-async-unhandled.ts": 2784, + "static-field-updates/main.ts": 2292, + "static-method-receivers.ts": 3195, + "stdio-values.mjs": 3475, + "stdio-write-errors.mjs": 3473, + "stdio-write-overrides.mjs": 2782, + "stored-native-builtins.js": 3709, + "stored-object-helpers.js": 3602, + "stream-dynamic-entry-kinds.cjs": 4557, + "stream-dynamic-entry-kinds.ts": 4257, + "stream-encoded-from-entries.cjs": 4266, + "stream-encoded-from-entries.ts": 5622, + "string-char-code-integer-loops.ts": 2285, + "string-code-points.ts": 3745, + "string-concat-number-parts.ts": 3405, + "string-construction-order.ts": 3532, + "string-field-append.ts": 3568, + "string-lifetimes-boundaries.ts": 2538, + "string-lifetimes-evaluation.ts": 3059, + "string-lifetimes-iteration.ts": 2631, + "string-lifetimes-operations.ts": 3387, + "string-normalize.ts": 2789, + "string-pattern-replacement.ts": 3618, + "string-scan-fast-paths.ts": 3272, + "string-split-checked-separator.mjs": 3453, + "string-split-traversal.ts": 4337, + "structural-class-properties.ts": 3247, + "structured-text-boundaries.js": 3686, + "structured-text-storage.ts": 3429, + "switch-integer-dispatch.ts": 3032, + "symbol-checked-boundary/main.ts": 3536, + "symbol-class-fields.ts": 2762, + "symbol-class-fields/main.cjs": 3297, + "symbol-class-methods/main.ts": 3256, + "symbol-fields-deferred-factory.ts": 2417, + "symbol-fields-inferred.js": 3396, + "symbol-object-properties/main.js": 3134, + "synchronous-callback-lifetimes.ts": 3731, + "terminal-stream-properties.ts": 3204, + "text-codec-values/main.ts": 34352, + "text-codec-var.ts": 32460, + "text-encode-into-boundaries.ts": 3355, + "timers-clear-many.ts": 3559, + "tuple-and-string-search.ts": 3678, + "tuple-array-union.ts": 3569, + "tuple-callback-visitation.ts": 4765, + "tuple-forof-visitation.ts": 3560, + "typed-array-bulk-conversion.mjs": 5651, + "typed-array-byte-io.js": 4933, + "typed-array-checked-index.js": 3214, + "typed-array-constructor-alias.ts": 3116, + "typed-array-constructor-identity.js": 2735, + "typed-array-constructor-union.ts": 2841, + "typed-array-constructor-values.mjs": 3638, + "typed-array-dynamic-methods.js": 3255, + "typed-array-integer-widths.ts": 3434, + "typed-array-nan-coded-reads.ts": 3804, + "typed-array-numeric-import.ts": 2396, + "typed-array-present-reads.ts": 4348, + "typed-array-reversed-storage.ts": 3192, + "typed-array-unknown.ts": 2874, + "typed-collection-iterator-references.ts": 4029, + "typed-collection-iterators.ts": 4109, + "typed-collection-views/main.ts": 3005, + "typed-index-arguments.ts": 2798, + "typed-prototype-methods.ts": 3814, + "typed-rest-callables.ts": 2881, + "typed-rest-filtered-return.ts": 3723, + "typedarray-native-inputs.js": 2740, + "typeof-checked-comparison.js": 2277, + "uint8array-sort-domains.ts": 3386, + "unicode-case-paths.ts": 3002, + "unicode-process-argv.ts": 3272, + "union-discriminant-width.ts": 3302, + "union-literal-scalar-discriminants.ts": 2833, + "union-literal-slot-conversion.ts": 4058, + "union-nested-layout-discriminant.ts": 3205, + "union-optional-semantic-identity.ts": 3833, + "union-record-clone.ts": 3862, + "union-record-structural-copy.ts": 3756, + "union-reference-comparison.ts": 2883, + "unknown-array-holes.ts": 2863, + "unknown-collections.ts": 4132, + "unknown-object-enumeration.ts": 4976, + "unknown-record-views.ts": 4014, + "url-runtime-base.ts": 3421, + "utf8-span-decoding.ts": 3446, + "util-parseargs-wrapped/main.ts": 3987, + "virtual-runtime-optional-returns.ts": 4683, + "weak-map-array-buffer.ts": 3291, + "weak-map-fresh-array.js": 2703, + "weak-map-native.js": 3899, + "weak-native-class-identity.ts": 2332, + "weak-set-native.js": 2464, + "worker-class-instance-clone.ts": 46305 } } From 577b0135a971413c885396f99945acb4639585d5 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 09:12:27 -0700 Subject: [PATCH 102/117] Add execution tiers to the IR and a report-only tier analysis Stage S2 of the two-tier design. IrFunction gains a tier (absent means static); lowering assigns it from function bodies, placing functions that use the dyn vocabulary in the dynamic tier, and the validator enforces invariant I1: a static function performs no dynamic operation, only boundary operations (dynFrom, dynCheck, kind tests) and moves. Serialized IR keeps the field out in this stage and loaders derive it again, so every IR, LLVM and executable artifact is unchanged. Every committed refusal and runtime fence becomes a recorded demotion request attributed to the binding, field, function instance, class or module the dynamic tier would take over, while the compiler still refuses and fences as before. `scriptc coverage` reports dynamic-tier statements (statementsDynamic), `--explain-dynamic[=]` prints the demotion chains, and `--tier=auto|static-only` is wired through build, run and coverage for stage S6; both modes compile identically today. Co-Authored-By: Claude Opus 5.5 --- docs/content/docs/cli.mdx | 6 + docs/content/docs/coverage.mdx | 13 +- packages/compiler/src/cli/command.ts | 43 +- packages/compiler/src/cli/usage.ts | 12 + packages/compiler/src/compile-types.ts | 10 + packages/compiler/src/coverage/report.ts | 148 ++++- .../compiler/src/coverage/verdict-cache.ts | 5 + packages/compiler/src/diagnostics/envelope.ts | 36 +- packages/compiler/src/executable/prepare.ts | 1 + packages/compiler/src/frontend/analysis.ts | 3 + .../compiler/src/frontend/lowering/lowerer.ts | 67 ++ .../compiler/src/frontend/tier-analysis.ts | 629 ++++++++++++++++++ packages/compiler/src/index.ts | 18 + packages/compiler/src/ir/ir.ts | 8 + packages/compiler/src/ir/serialize.ts | 24 +- packages/compiler/src/ir/tiers.test.ts | 142 ++++ packages/compiler/src/ir/tiers.ts | 157 +++++ packages/compiler/src/ir/validate.test.ts | 6 +- packages/compiler/src/ir/validate.ts | 12 + packages/compiler/src/library/prepare.ts | 2 + tests/coverage-fixtures/tier-demotions.ts | 25 + .../__snapshots__/coverage-divergences.txt | 1 + .../__snapshots__/coverage-dynamic-mix.txt | 1 + .../coverage-explain-dynamic.txt | 16 + .../harness/__snapshots__/coverage-js-gap.txt | 1 + .../harness/__snapshots__/coverage-mixed.txt | 1 + .../__snapshots__/coverage-npm-packages.txt | 1 + .../__snapshots__/coverage-tier-demotions.txt | 13 + .../__snapshots__/coverage-width-copies.txt | 1 + tests/harness/coverage.test.ts | 107 ++- 30 files changed, 1494 insertions(+), 15 deletions(-) create mode 100644 packages/compiler/src/frontend/tier-analysis.ts create mode 100644 packages/compiler/src/ir/tiers.test.ts create mode 100644 packages/compiler/src/ir/tiers.ts create mode 100644 tests/coverage-fixtures/tier-demotions.ts create mode 100644 tests/harness/__snapshots__/coverage-explain-dynamic.txt create mode 100644 tests/harness/__snapshots__/coverage-tier-demotions.txt diff --git a/docs/content/docs/cli.mdx b/docs/content/docs/cli.mdx index a6f75c6d3..e8596fc3d 100644 --- a/docs/content/docs/cli.mdx +++ b/docs/content/docs/cli.mdx @@ -127,6 +127,12 @@ Verifies and loads the installed precompiled runtime objects and vendored librar
--external-types <specifier=file.d.ts>
Coverage only. Map an exact bare module specifier to a local declaration file supplied by an embedder. Repeat the option for multiple modules. The declaration supplies checker types so application coverage can continue; runtime imports and values remain explicit SC1010 blockers. Relative paths resolve from the current working directory. Accepted files end in .d.ts, .d.mts, or .d.cts.
+
--tier <auto|static-only>
+
The tier policy for code that has no static lowering. auto is the default. static-only guarantees that the program contains no dynamic-tier demotions: every such construct stays a compile error in TypeScript and a deferred runtime error in JavaScript, which is how both modes behave today. Use it in CI to keep a program fully static. Library mode is always static-only. See Dynamic tier.
+ +
--explain-dynamic[=<name>]
+
Coverage only. After the report, list the functions that already operate on values typed only at runtime and the bindings, fields, functions, classes and modules that unsupported constructs would move to the dynamic tier, each with the diagnostic behind it. With a name such as x, Point, or Point.x, show only the matching units. See Dynamic tier.
+
--sanitize
Build an executable with AddressSanitizer and a reference-count audit at exit, the same checks scriptc's own test suite uses. Requires a C compiler and is available only for host builds. Not supported with --emit=asm or --emit=obj.
diff --git a/docs/content/docs/coverage.mdx b/docs/content/docs/coverage.mdx index 2d26e684b..805d7f612 100644 --- a/docs/content/docs/coverage.mdx +++ b/docs/content/docs/coverage.mdx @@ -36,6 +36,7 @@ When a program has unsupported operations, the report adds a group for each root statements analyzedExecutable statements in application code, excluding dependency implementation code. compile staticallyStatements that compile to native instructions. + in dynamic tierOf those, the statements in functions that operate on values typed only at runtime, such as any values and untyped JavaScript. Shown when there are any. See Dynamic tier. blockersUnsupported operations with counts, diagnostic codes, reasons, locations, and hints. in unreached codeBlockers in code the entry never reaches. A build never compiles that code, so these cannot fail it. differs from NodeSites that compile but can behave differently from Node.js. See Node divergences. @@ -51,6 +52,16 @@ If a function's signature can't compile, the statements in its body count as not + + +## Dynamic tier + +Code that operates on values whose types are known only at runtime, such as `any` values, the result of an untyped `JSON.parse`, or untyped JavaScript, compiles into dynamic-tier functions. They are native code too, but they check types and look up properties at runtime, so they are slower than code with static types. The report's `in dynamic tier` line counts their statements. + +`--explain-dynamic` lists those functions and the operation that makes each one dynamic. It also lists the units an unsupported construct would move to the dynamic tier: the binding, field, class, function, or module that has no static representation for the construct, with the diagnostic behind each one. These are the constructs the dynamic tier is planned to compile; today they remain blockers in TypeScript and deferred runtime errors in JavaScript. Add a name, such as `--explain-dynamic=Point`, to show only the matching units. With `--print=diagnostics`, the document gains a `tiers` object with the same information. + +`--tier=static-only` keeps every unsupported construct a blocker instead of moving it to the dynamic tier; code that already operates on runtime-typed values compiles as before. Today `auto`, the default, behaves the same way. + ## Diagnostic codes Coverage and `scriptc build` report the same diagnostic codes. Common ones include: @@ -160,7 +171,7 @@ For editors, CI annotations, and other tools, `scriptc coverage --print=diagnost stats - Coverage only, absent after a preflight failure: the report's statement counts. statementsDynamic is always 0 and remains for schema compatibility. + Coverage only, absent after a preflight failure: the report's statement counts. statementsStatic counts every statement that compiles to native code; statementsDynamic is the part of those in dynamic-tier functions. category diff --git a/packages/compiler/src/cli/command.ts b/packages/compiler/src/cli/command.ts index d729de866..6810cc8fb 100644 --- a/packages/compiler/src/cli/command.ts +++ b/packages/compiler/src/cli/command.ts @@ -7,8 +7,10 @@ import { coverageEnvelope, coveragePasses, renderCoverage, + renderExplainDynamic, type CoverageFailOn, } from "../coverage/report.js"; +import { TIER_MODES, type TierMode } from "../frontend/tier-analysis.js"; import { buildEnvelope } from "../diagnostics/envelope.js"; import { renderWarnings } from "../diagnostics/render.js"; import { isNativeOptimization } from "../backend/optimization.js"; @@ -45,8 +47,15 @@ function parseCli( ): ReturnType< typeof parseArgs<{ options: typeof CLI_OPTIONS; allowPositionals: true; allowNegative: true }> > { + // `--explain-dynamic` takes an optional value: alone it lists every unit. + const normalized = args.map((arg) => (arg === "--explain-dynamic" ? "--explain-dynamic=" : arg)); try { - return parseArgs({ args, options: CLI_OPTIONS, allowPositionals: true, allowNegative: true }); + return parseArgs({ + args: normalized, + options: CLI_OPTIONS, + allowPositionals: true, + allowNegative: true, + }); } catch (err) { // parseArgs appends a paragraph about `--` and positionals to the // unknown-option message; the first sentence is the part that names @@ -91,6 +100,8 @@ async function main(args: string[], host: CliHost): Promise { externalTypeArgs.length > 0 || values.out !== undefined || values["emit-ir"] || + values.tier !== undefined || + values["explain-dynamic"] !== undefined || !values["keep-llvm"] ) { fail( @@ -152,10 +163,12 @@ async function main(args: string[], host: CliHost): Promise { values["windows-subsystem"] !== undefined || values["detached-exit"] || (values["npm-static"] ?? []).length > 0 || - externalTypeArgs.length > 0 + externalTypeArgs.length > 0 || + values.tier !== undefined || + values["explain-dynamic"] !== undefined ) { fail( - "scriptc build --lib takes no --backend/--emit/--print/--optimization/--strip/--windows-subsystem/--detached-exit/--npm-static/--ffi/--external-types: the profile pins the emission and optimization, npm imports are judged automatically, outbound FFI belongs to executable builds, and external type mappings belong to coverage", + "scriptc build --lib takes no --backend/--emit/--print/--optimization/--strip/--windows-subsystem/--detached-exit/--npm-static/--ffi/--external-types/--tier/--explain-dynamic: the profile pins the emission and optimization, npm imports are judged automatically, outbound FFI belongs to executable builds, external type mappings belong to coverage, and library artifacts are static-tier only", ); } const profilePath = resolve(profileArg); @@ -223,6 +236,15 @@ async function main(args: string[], host: CliHost): Promise { fail(`--fail-on is a coverage option (a build already fails on blockers)\n\n${USAGE}`); } const failOn = failOnRaw as CoverageFailOn | undefined; + const tierRaw = values.tier; + if (tierRaw !== undefined && !(TIER_MODES as readonly string[]).includes(tierRaw)) { + fail(`unknown --tier value "${tierRaw}" (supported: ${TIER_MODES.join(", ")})\n\n${USAGE}`); + } + const tier = tierRaw as TierMode | undefined; + const explainDynamic = values["explain-dynamic"]; + if (explainDynamic !== undefined && command !== "coverage") { + fail(`--explain-dynamic is a coverage option\n\n${USAGE}`); + } if (printNativeLinkInfo && command !== "build") { fail(`--print=native-link-info is a build option\n\n${USAGE}`); } @@ -340,6 +362,8 @@ async function main(args: string[], host: CliHost): Promise { ...(npmStatic !== undefined ? { npmStatic } : {}), ...(ffiProfilePath !== undefined ? { ffiProfilePath } : {}), ...(Object.keys(externalTypes).length > 0 ? { externalTypes } : {}), + ...(tier !== undefined ? { tier } : {}), + ...(explainDynamic !== undefined ? { explainDynamic: true } : {}), }); if (printDiagnostics) { // Keep stdout pure JSON for tooling. @@ -354,6 +378,18 @@ async function main(args: string[], host: CliHost): Promise { process.stdout.write( renderCoverage(coverage, { color, sourceTexts, root: process.cwd() }) + "\n", ); + if (explainDynamic !== undefined && coverage.tiers !== undefined) { + process.stdout.write( + "\n" + + renderExplainDynamic(coverage.tiers, { + color, + sourceTexts, + root: process.cwd(), + query: explainDynamic, + }) + + "\n", + ); + } } return coveragePasses(coverage, failOn) ? 0 : 1; } @@ -386,6 +422,7 @@ async function main(args: string[], host: CliHost): Promise { ...(npmStatic !== undefined ? { npmStatic } : {}), ...(ffiProfilePath !== undefined ? { ffiProfilePath } : {}), ...(printNativeLinkInfo ? { nativeLinkInfo: true } : {}), + ...(tier !== undefined ? { tier } : {}), }); if (!result.ok) { if (printDiagnostics) { diff --git a/packages/compiler/src/cli/usage.ts b/packages/compiler/src/cli/usage.ts index a0388374b..97c56c274 100644 --- a/packages/compiler/src/cli/usage.ts +++ b/packages/compiler/src/cli/usage.ts @@ -69,6 +69,16 @@ Options: local declaration file. The declaration supplies types for analysis; the host module remains an explicit external-boundary blocker (repeatable) + --tier + tier policy (default: auto). static-only keeps every + construct without a static lowering a compile error, so + the program has no dynamic-tier demotions. Both modes + currently compile identically + --explain-dynamic[=] + coverage only: list the functions that operate on dynamic + values and the bindings, fields, functions, classes and + modules the dynamic tier would take over, with the + refusal behind each; a name shows only that unit's chain -h, --help show this help -v, --version print the version `; @@ -90,6 +100,8 @@ export const CLI_OPTIONS = { "npm-static": { type: "string", multiple: true }, "provenance-sources": { type: "boolean", default: false }, "external-types": { type: "string", multiple: true }, + tier: { type: "string" }, + "explain-dynamic": { type: "string" }, lib: { type: "boolean", default: false }, profile: { type: "string" }, help: { type: "boolean", short: "h", default: false }, diff --git a/packages/compiler/src/compile-types.ts b/packages/compiler/src/compile-types.ts index de2c1a335..f069df247 100644 --- a/packages/compiler/src/compile-types.ts +++ b/packages/compiler/src/compile-types.ts @@ -3,6 +3,7 @@ import type { NativeLinkInfo } from "./backend/native-link-info.js"; import type { NativeOptimization } from "./backend/optimization.js"; import type { ScrDiagnostic } from "./diagnostics/diagnostic.js"; import type { CoverageInput } from "./coverage/report.js"; +import type { TierMode } from "./frontend/tier-analysis.js"; export type CompileOutputKind = "ir" | "llvm" | "asm" | "obj" | "exe"; @@ -45,6 +46,10 @@ export interface CompileBaseOptions { /** Attach the machine-readable external link recipe to an object result. * Valid only with outputKind "obj"; it never invokes a linker. */ nativeLinkInfo?: boolean; + /** `--tier` (frontend/tier-analysis.ts). "static-only" keeps every demotion + * request a refusal (design invariant I2). Until demotion lands both modes + * compile exactly as before. */ + tier?: TierMode; } /** Executable compile options. This remains the compatibility type for the @@ -161,6 +166,11 @@ export interface AnalyzeOptions { * to analyze project code, but imported runtime values remain explicit * SC1010 blockers rather than being counted as executable. */ externalTypes?: Readonly>; + /** `--tier` (see CompileBaseOptions.tier). */ + tier?: TierMode; + /** `--explain-dynamic`: attach the tier-assignment report + * (CoverageInput.tiers). Such analyses bypass the verdict cache. */ + explainDynamic?: boolean; } export interface AnalyzeResult { diff --git a/packages/compiler/src/coverage/report.ts b/packages/compiler/src/coverage/report.ts index 9d0776d9a..730704f6f 100644 --- a/packages/compiler/src/coverage/report.ts +++ b/packages/compiler/src/coverage/report.ts @@ -17,10 +17,13 @@ import { type DiagnosticsEnvelope, type LocatedDiagnostic, type SourcePosition, + type TierUnitPosition, + type TiersEnvelope, } from "../diagnostics/envelope.js"; import { renderDiagnostics } from "../diagnostics/render.js"; import type { LowerStats } from "../frontend/lowering/lowerer.js"; import type { ProvenanceSources } from "../frontend/provenance-registry.js"; +import type { DemotionUnit, TierReport } from "../frontend/tier-analysis.js"; export interface CoverageInput { file: string; @@ -51,6 +54,9 @@ export interface CoverageInput { /** --provenance-sources: diagnostics of elided pure-annotated dead * consts (off the build; the provenance section names them). */ provenanceElided?: ScrDiagnostic[]; + /** --explain-dynamic: the report-only tier assignment (which bindings, + * fields, functions, classes and modules the dynamic tier would take). */ + tiers?: TierReport; /** True when tsc preflight failed — no coverage can be computed. */ preflightFailed: boolean; } @@ -180,6 +186,12 @@ export function renderCoverage(input: CoverageInput, opts: CoverageRenderOptions out.push(` statements analyzed ${total}`); out.push(` compile statically ${ok} ${c(pctColor, c(BOLD, `(${pct}%)`))}`); + const dynamic = dynamicStatements(input); + if (dynamic > 0) { + out.push( + ` in dynamic tier ${dynamic} ${c(DIM, "(operate on values typed only at runtime; --explain-dynamic lists them)")}`, + ); + } if (skipped > 0) { out.push( @@ -432,13 +444,147 @@ export function coverageEnvelope( stats: { statementsTotal: total, statementsStatic: ok, - statementsDynamic: 0, + statementsDynamic: dynamicStatements(input), statementsFailed: failed, functionsSkipped: skipped, percentStatic: total === 0 ? 100 : Math.floor((ok / total) * 100), }, }), + ...(input.tiers !== undefined ? { tiers: tiersEnvelope(input.tiers, locator) } : {}), groups, diagnostics: located, }; } + +/** Reached statements in dynamic-tier functions, never more than the + * compiled statements they are part of. */ +function dynamicStatements(input: CoverageInput): number { + const compiled = input.stats.statementsTotal - input.stats.statementsFailed; + return Math.max(0, Math.min(input.stats.statementsDynamic ?? 0, compiled)); +} + +function tiersEnvelope(tiers: TierReport, locator: SourceLocator): TiersEnvelope { + const at = (loc: { file: string; start: number }): SourcePosition => ({ + file: loc.file, + ...locator.position(loc.file, loc.start), + }); + const unit = (u: DemotionUnit): TierUnitPosition => ({ + kind: u.kind, + name: u.name, + ...(u.owner !== undefined ? { owner: u.owner } : {}), + ...at(u.loc), + }); + return { + mode: tiers.mode, + statementsDynamic: tiers.statementsDynamic, + dynamicFunctions: tiers.dynamicFunctions.map((fn) => ({ + name: fn.name, + ...at(fn.loc), + operation: fn.operation, + operationAt: at(fn.operationLoc), + statements: fn.statements, + })), + requests: tiers.requests.map((r) => ({ + unit: unit(r.unit), + enclosing: unit(r.enclosing), + seed: r.seed, + scope: r.scope, + code: r.code, + message: r.message, + ...at(r.loc), + })), + units: tiers.units.map((u) => ({ ...unit(u), requests: u.requests, sites: u.sites })), + }; +} + +/** IR function names as a user reads them: `%init.3` is a module's top + * level, `%Point.norm` the method `Point.norm`; generated helpers keep + * their `%`-prefixed names. */ +function functionDisplayName(name: string): string { + if (name.startsWith("%init.")) return ""; + if (/^%[A-Za-z_$][\w$]*\.[A-Za-z_$#][\w$]*$/.test(name)) return name.slice(1); + return name; +} + +function unitLabel(u: DemotionUnit, root: string | undefined): string { + if (u.kind === "module") return `module ${displayPath(u.name, root)}`; + if (u.kind === "binding" && u.owner !== undefined) return `binding ${u.name} in ${u.owner}`; + return `${u.kind} ${u.name}`; +} + +function unitMatches(u: DemotionUnit, query: string): boolean { + return ( + u.name === query || + u.name.endsWith(`.${query}`) || + u.name.split(" ")[0] === query || + `${u.owner ?? ""}:${u.name}` === query + ); +} + +/** `scriptc coverage --explain-dynamic[=]`: the dynamic tier today + * and the demotion chains the report-only analysis computed. With a query, + * only units whose name matches it (`x`, `Point.x`, `parse:x`). */ +export function renderExplainDynamic( + tiers: TierReport, + opts: CoverageRenderOptions & { query?: string } = {}, +): string { + const c = (code: string, s: string) => (opts.color ? code + s + RESET : s); + const locator = new SourceLocator(opts.sourceTexts); + const where = (loc: { file: string; start: number }) => { + const p = locator.position(loc.file, loc.start); + return `${displayPath(loc.file, opts.root)}:${p.line}:${p.column}`; + }; + const query = opts.query !== undefined && opts.query !== "" ? opts.query : undefined; + const out: string[] = []; + out.push( + ` ${c(BOLD, "dynamic tier")} ${c(DIM, `(tier assignment, report-only; --tier=${tiers.mode})`)}`, + ); + if (query === undefined) { + const fns = tiers.dynamicFunctions; + out.push( + ` ${fns.length} function${fns.length === 1 ? "" : "s"} already operate${fns.length === 1 ? "s" : ""} on dynamic values ${c(DIM, `(${tiers.statementsDynamic} statement${tiers.statementsDynamic === 1 ? "" : "s"})`)}`, + ); + for (const fn of fns) { + out.push( + ` ${functionDisplayName(fn.name)} ${c(DIM, `${where(fn.loc)}: ${fn.operation} at ${where(fn.operationLoc)}`)}`, + ); + } + } + const live = tiers.requests.filter((r) => r.scope !== "unreached" && r.seed !== "excluded"); + const excluded = tiers.requests.filter((r) => r.seed === "excluded").length; + const unreached = tiers.requests.filter((r) => r.scope === "unreached").length; + if (query === undefined) { + out.push(""); + out.push( + ` ${live.length} demotion request${live.length === 1 ? "" : "s"} ${c(DIM, "(refusals and fences the dynamic tier would replace)")}` + + (unreached > 0 ? c(DIM, `, ${unreached} more in unreached code`) : "") + + (excluded > 0 ? c(DIM, `, ${excluded} excluded by policy`) : ""), + ); + } + const units = tiers.units.filter((u) => query === undefined || unitMatches(u, query)); + if (query !== undefined && units.length === 0) { + out.push(` no demoted unit matches '${query}'`); + return out.join("\n"); + } + for (const u of units) { + const counts = [ + u.requests > 0 ? `${u.requests} request${u.requests === 1 ? "" : "s"}` : "", + u.sites > 0 ? `${u.sites} site${u.sites === 1 ? "" : "s"} inside` : "", + ] + .filter((s) => s !== "") + .join(", "); + out.push(` ${unitLabel(u, opts.root)} ${c(DIM, `${where(u.loc)} (${counts})`)}`); + if (query === undefined && u.requests === 0) continue; + for (const r of live) { + if (r.unit.kind !== u.kind || r.unit.name !== u.name || r.unit.loc.start !== u.loc.start) + continue; + if (r.unit.loc.file !== u.loc.file) continue; + out.push( + ` ${c(DIM, "<-")} ${r.code} ${r.seed} at ${where(r.loc)}: ${capMessage(r.message)}`, + ); + if (r.enclosing.name !== r.unit.name || r.enclosing.kind !== r.unit.kind) + out.push(` ${c(DIM, "->")} ${unitLabel(r.enclosing, opts.root)} turns dynamic`); + } + } + return out.join("\n"); +} diff --git a/packages/compiler/src/coverage/verdict-cache.ts b/packages/compiler/src/coverage/verdict-cache.ts index 841e2b57b..250259685 100644 --- a/packages/compiler/src/coverage/verdict-cache.ts +++ b/packages/compiler/src/coverage/verdict-cache.ts @@ -89,6 +89,9 @@ export function verdictKey( opts: AnalyzeOptions, cache: VerdictCacheOptions, ): string | null { + // The tier report carries source locations the semantic replay does not + // move; explaining analyses always lower. + if (opts.explainDynamic === true) return null; let ffi = ""; if (opts.ffiProfilePath !== undefined) { try { @@ -120,6 +123,8 @@ export function verdictKey( opts.ffiProfilePath ?? "", ffi, external.join("\n"), + // Demotion (stage S6) makes the tier mode part of the verdict. + ...(opts.tier === "static-only" ? ["tier=static-only"] : []), ].join("\0"), ); } diff --git a/packages/compiler/src/diagnostics/envelope.ts b/packages/compiler/src/diagnostics/envelope.ts index 39b193dd0..4c7c158d9 100644 --- a/packages/compiler/src/diagnostics/envelope.ts +++ b/packages/compiler/src/diagnostics/envelope.ts @@ -81,6 +81,34 @@ export interface DiagnosticGroup { sites: SourcePosition[]; } +export interface TierUnitPosition extends SourcePosition { + kind: "binding" | "field" | "function" | "class" | "module"; + name: string; + owner?: string; +} + +/** `scriptc coverage --explain-dynamic --print=diagnostics`: the tier + * assignment of frontend/tier-analysis.ts with source positions. */ +export interface TiersEnvelope { + mode: "auto" | "static-only"; + statementsDynamic: number; + dynamicFunctions: (SourcePosition & { + name: string; + operation: string; + operationAt: SourcePosition; + statements: number; + })[]; + requests: (SourcePosition & { + unit: TierUnitPosition; + enclosing: TierUnitPosition; + seed: string; + scope: string; + code: string; + message: string; + })[]; + units: (TierUnitPosition & { requests: number; sites: number })[]; +} + export interface DiagnosticsEnvelope { schema: typeof DIAGNOSTICS_SCHEMA; schemaVersion: typeof DIAGNOSTICS_SCHEMA_VERSION; @@ -97,8 +125,10 @@ export interface DiagnosticsEnvelope { stats?: { statementsTotal: number; statementsStatic: number; - /** Always 0: every compiled statement is native. Kept so schema - * version 1 consumers keep reading the same fields. */ + /** The compiled statements (counted in statementsStatic, which covers + * every statement that compiles to native code) that belong to + * dynamic-tier functions: code operating on values whose types are only + * known at runtime. */ statementsDynamic: number; statementsFailed: number; functionsSkipped: number; @@ -106,6 +136,8 @@ export interface DiagnosticsEnvelope { }; /** build only: the produced artifact path. */ artifact?: string; + /** coverage --explain-dynamic only: the report-only tier assignment. */ + tiers?: TiersEnvelope; groups: DiagnosticGroup[]; diagnostics: LocatedDiagnostic[]; } diff --git a/packages/compiler/src/executable/prepare.ts b/packages/compiler/src/executable/prepare.ts index f6012dd2a..7becd2358 100644 --- a/packages/compiler/src/executable/prepare.ts +++ b/packages/compiler/src/executable/prepare.ts @@ -69,6 +69,7 @@ export function prepareExecutableModule( lowered = fe.lower({ targetPlatform: buildPlatform, ...(ffi !== null ? { ffiImports: ffi.functions } : {}), + ...(opts.tier !== undefined ? { tierMode: opts.tier } : {}), }); timing("lower"); } catch (e) { diff --git a/packages/compiler/src/frontend/analysis.ts b/packages/compiler/src/frontend/analysis.ts index b38a267fa..87c7d22ca 100644 --- a/packages/compiler/src/frontend/analysis.ts +++ b/packages/compiler/src/frontend/analysis.ts @@ -90,6 +90,8 @@ export function analyzeWithFrontend( coverage: true, targetPlatform: buildPlatform, ...(ffi !== null ? { ffiImports: ffi.functions } : {}), + ...(opts.tier !== undefined ? { tierMode: opts.tier } : {}), + ...(opts.explainDynamic === true ? { tierReport: { preflight } } : {}), }); const provenance = provenanceSources(); return { @@ -109,6 +111,7 @@ export function analyzeWithFrontend( ...(provenance !== null ? { provenance } : {}), ...(lowered.statsByFile ? { statsByFile: lowered.statsByFile } : {}), ...(lowered.provenanceElided ? { provenanceElided: lowered.provenanceElided } : {}), + ...(lowered.tiers !== undefined ? { tiers: lowered.tiers } : {}), preflightFailed: false, }, sourceTexts: fe.sourceTexts(), diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index b4520d3be..c535d603f 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -110,6 +110,13 @@ import { ClassDynamicDispatch, trackClassFieldCreation } from "./class-dynamic-d import { ClassProtocols } from "./class-protocols.js"; import { earlyReadVarSymbols } from "./var-hoisting.js"; import { recordTextCodecClass } from "../../ir/ir.js"; +import { assignLegacyTiers, type DynamicFunction } from "../../ir/tiers.js"; +import { + analyzeTiers, + dynamicStatementCount, + type TierMode, + type TierReport, +} from "../tier-analysis.js"; import { DeferredModuleInitializers } from "./deferred-module-initializers.js"; import { finalizeClassMethodValues } from "./class-method-values.js"; import type { ClassSymbolKey } from "./symbol-fields.js"; @@ -627,6 +634,9 @@ export interface LowerStats { /** Functions whose signature couldn't be analyzed (bodies not counted). */ functionsSkipped: number; + /** Coverage only: reached statements that compile into dynamic-tier + * functions (tier-analysis.ts), a subset of the compiled statements. */ + statementsDynamic?: number; } /** Every identifier a binding name binds: the identifier itself, or all @@ -701,6 +711,11 @@ export interface LowerResult { /** Compile-time-detectable behavior differences from Node (SC6xxx * divergence warnings) in the program's own modules. Never failures. */ divergences?: ScrDiagnostic[]; + /** Functions lowering placed in the dynamic tier (ir/tiers.ts), present + * when there are any. */ + dynamicFunctions?: DynamicFunction[]; + /** LowerOptions.tierReport: the report-only tier assignment. */ + tiers?: TierReport; } export interface LowerOptions { @@ -750,6 +765,12 @@ export interface LowerOptions { /** The mapped entries plus relative declaration dependencies, attributed * to their owning external specifier. */ externalTypeSpecifiersByFile?: ReadonlyMap; + /** `--tier` (tier-analysis.ts); "auto" when absent. */ + tierMode?: TierMode; + /** Coverage only: compute the tier-assignment report (`--explain-dynamic`). + * `preflight` holds the import and package refusals coverage reports + * beside the lowering's own blockers; they request module demotions. */ + tierReport?: { preflight: readonly ScrDiagnostic[] }; } interface RuntimeFenceFallback { @@ -825,6 +846,8 @@ export interface LowererMode { externalTypes?: ReadonlyMap; /** LowerOptions.externalTypeSpecifiersByFile, shared by every pass. */ externalTypeSpecifiersByFile?: ReadonlyMap; + /** LowerOptions.tierMode, shared by every pass. */ + tierMode?: TierMode; } function directExternalTypeSpecifiersByFile( @@ -916,6 +939,7 @@ export function lowerToIr( const externalTypes = options.externalTypes ?? new Map(); const externalTypeSpecifiersByFile = options.externalTypeSpecifiersByFile ?? directExternalTypeSpecifiersByFile(externalTypes); + const tierMode = options.tierMode ?? "auto"; const validation = new Lowerer(program, entry, moduleOrder, { frontendServices: options.frontendServices, projectCheckJs: options.projectCheckJs ?? false, @@ -927,6 +951,7 @@ export function lowerToIr( workerTargets, externalTypes, externalTypeSpecifiersByFile, + tierMode, }); const ffiValidation = validateFfiImports(validation); timing("ffi-validate"); @@ -949,6 +974,7 @@ export function lowerToIr( workerTargets, externalTypes, externalTypeSpecifiersByFile, + tierMode, ffiBindingSymbols: ffiValidation.symbolsByName, }); for (const d of extraModuleCycleDiags) reachableEmit.pushDiag(d); @@ -979,6 +1005,7 @@ export function lowerToIr( ffiBindingSymbols: ffiValidation.symbolsByName, externalTypes, externalTypeSpecifiersByFile, + tierMode, }); for (const d of extraModuleCycleDiags) emit.pushDiag(d); for (const d of ffiValidation.diagnostics) emit.pushDiag(d); @@ -1037,18 +1064,42 @@ export function lowerToIr( ffiBindingSymbols: ffiValidation.symbolsByName, externalTypes, externalTypeSpecifiersByFile, + tierMode, }); const rem = remainder.run(); + timing("coverage-remainder"); + // Tiers (tier-analysis.ts): reached statements in dynamic-tier functions, + // and with tierReport the report-only demotion analysis. + const dynamicFunctions = resultLowerer.dynamicBodies; + const tiers = + options.tierReport === undefined + ? undefined + : analyzeTiers(program, { + mode: tierMode, + dynamicFunctions, + reached: [...options.tierReport.preflight, ...result.diagnostics], + deferred: result.runtimeFences, + unreached: [...rem.diagnostics, ...rem.runtimeFences], + }); + // A dynamic function's own statements can include ones that failed. + const statementsDynamic = Math.min( + tiers?.statementsDynamic ?? dynamicStatementCount(program, dynamicFunctions), + result.stats.statementsTotal - result.stats.statementsFailed, + ); + if (tiers !== undefined) tiers.statementsDynamic = statementsDynamic; + timing("tier-analysis", { dynamic: dynamicFunctions.length }); // Unreached JS statements whose fences deferred to runtime count as // failed statements in the remainder's stats, so their diagnostics must // travel with them: a failed statement is never left unexplained. return { ...result, + stats: { ...result.stats, statementsDynamic }, unreached: { diagnostics: rem.diagnostics, stats: rem.stats, ...(rem.runtimeFences.length > 0 ? { runtimeFences: rem.runtimeFences } : {}), }, + ...(tiers !== undefined ? { tiers } : {}), }; } @@ -2664,6 +2715,14 @@ export class Lowerer { /** Coverage remainder mode: the reachability gate inverts (see wantBody) * and no module is built. */ readonly remainder: boolean; + /** `--tier` (tier-analysis.ts). Stage S2 is report-only: both modes + * refuse and fence exactly as before. Stage S6 demotes the units of + * committed refusals in "auto" and keeps them refusals in "static-only". */ + readonly tierMode: TierMode; + /** Functions finishModule placed in the dynamic tier (ir/tiers.ts). */ + dynamicFunctions: DynamicFunction[] = []; + /** Their IR, for coverage's dynamic statement count. */ + dynamicBodies: IrFunction[] = []; /** Deferred collection diagnostics (failed signatures/class shapes) by * declaration symbol: an unreached declaration must not fail the build, * so its diagnostics wait until a reference makes them relevant. */ @@ -2750,6 +2809,7 @@ export class Lowerer { this.frontendServices = mode.frontendServices; this.reachable = mode.reachable ?? null; this.remainder = mode.remainder ?? false; + this.tierMode = mode.tierMode ?? "auto"; this.alreadyFlushed = mode.alreadyFlushed ?? new Set(); this.targetPlatform = mode.targetPlatform ?? process.platform; this.startupCrash = mode.startupCrash ?? null; @@ -6336,11 +6396,18 @@ export class Lowerer { }; if (module) sanitizeUnregisteredClassTypes(module, (name) => this.classes.has(name)); if (module) checkCycleBindingAccesses(this, module); + // Execution tiers from the final bodies (ir/tiers.ts). Assigned with or + // without a module: coverage reports the dynamic tier of programs that + // still have blockers. + this.dynamicFunctions = assignLegacyTiers(functions); + if (this.dynamicFunctions.length > 0) + this.dynamicBodies = functions.filter((fn) => fn.tier === "dynamic"); return { module, diagnostics: this.diags, runtimeFences: this.runtimeFences, stats: this.stats, + ...(this.dynamicFunctions.length > 0 ? { dynamicFunctions: this.dynamicFunctions } : {}), ...(this.statsByFile.size > 0 ? { statsByFile: this.statsByFile } : {}), ...(this.provenanceElided.length > 0 ? { provenanceElided: this.provenanceElided } : {}), }; diff --git a/packages/compiler/src/frontend/tier-analysis.ts b/packages/compiler/src/frontend/tier-analysis.ts new file mode 100644 index 000000000..ded7c5225 --- /dev/null +++ b/packages/compiler/src/frontend/tier-analysis.ts @@ -0,0 +1,629 @@ +/* Tier assignment, report-only (two-tier design, stage S2). + * + * The design assigns every binding, field, function instance, class and + * module a tier. Static is today's compiler; dynamic code operates on + * dynamic values. Demotion from static to dynamic is monotone and is seeded + * by `any`, untyped JavaScript, types and operations without a static + * lowering, reflection a static layout cannot answer, and dynamic modules + * (DESIGN.md §6). + * + * Stage S2 computes what WOULD be demoted without demoting anything: + * + * 1. Existing dynamic code. Functions whose bodies already use the `dyn` + * vocabulary are the dynamic tier today (ir/tiers.ts assigns them). The + * source statements whose lowering performs a dynamic operation are the + * coverage report's statementsDynamic. + * 2. Demotion requests. Every refusal or runtime fence the lowerer commits + * (today's poison sites: the SC1xxx/SC2xxx families) and every refused + * import or package becomes a request, attributed to the unit whose + * static representation could not express the construct. The lowerer + * still refuses or fences exactly as before; the requests are recorded + * from the committed diagnostics, so speculative probes that roll back + * record nothing. Under `--tier=static-only` every request stays today's + * refusal; stage S6 turns requests into demotions in the default mode. + * 3. Demoted units. A request demotes its unit, and the function instance + * containing the site turns dynamic (it would hold dynamic operations, + * invariant I1). Units are deduplicated; each keeps its requests, which + * is the chain `--explain-dynamic` prints. + * + * Attribution is syntactic and approximate: the site's innermost node, the + * operand it acts on, and that operand's declaration. Stage S6 replaces it + * with requests the failing lowering names exactly. */ +import type { ScrDiagnostic } from "../diagnostics/diagnostic.js"; +import type { IrFunction, SrcLoc } from "../ir/ir.js"; +import { dynamicOperationSites, type DynamicFunction } from "../ir/tiers.js"; +import * as ts from "./ts7/adapter.js"; + +/** `--tier`: "auto" (the default) will demote; "static-only" keeps every + * demotion request a refusal (design invariant I2). Identical in S2. */ +export type TierMode = "auto" | "static-only"; + +export const TIER_MODES: readonly TierMode[] = ["auto", "static-only"]; + +export type DemotionUnitKind = "binding" | "field" | "function" | "class" | "module"; + +export interface DemotionUnit { + kind: DemotionUnitKind; + /** Display name: `x`, `Point.x`, `parse`, `Parser.next`, `Point`, or the + * module's file path. */ + name: string; + /** Bindings: the function declaring a local, absent for module scope. */ + owner?: string; + /** The unit's declaration (the site itself when none is known). */ + loc: SrcLoc; +} + +/** Why a unit is demoted (DESIGN.md §6.2): a type with no static + * representation, an operation with no static lowering, reflection on a + * class, a use of a binding whose declaration was refused, a module or + * package that cannot be static, or a construct excluded by policy (no + * demotion: it stays a refusal). */ +export type DemotionSeed = "type" | "operation" | "reflection" | "cascade" | "module" | "excluded"; + +export type DemotionScope = "reached" | "deferred" | "unreached"; + +export interface DemotionRequest { + unit: DemotionUnit; + /** The function instance (or module top level) containing the site. */ + enclosing: DemotionUnit; + seed: DemotionSeed; + scope: DemotionScope; + code: string; + message: string; + loc: SrcLoc; +} + +export interface DemotedUnit extends DemotionUnit { + /** Requests naming this unit directly. */ + requests: number; + /** Requests whose sites this function instance or module contains. */ + sites: number; +} + +export interface TierDynamicFunction extends DynamicFunction { + /** Source statements with a dynamic operation in this function. */ + statements: number; +} + +export interface TierReport { + mode: TierMode; + /** Reached source statements that perform a dynamic operation. */ + statementsDynamic: number; + dynamicFunctions: TierDynamicFunction[]; + requests: DemotionRequest[]; + /** Units the requests would demote (reached and deferred scopes), + * deduplicated, by kind then source order. */ + units: DemotedUnit[]; +} + +/* ── statements of dynamic functions ─────────────────────────────────── */ + +function isClassLike(node: ts.Node): boolean { + return ts.isClassDeclaration(node) || ts.isClassExpression(node); +} + +/** The innermost node spanning exactly or containing [start, end). */ +function nodeAt(sf: ts.SourceFile, start: number, end: number): ts.Node { + let node: ts.Node = sf; + for (;;) { + let next: ts.Node | undefined; + node.forEachChild((child) => { + if (child.getStart(sf) <= start && end <= child.getEnd()) { + next = child; + return true; + } + return undefined; + }); + if (next === undefined) return node; + node = next; + } +} + +/** The source statement an IR location belongs to: the innermost + * statement containing it, or an arrow function's expression body. Null + * for synthetic locations. */ +function statementAt(program: ts.Program, loc: SrcLoc): ts.Node | null { + if (loc.start === 0 && loc.end === 0) return null; + const sf = program.getSourceFile(loc.file); + if (sf === undefined) return null; + let node: ts.Node | undefined = nodeAt(sf, loc.start, loc.end); + while (node !== undefined && !ts.isSourceFile(node)) { + const parent: ts.Node | undefined = node.parent; + if (parent !== undefined && ts.isArrowFunction(parent) && parent.body === node) return node; + if (ts.isStatement(node) && !ts.isBlock(node)) return node; + node = parent; + } + return null; +} + +/** Dynamic statements are the source statements whose lowering performs a + * dynamic operation (in the function itself or in a generated helper it + * calls). They count once however many functions and operations they + * involve. A function's tier is the unit of I1, but static operations + * inside a dynamic function stay static, so the statement is the honest + * measure of how much code is dynamic. */ +function dynamicFunctionReports( + program: ts.Program, + bodies: readonly IrFunction[], +): { functions: TierDynamicFunction[]; statements: number } { + const byLoc = new Map(); + const all = new Set(); + const functions: TierDynamicFunction[] = []; + for (const fn of bodies) { + const sites = dynamicOperationSites(fn); + if (sites.length === 0) continue; + const own = new Set(); + for (const site of sites) { + const key = `${site.loc.file}\0${site.loc.start}\0${site.loc.end}`; + let statement = byLoc.get(key); + if (statement === undefined) { + statement = statementAt(program, site.loc); + byLoc.set(key, statement); + } + if (statement === null) continue; + own.add(statement); + all.add(statement); + } + functions.push({ + name: fn.name, + loc: fn.loc, + operation: sites[0]!.operation, + operationLoc: sites[0]!.loc, + statements: own.size, + }); + } + return { functions, statements: all.size }; +} + +/* ── demotion requests ───────────────────────────────────────────────── */ + +const TYPE_CODES = new Set([ + "SC2001", + "SC2002", + "SC2003", + "SC2005", + "SC2006", + "SC2007", + "SC2008", + "SC2009", + "SC2011", + "SC1063", + "SC1100", + "SC1101", +]); +const MODULE_CODES = new Set([ + "SC1010", + "SC1012", + "SC1013", + "SC1014", + "SC1015", + "SC1016", + "SC2013", +]); +/** Runtime code generation (`eval`, `new Function`): excluded by policy, + * since the dynamic tier compiles ahead of time (DESIGN.md §12 class X). */ +const EXCLUDED_CODES = new Set(["SC2010"]); +const EXCLUDED_SURFACE = /^'(?:new Function|Function|eval)'/; + +/** Refusals and fences that name a static-tier gap. Type errors, + * environment and target refusals, divergences and internal errors are + * not demotion requests. */ +export function isDemotionCode(code: string): boolean { + return /^SC[12]\d{3}$/.test(code); +} + +function isFunctionLikeOrFile(node: ts.Node): boolean { + return ( + ts.isSourceFile(node) || + ts.isFunctionLikeDeclaration(node) || + ts.isClassStaticBlockDeclaration(node) + ); +} + +function nameText(name: ts.Node | undefined): string | null { + if (name === undefined) return null; + if (ts.isIdentifier(name) || ts.isPrivateIdentifier(name)) return name.text; + if (ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text; + return null; +} + +function className(node: ts.Node | undefined): string { + if (node === undefined) return ""; + if ((ts.isClassDeclaration(node) || ts.isClassExpression(node)) && node.name !== undefined) + return node.name.text; + const parent = node.parent; + if (parent !== undefined && ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) + return parent.name.text; + return ""; +} + +/** The display name of a function-like node, as a user would look it up. */ +function functionName(node: ts.Node): string { + if (ts.isSourceFile(node)) return ""; + if (ts.isClassStaticBlockDeclaration(node)) return `${className(node.parent)}.`; + if (ts.isConstructorDeclaration(node)) return `${className(node.parent)}.constructor`; + const own = ts.isFunctionLikeDeclaration(node) ? nameText(node.name) : null; + const parent = node.parent; + if (parent !== undefined && isClassLike(parent) && own !== null) + return `${className(parent)}.${own}`; + if (own !== null) return own; + if (parent !== undefined) { + if (ts.isVariableDeclaration(parent) || ts.isPropertyAssignment(parent)) { + const bound = nameText(parent.name); + if (bound !== null) return bound; + } + if ( + ts.isPropertyDeclaration(parent) && + parent.parent !== undefined && + isClassLike(parent.parent) + ) { + const field = nameText(parent.name); + if (field !== null) return `${className(parent.parent)}.${field}`; + } + if (ts.isBinaryExpression(parent) && parent.right === node) { + const left = parent.left; + if (ts.isIdentifier(left)) return left.text; + if (ts.isPropertyAccessExpression(left)) return left.getText(); + } + } + const sf = node.getSourceFile(); + const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart(sf)); + return ``; +} + +function locOfNode(node: ts.Node): SrcLoc { + const sf = node.getSourceFile(); + return { file: sf.fileName, start: node.getStart(sf), end: node.getEnd() }; +} + +function enclosingFunction(node: ts.Node): ts.Node { + let current: ts.Node | undefined = node.parent; + while (current !== undefined && !isFunctionLikeOrFile(current)) current = current.parent; + return current ?? node.getSourceFile(); +} + +function functionUnit(node: ts.Node, instance: string | null): DemotionUnit { + // Top-level code runs in the module's initializer function. + if (ts.isSourceFile(node)) + return { + kind: "function", + name: "", + loc: { file: node.fileName, start: 0, end: 0 }, + }; + const name = functionName(node); + return { + kind: "function", + name: instance === null ? name : `${name} ${instance}`, + loc: locOfNode(node), + }; +} + +/** Generic instances append their instantiation context to diagnostics + * (Lowerer.pushDiag: ` (instantiating 'f' with )`); the instance, not + * the source function, is the unit. Returns the type-argument text. */ +function instanceOf(message: string): string | null { + const at = message.lastIndexOf(" (instantiating "); + if (at < 0 || !message.endsWith(")")) return null; + const context = message.slice(at + 2, -1); + const withAt = context.indexOf(" with "); + return withAt < 0 ? context : context.slice(withAt + 6); +} + +/** Strip wrappers and walk receivers down to the value an operation acts + * on: `a.b.c(…)` → `a`, `(x as T)[k]` → `x`. Records whether the chain + * passes through `.prototype`. */ +function rootOf(expr: ts.Node): { root: ts.Node; viaPrototype: boolean } { + let node = expr; + let viaPrototype = false; + for (;;) { + if ( + ts.isParenthesizedExpression(node) || + ts.isAsExpression(node) || + ts.isNonNullExpression(node) || + ts.isAssertionExpression(node) || + ts.isSatisfiesExpression(node) || + ts.isSpreadElement(node) || + ts.isAwaitExpression(node) + ) { + node = node.expression!; + } else if (ts.isPropertyAccessExpression(node)) { + if (node.name.text === "prototype") viaPrototype = true; + node = node.expression; + } else if (ts.isElementAccessExpression(node) || ts.isCallExpression(node)) { + node = node.expression; + } else if ( + ts.isDeleteExpression(node) || + ts.isTypeOfExpression(node) || + ts.isVoidExpression(node) + ) { + node = node.expression; + } else { + return { root: node, viaPrototype }; + } + } +} + +const REFLECTION_NAMESPACES = new Set(["Object", "Reflect"]); + +/** The expression an operation at `node` acts on. Reflection calls + * (`Object.defineProperty(x, …)`, `Reflect.set(x, …)`) act on their first + * argument; `new C()` and `x instanceof C` on the class value. */ +function subjectOf(node: ts.Node): ts.Node { + let current = node; + // A refused callee or member name: the whole call or access is the site. + const parent = current.parent; + if (parent !== undefined && ts.isPropertyAccessExpression(parent) && parent.name === current) + current = parent; + if (ts.isCallExpression(current)) { + const callee = current.expression; + if ( + ts.isPropertyAccessExpression(callee) && + ts.isIdentifier(callee.expression) && + REFLECTION_NAMESPACES.has(callee.expression.text) && + current.arguments.length > 0 + ) { + return current.arguments[0]!; + } + return callee; + } + if (ts.isNewExpression(current)) return current.expression; + if (ts.isBinaryExpression(current)) { + if (current.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword) return current.right; + if (current.operatorToken.kind === ts.SyntaxKind.EqualsToken) return current.left; + } + return current; +} + +/** The declaration owning a type-refused node: the binding, parameter, + * field or function whose declared type has no static representation. */ +function typeOwnerOf(node: ts.Node): ts.Node | null { + let current: ts.Node | undefined = node; + while (current !== undefined && !ts.isSourceFile(current)) { + if ( + ts.isVariableDeclaration(current) || + ts.isParameter(current) || + ts.isBindingElement(current) || + ts.isPropertyDeclaration(current) || + ts.isPropertySignature(current) || + ts.isCatchClause(current) + ) { + return current; + } + if (ts.isFunctionLikeDeclaration(current) || isClassLike(current)) return current; + if (ts.isStatement(current)) return null; + current = current.parent; + } + return null; +} + +function isModuleObjectName(node: ts.Node): boolean { + return ts.isIdentifier(node) && (node.text === "exports" || node.text === "module"); +} + +class UnitResolver { + constructor(private readonly checker: ts.TypeChecker) {} + + /** The unit a declaration node denotes. */ + declarationUnit(decl: ts.Node): DemotionUnit | null { + if (isClassLike(decl)) return { kind: "class", name: className(decl), loc: locOfNode(decl) }; + if (ts.isFunctionLikeDeclaration(decl)) return functionUnit(decl, null); + if (ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl)) { + const field = nameText(decl.name) ?? ""; + const owner = decl.parent; + const ownerName = owner !== undefined && isClassLike(owner) ? className(owner) : null; + return { + kind: ownerName === null ? "binding" : "field", + name: ownerName === null ? field : `${ownerName}.${field}`, + loc: locOfNode(decl), + }; + } + if (ts.isCatchClause(decl)) { + const binding = decl.variableDeclaration; + if (binding === undefined) return null; + return this.declarationUnit(binding); + } + if (ts.isVariableDeclaration(decl) || ts.isParameter(decl) || ts.isBindingElement(decl)) { + const name = nameText(decl.name) ?? decl.name?.getText() ?? ""; + const scope = enclosingFunction(decl); + const unit: DemotionUnit = { kind: "binding", name, loc: locOfNode(decl) }; + if (ts.isParameter(decl) && ts.isFunctionLikeDeclaration(decl.parent)) + unit.owner = functionName(decl.parent); + else if (!ts.isSourceFile(scope)) unit.owner = functionName(scope); + return unit; + } + return null; + } + + /** The unit an operand expression denotes. */ + valueUnit(expr: ts.Node): { unit: DemotionUnit; reflection: boolean } | null { + const { root, viaPrototype } = rootOf(expr); + const sf = root.getSourceFile(); + if (root.kind === ts.SyntaxKind.ThisKeyword) { + const owner = enclosingFunction(root); + if (ts.isSourceFile(owner)) + return { + unit: { kind: "module", name: sf.fileName, loc: locOfNode(sf) }, + reflection: false, + }; + const cls = owner.parent; + if (cls !== undefined && isClassLike(cls)) { + // `this.f` names a field; `this` itself is the instance. + const access = root.parent; + if ( + access !== undefined && + ts.isPropertyAccessExpression(access) && + access.expression === root + ) { + return { + unit: { + kind: "field", + name: `${className(cls)}.${access.name.text}`, + loc: locOfNode(access), + }, + reflection: false, + }; + } + return { + unit: { kind: "class", name: className(cls), loc: locOfNode(cls) }, + reflection: viaPrototype, + }; + } + return null; + } + if (!ts.isIdentifier(root)) return null; + let symbol = this.checker.getSymbolAtLocation(root); + if (symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0) + symbol = this.checker.getAliasedSymbol(symbol); + const decls = symbol === undefined ? [] : this.checker.declarationsOf(symbol); + const decl = decls.find((d) => !d.getSourceFile().isDeclarationFile); + if (decl === undefined) { + // CommonJS `exports`/`module` as values: the module object. + if (isModuleObjectName(root)) + return { + unit: { kind: "module", name: sf.fileName, loc: locOfNode(sf) }, + reflection: false, + }; + return null; + } + if (ts.isSourceFile(decl)) + return { + unit: { kind: "module", name: decl.fileName, loc: locOfNode(decl) }, + reflection: false, + }; + const unit = this.declarationUnit(decl); + if (unit === null) return null; + // `C.prototype.m = …`, `Object.defineProperty(C.prototype, …)`: the + // class (or the constructor function's prototype object). + if (viaPrototype && (unit.kind === "class" || unit.kind === "function")) + return { unit: { ...unit, kind: "class" }, reflection: true }; + return { unit, reflection: unit.kind === "class" }; + } +} + +function seedOf(code: string, message: string): DemotionSeed { + if (EXCLUDED_CODES.has(code) || EXCLUDED_SURFACE.test(message)) return "excluded"; + if (code === "SC2004") return "cascade"; + if (MODULE_CODES.has(code)) return "module"; + if (TYPE_CODES.has(code)) return "type"; + return "operation"; +} + +/** One request for a committed refusal or fence diagnostic. */ +function requestFor( + program: ts.Program, + resolver: UnitResolver, + diag: ScrDiagnostic, + scope: DemotionScope, +): DemotionRequest | null { + if (!isDemotionCode(diag.code)) return null; + let seed = seedOf(diag.code, diag.message); + const base = { code: diag.code, message: diag.message, loc: diag.loc, scope }; + const sf = program.getSourceFile(diag.loc.file); + if (sf === undefined) { + const unit: DemotionUnit = { kind: "module", name: diag.loc.file, loc: diag.loc }; + return { ...base, unit, enclosing: unit, seed }; + } + const moduleUnit: DemotionUnit = { kind: "module", name: sf.fileName, loc: locOfNode(sf) }; + const node = nodeAt(sf, diag.loc.start, diag.loc.end); + const instance = instanceOf(diag.message); + const owner = ts.isSourceFile(node) ? sf : enclosingFunction(node); + const enclosing = functionUnit(owner, instance); + if (seed === "module" || ts.isSourceFile(node)) + return { ...base, unit: moduleUnit, enclosing, seed }; + let unit: DemotionUnit | null = null; + if (seed === "type") { + const decl = typeOwnerOf(node); + if (decl !== null) unit = resolver.declarationUnit(decl); + } + if (unit === null) { + const value = resolver.valueUnit(subjectOf(node)); + if (value !== null) { + unit = value.unit; + if (value.reflection && seed === "operation") seed = "reflection"; + } + } + return { ...base, unit: unit ?? enclosing, enclosing, seed }; +} + +function unitKey(unit: DemotionUnit): string { + return `${unit.kind}\0${unit.name}\0${unit.owner ?? ""}\0${unit.loc.file}\0${unit.loc.start}`; +} + +const KIND_ORDER: readonly DemotionUnitKind[] = ["module", "class", "field", "function", "binding"]; + +function demotedUnits(requests: readonly DemotionRequest[]): DemotedUnit[] { + const units = new Map(); + const entry = (unit: DemotionUnit): DemotedUnit => { + const key = unitKey(unit); + let found = units.get(key); + if (found === undefined) units.set(key, (found = { ...unit, requests: 0, sites: 0 })); + return found; + }; + for (const request of requests) { + if (request.scope === "unreached" || request.seed === "excluded") continue; + entry(request.unit).requests++; + entry(request.enclosing).sites++; + } + return [...units.values()].sort( + (a, b) => + KIND_ORDER.indexOf(a.kind) - KIND_ORDER.indexOf(b.kind) || + a.loc.file.localeCompare(b.loc.file) || + a.loc.start - b.loc.start || + a.name.localeCompare(b.name), + ); +} + +export interface TierAnalysisInput { + mode: TierMode; + /** The dynamic-tier IR functions of the reached program. */ + dynamicFunctions: readonly IrFunction[]; + reached: readonly ScrDiagnostic[]; + deferred: readonly ScrDiagnostic[]; + unreached: readonly ScrDiagnostic[]; +} + +/** Coverage's statementsDynamic (see dynamicFunctionReports). */ +export function dynamicStatementCount( + program: ts.Program, + dynamicFunctions: readonly IrFunction[], +): number { + return dynamicFunctionReports(program, dynamicFunctions).statements; +} + +export function analyzeTiers(program: ts.Program, input: TierAnalysisInput): TierReport { + const resolver = new UnitResolver(program.getTypeChecker()); + const requests: DemotionRequest[] = []; + const add = (diags: readonly ScrDiagnostic[], scope: DemotionScope): void => { + for (const diag of diags) { + let request: DemotionRequest | null; + try { + request = requestFor(program, resolver, diag, scope); + } catch { + // Attribution is best effort; a report never fails an analysis. + if (!isDemotionCode(diag.code)) continue; + const unit: DemotionUnit = { kind: "module", name: diag.loc.file, loc: diag.loc }; + request = { + unit, + enclosing: unit, + seed: seedOf(diag.code, diag.message), + scope, + code: diag.code, + message: diag.message, + loc: diag.loc, + }; + } + if (request !== null) requests.push(request); + } + }; + add(input.reached, "reached"); + add(input.deferred, "deferred"); + add(input.unreached, "unreached"); + const dynamic = dynamicFunctionReports(program, input.dynamicFunctions); + return { + mode: input.mode, + statementsDynamic: dynamic.statements, + dynamicFunctions: dynamic.functions, + requests, + units: demotedUnits(requests), + }; +} diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index c3009665a..56b787e18 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -172,11 +172,22 @@ export { } from "./diagnostics/render.js"; export { renderCoverage, + renderExplainDynamic, coverageEnvelope, coveragePasses, type CoverageInput, type CoverageFailOn, } from "./coverage/report.js"; +export { + TIER_MODES, + type DemotedUnit, + type DemotionRequest, + type DemotionSeed, + type DemotionUnit, + type DemotionUnitKind, + type TierMode, + type TierReport, +} from "./frontend/tier-analysis.js"; export { buildEnvelope, DIAGNOSTICS_SCHEMA_VERSION, @@ -208,6 +219,13 @@ export { } from "./compat/fetch-profile.js"; export { LIB_FN_SIGS } from "./ir/builtin-signatures.js"; export { validateModule } from "./ir/validate.js"; +export { + assignLegacyTiers, + dynamicOperationOf, + functionTier, + type DynamicFunction, + type IrTier, +} from "./ir/tiers.js"; export { deserializeModule, deserializeModuleBytes, diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 9591c684a..9a4a12189 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1656,6 +1656,14 @@ export interface IrFunction { sourceName?: string; /** Ordinary authored function declarations/expressions own a prototype. */ ownsPrototype?: true; + /** The function's execution tier (ir/tiers.ts). Absent means static: the + * function may use dynamic values only through boundary operations + * (dynFrom, dynCheck, kind tests) and moves, which the validator enforces + * (invariant I1). "dynamic" admits the dynamic operation vocabulary + * (dynKeyGet, dynCall, dyn.* builtins, ...). Lowering assigns the field + * from the body (assignLegacyTiers); stage S2 of the two-tier design + * keeps it out of serialized IR, so loaders derive it again. */ + tier?: "dynamic"; body: IrStmt[]; loc: SrcLoc; } diff --git a/packages/compiler/src/ir/serialize.ts b/packages/compiler/src/ir/serialize.ts index 54e210ea3..1d0e5364e 100644 --- a/packages/compiler/src/ir/serialize.ts +++ b/packages/compiler/src/ir/serialize.ts @@ -7,6 +7,7 @@ * text parts and decoded from bytes one function at a time; neither direction * materializes the complete document as a single string. */ import type { IrExpr, IrFunction, IrModule, IrStmt } from "./ir.js"; +import { deriveModuleTiers } from "./tiers.js"; // Version 16 removes embedded-engine types, operations, and module metadata. // Older modules can require runtime support that no longer exists. @@ -42,6 +43,19 @@ function encodeNumber(_key: string, value: unknown): unknown { return value; } +/** Stage S2 of the two-tier design keeps function tiers out of IR + * artifacts, so a report-only release changes no serialized byte; loaders + * derive them again (deriveModuleTiers). No IR node other than a function + * carries a `tier` key. */ +function encodeWithoutTier(key: string, value: unknown): unknown { + return key === "tier" ? undefined : encodeNumber(key, value); +} + +function encodeFunction(fn: IrFunction): string | undefined { + if (fn.tier !== undefined) return JSON.stringify(fn, encodeWithoutTier); + return ordinaryNumbers(fn) ? JSON.stringify(fn) : JSON.stringify(fn, encodeNumber); +} + /** The compact encoding as ordered parts: the module header up to the * function array, one part per function (with separate comma parts), and the * header's remainder. Concatenating the parts yields exactly @@ -58,9 +72,7 @@ export function serializeModuleParts(mod: IrModule): string[] { for (let index = 0; index < mod.functions.length; index++) { const fn = mod.functions[index]!; if (index > 0) parts.push(","); - parts.push( - (ordinaryNumbers(fn) ? JSON.stringify(fn) : JSON.stringify(fn, encodeNumber)) ?? "null", - ); + parts.push(encodeFunction(fn) ?? "null"); } parts.push("]" + header.slice(offset + slot.length)); return parts; @@ -70,7 +82,7 @@ export function serializeModuleParts(mod: IrModule): string[] { * readable default. Both return one string, so modules whose encoding * exceeds the host's string limit must use `serializeModuleParts`. */ export function serializeModule(mod: IrModule, compact = false): string { - if (!compact) return JSON.stringify(mod, encodeNumber, 2); + if (!compact) return JSON.stringify(mod, encodeWithoutTier, 2); return serializeModuleParts(mod).join(""); } @@ -96,7 +108,7 @@ function checkedVersion(mod: IrModule): IrModule { } export function deserializeModule(json: string): IrModule { - return checkedVersion(JSON.parse(json, decodeNumber) as IrModule); + return deriveModuleTiers(checkedVersion(JSON.parse(json, decodeNumber) as IrModule)); } /** A node as it reads back from the compact encoding: a fresh object, as @@ -249,5 +261,5 @@ export function deserializeModuleBytes(bytes: Buffer): IrModule { ); } mod.functions = functions; - return mod; + return deriveModuleTiers(mod); } diff --git a/packages/compiler/src/ir/tiers.test.ts b/packages/compiler/src/ir/tiers.test.ts new file mode 100644 index 000000000..c5f1ad4b8 --- /dev/null +++ b/packages/compiler/src/ir/tiers.test.ts @@ -0,0 +1,142 @@ +import { expect, test } from "vitest"; +import { BOOL, DYN, F64, STRING, VOID, type IrExpr, type IrFunction, type IrModule } from "./ir.js"; +import { + deserializeModule, + deserializeModuleBytes, + serializeModule, + serializeModuleParts, +} from "./serialize.js"; +import { + assignLegacyTiers, + dynamicOperationOf, + firstDynamicOperation, + functionTier, +} from "./tiers.js"; +import { validateModule } from "./validate.js"; + +const loc = { file: "tiers.ts", start: 0, end: 0 }; +const dynParam = { kind: "varRef", localId: "v", type: DYN, loc } as const satisfies IrExpr; + +function fn(name: string, value: IrExpr): IrFunction { + return { + name, + params: [{ localId: "v", name: "v", type: DYN }], + returnType: value.type, + locals: [{ id: "v", name: "v", type: DYN, mutable: false }], + body: [{ kind: "return", value, loc }], + loc, + }; +} + +function moduleOf(...functions: IrFunction[]): IrModule { + const main: IrFunction = { + name: "%main", + params: [], + returnType: VOID, + locals: [], + body: [], + loc, + }; + return { irVersion: 16, sourceFile: "tiers.ts", functions: [main, ...functions], entry: "%main" }; +} + +const keyGet: IrExpr = { + kind: "dynKeyGet", + key: { kind: "strLit", value: "name", type: STRING, loc }, + value: dynParam, + type: DYN, + loc, +}; + +test("dynamic operations and boundary operations are told apart", () => { + expect(dynamicOperationOf(keyGet)).toBe("dynKeyGet"); + expect( + dynamicOperationOf({ + kind: "libCall", + fn: "dyn.add", + args: [dynParam, dynParam], + type: DYN, + loc, + }), + ).toBe("dyn.add"); + expect( + dynamicOperationOf({ + kind: "call", + callee: "%dyn.class.property.12", + args: [dynParam], + type: DYN, + loc, + }), + ).toBe("%dyn.class.property"); + // Boundary operations: conversions and kind tests. + expect(dynamicOperationOf({ kind: "dynCheck", value: dynParam, type: F64, loc })).toBeNull(); + expect( + dynamicOperationOf({ + kind: "dynFrom", + value: { kind: "numLit", value: 1, type: F64, loc }, + type: DYN, + loc, + }), + ).toBeNull(); + expect( + dynamicOperationOf({ kind: "dynTest", test: "string", value: dynParam, type: BOOL, loc }), + ).toBeNull(); + expect( + dynamicOperationOf({ kind: "libCall", fn: "dyn.typedRefIs", args: [dynParam], type: DYN, loc }), + ).toBeNull(); + // Moves and calls of ordinary functions. + expect(dynamicOperationOf(dynParam)).toBeNull(); + expect( + dynamicOperationOf({ kind: "call", callee: "helper", args: [dynParam], type: DYN, loc }), + ).toBeNull(); +}); + +test("lowering's classification puts exactly the functions with dynamic operations in the dynamic tier", () => { + const reader = fn("reader", keyGet); + const mover = fn("mover", dynParam); + const dynamic = assignLegacyTiers([reader, mover]); + expect(dynamic.map((d) => [d.name, d.operation])).toEqual([["reader", "dynKeyGet"]]); + expect(functionTier(reader)).toBe("dynamic"); + expect(functionTier(mover)).toBe("static"); + expect(firstDynamicOperation(mover)).toBeNull(); +}); + +test("the validator enforces I1: static functions perform no dynamic operation", () => { + const reader = fn("reader", keyGet); + const errors = validateModule(moduleOf(reader)); + expect(errors.map((e) => e.message)).toEqual([ + "in reader: static-tier function performs the dynamic operation dynKeyGet", + ]); + reader.tier = "dynamic"; + expect(validateModule(moduleOf(reader))).toEqual([]); + // A logical operator over dynamic values applies ToBoolean to them. + const either = fn("either", { + kind: "logical", + op: "||", + left: dynParam, + right: dynParam, + type: DYN, + loc, + }); + expect(validateModule(moduleOf(either)).map((e) => e.message)).toEqual([ + "in either: static-tier function performs the dynamic operation logical", + ]); +}); + +test("serialized IR carries no tiers in stage S2, and loading derives them again", () => { + const reader = fn("reader", keyGet); + const mod = moduleOf(reader); + const untiered = serializeModule(mod, true); + assignLegacyTiers(mod.functions); + expect(reader.tier).toBe("dynamic"); + expect(serializeModule(mod, true)).toBe(untiered); + expect(serializeModuleParts(mod).join("")).toBe(untiered); + expect(serializeModule(mod)).not.toContain('"tier"'); + for (const loaded of [ + deserializeModule(untiered), + deserializeModuleBytes(Buffer.from(untiered)), + ]) { + expect(loaded.functions.map(functionTier)).toEqual(["static", "dynamic"]); + expect(validateModule(loaded)).toEqual([]); + } +}); diff --git a/packages/compiler/src/ir/tiers.ts b/packages/compiler/src/ir/tiers.ts new file mode 100644 index 000000000..201bc2a58 --- /dev/null +++ b/packages/compiler/src/ir/tiers.ts @@ -0,0 +1,157 @@ +/* Execution tiers (two-tier design, stage S2: report-only). + * + * Every IR function belongs to one of two tiers: + * + * - static: today's compiler. Exact layouts, direct calls, unboxed values. + * A static function may hold dynamic (`dyn`) values, pass them to calls, + * return them and store them, and it may cross the boundary with the + * boundary operations below, but it never operates on a dynamic value. + * - dynamic: code that operates on dynamic values with JavaScript semantics + * (property reads and writes, generic operators, calls of dynamic values, + * dynamic object and array construction). + * + * Invariant I1 (validate.ts): a static function contains no dynamic + * operation. Only boundary operations and moves may mix the tiers. Calls + * of generated `%dyn.*` helpers count as dynamic operations: they are the + * dynamic dispatch the lowering placed out of line. Calls of other dynamic + * functions are boundaries (the design's "call to a dynamic function"). + * + * Boundary operations: + * - `dynFrom` (static to dynamic, the design's `toJs`) and `caughtToDyn`; + * - `dynCheck` (dynamic to static, the design's `fromJs`); + * - kind tests that only inspect a dynamic value's tag (`dynTest`, the + * `dyn.*Is` and `dyn.typeof` builtins): the tag test of a conversion; + * - calls of non-`dyn.*` builtins whose signatures take or return `dyn` + * (typed APIs implemented through dyn, leak L6 of the design). They stay + * boundaries until stage S1 gives them typed signatures. + * + * Classification of existing code. The `dyn` vocabulary is today's + * dynamic tier (`ScrDyn`): `any`, untyped JavaScript, unschematized + * `JSON.parse`, and the generated dynamic dispatch helpers already lower to + * it. Lowering therefore assigns tiers from function bodies: a function + * containing a dynamic operation is dynamic, every other function is static + * (`assignLegacyTiers`). Demotion (stage S6) will add tier decisions that + * do not follow from a body; until then the classification is exact, and + * the validator guards it against later passes and hand-written IR. + * + * Serialization. Stage S2 must not change any artifact, so serialized IR + * omits `tier` (serialize.ts) and loaders derive it again with the same + * classification. The next IR version serializes the field. */ +import type { IrExpr, IrFunction, IrModule, SrcLoc } from "./ir.js"; +import { everyStmtList, type IrVisitor } from "./traverse.js"; + +export type IrTier = "static" | "dynamic"; + +export function functionTier(fn: IrFunction): IrTier { + return fn.tier === "dynamic" ? "dynamic" : "static"; +} + +/** `dyn.*` builtins that only inspect a dynamic value's kind: the tag test + * half of a dynamic-to-static conversion. */ +const DYN_KIND_TESTS: ReadonlySet = new Set([ + "dyn.typedRefIs", + "dyn.typedRefKeyIs", + "dyn.classIs", + "dyn.nativeSetIs", + "dyn.nativeMapIs", + "dyn.nativeUrlIs", + "dyn.nativeDateIs", + "dyn.nativeRegexIs", + "dyn.dataViewIs", + "dyn.typeof", +]); + +const DYN_HELPER_PREFIX = "%dyn."; + +/** `%dyn.class.property.12` → `%dyn.class.property`. */ +function dynHelperFamily(name: string): string { + return name.replace(/(\.\d+)+$/, ""); +} + +/** The dynamic operation an expression performs, named for reports + * (`dynKeyGet`, `dyn.keySet`, ...), or null for static operations, boundary + * operations and moves. Only the node itself is inspected. */ +export function dynamicOperationOf(e: IrExpr): string | null { + switch (e.kind) { + case "dynCall": + case "dynInvoke": + case "dynObjLit": + case "dynArrLit": + case "dynKeyGet": + case "dynHasKey": + case "dynScalarEq": + case "dynDestrCheck": + case "dynIterN": + return e.kind; + case "logical": + // `a || b` over dyn operands applies ToBoolean to a dynamic value. + return e.type.kind === "dyn" ? "logical" : null; + case "libCall": + return e.fn.startsWith("dyn.") && !DYN_KIND_TESTS.has(e.fn) ? e.fn : null; + case "call": + // Generated `%dyn.*` helpers are dynamic operations lowered out of + // line (class dynamic dispatch, dynamic HOF adapters). + return e.callee.startsWith(DYN_HELPER_PREFIX) ? dynHelperFamily(e.callee) : null; + default: + return null; + } +} + +export interface DynamicOperationSite { + operation: string; + loc: SrcLoc; +} + +function collectDynamicOperations(fn: IrFunction, first: boolean): DynamicOperationSite[] { + const found: DynamicOperationSite[] = []; + const visitor: IrVisitor = { + expr: (e) => { + const operation = dynamicOperationOf(e); + if (operation === null) return true; + found.push({ operation, loc: e.loc }); + return !first; + }, + stmt: () => true, + }; + everyStmtList(fn.body, visitor); + return found; +} + +/** The first dynamic operation in a function body, in traversal order. */ +export function firstDynamicOperation(fn: IrFunction): DynamicOperationSite | null { + return collectDynamicOperations(fn, true)[0] ?? null; +} + +/** Every dynamic operation in a function body (coverage reports). */ +export function dynamicOperationSites(fn: IrFunction): DynamicOperationSite[] { + return collectDynamicOperations(fn, false); +} + +/** A function the classification placed in the dynamic tier, with the + * operation that put it there. */ +export interface DynamicFunction { + name: string; + loc: SrcLoc; + operation: string; + operationLoc: SrcLoc; +} + +/** Assign every function its tier from its body (see the header). Returns + * the dynamic functions in module order. */ +export function assignLegacyTiers(functions: readonly IrFunction[]): DynamicFunction[] { + const dynamic: DynamicFunction[] = []; + for (const fn of functions) { + const site = firstDynamicOperation(fn); + if (site === null) continue; + fn.tier = "dynamic"; + dynamic.push({ name: fn.name, loc: fn.loc, operation: site.operation, operationLoc: site.loc }); + } + return dynamic; +} + +/** Loaders call this on deserialized modules (stage S2 serializes no + * tiers). */ +export function deriveModuleTiers(mod: IrModule): IrModule { + assignLegacyTiers(mod.functions); + return mod; +} diff --git a/packages/compiler/src/ir/validate.test.ts b/packages/compiler/src/ir/validate.test.ts index b7caf8c41..8086cc176 100644 --- a/packages/compiler/src/ir/validate.test.ts +++ b/packages/compiler/src/ir/validate.test.ts @@ -20,6 +20,7 @@ import { type IrUnionDef, } from "./ir.js"; import { deserializeModule, serializeModule } from "./serialize.js"; +import { assignLegacyTiers } from "./tiers.js"; import { validateModule } from "./validate.js"; const loc = { file: "numeric-read.ts", start: 0, end: 0 }; @@ -399,7 +400,7 @@ test.each(["sortPrimitive", "toSortedPrimitive"] as const)( ); function expressionModule(expr: IrExpr, unions: IrUnionDef[]): IrModule { - return { + const mod: IrModule = { irVersion: 16, sourceFile: loc.file, entry: "main", @@ -415,6 +416,9 @@ function expressionModule(expr: IrExpr, unions: IrUnionDef[]): IrModule { }, ], }; + // Lowering assigns tiers from function bodies (ir/tiers.ts). + assignLegacyTiers(mod.functions); + return mod; } test("numeric byte tokens and DataView stores validate their storage before emission", () => { diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index f7d30a1bb..1bac14de6 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -59,6 +59,7 @@ import { import { DYN_CLASS_PROPERTIES } from "./ir.js"; import { unionWideningTags } from "./analysis.js"; import { alwaysReturns } from "./control-flow.js"; +import { dynamicOperationOf, functionTier } from "./tiers.js"; import { LIB_FN_SIGS } from "./builtin-signatures.js"; import { REGEX_INTRINSIC_SIGS, STR_INTRINSIC_SIGS } from "./intrinsic-signatures.js"; @@ -1007,6 +1008,14 @@ function validateFunction( const locals = new Map(fn.locals.map((l) => [l.id, l])); const err = (message: string, loc: SrcLoc) => errors.push({ message: `in ${fn.name}: ${message}`, loc }); + // Invariant I1 (ir/tiers.ts): a static function reaches dynamic values + // only through boundary operations and moves. + const staticTier = functionTier(fn) === "static"; + const checkTier = (e: IrExpr): void => { + const operation = dynamicOperationOf(e); + if (operation !== null) + err(`static-tier function performs the dynamic operation ${operation}`, e.loc); + }; const asyncCaches = [ ["asyncCacheGlobal", fn.asyncCacheGlobal], @@ -1251,6 +1260,8 @@ function validateFunction( continue; } if (e.kind === "logical") { + // checkExpr already checked the root's tier. + if (staticTier && e !== root) checkTier(e); if ( e.type.kind !== "f64" && e.type.kind !== "string" && @@ -1294,6 +1305,7 @@ function validateFunction( } function checkExpr(e: IrExpr): void { + if (staticTier) checkTier(e); switch (e.kind) { case "numLit": case "strLit": diff --git a/packages/compiler/src/library/prepare.ts b/packages/compiler/src/library/prepare.ts index 94f20198a..298bb43bb 100644 --- a/packages/compiler/src/library/prepare.ts +++ b/packages/compiler/src/library/prepare.ts @@ -553,6 +553,8 @@ export function prepareLibrary( try { lowered = fe.lower({ targetPlatform: buildPlatform, + // Library artifacts are static-tier only (two-tier design I2). + tierMode: "static-only", ...(cbImports.length > 0 ? { ffiImports: cbImports } : {}), ...(cbImports.length > 0 ? { libraryCallbacks: true } : {}), // The profile-mapped exports are called from OUTSIDE the graph: diff --git a/tests/coverage-fixtures/tier-demotions.ts b/tests/coverage-fixtures/tier-demotions.ts new file mode 100644 index 000000000..52f2058f1 --- /dev/null +++ b/tests/coverage-fixtures/tier-demotions.ts @@ -0,0 +1,25 @@ +// The report-only tier assignment of `scriptc coverage --explain-dynamic`. +class Point { + constructor( + public x: number, + public y: number, + ) {} +} + +// Reflection on a class: the dynamic tier would give Point a prototype object. +(Point.prototype as any).norm = function () { + return 0; +}; + +// Already dynamic: a property read on an `any` value. +function readName(text: string): string { + const data: any = JSON.parse(text); + return String(data.name); +} + +// An operation without a static lowering, on a parameter. +function precise(n: number): string { + return n.toPrecision(3); +} + +console.log(readName('{"name":"a"}'), precise(1.5), new Point(1, 2).x); diff --git a/tests/harness/__snapshots__/coverage-divergences.txt b/tests/harness/__snapshots__/coverage-divergences.txt index 67c9b57e3..2f811f892 100644 --- a/tests/harness/__snapshots__/coverage-divergences.txt +++ b/tests/harness/__snapshots__/coverage-divergences.txt @@ -2,6 +2,7 @@ scriptc coverage tests/coverage-fixtures/divergences.ts statements analyzed 18 compile statically 18 (100%) + in dynamic tier 1 (operate on values typed only at runtime; --explain-dynamic lists them) fully static — all analyzed statements compile to native code. diff --git a/tests/harness/__snapshots__/coverage-dynamic-mix.txt b/tests/harness/__snapshots__/coverage-dynamic-mix.txt index a3e714bde..2ad84f0af 100644 --- a/tests/harness/__snapshots__/coverage-dynamic-mix.txt +++ b/tests/harness/__snapshots__/coverage-dynamic-mix.txt @@ -2,6 +2,7 @@ scriptc coverage tests/coverage-fixtures/dynamic-mix.ts statements analyzed 8 compile statically 7 (87%) + in dynamic tier 2 (operate on values typed only at runtime; --explain-dynamic lists them) blockers: ×1 SC2012 '.toPrecision()' on numbers cannot compile statically diff --git a/tests/harness/__snapshots__/coverage-explain-dynamic.txt b/tests/harness/__snapshots__/coverage-explain-dynamic.txt new file mode 100644 index 000000000..1c86a808c --- /dev/null +++ b/tests/harness/__snapshots__/coverage-explain-dynamic.txt @@ -0,0 +1,16 @@ + dynamic tier (tier assignment, report-only; --tier=auto) + 4 functions already operate on dynamic values (1 statement) + readName tests/coverage-fixtures/tier-demotions.ts:15:1: %dyn.error.stringConstructor at tests/coverage-fixtures/tier-demotions.ts:17:10 + %dyn.error.stringConstructor.0 tests/coverage-fixtures/tier-demotions.ts:17:10: dynCall at tests/coverage-fixtures/tier-demotions.ts:17:10 + %dyn.class.property.0 tests/coverage-fixtures/tier-demotions.ts:17:17: %dyn.class.readPropertiesOrEmpty at tests/coverage-fixtures/tier-demotions.ts:17:17 + %method.value:%%Error.toString tests/coverage-fixtures/tier-demotions.ts:17:10: dyn.this at tests/coverage-fixtures/tier-demotions.ts:17:10 + + 2 demotion requests (refusals and fences the dynamic tier would replace) + class Point tests/coverage-fixtures/tier-demotions.ts:2:1 (1 request) + <- SC1090 reflection at tests/coverage-fixtures/tier-demotions.ts:10:1: assignment to non-variables are not supported yet + -> function turns dynamic + function tests/coverage-fixtures/tier-demotions.ts:1:1 (1 site inside) + function precise tests/coverage-fixtures/tier-demotions.ts:21:1 (1 site inside) + binding n in precise tests/coverage-fixtures/tier-demotions.ts:21:18 (1 request) + <- SC2012 operation at tests/coverage-fixtures/tier-demotions.ts:22:10: '.toPrecision()' on numbers cannot compile statically + -> function precise turns dynamic \ No newline at end of file diff --git a/tests/harness/__snapshots__/coverage-js-gap.txt b/tests/harness/__snapshots__/coverage-js-gap.txt index 3150216b6..3b6fa678c 100644 --- a/tests/harness/__snapshots__/coverage-js-gap.txt +++ b/tests/harness/__snapshots__/coverage-js-gap.txt @@ -2,5 +2,6 @@ scriptc coverage tests/coverage-fixtures/js-gap/gap.js statements analyzed 5 compile statically 5 (100%) + in dynamic tier 3 (operate on values typed only at runtime; --explain-dynamic lists them) fully static — all analyzed statements compile to native code. \ No newline at end of file diff --git a/tests/harness/__snapshots__/coverage-mixed.txt b/tests/harness/__snapshots__/coverage-mixed.txt index 88b61c39b..c3b348f9c 100644 --- a/tests/harness/__snapshots__/coverage-mixed.txt +++ b/tests/harness/__snapshots__/coverage-mixed.txt @@ -2,6 +2,7 @@ scriptc coverage tests/coverage-fixtures/mixed.ts statements analyzed 13 compile statically 12 (92%) + in dynamic tier 1 (operate on values typed only at runtime; --explain-dynamic lists them) blockers: ×1 SC1031 object destructuring of non-record values (the source is array-typed) diff --git a/tests/harness/__snapshots__/coverage-npm-packages.txt b/tests/harness/__snapshots__/coverage-npm-packages.txt index 0ba05286a..475b10e45 100644 --- a/tests/harness/__snapshots__/coverage-npm-packages.txt +++ b/tests/harness/__snapshots__/coverage-npm-packages.txt @@ -2,6 +2,7 @@ scriptc coverage tests/corpus/native-npm-imports/main.ts statements analyzed 14 compile statically 14 (100%) + in dynamic tier 3 (operate on values typed only at runtime; --explain-dynamic lists them) npm package compilation: mathkit static diff --git a/tests/harness/__snapshots__/coverage-tier-demotions.txt b/tests/harness/__snapshots__/coverage-tier-demotions.txt new file mode 100644 index 000000000..7b52f9d63 --- /dev/null +++ b/tests/harness/__snapshots__/coverage-tier-demotions.txt @@ -0,0 +1,13 @@ +scriptc coverage tests/coverage-fixtures/tier-demotions.ts + + statements analyzed 5 + compile statically 3 (60%) + in dynamic tier 1 (operate on values typed only at runtime; --explain-dynamic lists them) + + blockers: + ×1 SC1090 assignment to non-variables + at tests/coverage-fixtures/tier-demotions.ts:10:1 + hint: this form is valid TypeScript but does not compile yet — rewrite it with a supported equivalent of the construct the message names (https://scriptc.dev/limitations lists the boundary) + ×1 SC2012 '.toPrecision()' on numbers cannot compile statically + at tests/coverage-fixtures/tier-demotions.ts:22:10 + hint: use a supported API or rewrite this operation for native compilation \ No newline at end of file diff --git a/tests/harness/__snapshots__/coverage-width-copies.txt b/tests/harness/__snapshots__/coverage-width-copies.txt index dd99d4bb5..46e8e949d 100644 --- a/tests/harness/__snapshots__/coverage-width-copies.txt +++ b/tests/harness/__snapshots__/coverage-width-copies.txt @@ -2,6 +2,7 @@ scriptc coverage tests/coverage-fixtures/width-copies.ts statements analyzed 14 compile statically 14 (100%) + in dynamic tier 1 (operate on values typed only at runtime; --explain-dynamic lists them) fully static — all analyzed statements compile to native code. diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index d4582d151..6148b13ac 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -3,7 +3,13 @@ import { globSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect, test } from "vitest"; -import { analyze, coverageEnvelope, coveragePasses, renderCoverage } from "@scriptc/compiler"; +import { + analyze, + coverageEnvelope, + coveragePasses, + renderCoverage, + renderExplainDynamic, +} from "@scriptc/compiler"; import { shardSelect, shardSuffix } from "./shard.js"; const repoRoot = join(import.meta.dirname, "../.."); @@ -230,6 +236,105 @@ test("CLI: build --print=diagnostics reports failures and divergence warnings as } }); +test("coverage counts the statements of dynamic-tier functions", async () => { + expect(analyze(join(repoRoot, "tests/corpus/400-fib.ts")).coverage.stats.statementsDynamic).toBe( + 0, + ); + const { coverage, sourceTexts } = analyze(fixture("tier-demotions.ts")); + expect(coverage.stats.statementsDynamic).toBe(1); + expect(coverage.tiers).toBeUndefined(); + expect(coverageEnvelope(coverage, { compilerVersion: "test", sourceTexts }).stats).toMatchObject({ + statementsTotal: 5, + statementsStatic: 3, + statementsDynamic: 1, + statementsFailed: 2, + }); + await expect(report(fixture("tier-demotions.ts"))).toMatchFileSnapshot( + "__snapshots__/coverage-tier-demotions.txt", + ); +}); + +test("--explain-dynamic attributes each refusal to the unit the dynamic tier would take", async () => { + const { coverage, sourceTexts } = analyze(fixture("tier-demotions.ts"), { explainDynamic: true }); + const tiers = coverage.tiers!; + expect(tiers.mode).toBe("auto"); + expect(tiers.statementsDynamic).toBe(1); + expect(tiers.dynamicFunctions.map((fn) => fn.name)).toContain("readName"); + const requests = [...tiers.requests].sort((a, b) => a.loc.start - b.loc.start); + expect( + requests.map((r) => [r.code, r.seed, r.scope, r.unit.kind, r.unit.name, r.enclosing.name]), + ).toEqual([ + ["SC1090", "reflection", "reached", "class", "Point", ""], + ["SC2012", "operation", "reached", "binding", "n", "precise"], + ]); + expect(tiers.units.map((u) => [u.kind, u.name, u.requests, u.sites])).toEqual([ + ["class", "Point", 1, 0], + ["function", "", 0, 1], + ["function", "precise", 0, 1], + ["binding", "n", 1, 0], + ]); + const envelope = coverageEnvelope(coverage, { compilerVersion: "test", sourceTexts }); + expect(envelope.tiers?.requests[0]).toMatchObject({ unit: { kind: expect.any(String) } }); + const relative = JSON.parse(JSON.stringify(tiers).replaceAll(repoRoot + "/", "")) as typeof tiers; + await expect(renderExplainDynamic(relative)).toMatchFileSnapshot( + "__snapshots__/coverage-explain-dynamic.txt", + ); + expect(renderExplainDynamic(relative, { query: "Point" })).toContain("class Point"); + expect(renderExplainDynamic(relative, { query: "Point" })).not.toContain("binding n"); + expect(renderExplainDynamic(relative, { query: "nothing" })).toContain( + "no demoted unit matches 'nothing'", + ); +}); + +test("CLI: --tier and --explain-dynamic", () => { + const scriptcCli = join(repoRoot, "packages/cli/src/main.ts"); + const outDir = mkdtempSync(join(tmpdir(), "scriptc-tier-")); + const run = (...args: string[]) => + spawnSync(process.execPath, ["--import", "tsx", scriptcCli, ...args], { + cwd: repoRoot, + encoding: "utf8", + env: { ...process.env, SCRIPTC_NO_CACHE: "1" }, + }); + try { + const explained = run( + "coverage", + fixture("tier-demotions.ts"), + "--explain-dynamic", + "--tier=static-only", + ); + expect(explained.status).toBe(0); + expect(explained.stdout).toContain("in dynamic tier 1"); + expect(explained.stdout).toContain("--tier=static-only"); + expect(explained.stdout).toContain("binding n in precise"); + const one = run("coverage", fixture("tier-demotions.ts"), "--explain-dynamic=Point"); + expect(one.stdout).toContain("class Point"); + expect(one.stdout).not.toContain("binding n in precise"); + const bad = run("coverage", fixture("tier-demotions.ts"), "--tier=dynamic-only"); + expect(bad.status).toBe(1); + expect(bad.stderr).toContain('unknown --tier value "dynamic-only"'); + const misplaced = run("build", fixture("tier-demotions.ts"), "--explain-dynamic"); + expect(misplaced.status).toBe(1); + expect(misplaced.stderr).toContain("--explain-dynamic is a coverage option"); + // Until demotion lands, static-only compiles exactly like the default. + const ir = (name: string, ...args: string[]) => { + const out = join(outDir, name); + const built = run( + "build", + join(repoRoot, "tests/corpus/400-fib.ts"), + "--emit=ir", + "-o", + out, + ...args, + ); + expect(built.status).toBe(0); + return readFileSync(out, "utf8"); + }; + expect(ir("static-only.ir.json", "--tier=static-only")).toBe(ir("auto.ir.json")); + } finally { + rmSync(outDir, { recursive: true, force: true }); + } +}); + test("fully static program reports 100%", () => { const out = report(join(repoRoot, "tests/corpus/400-fib.ts")); expect(out).toContain("(100%)"); From 4bba6c1e0b1f370c64c34ba8ea6528cd521f8010 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 11:30:08 -0500 Subject: [PATCH 103/117] Keep this PR's refreshed corpus costs after the main merge --- tests/harness/corpus-costs.json | 10772 +++++++++++++++--------------- 1 file changed, 5386 insertions(+), 5386 deletions(-) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 797986e20..622b64700 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1,1697 +1,1697 @@ { "note": "Milliseconds per corpus program on a GitHub-hosted ubuntu-24.04 runner: its differential plus llvm-differential case, per flavor (medians of green main runs). scripts/ci-corpus-costs.mjs refreshes it from CI logs.", "plain": { - "001-hello.ts": 3069, - "002-log-args.ts": 2728, - "100-number-format.ts": 3733, - "1000-json-stringify-basics.ts": 4746, - "1001-json-escapes-unicode.ts": 3114, - "1002-json-parse-cast.ts": 4816, - "1003-json-parse-unions.ts": 3373, - "1004-json-parse-errors.ts": 2257, - "1005-json-nested.ts": 3430, - "1006-json-fs-config.ts": 3508, - "1007-json-rc-stress.ts": 4738, - "1008-json-null-arms.ts": 3237, - "1009-json-optional-fields.ts": 3598, - "101-arithmetic.ts": 2904, - "1010-json-stringify-space.ts": 4663, - "1011-json-unknown-typeof.ts": 2914, - "102-comparisons.ts": 2408, - "1020-async-basics.ts": 2514, - "1021-async-ordering.ts": 2150, - "1022-async-exceptions.ts": 2155, - "1023-async-rc-stress.ts": 3249, - "1024-async-pending-exit.ts": 3248, - "1025-async-promise-capture.ts": 4134, - "1026-throw-promise.ts": 2862, - "1027-async-return-promise.ts": 3195, - "1028-async-return-record-literals.ts": 2979, - "1029-async-eager-chains.ts": 3200, - "103-ternary.ts": 2586, - "104-ternary-empty-arrays.ts": 3925, - "1050-comptime-tables.ts": 3449, - "1051-comptime-strings.ts": 4033, - "1052-comptime-records.ts": 4539, - "1053-comptime-json.ts": 2953, - "1054-comptime-modules/main.ts": 2477, - "110-number-radix.ts": 2253, - "111-record-entries.ts": 4124, - "1110-math-members.ts": 3859, - "1111-math-random.ts": 2956, - "1113-string-methods.ts": 3292, - "1114-string-unicode-island.ts": 2830, - "1115-parse-globals.ts": 2990, + "001-hello.ts": 3065, + "002-log-args.ts": 4101, + "100-number-format.ts": 4051, + "1000-json-stringify-basics.ts": 5187, + "1001-json-escapes-unicode.ts": 4569, + "1002-json-parse-cast.ts": 3516, + "1003-json-parse-unions.ts": 3382, + "1004-json-parse-errors.ts": 4383, + "1005-json-nested.ts": 5206, + "1006-json-fs-config.ts": 3979, + "1007-json-rc-stress.ts": 3920, + "1008-json-null-arms.ts": 3823, + "1009-json-optional-fields.ts": 4367, + "101-arithmetic.ts": 3258, + "1010-json-stringify-space.ts": 3979, + "1011-json-unknown-typeof.ts": 4108, + "102-comparisons.ts": 4061, + "1020-async-basics.ts": 3165, + "1021-async-ordering.ts": 3062, + "1022-async-exceptions.ts": 3356, + "1023-async-rc-stress.ts": 3530, + "1024-async-pending-exit.ts": 2901, + "1025-async-promise-capture.ts": 3471, + "1026-throw-promise.ts": 3173, + "1027-async-return-promise.ts": 2405, + "1028-async-return-record-literals.ts": 3561, + "1029-async-eager-chains.ts": 3698, + "103-ternary.ts": 3292, + "104-ternary-empty-arrays.ts": 4072, + "1050-comptime-tables.ts": 3518, + "1051-comptime-strings.ts": 2082, + "1052-comptime-records.ts": 3252, + "1053-comptime-json.ts": 3388, + "1054-comptime-modules/main.ts": 3286, + "110-number-radix.ts": 3749, + "111-record-entries.ts": 4017, + "1110-math-members.ts": 2615, + "1111-math-random.ts": 2691, + "1113-string-methods.ts": 3490, + "1114-string-unicode-island.ts": 2532, + "1115-parse-globals.ts": 2850, "1116-island-static-mix.ts": 3032, - "1117-typeof-static-union.ts": 2965, - "1118-object-spread-conditional.ts": 2667, - "1119-switch-union.ts": 3067, - "112-class-descriptor-key.js": 2522, - "1121-infinity-number-tostring.ts": 3370, - "1122-any-captures.ts": 3176, - "1124-union-narrowed-retag.ts": 2492, - "113-promise-checked-exits.ts": 2859, - "114-live-record-delete.ts": 2500, - "115-array-compound.js": 3135, - "116-text-decoder-runtime.js": 2862, - "117-weak-cache-cycle.js": 2266, - "118-fs-stored-callbacks.cjs": 3485, - "119-native-patterns.js": 3500, - "1200-regex-test-basics.ts": 3223, - "1201-regex-replace.ts": 3086, - "1202-regex-substitutions.ts": 3684, - "1203-regex-split.ts": 3320, - "1204-regex-empty-unicode.ts": 2968, - "1205-regex-rc-stress.ts": 2448, - "1300-errors-basics.ts": 2709, - "1301-errors-subclass.ts": 3447, - "1302-errors-typed-catch.ts": 3128, - "1303-errors-rc-stress.ts": 2776, - "1304-errors-uncaught.ts": 2907, - "1305-errors-async-rejections.ts": 2863, - "1306-errors-runtime-instances.ts": 2803, - "1350-path-normalize-join.ts": 2394, - "1351-path-parts.ts": 2228, - "1352-path-resolve-relative.ts": 3019, - "1353-os-basics.ts": 2682, - "1354-builtin-bare-specifiers.ts": 2284, - "1355-url-parse.ts": 2467, - "1356-url-file-bridge.ts": 3063, - "1357-fsp-roundtrip.ts": 3440, - "1358-crypto-random.ts": 2124, - "1359-json-module/main.ts": 2889, - "1360-spawn-sync.ts": 3158, - "1361-spawn-events.ts": 3000, - "1362-spawn-timers.ts": 8505, - "1363-spawn-unhandled-error.ts": 2724, - "1364-union-truthiness.ts": 2131, - "1365-union-logical.ts": 2948, - "1366-union-equality.ts": 2233, - "1367-destructuring.ts": 3492, - "1368-constructor-functions.ts": 2941, - "1369-promise-union.ts": 2048, - "1370-spread.ts": 2658, - "1371-union-template-tostring.ts": 2681, - "1372-loose-null-tests.ts": 2819, - "1373-union-array-arms.ts": 2414, - "140-bitwise-operators.ts": 3378, - "1400-typedarray-basics.ts": 3056, - "1401-typedarray-slice-set.ts": 2697, - "1402-buffer-encodings.ts": 3146, - "1403-buffer-fs.ts": 3327, - "1404-zlib-crypto-bytes.ts": 3318, - "1405-bytes-unions-arrays.ts": 2463, - "1406-dataview-mp4.ts": 2536, - "1407-dataview-bounds.ts": 3301, - "1408-string-indexing.ts": 2027, - "1409-typedarray-integer-loops.ts": 2940, - "1420-number-statics.ts": 2894, - "1421-number-parse-strings.ts": 2645, - "1422-date-iso.ts": 2686, - "1423-text-codec.ts": 4188, - "1424-fs-options.ts": 2662, - "1425-stdin-tty.ts": 2638, - "1426-stdin-read.ts": 2379, - "1427-fromcharcode-lastindexof.ts": 2109, - "1428-settled-await-order.ts": 2663, - "1429-promise-catch-finally.ts": 3486, - "1430-promise-race.ts": 4032, - "1431-caught-tostring.ts": 2082, - "1432-destructured-params.ts": 3251, - "1433-filter-narrow.ts": 3353, - "1434-async-never.ts": 2711, - "1435-math-spread.ts": 2665, - "1436-default-undef-param.ts": 2896, - "1437-pad-default.ts": 3003, - "1438-promise-all.ts": 6347, - "1440-interval-basics.ts": 3004, - "1441-interval-clear-cross.ts": 5524, - "1442-interval-throw.ts": 3148, - "1443-signal-handlers.ts": 5739, - "1444-exit-listeners.ts": 3270, - "1445-exit-process-exit.ts": 2515, - "1446-exit-uncaught.ts": 2709, - "1447-stdin-closed-events.ts": 2034, - "1448-stream-columns.ts": 2668, - "1450-incdec-expression.ts": 3189, - "1451-instanceof-uint8array-unknown.ts": 3003, - "1452-return-through-finally.ts": 2097, - "1453-pmap-settled.ts": 3863, - "1454-nonnull-narrow-and-fcc-bytes.ts": 2192, - "1455-lambda-union-return-adoption.ts": 3144, - "1460-console-error-warn.ts": 2229, - "1461-process-pid-getuid-kill.ts": 2853, - "1462-exec-sync.ts": 3145, - "1463-timeout-unref.ts": 2935, - "1464-env-writes.ts": 2594, - "1465-env-value.ts": 3233, - "1466-child-containers.ts": 2674, - "1467-string-match.ts": 2677, - "1468-exec-path.ts": 2974, - "1469-remove-listener.ts": 4038, - "1470-child-lifecycle.ts": 1948, - "1471-child-unref.ts": 6913, - "1472-errno-code.ts": 2768, - "1473-promisify-execfile.ts": 3155, - "1474-string-decoder.ts": 3057, - "1475-readline-closed-stdin.ts": 2826, - "1476-assign-expression.ts": 2557, - "1477-in-expressions.ts": 2740, - "1478-promise-reject.ts": 3143, - "1479-destructuring-assign.ts": 2933, - "1480-os-network-interfaces.ts": 3749, - "1481-string-case-static.ts": 1949, - "1482-spawnsync-error.ts": 2332, - "1483-array-slice.ts": 3329, - "1520-fs-wider-surface.ts": 3206, - "1520-string-split-static.ts": 2787, - "1521-fs-lstat-lock.ts": 2868, - "1521-string-trim-pad-static.ts": 2727, - "1522-parseint-static.ts": 2059, - "1522-spawnsync-options.ts": 3990, - "1523-isnan-floor-static.ts": 2552, - "1523-spawn-options.ts": 2955, - "1524-atomics-sleep-static.ts": 3221, - "1524-catch-narrowing.ts": 2221, - "1525-child-exit-signal.ts": 2022, - "1525-unknown-typeof-validation.ts": 2311, - "1526-set-spread.ts": 3277, - "1527-logical-mixed-operands.ts": 2920, - "1528-delete-records-env.ts": 3318, - "1529-class-with-statics.ts": 2626, - "1530-array-push-variadic.ts": 2272, - "1530-spread-override-completion.ts": 2333, - "1531-delete-optional-fields.ts": 2822, - "1531-process-arch-versions.ts": 2409, - "1532-array-splice-shift.ts": 2440, - "1532-union-shared-field-read.ts": 2449, - "1533-bool-equality.ts": 3130, - "1533-path-platform-namespaces.ts": 2472, - "1534-crypto-hash-chain.ts": 3303, - "1534-union-as-arm-cast.ts": 2773, - "1535-spawn-fd-stdio.ts": 3617, - "1535-union-param-defaults.ts": 2848, - "1536-destructuring-defaults.ts": 2783, - "1536-string-array-sweep.ts": 2930, - "1537-chalk-hybrid/main.ts": 3161, - "1537-os-release-spawnsync-stdio.ts": 2411, - "1538-await-promiselike-return.ts": 2433, - "1538-math-static-scalar.ts": 2674, - "1539-readonly-set-map.ts": 2573, - "1539-unknown-truthiness.ts": 2629, - "1540-os-userinfo.ts": 2636, - "1540-void-statement.ts": 2658, - "1541-fs-readdir-dirent.ts": 3093, - "1541-union-keyed-reads.ts": 4144, - "1542-map-promise-values.ts": 2657, - "1542-record-literal-into-union.ts": 3004, - "1543-rest-destructuring.ts": 2897, - "1543-set-server-handles.ts": 2927, - "1544-dyn-json-reads.ts": 3602, - "1544-string-matchall.ts": 2940, - "1545-spread-order-and-optional.ts": 2963, - "1546-union-element-reads.ts": 2716, - "1547-computed-key-fold.ts": 4334, - "1548-boolean-condition-forms.ts": 4675, - "1549-array-isarray-unions.ts": 3420, - "1550-param-defaults-func-set.ts": 3314, - "1551-dyn-receiver-methods.ts": 4271, - "1552-exec-options-record.ts": 3353, - "1553-truthy-hof-predicates.ts": 2475, - "1554-caught-into-unknown.ts": 2996, - "1555-index-spread-into-declared.ts": 3100, - "1556-union-retag-width-arms.ts": 2198, - "1557-url-host.ts": 2745, - "1558-any-joins-and-dyn-validation.ts": 2600, - "1559-conditional-spread-index-merge.ts": 3037, - "1560-forof-homogeneous-tuples.ts": 2478, - "1561-forof-strings.ts": 2503, - "1561-promise-then.ts": 3156, - "1562-optional-chain-tails.ts": 3390, - "1562-spawn-conditional-spread.ts": 3006, - "1563-forof-iterator-projections.ts": 3054, - "1563-string-raw-fold.ts": 2666, - "1564-fs-watch.ts": 3415, - "1564-string-raw.ts": 2651, - "1565-spawn-pipe-streams.ts": 3154, - "1565-union-element-join.ts": 2733, - "1566-child-duck-interface.ts": 2463, - "1567-server-close-override.ts": 2863, - "1568-x509-fingerprint.ts": 2419, - "1569-fsp-mkdir-unlink-chmod.ts": 2704, - "1570-child-unref-kill-reffed.ts": 8818, - "1571-optional-call-tostring-tail.ts": 4280, - "1571-stdin-set-raw-mode-non-tty.ts": 2435, - "1572-promise-reject-all-tuple.ts": 3046, - "1572-x509-validity-date-gettime.ts": 2933, - "1573-promisify-execfile-env-spread.ts": 3140, - "1573-tdz-scalar-forward-capture.ts": 2068, - "1574-dyn-optional-method-number-keys.ts": 3318, - "1574-promise-all-tuple-literal.ts": 3025, - "1575-unknown-assert-into-record.ts": 3248, - "1576-width-coercions.ts": 2888, - "1577-url-hostname.ts": 2352, - "1578-exec-input-optional.ts": 3178, - "1579-matchall-index.ts": 3025, - "1580-exec-env-conditional-spread.ts": 3275, - "1581-declare-const-read.ts": 2341, - "1582-timer-sleep-resolve.ts": 2315, - "1583-loops-and-stream-captures.ts": 3154, - "1584-union-field-unassigned.ts": 2858, - "1585-union-field-conditional-ctor.ts": 2073, - "1586-derived-field-before-super-init.ts": 2823, - "1590-js-unannotated.js": 2965, - "1591-js-closures.js": 2113, - "1592-js-classes.js": 4260, - "1593-js-jsdoc-records.js": 3366, - "1594-js-async.js": 2772, - "1595-js-island-gap/main.js": 2168, - "1596-cjs-modules/main.js": 2751, - "1597-mjs-graph/main.mjs": 2858, - "1598-cjs-builtin-require/main.js": 2109, - "1599-js-uncaught-throw.js": 1870, - "1600-assert-passing.ts": 3321, - "1601-assert-fail-exit.ts": 2842, - "1602-assert-caught-error.ts": 2041, - "1603-assert-scalar-messages.ts": 2650, - "1604-assert-deep-structures.ts": 3035, - "1605-assert-import-forms.ts": 3128, - "1606-assert-strict-module.ts": 2927, - "1607-assert-throws-match.ts": 2731, - "1608-cjs-assert/main.js": 3193, - "1609-assert-async.ts": 1990, - "1610-path-win32-full.ts": 1939, - "1611-url-file-bridge-neutral.ts": 2575, - "1612-cjs-module-globals.cjs": 2846, - "1613-cjs-esm-proxy-named/main.mjs": 2282, - "1614-js-fence-dodges.cjs": 2910, - "1615-cjs-export-shapes/main.cjs": 3349, - "1616-cjs-esm-lexer-invisible/main.mjs": 2499, - "1617-cjs-esm-lexer-visible/main.mjs": 2355, - "1618-cjs-esm-poisoned-tail/main.mjs": 2404, - "1619-cjs-esm-reexport-invisible/main.mjs": 2675, - "1620-cjs-require-effects-order/main.js": 2586, - "1621-cjs-require-cache-hit/main.js": 2101, - "1622-cjs-require-conditional/main.js": 2194, - "1623-cjs-require-diamond/main.js": 2241, - "1624-cjs-require-dir-mid-file/main.js": 2559, - "1625-cjs-require-lazy-fn/main.js": 2333, - "1626-cjs-require-mjs/main.js": 2430, - "1627-mjs-import-cjs-requires/main.mjs": 2803, - "1628-checked-dynamic-builtin-args.cjs": 2085, - "1629-require-main-filename.cjs": 2419, - "1630-inspect-scalars.ts": 2701, - "1630-rmsync-retry-options.cjs": 2427, - "1631-inspect-arrays.ts": 3949, - "1632-inspect-records.ts": 3013, - "1633-inspect-map-set.ts": 2316, - "1634-inspect-classes.ts": 3062, - "1635-inspect-buffer.ts": 2271, - "1636-util-format.ts": 2132, - "1637-inspect-dyn.ts": 3164, - "1638-inspect-cjs.cjs": 2023, - "1639-versions-openssl-probe.ts": 2845, - "1640-fd-read-decode.ts": 3219, - "1641-string-search.ts": 3172, - "1642-object-fromentries-rows.ts": 2713, - "1643-metadata-dyn-return.cjs": 3460, - "1644-ee-basics.ts": 2495, - "1645-ee-extends.ts": 2603, - "1646-ee-once-remove.ts": 2849, - "1647-ee-meta-events.ts": 2040, - "1648-ee-error-event.ts": 2703, - "1649-ee-names-counts.ts": 2487, - "1650-ee-prepend.ts": 2672, - "1651-ee-max-listeners.ts": 2331, - "1652-ee-snapshot.ts": 2031, - "1653-ee-cjs.cjs": 2472, - "1654-ee-namespace.ts": 2390, - "1655-spawnsync-neutral.ts": 4056, - "1656-execsync-neutral.ts": 2824, - "1657-spawn-async-neutral.ts": 3268, - "1660-buffer-read-write-num.ts": 3727, - "1661-buffer-encodings-full.ts": 2670, - "1662-string-decoder-encodings.ts": 2362, - "1663-buffer-compare-search-fill.ts": 3956, - "1664-dyn-fn-boundary.cjs": 2792, - "1665-dyn-fn-mustcall/main.cjs": 2827, - "1666-dyn-fn-identity.ts": 2623, - "1667-dyn-fn-not-callable.cjs": 2618, - "1668-dyn-fn-throws.cjs": 2216, - "1669-symbol-identity.ts": 2335, - "1670-symbol-registry.ts": 1852, - "1671-symbol-typeof.ts": 2343, - "1672-symbol-containers.ts": 2800, - "1673-symbol-cjs.cjs": 2407, - "1674-symbol-inspect.ts": 1818, - "1676-func-array-surface.ts": 2784, - "1677-emitter-listeners.ts": 2400, - "1678-emitter-dyn-listeners.cjs": 2358, - "1679-console-dyn.js": 2880, - "1680-assert-bytes.ts": 3465, - "1681-assert-funcs.ts": 2454, - "1685-stream-readable-basics.ts": 2506, - "1686-stream-readable-paused.ts": 2711, - "1687-stream-readable-flow-control.ts": 2359, - "1688-stream-writable-basics.ts": 2613, - "1689-stream-writable-async-drain.ts": 2671, - "1690-stream-duplex.ts": 2112, - "1691-stream-transform.ts": 1780, - "1692-stream-pipe.ts": 3345, - "1693-stream-pipe-backpressure.ts": 2344, - "1694-stream-destroy.ts": 1870, - "1695-stream-props.ts": 2766, - "1696-stream-read-inside-read.ts": 3023, - "1697-stream-tick-vs-timer.ts": 2275, - "1698-stream-uncaught-error.ts": 2523, - "1699-stream-callback-shapes.ts": 1972, - "1700-mustcall-common/main.cjs": 3401, - "1701-mustcall-exit-report/main.cjs": 3316, - "1702-dyn-proto-dispatch.cjs": 2744, - "1703-arguments-rest-props.cjs": 2431, - "1710-cjs-export-class/main.js": 2997, - "1711-cjs-export-single-values/main.js": 2866, - "1712-field-incdec.ts": 1828, - "1713-js-dyn-fields.js": 2492, - "1720-assert-throws-shape.ts": 2372, - "1721-assert-throws-regex-class.ts": 2125, - "1722-assert-rejects.ts": 2761, - "1723-assert-does-not-reject.ts": 2536, - "1724-assert-iferror.ts": 2883, - "1725-assert-symbols.ts": 2626, - "1726-promise-with-resolvers.ts": 2320, - "1727-assert-throws-shape-exit.ts": 2580, - "1730-countdown-symbol-keys/main.js": 2657, - "1731-symbol-field-shapes.cjs": 3005, - "1732-symbol-field-cross-module/main.js": 2509, - "1740-stream-extends-readable.ts": 2167, - "1741-stream-extends-writable.ts": 2479, - "1742-stream-extends-duplex-transform.ts": 2640, - "1743-stream-extends-vt-dispatch.ts": 2388, - "1744-stream-set-encoding.ts": 2886, - "1745-stream-encoding-js.cjs": 2861, - "1746-stream-for-await.ts": 2864, - "1747-stream-for-await-js.cjs": 2685, - "1750-http-agent-options.ts": 2435, - "1751-options-record-stance.ts": 3010, - "1760-surplus-args-drop.cjs": 2845, - "1761-emitter-special-event-names.cjs": 2672, - "1770-assert-dyn-strict.ts": 2841, - "1771-assert-dyn-deep.ts": 2098, - "1772-assert-dyn-js.cjs": 2493, - "1773-assert-dyn-exit.ts": 2809, - "1780-http-res-surface.ts": 3019, - "1781-http-server-shapes.cjs": 2697, - "1790-computed-key-folds.ts": 2567, - "1791-searchparams-core.ts": 2632, - "1792-searchparams-encoding.ts": 2548, - "1793-searchparams-iteration.ts": 2977, - "1794-searchparams-url-live.ts": 2027, - "1795-dyn-handle-request.cjs": 2079, - "1796-dyn-handle-body.cjs": 3120, - "1797-dyn-handle-socket.cjs": 2724, - "1798-dyn-handle-typed-box.ts": 2104, - "1800-immediate-basics.ts": 2313, - "1801-immediate-handle.ts": 2272, - "1802-immediate-unref-exit.ts": 2368, - "1803-timeout-refresh.ts": 2346, - "1804-timers-module.ts": 2379, - "1805-timer-callback-args.ts": 2475, - "1806-timer-delay-trunc.ts": 2847, - "1810-stream-options-const-record.ts": 2576, - "1811-stream-option-value-callbacks.cjs": 2945, - "1812-stream-super-options-forwarding.cjs": 3075, - "1813-stream-finished.ts": 2644, - "1814-stream-pipeline.cjs": 2915, - "1815-stream-state-reads.cjs": 2499, - "1820-static-block-basics.ts": 2475, - "1821-static-block-order.ts": 2605, - "1822-static-block-js.js": 1831, - "1823-static-instance-method-names.ts": 2522, - "1824-for-of-destructuring-defaults.ts": 2238, - "1825-exhaustive-typeof-switch.ts": 1814, - "1826-settimeout-arguments-callback.js": 2356, - "1830-enum-numeric-basics.ts": 2431, - "1831-enum-string-const-reverse.ts": 2780, - "1832-enum-modules/main.ts": 2343, - "1835-var-basics.ts": 2924, - "1836-var-loop-capture.ts": 2857, - "1837-var-undefined-hoisting.ts": 2785, - "1838-var-modules/main.ts": 2572, - "1839-var-js/main.cjs": 2766, - "1840-jsdoc-import-type-only/main.js": 2328, - "1850-overload-basics.ts": 2354, - "1851-overload-return-narrowing.ts": 2268, - "1852-overload-class-members.ts": 2874, - "1853-overload-modules/main.ts": 2339, - "1854-ambient-declare-fn.ts": 2384, - "1855-ambient-declare-fn-uncaught.ts": 2441, - "1870-unit-type-values.ts": 2730, - "1871-empty-array-never.ts": 2177, - "1872-template-tostring-composite.ts": 2526, - "1880-json-declared-field-order.ts": 2276, - "1881-default-anon/main.ts": 2233, - "1882-default-cjs-interop/main.ts": 2407, - "1883-default-exports/main.ts": 2358, - "1890-ns-imports/main.ts": 2428, - "1891-ns-reexport/main.ts": 2422, - "1940-class-values-basics.ts": 2483, - "1941-class-values-registry.ts": 2632, - "1942-class-expressions.ts": 2765, - "1943-class-statics-expanded.ts": 2459, - "1944-class-values-modules/main.ts": 2440, - "1950-generic-fn-values.ts": 2561, - "1951-generic-classes-basics.ts": 2197, - "1952-generic-class-statics-values.ts": 2662, - "1953-generic-class-hierarchy.ts": 3001, - "1954-generic-modules/main.ts": 2756, - "1960-namespace-basics.ts": 2647, - "1961-namespace-nested.ts": 2257, - "1962-namespace-classes.ts": 2660, - "1963-namespace-aliases.ts": 2070, - "1964-namespace-type-only.ts": 2445, - "1965-namespace-ambient.ts": 2332, - "1966-namespace-modules/main.ts": 2434, - "1967-namespace-alias-typeonly.ts": 2455, - "1968-namespace-import-eq-snapshot.ts": 2251, - "1970-decorators-basics.ts": 2885, - "1971-decorators-rebinding.ts": 2022, - "1972-decorators-throwing.ts": 2312, - "1973-decorators-ambient.ts": 2390, - "1980-primitive-proto-statics.ts": 3122, - "1981-date-utc.ts": 3440, - "1982-freeze-resolve-passthrough.ts": 2302, - "1983-array-tuple-surfaces.ts": 3057, - "1990-labels-basics.ts": 2548, - "1991-for-in-loops.ts": 2966, - "1992-small-syntax.ts": 1927, - "200-strings.ts": 2314, - "2000-generic-methods-basic.ts": 2743, - "2001-generic-methods-generic-class.ts": 2632, - "2002-generic-methods-inheritance.ts": 3264, - "2003-generic-methods-object-literal.ts": 2644, - "2004-generic-methods-statics.ts": 2578, - "201-templates.ts": 2516, - "2010-generators-basics.ts": 1908, - "2011-generators-forof.ts": 2574, - "2012-generators-return-throw.ts": 2779, - "2013-generators-sent-values.ts": 2065, - "2014-generators-values.ts": 2940, - "2015-generators-yieldstar.ts": 1953, - "2016-generators-rc-stress.ts": 2595, - "2017-generators-async.ts": 2715, - "2018-generators-uncaught.ts": 2356, - "2019-generators-loops.ts": 2496, - "2020-generic-value-bindings.ts": 2351, - "2021-generic-value-binding-modules/main.ts": 2687, - "2022-width-index-capture.ts": 2751, - "2023-width-readonly.ts": 2800, - "2024-width-array-elems.ts": 2726, - "2025-width-union-compose.ts": 2851, - "2026-width-spread.ts": 2485, - "2030-width-nested.ts": 2774, - "2031-width-tuples.ts": 2693, - "2032-cjs-export-assigned-class-expression/main.cjs": 2477, - "2033-property-assigned-class-extends.cjs": 2618, - "2035-ternary-array-retag.cjs": 2404, - "2036-evolving-array-decl.cjs": 2542, - "2037-fn-decl-hoisting.cjs": 2645, - "2038-evolving-array-js.cjs": 3054, - "2040-any-bindings.ts": 2984, - "2040-mixin-heritage.ts": 2131, - "2041-any-params-returns.ts": 2687, - "2041-mixin-values.ts": 2744, - "2042-any-flow-loops.ts": 2769, - "2042-mixin-modules/main.ts": 1924, - "2043-any-dom-values.ts": 2778, - "2043-mixin-rc-stress.ts": 2775, - "2044-vtable-sibling-slots.ts": 2571, - "2045-objlit-accessors-basic.ts": 2640, - "2045-parameter-properties.ts": 2113, - "2046-abstract-classes.ts": 3000, - "2046-objlit-accessors-effects.ts": 2795, - "2047-objlit-accessors-shapes.ts": 2983, - "2047-optional-class-fields.ts": 2949, - "2050-dynamic-import-own-module/main.ts": 2608, - "2051-dynamic-import-then/main.ts": 2467, - "2052-dynamic-import-self.ts": 2449, - "2053-typeof-static-fold.ts": 2181, - "2054-destructuring-island-source.ts": 2707, - "2060-empty-tuple.ts": 2373, - "2070-computed-key-folds.ts": 2645, - "2071-integer-key-enumeration-order.ts": 3006, - "2072-expando-function-members.ts": 2512, - "2073-destructuring-assignment.ts": 2535, - "2074-island-destructuring.ts": 2609, - "2075-index-signature-runtime-keys.ts": 1981, - "2080-destructuring-defaults.ts": 2417, - "2081-destructuring-rest.ts": 2774, - "2082-destructuring-assignment.ts": 2489, - "2085-destructuring-heads-rest-params.ts": 2668, - "2087-destructuring-for-heads.ts": 2521, - "2090-index-signature-number-keys.ts": 1958, - "2091-index-signature-string-intersection.ts": 2567, - "2092-package-imports/main.ts": 2340, - "2093-timers-promises.ts": 2743, - "2094-diagnostics-channel.ts": 1983, - "2095-js-catch-unknown.js": 2499, - "2096-os-type.ts": 2709, - "2097-js-evolving-globals.js": 2560, - "210-string-methods.ts": 2593, - "2100-stream-default-hwm.ts": 2961, - "2101-dyn-param-defaults.ts": 2737, - "2102-empty-pattern-decls.ts": 2787, - "2105-computed-key-static-folds.ts": 2507, - "2106-comma-expressions.ts": 2500, - "211-string-unicode.ts": 1823, - "2110-top-object-types.ts": 1971, - "2111-json-stringify-unknown.ts": 2830, - "2112-array-at-findlast.ts": 2001, - "2113-string-index-methods.js": 2989, - "212-string-aliasing-append.ts": 1909, - "2120-package-self-import/main.ts": 1825, - "2121-esm-cycle-inert-backedge/main.ts": 1748, - "2123-ambient-import-crash/main.ts": 1870, - "2124-imports-field-wildcard/main.ts": 2082, - "2140-uri-component-codecs.ts": 1955, - "2160-dc-tracing-channel.cjs": 2212, - "2161-js-object-literal-identity.cjs": 2587, - "2162-js-dyn-destructure.cjs": 2628, - "2163-js-selfref-const.cjs": 2533, - "2164-js-then-dyn-handler.cjs": 2503, - "2165-js-throw-dyn.cjs": 2509, - "2166-cjs-getter-this/main.cjs": 2420, - "2170-island-array-exits.ts": 3096, - "2171-island-json-stringify.ts": 2652, - "2172-island-regexp-boundary.ts": 2763, - "2190-new-object-and-string-wrappers.ts": 1860, - "2191-uri-encoders.ts": 2586, - "2192-object-default-tostring.ts": 2607, - "2193-discarded-stdlib-reads.ts": 2445, - "2194-ambient-undef-chains.ts": 2022, - "2195-require-missing-package/main.mjs": 2412, - "2196-island-computed-key-chain.ts": 2831, - "2210-dyn-promise-crossing.cjs": 1918, - "2211-dc-trace-promise.cjs": 2793, - "2212-unhandled-rejection-listener.cjs": 2511, - "2213-async-local-storage.cjs": 2825, - "2214-dc-bind-store.cjs": 2651, - "2215-process-emit-warning-exit.cjs": 2666, - "2240-width-class-into-record.ts": 2573, - "2241-width-record-into-class.ts": 2686, - "2242-width-statics-into-record.ts": 2654, - "2243-width-assert-satisfies-shapes.ts": 2411, - "2250-tagged-templates.ts": 2617, - "2252-class-iterators.ts": 3448, - "2253-union-coercions.ts": 2899, - "2260-http2-constants.cjs": 2471, - "2280-builtin-namespace-destructure.cjs": 2645, - "2281-domexception-atob-btoa.cjs": 2853, - "2282-queue-microtask.cjs": 2526, - "2283-structured-clone.cjs": 3050, - "2284-regexp-constructor.cjs": 1945, - "2285-iferror-dyn.cjs": 2665, - "2286-dyn-object-walks.cjs": 2662, - "2300-dyn-record-spread-and-keyed-access.cjs": 2261, - "2301-cjs-export-table-dom-attach.cjs": 2384, - "2310-process-next-tick.ts": 2843, - "2311-next-tick-js-callbacks.js": 2254, - "2312-stream-underscore-assign.ts": 2790, - "2313-stream-underscore-assign-js.cjs": 2842, - "2314-process-introspection.ts": 2971, - "2320-await-unit.ts": 2748, - "2321-emitter-static-setmax.cjs": 2272, - "2322-dyn-array-sort.cjs": 1886, - "2323-timer-callback-returns.ts": 2523, - "2330-tls-server-runtime-options.cjs": 2677, - "2331-tls-server-options-typed.ts": 2790, - "2350-nan-global.ts": 2734, - "2351-async-methods.ts": 2622, - "2352-void-coercions.ts": 1788, - "2353-decorators-member-ambient.ts": 2547, - "2354-decorators-expression-ambient.ts": 2465, - "2360-tuple-to-array.ts": 2471, - "2361-assign-index-record.ts": 3021, - "2362-execsync-inherit.ts": 2693, - "2363-nullish-retag.ts": 2801, - "2364-in-runtime-key.ts": 2572, - "2365-dyn-into-island.ts": 1996, - "2366-string-well-formed.ts": 2147, - "2367-regexp-escape.ts": 2470, - "2368-set-methods.ts": 2846, - "2369-promise-try.ts": 2170, - "2370-group-by.ts": 2298, - "2371-iterator-helpers.ts": 2730, - "2380-buffer-module-named-import.ts": 2400, - "2381-builtin-default-imports.js": 2365, - "2382-cycle-two-decl/main.ts": 1682, - "2383-cycle-assertdoc/main.js": 2760, - "2384-cycle-mixed-bindings/main.ts": 1815, - "2385-builtin-reexport-facade/main.ts": 1834, - "2386-string-to-chars.ts": 2748, - "2387-tonumber-argv.ts": 2345, - "2388-tonumber-grammar-zoo.ts": 2619, - "2389-tonumber-unary-plus.ts": 2473, - "2390-dot-requires/main.cjs": 2365, - "2391-default-builtin-imports/main.ts": 3036, - "2392-block-guard-alias-scope.ts": 2477, - "2393-loop-exit-guard-narrow.ts": 2791, - "2394-loop-narrow-containment.ts": 2749, - "2395-while-cond-guard.ts": 2574, - "2396-born-narrowed-decl.ts": 2435, - "2397-branch-kill-merge.ts": 2334, - "2398-switch-arm-kill.ts": 2438, - "2399-reassign-kill-polarity.ts": 2238, - "240-stdout-write.ts": 2820, - "2400-kill-return-edge.ts": 2315, - "2401-kill-break-staging.ts": 2347, - "2402-labeled-break-kill.ts": 2610, - "2403-kill-continue-backedge.ts": 2391, - "2404-kill-throw-catch.ts": 2611, - "2405-sibling-arm-narrow.ts": 2300, - "2406-switch-clause-sibling-narrow.ts": 1885, - "2407-infinite-loop-seal.ts": 2596, - "2408-loop-terminality-reopen.ts": 2452, - "2409-loop-body-return-not-terminal.ts": 1860, - "2410-stacked-cases-terminality.ts": 2588, - "2411-exhaustive-switch-terminality.ts": 2704, - "2412-dowhile-guard-trailing-test.ts": 2401, - "2413-dowhile-kill-renarrow.ts": 2389, - "2414-dowhile-continue-kill.ts": 2546, - "2415-dowhile-break-trailing-test.ts": 2461, - "2416-spread-ternary-positions.ts": 2790, - "2417-ternary-local-inference.ts": 2737, - "2418-wrapped-ternary-arms.ts": 2485, - "2419-selector-ternary-union.ts": 2554, - "2420-nullish-null-identity.ts": 2418, - "2421-float-lane-inference.ts": 2337, - "2422-ieee-div-rem-corners.ts": 2498, - "2423-param-null-reassign.ts": 2447, - "2424-ternary-miss-first-narrowing.ts": 2373, - "2425-elseif-head-exit-narrow.ts": 2194, - "2426-default-snapshot-mutable/main.ts": 2194, - "2427-perf-hooks-now.ts": 2489, - "2428-field-redeclare-inherited.ts": 2204, - "2429-destructure-class-instance.ts": 2362, - "2430-empty-literal-unknown-field.js": 2633, - "2431-primitive-ctor-values.ts": 2702, - "2432-generic-member-fields-async.ts": 2679, - "2433-as-const-command-tables.ts": 2271, - "2434-deferred-init-fields.ts": 2673, - "2435-loose-same-kind-equality.ts": 2441, - "2440-console-inspect-args.ts": 3150, - "2441-console-process-argv.ts": 2027, - "2442-union-literal-arm-widening.ts": 2300, - "2443-union-literal-shadow-narrowing.ts": 2799, - "2444-union-literal-reducer-spread.ts": 2545, - "2445-math-minmax-nary.ts": 2355, - "2446-performance-global.ts": 2453, - "2447-island-boundary-slots/main.ts": 3241, - "2448-entries-null-arms-regex-arrays.ts": 3215, - "2450-private-instance-methods.ts": 2581, - "2451-private-fields.ts": 2918, - "2452-private-statics.ts": 2431, - "2453-private-accessors.ts": 2589, - "2454-private-generator-methods.ts": 2809, - "2455-private-brand-checks.ts": 2369, - "2456-private-async-methods.ts": 2625, - "2457-private-members.js": 2014, - "2460-qs-parse-grammar.ts": 2706, - "2461-qs-parse-options.ts": 2139, - "2462-qs-stringify.ts": 2756, - "2463-qs-escape-unescape.ts": 2677, - "2464-qs-require-forms.cjs": 2768, - "2470-mockable-module-shape.js": 3152, - "2471-record-keyed-write-hasown.js": 2699, - "2472-string-regexp-union.ts": 2532, - "2473-option-table-widths.js": 2095, - "2474-island-literal-forms.ts": 2881, - "2475-variadic-wrapper-island.js": 2240, - "2476-map-regex-values.ts": 2431, - "2480-recursive-record-tree.ts": 2075, - "2481-mutual-recursive-records.ts": 2525, - "2482-recursive-union-tree.ts": 2633, - "2483-recursive-record-cycles.ts": 2479, - "2484-json-stringify-circular.ts": 2869, - "2485-inspect-circular-refs.ts": 2957, - "2486-recursive-record-boundaries.ts": 2857, - "2487-recursive-deep-equal.ts": 2516, - "2488-ast-walker.ts": 2925, - "2490-find-miss-null-compare.ts": 2051, - "2491-strict-unit-compare-no-arm.ts": 2381, - "2492-loose-null-compare-unions.ts": 2451, - "2493-switch-unit-cases.ts": 2503, - "2494-no-arm-compare-effects.ts": 2501, - "2500-net-autosel-timeout.ts": 2202, - "2510-dyn-evolving-array-map.ts": 2611, - "2511-dyn-evolving-array-filter-foreach.ts": 2729, - "2512-dyn-evolving-array-mixed-push.ts": 2656, - "2520-private-statics-class-name-calls.ts": 2568, - "2521-private-statics-class-expression.ts": 2429, - "2522-private-statics-decorated.ts": 2492, - "2523-private-statics-aliased-class.ts": 2618, - "2530-object-destructuring-decl.ts": 2513, - "2531-array-tuple-destructuring-decl.ts": 2504, - "2532-param-destructuring-options.ts": 2714, - "2533-forof-destructuring.ts": 2583, - "2534-object-rest-decl.ts": 2277, - "2535-destructuring-assign-basics.ts": 2758, - "2536-destructuring-assign-nested.ts": 2761, - "2537-destructuring-assign-member-targets.ts": 2552, - "2538-destructuring-assign-class-source.ts": 2658, - "2539-class-instance-rest.ts": 2852, - "2540-accessor-destructuring-defaults.ts": 2732, - "2541-destructuring-eval-order.ts": 2121, - "2550-generics-keyof-pick.ts": 2790, - "2551-generics-value-aliases.ts": 2489, - "2552-generics-iface-methods.ts": 2118, - "2553-generics-signature-bindings.ts": 2838, - "2554-generics-frontier-mix.ts": 2857, - "2555-generics-keyof-writes.ts": 2600, - "2556-crypto-introspection.ts": 2362, - "2556-width-hybrid-shapes.ts": 3063, - "2557-tls-ca-store.ts": 2877, - "2557-width-field-lifts.ts": 2899, - "2558-index-signature-func-values.ts": 2980, - "2558-rejection-events.cjs": 2741, - "2559-index-signature-container-values.ts": 2921, - "2560-arraybuffer-dataview-set.ts": 2985, - "2561-object-is.ts": 3314, - "2562-intl-numberformat-en-us.ts": 1713, - "2563-stream-promises-pipeline.ts": 2673, - "2564-stream-promises-finished.ts": 2596, - "2565-stream-promises-js.cjs": 2121, - "2566-promise-reject-dyn-reason.js": 2527, - "2567-rest-spread-forward.js": 3263, - "2568-rest-spread-forward-dynamic.js": 2990, - "2569-upcast-identity.ts": 1878, - "2570-buffer-arg-validation.cjs": 4190, - "2571-searchparams-arg-validation.cjs": 2897, - "2572-readable-emitted-readable-flag.cjs": 2583, - "2573-fs-url-arg-ladders.cjs": 2789, - "2574-emitter-max-listeners-ladders.cjs": 2728, - "2575-string-destructuring-decl.ts": 2831, - "2576-string-destructuring-assign.ts": 2718, - "2577-builtin-global-destructuring.js": 2482, - "2578-jsval-into-unknown-rows.ts": 2821, - "2579-jsval-object-param-crossing.js": 2723, - "2580-jsval-routed-keyed-ops.js": 2125, - "2581-jsval-routed-calls.js": 3090, - "2582-jsval-object-statics.js": 2972, - "2582-jsval-routed-keyed-ops.js": 2851, - "2583-dyn-nullish-coalesce.js": 2185, - "2583-jsval-routed-calls.js": 2972, - "2584-jsval-object-statics.js": 2832, - "2584-union-dyn-collapse.ts": 2220, - "2585-dyn-nullish-coalesce.js": 2398, - "2585-unknown-array.ts": 2751, - "2586-object-assign-spread.js": 3004, - "2587-array-entries-forof.ts": 2555, - "2588-array-entries-chains.ts": 3001, - "2589-object-create-null.cjs": 2994, - "2590-object-create-dynamic.js": 3188, - "2591-ambient-generic-traps.ts": 2461, - "2592-ambient-trap-uncaught.ts": 2508, - "2593-generic-inert-bindings.ts": 2003, - "2594-nullish-generic-bindings.ts": 2473, - "2595-fs-arg-ladders.cjs": 3590, - "2596-net-arg-ladders.cjs": 2708, - "2597-dgram-send-ladders.cjs": 3185, - "2598-tls-arg-ladders.cjs": 3457, - "2599-stream-arg-ladders.cjs": 2639, - "2600-dyn-keyed-write-harness.js": 2645, - "2601-dyn-keyed-write-ops.js": 2850, - "2602-dyn-array-destructure.js": 3140, - "2603-island-keyed-write-dyn.js": 2307, - "2604-cycle-classes-mutual/main.ts": 2453, - "2605-cycle-three-module/main.ts": 2707, - "2606-dynamic-import-cycle/main.ts": 2783, - "2608-regex-named-groups.ts": 3177, - "2609-regex-named-replace.ts": 2707, - "2610-regex-named-matchall.ts": 2590, - "2611-regex-named-groups-js.cjs": 2302, - "2613-for-init-uninitialized-let.ts": 2413, - "2614-trap-binding-later-writes.ts": 2362, - "2615-nullish-field-record-binding.ts": 2480, - "2616-js-collect-probe-defers.js": 2756, - "2617-enum-static-field-import/main.ts": 2551, - "2618-ee-emit-override.ts": 2613, - "2619-ee-override-chain.ts": 2034, - "2620-ee-override-once-order.ts": 2930, - "2621-ee-override-error-throw.ts": 2533, - "2622-ee-override-filter.ts": 2677, - "2623-ee-job-queue.ts": 2500, - "2624-ee-override-js.cjs": 2183, - "2625-bytes-views.ts": 2152, - "2626-stream-event-names.ts": 2499, - "2627-stream-ticks-are-nextticks.ts": 2708, - "2628-stream-push-encodings.cjs": 2440, - "2629-stream-consumers.ts": 2913, - "2630-stream-consumers-errors.ts": 2991, - "2631-create-require/main.ts": 3044, - "2632-dyn-jsval-iterate.js": 2878, - "2633-island-promise-crossing.js": 3370, - "2634-stream-pipeline-arg-ladders.cjs": 2714, - "2635-trap-binding-unmappable-written.ts": 2160, - "2636-trap-binding-ambient-rooted-rewrite.ts": 2374, - "2637-create-require-bare/main.ts": 2239, - "2638-http-dyn-res-compat.cjs": 3131, - "2639-http-dyn-req-pause.cjs": 2921, - "2640-net-dyn-socket-compat.cjs": 2968, - "2641-http-agent-surface.cjs": 3429, - "2642-http-agent-maxsockets.cjs": 2699, - "2643-or-default-retag.ts": 2845, - "2644-http-client-url-argument.ts": 2453, - "2645-https-client-url-argument.ts": 2836, - "2646-top-level-await.ts": 2403, - "2647-top-level-await-modules/main.ts": 2235, - "2648-top-level-await-rejection.ts": 1959, - "2649-top-level-await-pending.ts": 2384, - "2650-top-level-await-self-import.ts": 1987, - "2651-top-level-await-pending-unhandled.ts": 2002, - "2652-top-level-await-dynamic/main.ts": 2598, - "2653-top-level-await-rejection-stops-loop.ts": 2523, - "2654-top-level-await-unrelated-rejection.ts": 2015, - "2655-top-level-await-cycle/main.ts": 2308, - "2656-top-level-await-cycle-order/main.ts": 4054, - "2657-top-level-await-cycle-dynamic/main.ts": 2392, - "2658-top-level-await-sync-completion/main.ts": 2314, - "2659-top-level-await-dynamic-cycle/main.ts": 2467, - "2660-top-level-await-cycle-rejection/main.ts": 2494, - "2661-top-level-await-dynamic-runtime-root/main.ts": 2327, - "2662-top-level-await-cycle-external-wait/main.ts": 2397, - "2663-top-level-await-dependency-errors/main.ts": 2080, - "2664-top-level-await-same-checkpoint-rejection.ts": 2543, - "2665-top-level-await-unhandled-listener-liveness.ts": 2570, - "2666-array-to-sorted.ts": 6667, - "2668-stored-number-array-iterator.ts": 2876, - "2669-array-copying-methods.ts": 3089, - "2670-uint8array-copy-iterate.ts": 2885, - "2671-array-copying-js.cjs": 2315, - "2672-http-request-response-callback.ts": 2962, - "2673-top-level-await-implicit-module.ts": 2333, - "2674-top-level-for-await-implicit-module.ts": 2353, - "2675-create-require-nested-esm.js": 2188, - "2675-process-self-reexec.ts": 2836, - "2676-indexed-read-strict-equality.ts": 2408, - "2676-record-clone-overrides.ts": 2543, - "2676-top-level-await-ambiguous/main.ts": 2576, - "2677-runtime-optional-closure.ts": 4255, - "2677-top-level-await-module-scope/main.ts": 2463, - "2678-date-instances.ts": 2194, - "2678-large-string-sparse-index.ts": 2586, - "2678-util-parseargs.ts": 4462, - "2679-util-parseargs-cjs.cjs": 4905, - "2680-util-parseargs-default.ts": 1889, - "2681-util-parseargs-dynamic.js": 2618, - "2682-fs-rename.ts": 3414, - "2683-filter-truthy-predicate.ts": 3055, - "2683-fs-rename-js.cjs": 4058, - "2684-filter-no-predicate-dyn.cjs": 2608, - "2684-fs-rename-abort.ts": 2639, - "2685-array-unshift-reverse.ts": 3540, - "2685-fs-write-sync.ts": 2779, - "2686-fs-file-handle.ts": 3096, - "2687-fsp-write-file-options.ts": 2864, - "2687-process-write-args.ts": 2396, - "2688-fs-stats-disk-fields.ts": 3953, - "2689-http-server-timeout-properties.ts": 2717, - "2690-https-server-timeout-option.ts": 2702, - "2691-retained-lowering-record-order.ts": 2988, - "2692-inline-record-assert-index.ts": 2526, - "2692-string-accumulation.ts": 2081, - "2693-math-constants.ts": 1991, - "2700-array-sort-complexity.ts": 2921, - "2700-http-static-trailers.ts": 2864, - "2700-wasi-core.ts": 2423, - "2701-array-sort-snapshot.ts": 2953, - "2701-http-static-trailer-wire.ts": 4541, - "2701-import-meta/main.mjs": 2520, - "2702-http-static-trailer-end.ts": 2827, - "2702-type-import-link-static/main.ts": 2535, - "2702-uint8array-to-sorted.ts": 2284, - "2703-array-sparse-sort.ts": 4504, - "2703-type-import-link-static-reexport/main.ts": 3626, - "2704-array-sparse-to-sorted.ts": 4339, - "2704-type-import-link-static-success/main.ts": 2363, - "2705-array-sparse-sort-append.ts": 4401, - "2705-type-import-link-dynamic/main.ts": 1851, - "2706-array-search-missing-needle.ts": 2603, - "2706-type-import-link-dynamic-success/main.ts": 2413, - "2707-array-search-huge-sparse.ts": 45742, - "2707-type-import-link-static-default-reexport/main.ts": 2437, - "2708-type-import-link-dynamic/main.ts": 2892, - "2720-array-read-parity.ts": 3049, - "2721-array-nested-missing-receiver.ts": 2315, - "2750-array-sparse-foundation.ts": 3742, - "2751-buffer-concat-sparse-list.ts": 4185, - "2752-array-optional-stores.ts": 2347, - "2753-array-optional-method-values.ts": 3965, - "2754-array-property-undefined.ts": 2255, - "2755-array-optional-literal-forwarding.ts": 2583, - "2780-array-parity-composition.ts": 6251, - "2781-array-missing-value-escape.ts": 2554, - "2782-array-sparse-callbacks.ts": 3284, - "2783-array-defaults-rest.ts": 2724, - "2784-array-reduce-missing-result.ts": 2691, - "2785-array-missing-destructuring.ts": 2806, - "2786-array-sparse-serialization.ts": 2888, - "2787-array-missing-string-arithmetic.ts": 1877, - "2788-array-missing-builtin-conversions.ts": 1930, - "2789-array-missing-optional-tostring.ts": 1731, - "2790-dynamic-import-self-name/main.ts": 2308, - "2791-record-optional-keys.ts": 2478, - "2792-record-optional-spread-entries.ts": 2703, - "2793-union-conversion-identity-capture.ts": 1753, - "2794-array-generic-callback-values.ts": 2420, - "2795-array-optional-typedarray-source.ts": 1737, - "2796-array-sparse-class-value-instanceof.ts": 2296, - "2800-array-expression-consumers.ts": 2565, - "2801-array-switch-consumers.ts": 2471, - "2820-array-missing-method-receivers.ts": 2123, - "2821-array-optional-numeric-comparisons.ts": 2408, - "2830-cjs-require-self-name/main.cjs": 2633, - "2840-finally-completions.ts": 2505, - "2841-using-sync.ts": 2632, - "2842-await-using.ts": 1790, - "2843-using-suppressed-error.ts": 2235, - "2844-node-disposable-resources.ts": 2658, - "2845-for-using-of.ts": 4410, - "2846-generator-using.ts": 2392, - "2850-async-generators-protocol.ts": 3002, - "2851-async-generators-values.ts": 4379, - "2852-timers-promises-interval.ts": 2511, - "2854-leading-bom-literals.ts": 2528, - "2855-searchparams-sort-complexity.ts": 2416, - "2856-dynamic-any-local-operators.ts": 1839, - "2857-branded-primitives.ts": 1736, - "2858-import-meta-resolve/main.mjs": 2679, - "2859-import-meta-resolve-dynamic/main.mjs": 2295, - "2860-require-resolve/main.cjs": 2780, - "2861-readable-iterator-close.ts": 3207, - "2862-web-readable-async-iteration.ts": 3375, - "2863-class-async-iterator.ts": 2531, - "2864-array-class-method-receivers.ts": 1837, - "2865-cjs-process-alias.cjs": 2734, - "2866-dyn-switch.ts": 1772, - "2867-array-shift-length.js": 2411, - "2868-empty-record-promise-presence.js": 2531, - "2869-nullish-mixed-lazy.ts": 2433, - "2870-and-dropped-truthy-arm.ts": 2606, - "2871-optional-promise-to-unknown.ts": 2387, - "2872-unobserved-dynamic-event.ts": 2191, - "2873-optional-receiver-loop-lifetime.js": 2453, - "2874-nullable-callback-field-cycle.js": 2707, - "2875-evolving-let-read-before-write.js": 3668, - "2876-class-unknown-roundtrip.ts": 2817, - "2877-child-unknown-roundtrip.ts": 2660, - "2878-class-private-unknown.cjs": 4040, - "2880-cjs-module-graph/main.cjs": 2924, - "2890-crypto-static-utility.ts": 2261, - "2891-json-record-key-escapes.ts": 2705, - "2892-windows-console-unicode.ts": 2266, - "2893-child-stdin-duplex.ts": 3340, - "2894-child-stdin-backpressure.ts": 3131, - "2895-child-stdin-write-after-end.ts": 2384, - "2896-child-stdin-write-after-finish.ts": 2871, - "2897-child-stdin-destroy.ts": 2871, - "2898-child-stdin-spawn-failure.ts": 2549, - "2899-nested-mutual-recursion.ts": 2721, - "2900-float64array-static.ts": 2799, - "2900-void-conditional-arrow.ts": 2537, - "2901-bigint-core.ts": 2424, - "2902-bigint-bytes.ts": 2498, - "2903-bigint-storage.ts": 2708, - "2904-bigint-errors.ts": 2577, - "2905-bigint-edges.ts": 2439, - "2906-bigint-wasi-width.ts": 1786, - "2910-overloaded-callable-alias.ts": 2648, - "2911-execfile-callback.ts": 2191, - "2912-execfile-callback-options.ts": 2127, - "2912-promisify-fs-readfile.ts": 2460, - "2913-builtin-callable-alias.ts": 2481, - "2914-fixed-tuple-call-spread.ts": 2974, - "2915-path-function-values.ts": 2177, - "2916-path-function-values-cjs.ts": 2451, - "2917-builtin-callable-widths.ts": 2149, - "2918-builtin-callable-widths-cjs.ts": 2749, - "2919-fs-function-values.ts": 2635, - "2920-fs-promises-function-values.ts": 1999, - "2921-zlib-callbacks.ts": 2825, - "2922-dyn-bitwise-not.cjs": 2337, - "2923-cjs-factory-export/main.cjs": 2557, - "2930-union-receiver-calls.ts": 3403, - "2931-union-dynamic-field-call.js": 3002, - "2932-create-require-program/main.ts": 2467, - "2933-static-dynamic-import/main.ts": 2896, - "2934-static-import-stored.ts": 2404, - "2935-module-namespace-values/main.ts": 2608, - "2936-static-loose-equality.ts": 3140, - "2937-bitwise-hot-loop.ts": 2268, - "2938-fs-sync-overloads.cjs": 1857, - "2939-child-shell-text.ts": 3041, - "2940-date-parse.ts": 2483, - "2940-fsp-realpath.ts": 2587, - "2941-fsp-lstat-identity.ts": 2657, - "2941-process-exit-code.ts": 1743, - "2942-fsp-readdir-dirent.ts": 2911, - "2942-process-exit-code-override.ts": 1751, - "2943-process-exit-code-invalid.ts": 2583, - "2944-process-exit-code-wrap.ts": 2435, - "2945-url-origin-username.ts": 1863, - "2946-child-fork-ipc/main.ts": 3271, - "2946-url-port-hash.ts": 2587, - "2947-set-readonly-seeds.ts": 2456, - "2948-child-fork-eof-callback/main.ts": 3043, - "2948-stdio-callback-record.ts": 2421, - "2949-child-fork-default/main.mjs": 2736, - "2949-url-password.ts": 2744, - "2950-fs-descriptor-publication.ts": 2681, - "2951-math-static-analytic.ts": 3121, - "2952-math-static-remaining.ts": 2862, - "2953-http-header-validation.ts": 2956, - "2954-http-outgoing-headers.ts": 2822, - "2955-http-static-state.ts": 2955, - "2956-http-static-informational.ts": 3085, - "2957-http-static-response-controls.ts": 2273, - "2961-emitter-computed-names.cjs": 2632, - "2962-emitter-computed-optional.ts": 2051, - "2963-child-fork-dispatch/main.ts": 2809, - "2964-indexed-compound.ts": 2982, - "2966-numeric-array-read-fusion.ts": 2045, - "2967-numeric-array-read-lifetime.ts": 3048, - "2968-numeric-array-borrow.ts": 2914, - "2969-scalar-record-results.ts": 2620, - "2970-constant-numeric-tables.ts": 2078, - "2971-constant-table-modules/main.ts": 2587, - "2972-http-static-distinct-snapshots.ts": 2220, - "2972-math-receiver-borrow.ts": 3503, - "2973-http-static-agent.ts": 3163, - "2973-integer-bitwise-arithmetic.ts": 2756, - "2974-array-search-from-index.ts": 120636, - "2974-http-static-module-values.ts": 2696, - "2974-numeric-remainder.ts": 2784, - "2975-bigint-default-radix.ts": 1741, - "2975-http-static-client-controls.ts": 2204, - "2976-http-static-incoming-state.ts": 2949, - "2976-json-stringify-no-arguments.js": 2583, - "2977-http-static-incoming-timeout.ts": 2724, - "2977-nested-array-binding-defaults.js": 2760, - "2978-http-static-client-timeout.ts": 3060, - "2978-regexp-optional-subject.js": 2540, - "2979-array-search-mixed-needles.js": 2011, - "2979-http-static-server-timeout.ts": 2740, - "2980-http-static-server-timeout-default.ts": 2671, - "2980-string-position-arguments.js": 2246, - "2981-http-static-events.ts": 1817, - "2981-string-optional-positions.ts": 1836, - "2982-http-static-close-all.ts": 2421, - "2982-string-position-coercion-order.js": 3081, - "2983-http-static-close-idle.ts": 2006, - "2984-http-static-close-upgrade.ts": 2129, - "2985-http-static-message-destroy.ts": 2630, - "2986-http-static-client-socket-finish.ts": 1940, - "2987-http-static-timeout-errors.ts": 2737, - "2988-http-static-client-abort.ts": 2025, - "2989-http-static-response-timeout-handled.ts": 2928, - "2990-http-static-request-timeout-handled.ts": 2599, - "2991-array-indexed-equality.ts": 2993, - "2992-stream-rows.ts": 2556, - "2993-fiber-stack-lifetimes.ts": 3202, - "2994-fromcharcode-scalar.ts": 2833, - "2995-math-hyperbolic.ts": 2687, - "2996-math-near-one.ts": 2252, - "2997-math-integer-float.ts": 3190, - "300-if-else.ts": 2219, - "3001-caught-typeof-object.js": 2450, - "3002-promise-then-two.ts": 2484, - "301-while.ts": 2153, - "302-for.ts": 1918, - "3020-string-last-index-position.ts": 2434, - "3021-buffer-union-narrow-callback.ts": 2866, - "3022-string-affix-positions.ts": 2229, - "3023-string-affix-position-coercion.js": 3333, - "3024-string-number-narrow-for-in.ts": 2650, - "3025-string-search-position-coercion.js": 2447, - "3026-array-last-index-of.js": 2579, - "3027-array-last-index-of-records.ts": 2304, - "3028-string-search-dynamic-needle.js": 2564, - "3029-string-search-union-needle.js": 1657, - "303-break-continue.ts": 2442, - "3030-array-search-no-arg.js": 3027, - "3031-array-relative-index-coercion.js": 2940, - "3031-string-last-index-search-value.js": 2407, - "3032-string-search-value.js": 2579, - "3033-string-search-needle-coercion.js": 2232, - "3034-arguments-with-parameters.js": 2126, - "3035-string-positioned-search-value.js": 2449, - "3036-string-object-search-value.js": 1849, - "3037-number-nullish-conversion.js": 2478, - "3038-number-scalar-unions.ts": 1881, - "3039-string-repeat-count.js": 2372, - "304-compound-incdec.ts": 2266, - "3040-string-prototype-call.js": 2389, - "3041-string-prototype-object-call.js": 2679, - "3042-string-padding-coercion.js": 2923, - "3043-string-split-arguments.js": 3247, - "3044-array-slice-splice-positions.js": 2966, - "3045-array-indexed-mutation.js": 2960, - "3046-array-indexed-ref-identity.ts": 2358, - "3047-object-prototype-tag.js": 2265, - "3048-object-own-prototype.ts": 3162, - "3049-array-flat-depth.ts": 2904, - "305-truthiness.ts": 2588, - "3050-array-splice-insert.ts": 2779, - "3051-array-join-default.ts": 2220, - "3052-array-construction.ts": 2520, - "3053-array-construction-js.js": 2821, - "3054-dynamic-abort-record.ts": 2818, - "3055-default-builtin-nodenext/main.ts": 2044, - "3056-default-builtin-bundler/main.ts": 2874, - "3057-default-builtin-nodenext-dynamic/main.ts": 1912, - "3058-optional-array-chain-join.ts": 2986, - "3059-arguments-property-names.ts": 1856, - "3061-concurrent-fiber-stacks.ts": 2766, - "3062-runtime-optional-record-guards.ts": 3210, - "3063-runtime-optional-class-guards.ts": 2677, - "3064-installed-entry-imports/main.ts": 1867, - "3065-installed-entry-js/main.js": 2294, - "3066-source-debugging/main.ts": 2276, - "3067-cjs-function-export-require/main.cjs": 1963, - "3068-debug-variables/main.ts": 2578, - "3068-url-checked-identity.ts": 2207, - "3069-set-checked-seed.js": 2608, - "3069-tuple-spread.ts": 2969, - "3070-checked-object-accessors.js": 2496, - "3070-collection-views.ts": 2799, - "3071-checked-specialization-narrowing.js": 2715, - "3071-map-contextual-record-seeds.ts": 3095, - "3072-optional-union-receivers.ts": 2303, - "3072-weak-process-streams.js": 2885, - "3073-optional-callable-module.js": 2520, - "3073-union-keyed-reads.ts": 2905, - "3074-discriminated-intersections.ts": 2460, - "3075-recursive-contextual-literals.ts": 3335, - "3076-nullish-record-defaults.ts": 2894, - "3077-optional-union-array-reads.ts": 2500, - "3078-forward-mutable-captures.ts": 3097, - "3079-forward-mutable-tdz.ts": 2796, - "3080-exhaustive-never-bindings.ts": 2704, - "3081-recursive-array-destinations.ts": 2667, - "3082-forward-write-unwind.ts": 2538, - "3083-set-string-seed.ts": 2595, - "3084-record-own-membership.ts": 2879, - "3085-conditional-record-construction.ts": 2874, - "3086-error-constructor-options.ts": 2970, - "3087-error-options-lifetime.ts": 2675, - "3088-array-wide-callbacks.ts": 2690, - "3089-array-find-narrowing.ts": 2833, - "3090-json-discriminated-records.ts": 3066, - "3091-json-recursive-discriminants.ts": 2220, - "3092-number-union-predicates.ts": 2324, - "3093-error-option-data.ts": 2104, - "3094-json-replacer-traversal.ts": 2818, - "3095-json-reviver-traversal.ts": 2804, - "3096-json-callback-nonfinite.ts": 2753, - "3097-json-callback-reentrancy.ts": 2198, - "3098-json-callback-space.ts": 2839, - "3099-json-callback-functions.ts": 3102, - "3100-json-callback-holder.js": 2748, - "3101-json-callback-bytes.ts": 2087, - "3102-json-unknown-fields.ts": 2238, - "3103-scalar-record-nested-control-flow.ts": 2806, - "3104-native-analysis-tables-loops.ts": 2680, - "3105-nullable-collections.ts": 2913, - "3106-mixed-insertion-spreads.ts": 3159, - "3107-nullable-collection-lifetimes.ts": 3025, - "3108-for-await-sync-arrays.js": 3537, - "3108-identity-map-keys.ts": 3249, - "3109-destructuring-unknown-defaults.js": 2565, - "3109-identity-union-collections.ts": 3588, - "3110-builtin-error-families.ts": 2812, - "3110-identity-collection-mutation.ts": 2831, - "3111-identity-collection-cycles.ts": 2915, - "3112-union-switch-control-flow.ts": 2075, - "3113-union-array-removal.ts": 3111, - "3114-union-record-field-write.ts": 2886, - "3115-zlib-static-compression-levels.ts": 2667, - "3116-sequence-expression-lifetimes.ts": 2953, - "3117-unknown-switch-control-flow.ts": 2388, - "3118-recursive-union-spread.ts": 3091, - "3119-runtime-optional-spread.ts": 3563, - "3120-dynamic-property-descriptors.js": 2806, - "3120-generator-method-loop-bindings.ts": 2970, - "3120-ir-nonfinite-numbers.ts": 2756, - "3121-compound-assignment-values.js": 2784, - "3121-dynamic-accessor-descriptors.js": 2889, - "3122-dynamic-delete-descriptors.cjs": 2435, - "3122-dynamic-delete-descriptors.js": 2554, - "3122-js-async-class-methods.js": 2294, - "3123-destructured-global-tdz.js": 2755, - "3124-array-prototype-borrow.js": 2322, - "3125-regex-global-match.ts": 2783, - "3126-js-number-radix/main.ts": 2820, - "3127-spawn-runtime-options.ts": 3072, - "3128-regex-last-index.ts": 1823, - "3129-js-token-union/main.ts": 2769, - "3130-child-generic-streams.ts": 2981, - "3131-child-rest-listeners.js": 2627, - "3132-child-generic-stream-completion.ts": 5669, - "3133-text-decoder-streaming.ts": 2916, - "3134-fs-vectors.ts": 2782, - "3135-fs-file-handle-controls.ts": 3077, - "3136-fs-file-handle-options.ts": 3203, - "3137-fs-vector-callbacks.cjs": 3063, - "3138-array-large-storage.ts": 4112, - "3139-regex-native-deep-alternatives.ts": 26910, - "3140-array-dense-access.ts": 3431, - "3141-map-string-key-hash.ts": 3132, - "3150-integer-remainder.ts": 3203, - "3151-array-push-writes.ts": 3025, - "3170-number-conversion-fast-paths.ts": 2101, - "3171-method-census-data-writes.ts": 3216, - "400-fib.ts": 2634, - "401-mutual-recursion.ts": 2541, - "402-string-functions.ts": 2183, - "403-void-and-params.ts": 2239, - "4030-runtime-object-truthiness.ts": 2407, - "4031-event-emitter-long-tuples.ts": 2624, - "4032-inline-rc-fast-paths.ts": 3924, - "404-rc-stress.ts": 2608, - "4040-adapted-function-identity.ts": 3296, - "4041-adapted-function-properties.ts": 2613, - "4042-object-is-union-subclass.ts": 2694, - "4043-nonnull-missing-element.ts": 2672, - "4044-adapted-callback-modules/main.ts": 2828, - "4045-optional-element-projections.ts": 2963, - "4046-captured-parameter-values.ts": 3070, - "4047-captured-parameter-rebinding.ts": 2848, - "405-params-optional.ts": 1924, - "406-params-defaults.ts": 1978, - "4060-cycle-shared-instance/main.ts": 2198, - "4060-stack-union-reads.ts": 3362, - "4061-cycle-evaluation-order/main.ts": 2399, - "4061-nullable-ref-fields.ts": 4246, - "4062-cycle-tdz-read/main.ts": 2254, - "4063-cycle-hoisted-calls/main.ts": 2402, - "4064-cycle-classes-after-init/main.ts": 2048, - "4065-cycle-init-throws/main.ts": 2640, - "4066-cycle-top-level-tdz/main.ts": 2245, - "4067-dynamic-import-cycle-tdz/main.ts": 2515, - "407-params-rest.ts": 2698, - "408-params-ctors-inheritance.ts": 2092, - "4080-optional-read-presence-tests.ts": 2936, - "4080-string-index-bounds.ts": 2863, - "4081-hoisted-function-tdz.ts": 2788, - "4081-string-index-unproven.ts": 2335, - "4082-hoisted-function-tdz-uncaught.ts": 1949, - "4083-dynamic-import-failure/main.ts": 2717, - "4084-record-optional-field-copies.ts": 2527, - "4085-generator-loop-close.ts": 2591, - "4086-optional-capture-defaults.ts": 2395, - "4088-class-static-tdz.ts": 2363, - "4089-class-wrapper-tdz.js": 2402, - "409-params-async-generics.ts": 2098, - "4090-computed-key-tdz.js": 2605, - "4091-class-evaluation-deferred.ts": 2199, - "410-params-rc-stress.ts": 2565, - "4140-array-callback-split-visit.ts": 4386, - "4141-array-callback-ambient-receiver/main.ts": 2299, - "4142-array-callback-factories.ts": 3208, - "4143-union-refinement-intersection-arms.ts": 2685, - "420-dead-strip-modules/main.ts": 2527, - "4290-acyclic-immutable-trees.ts": 3246, - "4291-acyclic-constructor-escapes.ts": 2909, - "4292-acyclic-readonly-bypass.ts": 3024, - "4293-acyclic-dynamic-writes.ts": 2956, - "4294-console-line-sizes.ts": 5873, - "4295-console-template-parts.ts": 2597, - "4296-console-glued-long-parts.ts": 2868, - "4410-inline-object-allocation.ts": 3093, - "4411-nullable-ref-values.ts": 4434, - "4412-nullable-record-values.ts": 3635, - "4413-cycle-old-late-death.ts": 2102, - "4413-nullable-null-and-undefined.ts": 2783, - "4414-cycle-old-weak-keys.ts": 2960, - "4414-nullable-string-values.ts": 3874, - "4415-identity-borrowed-operands.ts": 2087, - "4415-nullable-container-values.ts": 3581, - "4431-exception-pending-contexts.ts": 3035, - "4432-checked-downcast-failures.ts": 3246, - "4451-int32-field-storage.ts": 3457, - "4452-int32-field-dynamic-writes.ts": 3861, - "4453-int32-closed-locals.ts": 2280, + "1117-typeof-static-union.ts": 3626, + "1118-object-spread-conditional.ts": 2554, + "1119-switch-union.ts": 2726, + "112-class-descriptor-key.js": 2549, + "1121-infinity-number-tostring.ts": 3208, + "1122-any-captures.ts": 3054, + "1124-union-narrowed-retag.ts": 3578, + "113-promise-checked-exits.ts": 3586, + "114-live-record-delete.ts": 3626, + "115-array-compound.js": 3341, + "116-text-decoder-runtime.js": 2988, + "117-weak-cache-cycle.js": 2923, + "118-fs-stored-callbacks.cjs": 4172, + "119-native-patterns.js": 3825, + "1200-regex-test-basics.ts": 3353, + "1201-regex-replace.ts": 3417, + "1202-regex-substitutions.ts": 2747, + "1203-regex-split.ts": 3543, + "1204-regex-empty-unicode.ts": 3255, + "1205-regex-rc-stress.ts": 3482, + "1300-errors-basics.ts": 4832, + "1301-errors-subclass.ts": 1974, + "1302-errors-typed-catch.ts": 3160, + "1303-errors-rc-stress.ts": 3496, + "1304-errors-uncaught.ts": 2419, + "1305-errors-async-rejections.ts": 3908, + "1306-errors-runtime-instances.ts": 3226, + "1350-path-normalize-join.ts": 3294, + "1351-path-parts.ts": 3299, + "1352-path-resolve-relative.ts": 3380, + "1353-os-basics.ts": 3216, + "1354-builtin-bare-specifiers.ts": 3413, + "1355-url-parse.ts": 3188, + "1356-url-file-bridge.ts": 3020, + "1357-fsp-roundtrip.ts": 3377, + "1358-crypto-random.ts": 3134, + "1359-json-module/main.ts": 3195, + "1360-spawn-sync.ts": 3446, + "1361-spawn-events.ts": 3606, + "1362-spawn-timers.ts": 9552, + "1363-spawn-unhandled-error.ts": 3308, + "1364-union-truthiness.ts": 2872, + "1365-union-logical.ts": 3452, + "1366-union-equality.ts": 2813, + "1367-destructuring.ts": 3209, + "1368-constructor-functions.ts": 1858, + "1369-promise-union.ts": 2635, + "1370-spread.ts": 2894, + "1371-union-template-tostring.ts": 3244, + "1372-loose-null-tests.ts": 3198, + "1373-union-array-arms.ts": 3455, + "140-bitwise-operators.ts": 3457, + "1400-typedarray-basics.ts": 2651, + "1401-typedarray-slice-set.ts": 4371, + "1402-buffer-encodings.ts": 3496, + "1403-buffer-fs.ts": 3517, + "1404-zlib-crypto-bytes.ts": 3174, + "1405-bytes-unions-arrays.ts": 4083, + "1406-dataview-mp4.ts": 3511, + "1407-dataview-bounds.ts": 2861, + "1408-string-indexing.ts": 3596, + "1409-typedarray-integer-loops.ts": 3161, + "1420-number-statics.ts": 1931, + "1421-number-parse-strings.ts": 2420, + "1422-date-iso.ts": 3107, + "1423-text-codec.ts": 4835, + "1424-fs-options.ts": 3321, + "1425-stdin-tty.ts": 2403, + "1426-stdin-read.ts": 3082, + "1427-fromcharcode-lastindexof.ts": 3173, + "1428-settled-await-order.ts": 1798, + "1429-promise-catch-finally.ts": 3573, + "1430-promise-race.ts": 3479, + "1431-caught-tostring.ts": 3384, + "1432-destructured-params.ts": 2875, + "1433-filter-narrow.ts": 3756, + "1434-async-never.ts": 3046, + "1435-math-spread.ts": 2761, + "1436-default-undef-param.ts": 2349, + "1437-pad-default.ts": 3147, + "1438-promise-all.ts": 6716, + "1440-interval-basics.ts": 2538, + "1441-interval-clear-cross.ts": 6428, + "1442-interval-throw.ts": 3155, + "1443-signal-handlers.ts": 5897, + "1444-exit-listeners.ts": 2050, + "1445-exit-process-exit.ts": 3031, + "1446-exit-uncaught.ts": 3104, + "1447-stdin-closed-events.ts": 2554, + "1448-stream-columns.ts": 2939, + "1450-incdec-expression.ts": 3366, + "1451-instanceof-uint8array-unknown.ts": 3581, + "1452-return-through-finally.ts": 2366, + "1453-pmap-settled.ts": 3689, + "1454-nonnull-narrow-and-fcc-bytes.ts": 3631, + "1455-lambda-union-return-adoption.ts": 3317, + "1460-console-error-warn.ts": 2928, + "1461-process-pid-getuid-kill.ts": 2613, + "1462-exec-sync.ts": 3611, + "1463-timeout-unref.ts": 2351, + "1464-env-writes.ts": 2366, + "1465-env-value.ts": 3573, + "1466-child-containers.ts": 3261, + "1467-string-match.ts": 2763, + "1468-exec-path.ts": 1874, + "1469-remove-listener.ts": 3366, + "1470-child-lifecycle.ts": 3503, + "1471-child-unref.ts": 7428, + "1472-errno-code.ts": 3503, + "1473-promisify-execfile.ts": 3923, + "1474-string-decoder.ts": 3543, + "1475-readline-closed-stdin.ts": 2561, + "1476-assign-expression.ts": 2094, + "1477-in-expressions.ts": 2351, + "1478-promise-reject.ts": 3535, + "1479-destructuring-assign.ts": 3422, + "1480-os-network-interfaces.ts": 3878, + "1481-string-case-static.ts": 1956, + "1482-spawnsync-error.ts": 3384, + "1483-array-slice.ts": 2259, + "1520-fs-wider-surface.ts": 2338, + "1520-string-split-static.ts": 2323, + "1521-fs-lstat-lock.ts": 2828, + "1521-string-trim-pad-static.ts": 3386, + "1522-parseint-static.ts": 3245, + "1522-spawnsync-options.ts": 5207, + "1523-isnan-floor-static.ts": 2460, + "1523-spawn-options.ts": 3155, + "1524-atomics-sleep-static.ts": 3514, + "1524-catch-narrowing.ts": 3000, + "1525-child-exit-signal.ts": 3280, + "1525-unknown-typeof-validation.ts": 3939, + "1526-set-spread.ts": 3125, + "1527-logical-mixed-operands.ts": 3109, + "1528-delete-records-env.ts": 3666, + "1529-class-with-statics.ts": 2773, + "1530-array-push-variadic.ts": 2981, + "1530-spread-override-completion.ts": 2727, + "1531-delete-optional-fields.ts": 3366, + "1531-process-arch-versions.ts": 3284, + "1532-array-splice-shift.ts": 3298, + "1532-union-shared-field-read.ts": 3134, + "1533-bool-equality.ts": 2685, + "1533-path-platform-namespaces.ts": 2976, + "1534-crypto-hash-chain.ts": 3181, + "1534-union-as-arm-cast.ts": 1932, + "1535-spawn-fd-stdio.ts": 2678, + "1535-union-param-defaults.ts": 3163, + "1536-destructuring-defaults.ts": 2281, + "1536-string-array-sweep.ts": 2437, + "1537-chalk-hybrid/main.ts": 2748, + "1537-os-release-spawnsync-stdio.ts": 1762, + "1538-await-promiselike-return.ts": 3032, + "1538-math-static-scalar.ts": 3194, + "1539-readonly-set-map.ts": 2459, + "1539-unknown-truthiness.ts": 3106, + "1540-os-userinfo.ts": 3344, + "1540-void-statement.ts": 2967, + "1541-fs-readdir-dirent.ts": 3638, + "1541-union-keyed-reads.ts": 3287, + "1542-map-promise-values.ts": 2441, + "1542-record-literal-into-union.ts": 3261, + "1543-rest-destructuring.ts": 2933, + "1543-set-server-handles.ts": 1958, + "1544-dyn-json-reads.ts": 2284, + "1544-string-matchall.ts": 2886, + "1545-spread-order-and-optional.ts": 3651, + "1546-union-element-reads.ts": 3172, + "1547-computed-key-fold.ts": 3047, + "1548-boolean-condition-forms.ts": 2170, + "1549-array-isarray-unions.ts": 3931, + "1550-param-defaults-func-set.ts": 2398, + "1551-dyn-receiver-methods.ts": 3835, + "1552-exec-options-record.ts": 3202, + "1553-truthy-hof-predicates.ts": 3421, + "1554-caught-into-unknown.ts": 3543, + "1555-index-spread-into-declared.ts": 3633, + "1556-union-retag-width-arms.ts": 2627, + "1557-url-host.ts": 2357, + "1558-any-joins-and-dyn-validation.ts": 3196, + "1559-conditional-spread-index-merge.ts": 3131, + "1560-forof-homogeneous-tuples.ts": 3159, + "1561-forof-strings.ts": 2864, + "1561-promise-then.ts": 2385, + "1562-optional-chain-tails.ts": 3642, + "1562-spawn-conditional-spread.ts": 3319, + "1563-forof-iterator-projections.ts": 2786, + "1563-string-raw-fold.ts": 2587, + "1564-fs-watch.ts": 3261, + "1564-string-raw.ts": 2451, + "1565-spawn-pipe-streams.ts": 3391, + "1565-union-element-join.ts": 2486, + "1566-child-duck-interface.ts": 2840, + "1567-server-close-override.ts": 3237, + "1568-x509-fingerprint.ts": 3907, + "1569-fsp-mkdir-unlink-chmod.ts": 2903, + "1570-child-unref-kill-reffed.ts": 8636, + "1571-optional-call-tostring-tail.ts": 2889, + "1571-stdin-set-raw-mode-non-tty.ts": 2975, + "1572-promise-reject-all-tuple.ts": 3556, + "1572-x509-validity-date-gettime.ts": 3310, + "1573-promisify-execfile-env-spread.ts": 2814, + "1573-tdz-scalar-forward-capture.ts": 1712, + "1574-dyn-optional-method-number-keys.ts": 3878, + "1574-promise-all-tuple-literal.ts": 2253, + "1575-unknown-assert-into-record.ts": 1861, + "1576-width-coercions.ts": 2898, + "1577-url-hostname.ts": 2901, + "1578-exec-input-optional.ts": 3273, + "1579-matchall-index.ts": 3564, + "1580-exec-env-conditional-spread.ts": 2271, + "1581-declare-const-read.ts": 3037, + "1582-timer-sleep-resolve.ts": 3206, + "1583-loops-and-stream-captures.ts": 3193, + "1584-union-field-unassigned.ts": 3119, + "1585-union-field-conditional-ctor.ts": 3101, + "1586-derived-field-before-super-init.ts": 2618, + "1590-js-unannotated.js": 2053, + "1591-js-closures.js": 2387, + "1592-js-classes.js": 4973, + "1593-js-jsdoc-records.js": 3116, + "1594-js-async.js": 2589, + "1595-js-island-gap/main.js": 3108, + "1596-cjs-modules/main.js": 3096, + "1597-mjs-graph/main.mjs": 2863, + "1598-cjs-builtin-require/main.js": 2598, + "1599-js-uncaught-throw.js": 1785, + "1600-assert-passing.ts": 3203, + "1601-assert-fail-exit.ts": 2955, + "1602-assert-caught-error.ts": 2978, + "1603-assert-scalar-messages.ts": 3055, + "1604-assert-deep-structures.ts": 3591, + "1605-assert-import-forms.ts": 2429, + "1606-assert-strict-module.ts": 3039, + "1607-assert-throws-match.ts": 2826, + "1608-cjs-assert/main.js": 3263, + "1609-assert-async.ts": 3342, + "1610-path-win32-full.ts": 2405, + "1611-url-file-bridge-neutral.ts": 2476, + "1612-cjs-module-globals.cjs": 2856, + "1613-cjs-esm-proxy-named/main.mjs": 2613, + "1614-js-fence-dodges.cjs": 1967, + "1615-cjs-export-shapes/main.cjs": 2975, + "1616-cjs-esm-lexer-invisible/main.mjs": 2660, + "1617-cjs-esm-lexer-visible/main.mjs": 3090, + "1618-cjs-esm-poisoned-tail/main.mjs": 2780, + "1619-cjs-esm-reexport-invisible/main.mjs": 2185, + "1620-cjs-require-effects-order/main.js": 1410, + "1621-cjs-require-cache-hit/main.js": 2836, + "1622-cjs-require-conditional/main.js": 2564, + "1623-cjs-require-diamond/main.js": 2652, + "1624-cjs-require-dir-mid-file/main.js": 2573, + "1625-cjs-require-lazy-fn/main.js": 2246, + "1626-cjs-require-mjs/main.js": 2951, + "1627-mjs-import-cjs-requires/main.mjs": 2683, + "1628-checked-dynamic-builtin-args.cjs": 1896, + "1629-require-main-filename.cjs": 2867, + "1630-inspect-scalars.ts": 2361, + "1630-rmsync-retry-options.cjs": 2984, + "1631-inspect-arrays.ts": 3811, + "1632-inspect-records.ts": 4779, + "1633-inspect-map-set.ts": 3008, + "1634-inspect-classes.ts": 3344, + "1635-inspect-buffer.ts": 2898, + "1636-util-format.ts": 2261, + "1637-inspect-dyn.ts": 2934, + "1638-inspect-cjs.cjs": 3133, + "1639-versions-openssl-probe.ts": 2209, + "1640-fd-read-decode.ts": 3309, + "1641-string-search.ts": 2951, + "1642-object-fromentries-rows.ts": 3231, + "1643-metadata-dyn-return.cjs": 3375, + "1644-ee-basics.ts": 3158, + "1645-ee-extends.ts": 2448, + "1646-ee-once-remove.ts": 2581, + "1647-ee-meta-events.ts": 2563, + "1648-ee-error-event.ts": 2097, + "1649-ee-names-counts.ts": 2941, + "1650-ee-prepend.ts": 3190, + "1651-ee-max-listeners.ts": 2691, + "1652-ee-snapshot.ts": 2882, + "1653-ee-cjs.cjs": 2645, + "1654-ee-namespace.ts": 2314, + "1655-spawnsync-neutral.ts": 4787, + "1656-execsync-neutral.ts": 3015, + "1657-spawn-async-neutral.ts": 3128, + "1660-buffer-read-write-num.ts": 2511, + "1661-buffer-encodings-full.ts": 3466, + "1662-string-decoder-encodings.ts": 3207, + "1663-buffer-compare-search-fill.ts": 3063, + "1664-dyn-fn-boundary.cjs": 2280, + "1665-dyn-fn-mustcall/main.cjs": 2798, + "1666-dyn-fn-identity.ts": 3303, + "1667-dyn-fn-not-callable.cjs": 2431, + "1668-dyn-fn-throws.cjs": 3052, + "1669-symbol-identity.ts": 3194, + "1670-symbol-registry.ts": 2198, + "1671-symbol-typeof.ts": 2786, + "1672-symbol-containers.ts": 2209, + "1673-symbol-cjs.cjs": 2979, + "1674-symbol-inspect.ts": 2795, + "1676-func-array-surface.ts": 2945, + "1677-emitter-listeners.ts": 4548, + "1678-emitter-dyn-listeners.cjs": 3185, + "1679-console-dyn.js": 2910, + "1680-assert-bytes.ts": 3154, + "1681-assert-funcs.ts": 1828, + "1685-stream-readable-basics.ts": 2976, + "1686-stream-readable-paused.ts": 2831, + "1687-stream-readable-flow-control.ts": 2863, + "1688-stream-writable-basics.ts": 2245, + "1689-stream-writable-async-drain.ts": 1562, + "1690-stream-duplex.ts": 3124, + "1691-stream-transform.ts": 2070, + "1692-stream-pipe.ts": 2661, + "1693-stream-pipe-backpressure.ts": 2944, + "1694-stream-destroy.ts": 2243, + "1695-stream-props.ts": 2801, + "1696-stream-read-inside-read.ts": 2398, + "1697-stream-tick-vs-timer.ts": 2703, + "1698-stream-uncaught-error.ts": 2045, + "1699-stream-callback-shapes.ts": 2523, + "1700-mustcall-common/main.cjs": 3695, + "1701-mustcall-exit-report/main.cjs": 4202, + "1702-dyn-proto-dispatch.cjs": 3277, + "1703-arguments-rest-props.cjs": 2983, + "1710-cjs-export-class/main.js": 3030, + "1711-cjs-export-single-values/main.js": 2594, + "1712-field-incdec.ts": 1845, + "1713-js-dyn-fields.js": 2654, + "1720-assert-throws-shape.ts": 2898, + "1721-assert-throws-regex-class.ts": 3751, + "1722-assert-rejects.ts": 2848, + "1723-assert-does-not-reject.ts": 3358, + "1724-assert-iferror.ts": 1705, + "1725-assert-symbols.ts": 2141, + "1726-promise-with-resolvers.ts": 2575, + "1727-assert-throws-shape-exit.ts": 2905, + "1730-countdown-symbol-keys/main.js": 2273, + "1731-symbol-field-shapes.cjs": 2895, + "1732-symbol-field-cross-module/main.js": 2678, + "1740-stream-extends-readable.ts": 2983, + "1741-stream-extends-writable.ts": 2337, + "1742-stream-extends-duplex-transform.ts": 3417, + "1743-stream-extends-vt-dispatch.ts": 2520, + "1744-stream-set-encoding.ts": 3582, + "1745-stream-encoding-js.cjs": 2993, + "1746-stream-for-await.ts": 4666, + "1747-stream-for-await-js.cjs": 3552, + "1750-http-agent-options.ts": 2667, + "1751-options-record-stance.ts": 3044, + "1760-surplus-args-drop.cjs": 2775, + "1761-emitter-special-event-names.cjs": 2427, + "1770-assert-dyn-strict.ts": 3393, + "1771-assert-dyn-deep.ts": 3639, + "1772-assert-dyn-js.cjs": 2854, + "1773-assert-dyn-exit.ts": 2368, + "1780-http-res-surface.ts": 2318, + "1781-http-server-shapes.cjs": 3339, + "1790-computed-key-folds.ts": 2833, + "1791-searchparams-core.ts": 2212, + "1792-searchparams-encoding.ts": 2305, + "1793-searchparams-iteration.ts": 3412, + "1794-searchparams-url-live.ts": 2492, + "1795-dyn-handle-request.cjs": 3337, + "1796-dyn-handle-body.cjs": 3287, + "1797-dyn-handle-socket.cjs": 2497, + "1798-dyn-handle-typed-box.ts": 2870, + "1800-immediate-basics.ts": 2802, + "1801-immediate-handle.ts": 2655, + "1802-immediate-unref-exit.ts": 2450, + "1803-timeout-refresh.ts": 2797, + "1804-timers-module.ts": 2773, + "1805-timer-callback-args.ts": 2736, + "1806-timer-delay-trunc.ts": 2060, + "1810-stream-options-const-record.ts": 2542, + "1811-stream-option-value-callbacks.cjs": 2462, + "1812-stream-super-options-forwarding.cjs": 3383, + "1813-stream-finished.ts": 2720, + "1814-stream-pipeline.cjs": 3409, + "1815-stream-state-reads.cjs": 2880, + "1820-static-block-basics.ts": 1635, + "1821-static-block-order.ts": 2551, + "1822-static-block-js.js": 2387, + "1823-static-instance-method-names.ts": 1936, + "1824-for-of-destructuring-defaults.ts": 2145, + "1825-exhaustive-typeof-switch.ts": 2973, + "1826-settimeout-arguments-callback.js": 2489, + "1830-enum-numeric-basics.ts": 2207, + "1831-enum-string-const-reverse.ts": 1943, + "1832-enum-modules/main.ts": 2350, + "1835-var-basics.ts": 2804, + "1836-var-loop-capture.ts": 3197, + "1837-var-undefined-hoisting.ts": 2836, + "1838-var-modules/main.ts": 2550, + "1839-var-js/main.cjs": 2492, + "1840-jsdoc-import-type-only/main.js": 1919, + "1850-overload-basics.ts": 2640, + "1851-overload-return-narrowing.ts": 1736, + "1852-overload-class-members.ts": 2774, + "1853-overload-modules/main.ts": 2509, + "1854-ambient-declare-fn.ts": 2603, + "1855-ambient-declare-fn-uncaught.ts": 1999, + "1870-unit-type-values.ts": 2905, + "1871-empty-array-never.ts": 2516, + "1872-template-tostring-composite.ts": 1682, + "1880-json-declared-field-order.ts": 3529, + "1881-default-anon/main.ts": 2084, + "1882-default-cjs-interop/main.ts": 2606, + "1883-default-exports/main.ts": 2612, + "1890-ns-imports/main.ts": 2704, + "1891-ns-reexport/main.ts": 2129, + "1940-class-values-basics.ts": 2668, + "1941-class-values-registry.ts": 2870, + "1942-class-expressions.ts": 2682, + "1943-class-statics-expanded.ts": 2734, + "1944-class-values-modules/main.ts": 2146, + "1950-generic-fn-values.ts": 2755, + "1951-generic-classes-basics.ts": 3235, + "1952-generic-class-statics-values.ts": 2233, + "1953-generic-class-hierarchy.ts": 2990, + "1954-generic-modules/main.ts": 2377, + "1960-namespace-basics.ts": 2728, + "1961-namespace-nested.ts": 2156, + "1962-namespace-classes.ts": 2835, + "1963-namespace-aliases.ts": 2550, + "1964-namespace-type-only.ts": 2471, + "1965-namespace-ambient.ts": 2707, + "1966-namespace-modules/main.ts": 2766, + "1967-namespace-alias-typeonly.ts": 2273, + "1968-namespace-import-eq-snapshot.ts": 2594, + "1970-decorators-basics.ts": 2916, + "1971-decorators-rebinding.ts": 2369, + "1972-decorators-throwing.ts": 2667, + "1973-decorators-ambient.ts": 2709, + "1980-primitive-proto-statics.ts": 3013, + "1981-date-utc.ts": 2644, + "1982-freeze-resolve-passthrough.ts": 3023, + "1983-array-tuple-surfaces.ts": 3232, + "1990-labels-basics.ts": 2990, + "1991-for-in-loops.ts": 3611, + "1992-small-syntax.ts": 3054, + "200-strings.ts": 1903, + "2000-generic-methods-basic.ts": 2832, + "2001-generic-methods-generic-class.ts": 2741, + "2002-generic-methods-inheritance.ts": 2972, + "2003-generic-methods-object-literal.ts": 3023, + "2004-generic-methods-statics.ts": 2292, + "201-templates.ts": 2534, + "2010-generators-basics.ts": 1525, + "2011-generators-forof.ts": 2217, + "2012-generators-return-throw.ts": 3262, + "2013-generators-sent-values.ts": 2117, + "2014-generators-values.ts": 2991, + "2015-generators-yieldstar.ts": 2892, + "2016-generators-rc-stress.ts": 2942, + "2017-generators-async.ts": 1965, + "2018-generators-uncaught.ts": 2403, + "2019-generators-loops.ts": 2116, + "2020-generic-value-bindings.ts": 3355, + "2021-generic-value-binding-modules/main.ts": 2720, + "2022-width-index-capture.ts": 2258, + "2023-width-readonly.ts": 2519, + "2024-width-array-elems.ts": 2776, + "2025-width-union-compose.ts": 3243, + "2026-width-spread.ts": 1625, + "2030-width-nested.ts": 3160, + "2031-width-tuples.ts": 2019, + "2032-cjs-export-assigned-class-expression/main.cjs": 2230, + "2033-property-assigned-class-extends.cjs": 2058, + "2035-ternary-array-retag.cjs": 2602, + "2036-evolving-array-decl.cjs": 2125, + "2037-fn-decl-hoisting.cjs": 1595, + "2038-evolving-array-js.cjs": 2965, + "2040-any-bindings.ts": 3143, + "2040-mixin-heritage.ts": 3206, + "2041-any-params-returns.ts": 2996, + "2041-mixin-values.ts": 3090, + "2042-any-flow-loops.ts": 3104, + "2042-mixin-modules/main.ts": 2762, + "2043-any-dom-values.ts": 3345, + "2043-mixin-rc-stress.ts": 2605, + "2044-vtable-sibling-slots.ts": 3123, + "2045-objlit-accessors-basic.ts": 2774, + "2045-parameter-properties.ts": 3393, + "2046-abstract-classes.ts": 2184, + "2046-objlit-accessors-effects.ts": 2948, + "2047-objlit-accessors-shapes.ts": 1767, + "2047-optional-class-fields.ts": 2566, + "2050-dynamic-import-own-module/main.ts": 2384, + "2051-dynamic-import-then/main.ts": 2679, + "2052-dynamic-import-self.ts": 2722, + "2053-typeof-static-fold.ts": 2817, + "2054-destructuring-island-source.ts": 2995, + "2060-empty-tuple.ts": 2635, + "2070-computed-key-folds.ts": 2872, + "2071-integer-key-enumeration-order.ts": 3125, + "2072-expando-function-members.ts": 2341, + "2073-destructuring-assignment.ts": 2794, + "2074-island-destructuring.ts": 2364, + "2075-index-signature-runtime-keys.ts": 2866, + "2080-destructuring-defaults.ts": 1887, + "2081-destructuring-rest.ts": 3136, + "2082-destructuring-assignment.ts": 2594, + "2085-destructuring-heads-rest-params.ts": 2973, + "2087-destructuring-for-heads.ts": 2753, + "2090-index-signature-number-keys.ts": 2175, + "2091-index-signature-string-intersection.ts": 2763, + "2092-package-imports/main.ts": 2350, + "2093-timers-promises.ts": 2872, + "2094-diagnostics-channel.ts": 2689, + "2095-js-catch-unknown.js": 2633, + "2096-os-type.ts": 1968, + "2097-js-evolving-globals.js": 2880, + "210-string-methods.ts": 2798, + "2100-stream-default-hwm.ts": 2089, + "2101-dyn-param-defaults.ts": 2260, + "2102-empty-pattern-decls.ts": 1677, + "2105-computed-key-static-folds.ts": 2815, + "2106-comma-expressions.ts": 2657, + "211-string-unicode.ts": 2741, + "2110-top-object-types.ts": 2919, + "2111-json-stringify-unknown.ts": 2401, + "2112-array-at-findlast.ts": 1741, + "2113-string-index-methods.js": 1867, + "212-string-aliasing-append.ts": 2513, + "2120-package-self-import/main.ts": 2334, + "2121-esm-cycle-inert-backedge/main.ts": 2266, + "2123-ambient-import-crash/main.ts": 2890, + "2124-imports-field-wildcard/main.ts": 2153, + "2140-uri-component-codecs.ts": 2446, + "2160-dc-tracing-channel.cjs": 2881, + "2161-js-object-literal-identity.cjs": 2928, + "2162-js-dyn-destructure.cjs": 2896, + "2163-js-selfref-const.cjs": 2717, + "2164-js-then-dyn-handler.cjs": 2572, + "2165-js-throw-dyn.cjs": 2672, + "2166-cjs-getter-this/main.cjs": 2899, + "2170-island-array-exits.ts": 2722, + "2171-island-json-stringify.ts": 2071, + "2172-island-regexp-boundary.ts": 2828, + "2190-new-object-and-string-wrappers.ts": 2625, + "2191-uri-encoders.ts": 2849, + "2192-object-default-tostring.ts": 2537, + "2193-discarded-stdlib-reads.ts": 2594, + "2194-ambient-undef-chains.ts": 1718, + "2195-require-missing-package/main.mjs": 2757, + "2196-island-computed-key-chain.ts": 2575, + "2210-dyn-promise-crossing.cjs": 2319, + "2211-dc-trace-promise.cjs": 1935, + "2212-unhandled-rejection-listener.cjs": 2879, + "2213-async-local-storage.cjs": 2883, + "2214-dc-bind-store.cjs": 2240, + "2215-process-emit-warning-exit.cjs": 3330, + "2240-width-class-into-record.ts": 2571, + "2241-width-record-into-class.ts": 2500, + "2242-width-statics-into-record.ts": 1787, + "2243-width-assert-satisfies-shapes.ts": 2738, + "2250-tagged-templates.ts": 2408, + "2252-class-iterators.ts": 3611, + "2253-union-coercions.ts": 2810, + "2260-http2-constants.cjs": 2702, + "2280-builtin-namespace-destructure.cjs": 2594, + "2281-domexception-atob-btoa.cjs": 2615, + "2282-queue-microtask.cjs": 2780, + "2283-structured-clone.cjs": 3105, + "2284-regexp-constructor.cjs": 2648, + "2285-iferror-dyn.cjs": 2717, + "2286-dyn-object-walks.cjs": 3110, + "2300-dyn-record-spread-and-keyed-access.cjs": 2464, + "2301-cjs-export-table-dom-attach.cjs": 2425, + "2310-process-next-tick.ts": 2609, + "2311-next-tick-js-callbacks.js": 2450, + "2312-stream-underscore-assign.ts": 2473, + "2313-stream-underscore-assign-js.cjs": 3017, + "2314-process-introspection.ts": 3479, + "2320-await-unit.ts": 2334, + "2321-emitter-static-setmax.cjs": 2697, + "2322-dyn-array-sort.cjs": 3014, + "2323-timer-callback-returns.ts": 3852, + "2330-tls-server-runtime-options.cjs": 2565, + "2331-tls-server-options-typed.ts": 1980, + "2350-nan-global.ts": 3180, + "2351-async-methods.ts": 2138, + "2352-void-coercions.ts": 2843, + "2353-decorators-member-ambient.ts": 3089, + "2354-decorators-expression-ambient.ts": 1841, + "2360-tuple-to-array.ts": 2335, + "2361-assign-index-record.ts": 3492, + "2362-execsync-inherit.ts": 2484, + "2363-nullish-retag.ts": 2875, + "2364-in-runtime-key.ts": 2156, + "2365-dyn-into-island.ts": 2339, + "2366-string-well-formed.ts": 2760, + "2367-regexp-escape.ts": 2791, + "2368-set-methods.ts": 3237, + "2369-promise-try.ts": 2605, + "2370-group-by.ts": 3569, + "2371-iterator-helpers.ts": 3561, + "2380-buffer-module-named-import.ts": 2746, + "2381-builtin-default-imports.js": 2945, + "2382-cycle-two-decl/main.ts": 2560, + "2383-cycle-assertdoc/main.js": 3011, + "2384-cycle-mixed-bindings/main.ts": 2477, + "2385-builtin-reexport-facade/main.ts": 2948, + "2386-string-to-chars.ts": 2475, + "2387-tonumber-argv.ts": 3071, + "2388-tonumber-grammar-zoo.ts": 3157, + "2389-tonumber-unary-plus.ts": 2176, + "2390-dot-requires/main.cjs": 2329, + "2391-default-builtin-imports/main.ts": 2387, + "2392-block-guard-alias-scope.ts": 2363, + "2393-loop-exit-guard-narrow.ts": 2936, + "2394-loop-narrow-containment.ts": 2244, + "2395-while-cond-guard.ts": 2443, + "2396-born-narrowed-decl.ts": 2276, + "2397-branch-kill-merge.ts": 2681, + "2398-switch-arm-kill.ts": 3027, + "2399-reassign-kill-polarity.ts": 2662, + "240-stdout-write.ts": 1918, + "2400-kill-return-edge.ts": 2414, + "2401-kill-break-staging.ts": 2162, + "2402-labeled-break-kill.ts": 2493, + "2403-kill-continue-backedge.ts": 2457, + "2404-kill-throw-catch.ts": 1792, + "2405-sibling-arm-narrow.ts": 1781, + "2406-switch-clause-sibling-narrow.ts": 2641, + "2407-infinite-loop-seal.ts": 2308, + "2408-loop-terminality-reopen.ts": 2756, + "2409-loop-body-return-not-terminal.ts": 2759, + "2410-stacked-cases-terminality.ts": 2830, + "2411-exhaustive-switch-terminality.ts": 2112, + "2412-dowhile-guard-trailing-test.ts": 2230, + "2413-dowhile-kill-renarrow.ts": 2630, + "2414-dowhile-continue-kill.ts": 2624, + "2415-dowhile-break-trailing-test.ts": 2524, + "2416-spread-ternary-positions.ts": 2956, + "2417-ternary-local-inference.ts": 2300, + "2418-wrapped-ternary-arms.ts": 2768, + "2419-selector-ternary-union.ts": 2727, + "2420-nullish-null-identity.ts": 2533, + "2421-float-lane-inference.ts": 2620, + "2422-ieee-div-rem-corners.ts": 2629, + "2423-param-null-reassign.ts": 2622, + "2424-ternary-miss-first-narrowing.ts": 2228, + "2425-elseif-head-exit-narrow.ts": 2186, + "2426-default-snapshot-mutable/main.ts": 2520, + "2427-perf-hooks-now.ts": 2346, + "2428-field-redeclare-inherited.ts": 2882, + "2429-destructure-class-instance.ts": 2852, + "2430-empty-literal-unknown-field.js": 2190, + "2431-primitive-ctor-values.ts": 2149, + "2432-generic-member-fields-async.ts": 3225, + "2433-as-const-command-tables.ts": 3139, + "2434-deferred-init-fields.ts": 2789, + "2435-loose-same-kind-equality.ts": 2652, + "2440-console-inspect-args.ts": 3314, + "2441-console-process-argv.ts": 2095, + "2442-union-literal-arm-widening.ts": 2062, + "2443-union-literal-shadow-narrowing.ts": 2856, + "2444-union-literal-reducer-spread.ts": 2705, + "2445-math-minmax-nary.ts": 2093, + "2446-performance-global.ts": 2484, + "2447-island-boundary-slots/main.ts": 3456, + "2448-entries-null-arms-regex-arrays.ts": 2911, + "2450-private-instance-methods.ts": 2310, + "2451-private-fields.ts": 2058, + "2452-private-statics.ts": 2844, + "2453-private-accessors.ts": 2851, + "2454-private-generator-methods.ts": 2328, + "2455-private-brand-checks.ts": 2840, + "2456-private-async-methods.ts": 2932, + "2457-private-members.js": 2832, + "2460-qs-parse-grammar.ts": 2844, + "2461-qs-parse-options.ts": 2944, + "2462-qs-stringify.ts": 3219, + "2463-qs-escape-unescape.ts": 2133, + "2464-qs-require-forms.cjs": 2362, + "2470-mockable-module-shape.js": 3020, + "2471-record-keyed-write-hasown.js": 2921, + "2472-string-regexp-union.ts": 1528, + "2473-option-table-widths.js": 2792, + "2474-island-literal-forms.ts": 2730, + "2475-variadic-wrapper-island.js": 2962, + "2476-map-regex-values.ts": 1895, + "2480-recursive-record-tree.ts": 2781, + "2481-mutual-recursive-records.ts": 2829, + "2482-recursive-union-tree.ts": 2626, + "2483-recursive-record-cycles.ts": 2385, + "2484-json-stringify-circular.ts": 1936, + "2485-inspect-circular-refs.ts": 3139, + "2486-recursive-record-boundaries.ts": 3118, + "2487-recursive-deep-equal.ts": 2998, + "2488-ast-walker.ts": 3274, + "2490-find-miss-null-compare.ts": 2608, + "2491-strict-unit-compare-no-arm.ts": 2376, + "2492-loose-null-compare-unions.ts": 2805, + "2493-switch-unit-cases.ts": 2280, + "2494-no-arm-compare-effects.ts": 2159, + "2500-net-autosel-timeout.ts": 2195, + "2510-dyn-evolving-array-map.ts": 1961, + "2511-dyn-evolving-array-filter-foreach.ts": 2859, + "2512-dyn-evolving-array-mixed-push.ts": 1607, + "2520-private-statics-class-name-calls.ts": 2420, + "2521-private-statics-class-expression.ts": 1848, + "2522-private-statics-decorated.ts": 3008, + "2523-private-statics-aliased-class.ts": 2743, + "2530-object-destructuring-decl.ts": 2036, + "2531-array-tuple-destructuring-decl.ts": 2908, + "2532-param-destructuring-options.ts": 2917, + "2533-forof-destructuring.ts": 2821, + "2534-object-rest-decl.ts": 2914, + "2535-destructuring-assign-basics.ts": 2888, + "2536-destructuring-assign-nested.ts": 2697, + "2537-destructuring-assign-member-targets.ts": 1747, + "2538-destructuring-assign-class-source.ts": 2594, + "2539-class-instance-rest.ts": 2144, + "2540-accessor-destructuring-defaults.ts": 2790, + "2541-destructuring-eval-order.ts": 2901, + "2550-generics-keyof-pick.ts": 2724, + "2551-generics-value-aliases.ts": 2899, + "2552-generics-iface-methods.ts": 2924, + "2553-generics-signature-bindings.ts": 1690, + "2554-generics-frontier-mix.ts": 2607, + "2555-generics-keyof-writes.ts": 2074, + "2556-crypto-introspection.ts": 2165, + "2556-width-hybrid-shapes.ts": 1904, + "2557-tls-ca-store.ts": 3159, + "2557-width-field-lifts.ts": 3231, + "2558-index-signature-func-values.ts": 2869, + "2558-rejection-events.cjs": 1923, + "2559-index-signature-container-values.ts": 2319, + "2560-arraybuffer-dataview-set.ts": 3376, + "2561-object-is.ts": 3499, + "2562-intl-numberformat-en-us.ts": 2371, + "2563-stream-promises-pipeline.ts": 3059, + "2564-stream-promises-finished.ts": 1663, + "2565-stream-promises-js.cjs": 2464, + "2566-promise-reject-dyn-reason.js": 2041, + "2567-rest-spread-forward.js": 3238, + "2568-rest-spread-forward-dynamic.js": 2074, + "2569-upcast-identity.ts": 2471, + "2570-buffer-arg-validation.cjs": 4288, + "2571-searchparams-arg-validation.cjs": 2294, + "2572-readable-emitted-readable-flag.cjs": 2792, + "2573-fs-url-arg-ladders.cjs": 3144, + "2574-emitter-max-listeners-ladders.cjs": 2768, + "2575-string-destructuring-decl.ts": 3093, + "2576-string-destructuring-assign.ts": 1948, + "2577-builtin-global-destructuring.js": 1471, + "2578-jsval-into-unknown-rows.ts": 2895, + "2579-jsval-object-param-crossing.js": 2920, + "2580-jsval-routed-keyed-ops.js": 2793, + "2581-jsval-routed-calls.js": 2527, + "2582-jsval-object-statics.js": 3114, + "2582-jsval-routed-keyed-ops.js": 3012, + "2583-dyn-nullish-coalesce.js": 2872, + "2583-jsval-routed-calls.js": 3060, + "2584-jsval-object-statics.js": 3017, + "2584-union-dyn-collapse.ts": 3110, + "2585-dyn-nullish-coalesce.js": 3233, + "2585-unknown-array.ts": 3147, + "2586-object-assign-spread.js": 3063, + "2587-array-entries-forof.ts": 2868, + "2588-array-entries-chains.ts": 2948, + "2589-object-create-null.cjs": 2175, + "2590-object-create-dynamic.js": 2548, + "2591-ambient-generic-traps.ts": 2668, + "2592-ambient-trap-uncaught.ts": 2071, + "2593-generic-inert-bindings.ts": 2582, + "2594-nullish-generic-bindings.ts": 2649, + "2595-fs-arg-ladders.cjs": 3450, + "2596-net-arg-ladders.cjs": 3163, + "2597-dgram-send-ladders.cjs": 3471, + "2598-tls-arg-ladders.cjs": 2644, + "2599-stream-arg-ladders.cjs": 2952, + "2600-dyn-keyed-write-harness.js": 3162, + "2601-dyn-keyed-write-ops.js": 2780, + "2602-dyn-array-destructure.js": 2123, + "2603-island-keyed-write-dyn.js": 2776, + "2604-cycle-classes-mutual/main.ts": 2653, + "2605-cycle-three-module/main.ts": 2386, + "2606-dynamic-import-cycle/main.ts": 2580, + "2608-regex-named-groups.ts": 3189, + "2609-regex-named-replace.ts": 2460, + "2610-regex-named-matchall.ts": 1815, + "2611-regex-named-groups-js.cjs": 3151, + "2613-for-init-uninitialized-let.ts": 2759, + "2614-trap-binding-later-writes.ts": 1833, + "2615-nullish-field-record-binding.ts": 2522, + "2616-js-collect-probe-defers.js": 2932, + "2617-enum-static-field-import/main.ts": 2674, + "2618-ee-emit-override.ts": 2416, + "2619-ee-override-chain.ts": 2759, + "2620-ee-override-once-order.ts": 2863, + "2621-ee-override-error-throw.ts": 2669, + "2622-ee-override-filter.ts": 2972, + "2623-ee-job-queue.ts": 2457, + "2624-ee-override-js.cjs": 2851, + "2625-bytes-views.ts": 1866, + "2626-stream-event-names.ts": 3082, + "2627-stream-ticks-are-nextticks.ts": 2115, + "2628-stream-push-encodings.cjs": 2780, + "2629-stream-consumers.ts": 3333, + "2630-stream-consumers-errors.ts": 2597, + "2631-create-require/main.ts": 3215, + "2632-dyn-jsval-iterate.js": 3094, + "2633-island-promise-crossing.js": 2715, + "2634-stream-pipeline-arg-ladders.cjs": 2970, + "2635-trap-binding-unmappable-written.ts": 2644, + "2636-trap-binding-ambient-rooted-rewrite.ts": 2711, + "2637-create-require-bare/main.ts": 2926, + "2638-http-dyn-res-compat.cjs": 3551, + "2639-http-dyn-req-pause.cjs": 2114, + "2640-net-dyn-socket-compat.cjs": 3221, + "2641-http-agent-surface.cjs": 3393, + "2642-http-agent-maxsockets.cjs": 2445, + "2643-or-default-retag.ts": 2951, + "2644-http-client-url-argument.ts": 3003, + "2645-https-client-url-argument.ts": 1965, + "2646-top-level-await.ts": 1994, + "2647-top-level-await-modules/main.ts": 2883, + "2648-top-level-await-rejection.ts": 2548, + "2649-top-level-await-pending.ts": 2420, + "2650-top-level-await-self-import.ts": 2738, + "2651-top-level-await-pending-unhandled.ts": 1959, + "2652-top-level-await-dynamic/main.ts": 1976, + "2653-top-level-await-rejection-stops-loop.ts": 2530, + "2654-top-level-await-unrelated-rejection.ts": 2557, + "2655-top-level-await-cycle/main.ts": 2575, + "2656-top-level-await-cycle-order/main.ts": 2788, + "2657-top-level-await-cycle-dynamic/main.ts": 1945, + "2658-top-level-await-sync-completion/main.ts": 2486, + "2659-top-level-await-dynamic-cycle/main.ts": 2311, + "2660-top-level-await-cycle-rejection/main.ts": 1648, + "2661-top-level-await-dynamic-runtime-root/main.ts": 2615, + "2662-top-level-await-cycle-external-wait/main.ts": 2307, + "2663-top-level-await-dependency-errors/main.ts": 2145, + "2664-top-level-await-same-checkpoint-rejection.ts": 2652, + "2665-top-level-await-unhandled-listener-liveness.ts": 3003, + "2666-array-to-sorted.ts": 5347, + "2668-stored-number-array-iterator.ts": 2840, + "2669-array-copying-methods.ts": 2792, + "2670-uint8array-copy-iterate.ts": 2664, + "2671-array-copying-js.cjs": 2591, + "2672-http-request-response-callback.ts": 2953, + "2673-top-level-await-implicit-module.ts": 1743, + "2674-top-level-for-await-implicit-module.ts": 2697, + "2675-create-require-nested-esm.js": 2199, + "2675-process-self-reexec.ts": 2588, + "2676-indexed-read-strict-equality.ts": 2188, + "2676-record-clone-overrides.ts": 2426, + "2676-top-level-await-ambiguous/main.ts": 2482, + "2677-runtime-optional-closure.ts": 3477, + "2677-top-level-await-module-scope/main.ts": 2623, + "2678-date-instances.ts": 3208, + "2678-large-string-sparse-index.ts": 2981, + "2678-util-parseargs.ts": 5281, + "2679-util-parseargs-cjs.cjs": 3377, + "2680-util-parseargs-default.ts": 2722, + "2681-util-parseargs-dynamic.js": 1944, + "2682-fs-rename.ts": 3375, + "2683-filter-truthy-predicate.ts": 2838, + "2683-fs-rename-js.cjs": 1913, + "2684-filter-no-predicate-dyn.cjs": 2576, + "2684-fs-rename-abort.ts": 2742, + "2685-array-unshift-reverse.ts": 2654, + "2685-fs-write-sync.ts": 2517, + "2686-fs-file-handle.ts": 3648, + "2687-fsp-write-file-options.ts": 2384, + "2687-process-write-args.ts": 2846, + "2688-fs-stats-disk-fields.ts": 2938, + "2689-http-server-timeout-properties.ts": 3060, + "2690-https-server-timeout-option.ts": 2700, + "2691-retained-lowering-record-order.ts": 4234, + "2692-inline-record-assert-index.ts": 2826, + "2692-string-accumulation.ts": 2691, + "2693-math-constants.ts": 2761, + "2700-array-sort-complexity.ts": 2705, + "2700-http-static-trailers.ts": 2446, + "2700-wasi-core.ts": 2208, + "2701-array-sort-snapshot.ts": 2717, + "2701-http-static-trailer-wire.ts": 2689, + "2701-import-meta/main.mjs": 2846, + "2702-http-static-trailer-end.ts": 2522, + "2702-type-import-link-static/main.ts": 1984, + "2702-uint8array-to-sorted.ts": 2225, + "2703-array-sparse-sort.ts": 5044, + "2703-type-import-link-static-reexport/main.ts": 2359, + "2704-array-sparse-to-sorted.ts": 4461, + "2704-type-import-link-static-success/main.ts": 2324, + "2705-array-sparse-sort-append.ts": 5020, + "2705-type-import-link-dynamic/main.ts": 2074, + "2706-array-search-missing-needle.ts": 1941, + "2706-type-import-link-dynamic-success/main.ts": 2411, + "2707-array-search-huge-sparse.ts": 45551, + "2707-type-import-link-static-default-reexport/main.ts": 2522, + "2708-type-import-link-dynamic/main.ts": 2609, + "2720-array-read-parity.ts": 1979, + "2721-array-nested-missing-receiver.ts": 2483, + "2750-array-sparse-foundation.ts": 2217, + "2751-buffer-concat-sparse-list.ts": 2792, + "2752-array-optional-stores.ts": 2339, + "2753-array-optional-method-values.ts": 2060, + "2754-array-property-undefined.ts": 2275, + "2755-array-optional-literal-forwarding.ts": 2382, + "2780-array-parity-composition.ts": 6446, + "2781-array-missing-value-escape.ts": 1639, + "2782-array-sparse-callbacks.ts": 3365, + "2783-array-defaults-rest.ts": 2775, + "2784-array-reduce-missing-result.ts": 2916, + "2785-array-missing-destructuring.ts": 2952, + "2786-array-sparse-serialization.ts": 3296, + "2787-array-missing-string-arithmetic.ts": 2457, + "2788-array-missing-builtin-conversions.ts": 2610, + "2789-array-missing-optional-tostring.ts": 2734, + "2790-dynamic-import-self-name/main.ts": 2631, + "2791-record-optional-keys.ts": 1771, + "2792-record-optional-spread-entries.ts": 2836, + "2793-union-conversion-identity-capture.ts": 1991, + "2794-array-generic-callback-values.ts": 2454, + "2795-array-optional-typedarray-source.ts": 2778, + "2796-array-sparse-class-value-instanceof.ts": 1902, + "2800-array-expression-consumers.ts": 2537, + "2801-array-switch-consumers.ts": 2609, + "2820-array-missing-method-receivers.ts": 1866, + "2821-array-optional-numeric-comparisons.ts": 2322, + "2830-cjs-require-self-name/main.cjs": 1845, + "2840-finally-completions.ts": 2496, + "2841-using-sync.ts": 2927, + "2842-await-using.ts": 2618, + "2843-using-suppressed-error.ts": 2318, + "2844-node-disposable-resources.ts": 2824, + "2845-for-using-of.ts": 2486, + "2846-generator-using.ts": 2761, + "2850-async-generators-protocol.ts": 3258, + "2851-async-generators-values.ts": 2768, + "2852-timers-promises-interval.ts": 2398, + "2854-leading-bom-literals.ts": 1935, + "2855-searchparams-sort-complexity.ts": 2792, + "2856-dynamic-any-local-operators.ts": 2781, + "2857-branded-primitives.ts": 2351, + "2858-import-meta-resolve/main.mjs": 1967, + "2859-import-meta-resolve-dynamic/main.mjs": 1446, + "2860-require-resolve/main.cjs": 2029, + "2861-readable-iterator-close.ts": 3028, + "2862-web-readable-async-iteration.ts": 3505, + "2863-class-async-iterator.ts": 2866, + "2864-array-class-method-receivers.ts": 2760, + "2865-cjs-process-alias.cjs": 2491, + "2866-dyn-switch.ts": 1865, + "2867-array-shift-length.js": 1558, + "2868-empty-record-promise-presence.js": 2022, + "2869-nullish-mixed-lazy.ts": 2676, + "2870-and-dropped-truthy-arm.ts": 2329, + "2871-optional-promise-to-unknown.ts": 2191, + "2872-unobserved-dynamic-event.ts": 2513, + "2873-optional-receiver-loop-lifetime.js": 1923, + "2874-nullable-callback-field-cycle.js": 2614, + "2875-evolving-let-read-before-write.js": 2456, + "2876-class-unknown-roundtrip.ts": 2982, + "2877-child-unknown-roundtrip.ts": 2124, + "2878-class-private-unknown.cjs": 2900, + "2880-cjs-module-graph/main.cjs": 2229, + "2890-crypto-static-utility.ts": 3535, + "2891-json-record-key-escapes.ts": 3128, + "2892-windows-console-unicode.ts": 2483, + "2893-child-stdin-duplex.ts": 3150, + "2894-child-stdin-backpressure.ts": 2319, + "2895-child-stdin-write-after-end.ts": 3184, + "2896-child-stdin-write-after-finish.ts": 2909, + "2897-child-stdin-destroy.ts": 3007, + "2898-child-stdin-spawn-failure.ts": 2417, + "2899-nested-mutual-recursion.ts": 2782, + "2900-float64array-static.ts": 2797, + "2900-void-conditional-arrow.ts": 2455, + "2901-bigint-core.ts": 2012, + "2902-bigint-bytes.ts": 2175, + "2903-bigint-storage.ts": 2677, + "2904-bigint-errors.ts": 2992, + "2905-bigint-edges.ts": 2250, + "2906-bigint-wasi-width.ts": 2455, + "2910-overloaded-callable-alias.ts": 2480, + "2911-execfile-callback.ts": 2820, + "2912-execfile-callback-options.ts": 2673, + "2912-promisify-fs-readfile.ts": 1599, + "2913-builtin-callable-alias.ts": 2823, + "2914-fixed-tuple-call-spread.ts": 2909, + "2915-path-function-values.ts": 2957, + "2916-path-function-values-cjs.ts": 2512, + "2917-builtin-callable-widths.ts": 3024, + "2918-builtin-callable-widths-cjs.ts": 2656, + "2919-fs-function-values.ts": 3021, + "2920-fs-promises-function-values.ts": 2741, + "2921-zlib-callbacks.ts": 3153, + "2922-dyn-bitwise-not.cjs": 2708, + "2923-cjs-factory-export/main.cjs": 2093, + "2930-union-receiver-calls.ts": 2543, + "2931-union-dynamic-field-call.js": 2484, + "2932-create-require-program/main.ts": 2505, + "2933-static-dynamic-import/main.ts": 2593, + "2934-static-import-stored.ts": 2045, + "2935-module-namespace-values/main.ts": 2788, + "2936-static-loose-equality.ts": 3392, + "2937-bitwise-hot-loop.ts": 2487, + "2938-fs-sync-overloads.cjs": 1878, + "2939-child-shell-text.ts": 3433, + "2940-date-parse.ts": 2705, + "2940-fsp-realpath.ts": 2908, + "2941-fsp-lstat-identity.ts": 3091, + "2941-process-exit-code.ts": 2544, + "2942-fsp-readdir-dirent.ts": 3069, + "2942-process-exit-code-override.ts": 2534, + "2943-process-exit-code-invalid.ts": 2277, + "2944-process-exit-code-wrap.ts": 1815, + "2945-url-origin-username.ts": 2639, + "2946-child-fork-ipc/main.ts": 3716, + "2946-url-port-hash.ts": 1906, + "2947-set-readonly-seeds.ts": 2763, + "2948-child-fork-eof-callback/main.ts": 2163, + "2948-stdio-callback-record.ts": 2566, + "2949-child-fork-default/main.mjs": 3027, + "2949-url-password.ts": 1993, + "2950-fs-descriptor-publication.ts": 2687, + "2951-math-static-analytic.ts": 3185, + "2952-math-static-remaining.ts": 2865, + "2953-http-header-validation.ts": 2969, + "2954-http-outgoing-headers.ts": 3565, + "2955-http-static-state.ts": 2954, + "2956-http-static-informational.ts": 2194, + "2957-http-static-response-controls.ts": 3186, + "2961-emitter-computed-names.cjs": 1565, + "2962-emitter-computed-optional.ts": 2714, + "2963-child-fork-dispatch/main.ts": 3146, + "2964-indexed-compound.ts": 3331, + "2966-numeric-array-read-fusion.ts": 3033, + "2967-numeric-array-read-lifetime.ts": 2835, + "2968-numeric-array-borrow.ts": 2871, + "2969-scalar-record-results.ts": 2889, + "2970-constant-numeric-tables.ts": 3083, + "2971-constant-table-modules/main.ts": 2199, + "2972-http-static-distinct-snapshots.ts": 3234, + "2972-math-receiver-borrow.ts": 3625, + "2973-http-static-agent.ts": 2730, + "2973-integer-bitwise-arithmetic.ts": 2687, + "2974-array-search-from-index.ts": 104135, + "2974-http-static-module-values.ts": 2450, + "2974-numeric-remainder.ts": 3031, + "2975-bigint-default-radix.ts": 2379, + "2975-http-static-client-controls.ts": 2663, + "2976-http-static-incoming-state.ts": 2293, + "2976-json-stringify-no-arguments.js": 2688, + "2977-http-static-incoming-timeout.ts": 2143, + "2977-nested-array-binding-defaults.js": 2455, + "2978-http-static-client-timeout.ts": 2987, + "2978-regexp-optional-subject.js": 2083, + "2979-array-search-mixed-needles.js": 2924, + "2979-http-static-server-timeout.ts": 2502, + "2980-http-static-server-timeout-default.ts": 2655, + "2980-string-position-arguments.js": 2015, + "2981-http-static-events.ts": 2563, + "2981-string-optional-positions.ts": 2841, + "2982-http-static-close-all.ts": 1931, + "2982-string-position-coercion-order.js": 2986, + "2983-http-static-close-idle.ts": 2485, + "2984-http-static-close-upgrade.ts": 2815, + "2985-http-static-message-destroy.ts": 2511, + "2986-http-static-client-socket-finish.ts": 2889, + "2987-http-static-timeout-errors.ts": 2695, + "2988-http-static-client-abort.ts": 2770, + "2989-http-static-response-timeout-handled.ts": 2973, + "2990-http-static-request-timeout-handled.ts": 3045, + "2991-array-indexed-equality.ts": 3039, + "2992-stream-rows.ts": 1990, + "2993-fiber-stack-lifetimes.ts": 3353, + "2994-fromcharcode-scalar.ts": 2251, + "2995-math-hyperbolic.ts": 3028, + "2996-math-near-one.ts": 2750, + "2997-math-integer-float.ts": 2792, + "300-if-else.ts": 2615, + "3001-caught-typeof-object.js": 2565, + "3002-promise-then-two.ts": 3076, + "301-while.ts": 2690, + "302-for.ts": 2617, + "3020-string-last-index-position.ts": 2669, + "3021-buffer-union-narrow-callback.ts": 3133, + "3022-string-affix-positions.ts": 2471, + "3023-string-affix-position-coercion.js": 2793, + "3024-string-number-narrow-for-in.ts": 2773, + "3025-string-search-position-coercion.js": 2152, + "3026-array-last-index-of.js": 2967, + "3027-array-last-index-of-records.ts": 1994, + "3028-string-search-dynamic-needle.js": 2238, + "3029-string-search-union-needle.js": 2519, + "303-break-continue.ts": 2536, + "3030-array-search-no-arg.js": 2653, + "3031-array-relative-index-coercion.js": 3093, + "3031-string-last-index-search-value.js": 1619, + "3032-string-search-value.js": 2450, + "3033-string-search-needle-coercion.js": 2494, + "3034-arguments-with-parameters.js": 3025, + "3035-string-positioned-search-value.js": 3075, + "3036-string-object-search-value.js": 2233, + "3037-number-nullish-conversion.js": 2181, + "3038-number-scalar-unions.ts": 2410, + "3039-string-repeat-count.js": 2478, + "304-compound-incdec.ts": 2719, + "3040-string-prototype-call.js": 3243, + "3041-string-prototype-object-call.js": 2455, + "3042-string-padding-coercion.js": 3099, + "3043-string-split-arguments.js": 2355, + "3044-array-slice-splice-positions.js": 2214, + "3045-array-indexed-mutation.js": 3434, + "3046-array-indexed-ref-identity.ts": 2361, + "3047-object-prototype-tag.js": 3196, + "3048-object-own-prototype.ts": 3472, + "3049-array-flat-depth.ts": 1949, + "305-truthiness.ts": 2568, + "3050-array-splice-insert.ts": 3099, + "3051-array-join-default.ts": 1846, + "3052-array-construction.ts": 3399, + "3053-array-construction-js.js": 1676, + "3054-dynamic-abort-record.ts": 1731, + "3055-default-builtin-nodenext/main.ts": 2687, + "3056-default-builtin-bundler/main.ts": 2789, + "3057-default-builtin-nodenext-dynamic/main.ts": 2579, + "3058-optional-array-chain-join.ts": 2967, + "3059-arguments-property-names.ts": 2947, + "3061-concurrent-fiber-stacks.ts": 2717, + "3062-runtime-optional-record-guards.ts": 3531, + "3063-runtime-optional-class-guards.ts": 3234, + "3064-installed-entry-imports/main.ts": 2104, + "3065-installed-entry-js/main.js": 2454, + "3066-source-debugging/main.ts": 2680, + "3067-cjs-function-export-require/main.cjs": 2781, + "3068-debug-variables/main.ts": 2201, + "3068-url-checked-identity.ts": 3005, + "3069-set-checked-seed.js": 3167, + "3069-tuple-spread.ts": 3057, + "3070-checked-object-accessors.js": 3314, + "3070-collection-views.ts": 2586, + "3071-checked-specialization-narrowing.js": 2429, + "3071-map-contextual-record-seeds.ts": 2886, + "3072-optional-union-receivers.ts": 3001, + "3072-weak-process-streams.js": 2971, + "3073-optional-callable-module.js": 2030, + "3073-union-keyed-reads.ts": 3228, + "3074-discriminated-intersections.ts": 3008, + "3075-recursive-contextual-literals.ts": 3333, + "3076-nullish-record-defaults.ts": 3030, + "3077-optional-union-array-reads.ts": 2968, + "3078-forward-mutable-captures.ts": 1926, + "3079-forward-mutable-tdz.ts": 2889, + "3080-exhaustive-never-bindings.ts": 2787, + "3081-recursive-array-destinations.ts": 2576, + "3082-forward-write-unwind.ts": 2875, + "3083-set-string-seed.ts": 2684, + "3084-record-own-membership.ts": 3102, + "3085-conditional-record-construction.ts": 1925, + "3086-error-constructor-options.ts": 3227, + "3087-error-options-lifetime.ts": 2113, + "3088-array-wide-callbacks.ts": 2993, + "3089-array-find-narrowing.ts": 3128, + "3090-json-discriminated-records.ts": 3480, + "3091-json-recursive-discriminants.ts": 2300, + "3092-number-union-predicates.ts": 2639, + "3093-error-option-data.ts": 2191, + "3094-json-replacer-traversal.ts": 2898, + "3095-json-reviver-traversal.ts": 2824, + "3096-json-callback-nonfinite.ts": 1927, + "3097-json-callback-reentrancy.ts": 3321, + "3098-json-callback-space.ts": 2551, + "3099-json-callback-functions.ts": 3507, + "3100-json-callback-holder.js": 3048, + "3101-json-callback-bytes.ts": 2658, + "3102-json-unknown-fields.ts": 2725, + "3103-scalar-record-nested-control-flow.ts": 3195, + "3104-native-analysis-tables-loops.ts": 1557, + "3105-nullable-collections.ts": 1888, + "3106-mixed-insertion-spreads.ts": 3368, + "3107-nullable-collection-lifetimes.ts": 3149, + "3108-for-await-sync-arrays.js": 4447, + "3108-identity-map-keys.ts": 3401, + "3109-destructuring-unknown-defaults.js": 2735, + "3109-identity-union-collections.ts": 3270, + "3110-builtin-error-families.ts": 2441, + "3110-identity-collection-mutation.ts": 2906, + "3111-identity-collection-cycles.ts": 3069, + "3112-union-switch-control-flow.ts": 2641, + "3113-union-array-removal.ts": 3416, + "3114-union-record-field-write.ts": 3033, + "3115-zlib-static-compression-levels.ts": 2443, + "3116-sequence-expression-lifetimes.ts": 3044, + "3117-unknown-switch-control-flow.ts": 2684, + "3118-recursive-union-spread.ts": 2422, + "3119-runtime-optional-spread.ts": 2447, + "3120-dynamic-property-descriptors.js": 3293, + "3120-generator-method-loop-bindings.ts": 3248, + "3120-ir-nonfinite-numbers.ts": 3000, + "3121-compound-assignment-values.js": 2549, + "3121-dynamic-accessor-descriptors.js": 3250, + "3122-dynamic-delete-descriptors.cjs": 2600, + "3122-dynamic-delete-descriptors.js": 2091, + "3122-js-async-class-methods.js": 2297, + "3123-destructured-global-tdz.js": 2836, + "3124-array-prototype-borrow.js": 3537, + "3125-regex-global-match.ts": 2402, + "3126-js-number-radix/main.ts": 3052, + "3127-spawn-runtime-options.ts": 3285, + "3128-regex-last-index.ts": 3076, + "3129-js-token-union/main.ts": 2700, + "3130-child-generic-streams.ts": 3044, + "3131-child-rest-listeners.js": 2943, + "3132-child-generic-stream-completion.ts": 6235, + "3133-text-decoder-streaming.ts": 2265, + "3134-fs-vectors.ts": 2815, + "3135-fs-file-handle-controls.ts": 2278, + "3136-fs-file-handle-options.ts": 3814, + "3137-fs-vector-callbacks.cjs": 3509, + "3138-array-large-storage.ts": 4245, + "3139-regex-native-deep-alternatives.ts": 27587, + "3140-array-dense-access.ts": 3800, + "3141-map-string-key-hash.ts": 2566, + "3150-integer-remainder.ts": 3289, + "3151-array-push-writes.ts": 3227, + "3170-number-conversion-fast-paths.ts": 2553, + "3171-method-census-data-writes.ts": 3442, + "400-fib.ts": 2589, + "401-mutual-recursion.ts": 2527, + "402-string-functions.ts": 2176, + "403-void-and-params.ts": 2350, + "4030-runtime-object-truthiness.ts": 2749, + "4031-event-emitter-long-tuples.ts": 2083, + "4032-inline-rc-fast-paths.ts": 4192, + "404-rc-stress.ts": 2456, + "4040-adapted-function-identity.ts": 2867, + "4041-adapted-function-properties.ts": 2991, + "4042-object-is-union-subclass.ts": 2310, + "4043-nonnull-missing-element.ts": 2433, + "4044-adapted-callback-modules/main.ts": 2886, + "4045-optional-element-projections.ts": 3138, + "4046-captured-parameter-values.ts": 3423, + "4047-captured-parameter-rebinding.ts": 2500, + "405-params-optional.ts": 2755, + "406-params-defaults.ts": 2105, + "4060-cycle-shared-instance/main.ts": 2837, + "4060-stack-union-reads.ts": 3299, + "4061-cycle-evaluation-order/main.ts": 2712, + "4061-nullable-ref-fields.ts": 4653, + "4062-cycle-tdz-read/main.ts": 1857, + "4063-cycle-hoisted-calls/main.ts": 2616, + "4064-cycle-classes-after-init/main.ts": 2926, + "4065-cycle-init-throws/main.ts": 2592, + "4066-cycle-top-level-tdz/main.ts": 1456, + "4067-dynamic-import-cycle-tdz/main.ts": 2785, + "407-params-rest.ts": 2693, + "408-params-ctors-inheritance.ts": 2837, + "4080-optional-read-presence-tests.ts": 2357, + "4080-string-index-bounds.ts": 2174, + "4081-hoisted-function-tdz.ts": 3131, + "4081-string-index-unproven.ts": 2850, + "4082-hoisted-function-tdz-uncaught.ts": 2634, + "4083-dynamic-import-failure/main.ts": 2355, + "4084-record-optional-field-copies.ts": 2952, + "4085-generator-loop-close.ts": 3078, + "4086-optional-capture-defaults.ts": 2684, + "4088-class-static-tdz.ts": 2183, + "4089-class-wrapper-tdz.js": 2911, + "409-params-async-generics.ts": 1894, + "4090-computed-key-tdz.js": 2483, + "4091-class-evaluation-deferred.ts": 3134, + "410-params-rc-stress.ts": 1591, + "4140-array-callback-split-visit.ts": 4467, + "4141-array-callback-ambient-receiver/main.ts": 2178, + "4142-array-callback-factories.ts": 3521, + "4143-union-refinement-intersection-arms.ts": 3254, + "420-dead-strip-modules/main.ts": 2523, + "4290-acyclic-immutable-trees.ts": 3062, + "4291-acyclic-constructor-escapes.ts": 2390, + "4292-acyclic-readonly-bypass.ts": 1956, + "4293-acyclic-dynamic-writes.ts": 3149, + "4294-console-line-sizes.ts": 5491, + "4295-console-template-parts.ts": 3025, + "4296-console-glued-long-parts.ts": 4102, + "4410-inline-object-allocation.ts": 3371, + "4411-nullable-ref-values.ts": 3446, + "4412-nullable-record-values.ts": 3505, + "4413-cycle-old-late-death.ts": 3210, + "4413-nullable-null-and-undefined.ts": 3960, + "4414-cycle-old-weak-keys.ts": 2210, + "4414-nullable-string-values.ts": 3960, + "4415-identity-borrowed-operands.ts": 2923, + "4415-nullable-container-values.ts": 4078, + "4431-exception-pending-contexts.ts": 3547, + "4432-checked-downcast-failures.ts": 3362, + "4451-int32-field-storage.ts": 3587, + "4452-int32-field-dynamic-writes.ts": 2629, + "4453-int32-closed-locals.ts": 2708, "4454-int32-field-reflection-reads.ts": 3626, "4455-live-view-reads-without-stores.ts": 3673, - "4471-unassigned-field-reads.ts": 3309, - "4476-string-ascii-header-fact.ts": 2846, - "4477-buffer-write-ascii-runs.ts": 2125, - "4478-string-large-index-reads.ts": 3334, - "4481-array-optional-push.ts": 3059, - "4482-instanceof-static-class-optional.ts": 2994, - "4483-array-splice-statement.ts": 3331, - "4484-array-length-reset.ts": 2664, - "4485-array-splice-optional-item.ts": 2526, - "4486-array-field-element-borrows.ts": 2341, - "4487-array-literal-optional-values.ts": 2248, - "4520-optional-guard-narrowing.ts": 2281, - "4521-array-callback-element-presence.ts": 4131, - "4522-captured-parameter-lifetimes.ts": 2903, - "4523-array-pop-removal.ts": 2536, - "4524-array-callback-supertype-params.ts": 3251, - "4541-nullable-wrap-borrows.ts": 2882, - "4542-preserving-call-borrows.ts": 3130, - "4543-walk-borrowed-locals.ts": 3034, - "4544-checked-cast-aliases.ts": 2574, - "4545-borrowed-returns.ts": 3551, - "4546-rebound-borrowed-params.ts": 2811, - "4560-field-store-borrowed-receivers.ts": 3116, - "4561-virtual-borrowed-parameters.ts": 3237, - "4562-string-self-concat-move.ts": 2061, - "4563-array-read-projection-receivers.ts": 2512, - "4564-literal-choice-strings.ts": 2795, - "4568-for-of-hole-elements.ts": 2661, - "4569-shorthand-missing-elements.ts": 3064, - "4570-map-lookup-default-record.ts": 2901, - "4591-weak-keys-union-records.ts": 2778, - "4592-cycle-const-from-import/main.ts": 2529, - "4593-weak-keys-empty-objects.ts": 2806, - "4594-union-class-field-mixed-types.ts": 3153, - "4595-union-class-field-optional-receiver.ts": 1997, - "4596-error-subclass-int-fields.ts": 2606, - "4596-tdz-nullable-forward-capture.ts": 3433, - "4597-callback-field-method-name.ts": 2519, - "4598-live-array-ref-element-access.ts": 4363, - "4598-map-set-clear-reuse.ts": 4118, - "4598-os-available-parallelism.ts": 2474, - "4598-publish-constructor-stores.ts": 2635, - "4599-construction-only-field-borrows.ts": 3147, - "4600-construction-only-fields-dynamic-writes.ts": 2319, - "4601-cycle-holders.ts": 2904, - "4602-constructor-escape-order.ts": 2703, - "4610-array-ext-dyn-refresh.ts": 3049, - "4620-optional-chain-borrowed-receivers.ts": 3006, - "4621-edge-preserving-callees/main.ts": 2464, - "4630-contract-int32.ts": 2586, - "4630-reference-write-call-arguments.ts": 2892, - "4631-contract-nothrow.ts": 2842, - "4631-reference-write-aliases.ts": 2922, - "4632-contract-immutable.ts": 2582, - "4632-reference-write-loops-and-walks.ts": 2399, - "4633-contract-program-lifetime.ts": 3449, - "4633-reference-write-callbacks-returns.ts": 2678, - "4634-contract-program-lifetime-publish.ts": 4573, - "4634-optional-element-borrowed-returns.ts": 2111, - "4640-bitwise-identity-ranges.ts": 2671, - "4641-nothrow-try-catch.ts": 2141, - "4642-acyclic-contract.ts": 2859, - "4650-stale-property-narrowing.ts": 2759, - "4651-map-string-get-entry.ts": 3114, - "4652-stale-closure-binding-narrowing.ts": 3092, - "4660-typed-rest-spread-forwarding.ts": 2331, - "4671-scoped-array-read-borrows.ts": 2575, - "4690-cycle-bypass-long-lived.ts": 4228, - "4691-publish-constructor-self-alias.ts": 2964, - "4692-borrowed-result-mutating-callees.ts": 2766, - "4720-cold-throw-paths.ts": 3228, - "4721-integer-induction-numbers.ts": 2974, - "4730-touint32-large-magnitudes.ts": 2198, - "4731-string-mixed-ascii-slices.ts": 3160, - "4732-buffer-write-utf16le-runs.ts": 3120, - "4733-typed-array-read-compares.ts": 2977, - "4750-map-string-absent-filter.ts": 3464, - "4751-string-search-multibyte-needles.ts": 2454, - "4795-published-untyped-member-reads.ts": 3340, - "4806-uint32-loop-accumulators.ts": 2740, - "4810-union-identity-retags.ts": 4045, - "4811-union-retag-checked-cast.ts": 2819, - "4812-int32-wrapping-sums.ts": 3339, - "4813-typed-array-read-equality-bindings.ts": 3997, - "4820-sort-comparator-lent-arguments.ts": 2782, - "4821-callback-lent-arguments.ts": 3485, - "4822-stable-capture-reads.ts": 2483, - "4823-array-store-receivers.ts": 2858, - "4830-typed-teardown-chains.ts": 3292, - "4831-cycle-bypass-probe-windows.ts": 3738, - "4840-array-hole-free-prefix.ts": 3550, - "4860-int32-local-storage.ts": 3699, - "4870-array-pipeline-fusion.ts": 6694, - "4871-array-pipeline-analytics.ts": 4274, - "4872-array-pipeline-temporaries.ts": 7763, - "4875-stream-consumers-array-buffer.ts": 3017, - "4876-array-buffer-inspect.ts": 2569, - "4880-await-call-turn-order.ts": 2784, - "4881-await-call-exceptions.ts": 2757, - "4882-await-call-request-chain.ts": 2151, - "4883-await-values-and-hops.ts": 2520, - "4884-await-call-unhandled-sibling.ts": 2379, - "4885-await-call-checkpoints.ts": 2128, - "4890-regex-literal-sites.ts": 3484, - "4891-regex-plain-text-patterns.ts": 2502, - "4892-regex-exec-read-captures.ts": 3120, - "4900-bigint-division-cross-check.ts": 3532, - "4900-console-instances.ts": 3723, - "4901-bigint-radix-text.ts": 3090, - "4901-console-instance-errors.ts": 3055, - "4902-bigint-compound-assign.ts": 2449, - "4903-bigint-fixed-width.ts": 2818, - "4904-bigint-large-products.ts": 2953, - "4905-bigint-fixed-width-fusion.ts": 3047, - "4906-bigint-small-value-trees.ts": 3132, - "4907-bigint-random-trees.ts": 4068, - "4910-hole-free-prefix-upkeep.ts": 3149, - "4920-string-literal-switch.ts": 4588, - "4930-typed-record-reflection.ts": 4183, - "4931-typed-data-generic-walks.ts": 4062, - "4932-typed-json-unknown.ts": 3239, - "4940-async-return-adoption.ts": 2845, - "4941-async-return-adoption-try.ts": 3156, - "4942-async-return-adoption-values.ts": 3620, - "4943-async-return-adoption-interleaved.ts": 2831, - "4950-regex-compiled-captures.ts": 5723, - "4951-regex-compiled-last-index.ts": 3059, - "4952-regex-compiled-anchors-classes.ts": 2426, - "4953-regex-compiled-backtracking.ts": 3365, - "4954-regex-log-report.ts": 3193, - "4955-regex-compiled-differential.ts": 24862, - "4970-int32-call-abi.ts": 2508, - "4980-generator-early-exit-finally.ts": 2836, - "4981-generator-delegation-iterables.ts": 4874, - "4982-generator-sent-values.ts": 2242, - "4983-generator-reuse-iterables.ts": 3066, - "4984-generator-exceptions.ts": 2959, - "4985-generator-lazy-pipeline.ts": 2708, - "4986-generator-default-channels.ts": 3119, - "4987-generator-closures-methods.ts": 2675, - "4988-generator-async-interplay.ts": 2141, - "4989-generator-step-drives.ts": 4185, - "4990-lone-surrogates.ts": 3319, - "4991-lone-surrogate-halves.ts": 2978, - "4992-lone-surrogate-search.ts": 2759, - "4993-lone-surrogate-json.ts": 2994, - "4994-lone-surrogate-uri.ts": 2786, - "4995-lone-surrogate-regex.ts": 3169, - "4996-lone-surrogate-stdio.ts": 2201, - "4997-lone-surrogate-stdout-patch.js": 2754, - "4998-lone-surrogate-buffers.ts": 3060, - "4999-lone-surrogate-io.ts": 4219, - "500-array-basics.ts": 2646, - "501-array-push-pop.ts": 2128, - "5010-lifetime-region-generations.ts": 2950, - "5011-lifetime-region-outside-references.ts": 2816, - "5012-lifetime-region-shapes.ts": 3847, - "5013-lifetime-region-async.ts": 3198, - "5014-lifetime-region-nesting.ts": 2741, - "5015-lifetime-region-publish.ts": 2749, - "5016-lifetime-region-weak-keys.ts": 2541, - "5017-lifetime-region-cycles.ts": 2989, - "5018-lifetime-region-hierarchies.ts": 3642, - "5019-lifetime-region-values.ts": 2516, - "502-array-for-of.ts": 2614, - "5020-lifetime-region-large.ts": 3840, - "5021-lifetime-region-opaque-holders.ts": 2702, - "5022-lifetime-region-workers.ts": 3127, - "503-array-functions.ts": 2610, - "504-array-rc-stress.ts": 2247, - "5040-promise-all-race-turns.ts": 3415, - "5041-promise-all-turns.js": 5156, - "5042-async-generator-return-promise.ts": 3112, - "5043-async-generator-return-forms.ts": 3029, - "5045-generator-delegation-typed-next.ts": 3463, - "5046-generator-delegation-return-throw.ts": 2606, - "5047-generator-delegation-iterables-typed.ts": 4378, - "5048-generator-delegation-async.ts": 4885, - "5049-generator-delegation-edges.ts": 2538, - "5050-inherited-in-membership.ts": 3142, - "5051-typed-record-prototypes.ts": 3140, - "5052-class-for-in-unknown.ts": 2653, - "5053-json-replacer-arrays.ts": 4713, - "5054-required-field-delete.ts": 2632, - "5055-object-create-record-literal.ts": 2065, - "5056-generator-in-unknown.ts": 3903, - "5060-child-fork-exit-after-messages/main.ts": 2572, - "5061-child-fork-local-disconnect/main.ts": 3248, - "5062-child-fork-message-before-eof/main.ts": 4732, - "5065-global-increment-initializers.ts": 3985, - "5066-global-compound-updates.ts": 2635, - "5067-global-updates-in-functions.ts": 2589, - "5068-global-var-let-const-updates.ts": 2726, - "5069-global-update-modules/main.ts": 2372, - "5070-optional-read-bindings.ts": 2144, - "5071-optional-chain-scalars.ts": 2192, - "5072-optional-nullish-ternary.ts": 2587, - "5073-optional-results.ts": 2727, - "5074-optional-pop-shift.ts": 2568, - "5075-optional-reads-unchecked/main.ts": 4996, - "5076-optional-escapes.ts": 2735, - "5080-boolean-array-storage.ts": 5236, - "5081-boolean-array-dynamic-views.ts": 2815, - "5085-promise-allsettled-turns.ts": 3332, - "5086-promise-any-turns.ts": 3297, - "5087-promise-allsettled-any-dyn.js": 3767, - "5088-promise-combinator-thenables.js": 4248, - "5089-promise-settled-records.ts": 3528, - "5090-generator-finished-result-value.ts": 2964, - "5091-generator-delegation-arrays-strings.ts": 2768, - "5092-generator-delegation-sets-maps.ts": 3565, - "5095-console-count-group.ts": 2753, - "5096-console-assert-dir.ts": 4648, - "5097-console-table.ts": 2620, - "5098-console-time-warnings.ts": 6302, - "5099-console-methods-dynamic.cjs": 2644, - "510-array-map-filter-foreach.ts": 2991, - "511-array-indexof-includes.ts": 2657, - "5110-var-hoisting-early-reads.ts": 2806, - "5111-var-hoisting-closures-classes.ts": 2117, - "5112-var-hoisting-function-scope.ts": 2614, - "5113-tdz-let-const-class.ts": 3154, - "5114-var-hoisting-js.js": 4536, - "5115-regex-replace-compiled.ts": 2608, - "5116-regex-capture-reads.ts": 3064, - "5117-regex-log-report-spans.ts": 3404, - "5118-regex-replace-char-chains.ts": 2444, - "512-array-join-chains.ts": 2376, - "5120-frame-records.ts": 2615, - "5121-frame-objects.ts": 2616, - "5122-frame-result-slots.ts": 2622, - "5123-frame-reassigned.ts": 2564, - "5124-frame-objects-control.ts": 3061, - "5125-frame-mutating-methods.ts": 2527, - "5126-frame-returned-params.ts": 2697, - "5127-frame-loop-bindings.ts": 2824, - "513-array-methods-rc-stress.ts": 2641, - "5130-event-target-dispatch.js": 3752, - "5131-event-target-listener-errors.js": 3003, - "5132-event-target-typed.ts": 3341, - "5133-abort-signal-event-target.ts": 3302, - "5134-events-error-monitor.ts": 2664, - "5135-event-target-warnings.js": 2890, - "5136-events-error-monitor-string-name.ts": 2380, - "5137-events-error-monitor-computed-name.js": 3077, - "5138-events-error-monitor-shared-listener.ts": 2001, - "5139-event-target-listener-throw.ts": 1965, - "514-array-find-some-every.ts": 2998, - "5140-os-host-facts.ts": 3248, - "5141-os-constants.ts": 2402, - "5142-path-parse-format.ts": 2850, - "5145-path-matches-glob-basics.ts": 2904, - "5146-path-matches-glob-braces.ts": 4866, - "5147-path-matches-glob-extglob.ts": 2653, - "5148-path-matches-glob-classes.ts": 2765, - "5149-path-matches-glob-win32.ts": 2754, - "515-array-flatmap.ts": 3015, - "5150-small-array-inline-slots.ts": 3276, - "5155-cycle-header-types.ts": 3561, - "516-array-reduce.ts": 3293, - "5160-field-callback-receiver.ts": 3482, - "5161-field-callback-receiver-escape.ts": 2665, - "5162-field-method-reference-receiver.ts": 2779, - "5163-field-callback-receiver.cjs": 2875, - "5164-worker-field-callback-receiver.ts": 3147, - "5165-interface-method-dispatch.ts": 2641, - "5166-interface-method-values.ts": 4036, - "5167-interface-method-order.ts": 3679, - "5168-interface-method-hierarchy.ts": 4400, - "5169-interface-method-chains.ts": 2934, - "517-array-hof-index-args.ts": 2918, - "5170-string-scan-eviction.ts": 2885, - "5171-lone-surrogate-replace-seams.ts": 3463, - "5175-forin-typed-as-unknown.ts": 3333, - "5176-object-keys-typed-as-unknown.ts": 3148, - "5177-forin-dynamic-objects.ts": 2926, - "5178-forin-keys-js.js": 2135, - "5179-forin-typed-shapes.ts": 3197, - "518-array-sort.ts": 2699, - "518-promise-void-union-callbacks.ts": 1929, - "5180-interface-arrays.ts": 3267, - "5181-interface-array-methods.ts": 7443, - "5182-interface-array-boundaries.ts": 3225, - "5183-interface-property-reads.ts": 3018, - "5184-interface-property-objects.ts": 3161, - "5185-util-inherits.cjs": 3120, - "5186-util-inherits.ts": 3012, - "5187-util-deprecate.cjs": 3705, - "5188-util-deprecate-flags.cjs": 2866, - "5189-util-deprecate.ts": 2361, - "519-array-from-length.ts": 3817, - "519-promise-union-await-values.ts": 2296, - "5190-util-callbackify.cjs": 3512, - "5191-util-callbackify.ts": 2893, - "5192-util-debuglog.cjs": 3224, - "5193-util-debuglog.ts": 4346, - "5194-process-emit-warning-tick.cjs": 2199, - "5195-object-entries-typed-as-unknown.ts": 2787, - "5196-object-values-typed-as-unknown.ts": 2984, - "5197-object-entries-dynamic-objects.ts": 3371, - "5198-object-entries-values-js.js": 2819, - "5199-object-entries-identity.ts": 3133, - "520-map-basics.ts": 2629, - "5200-array-sort-keyed-numbers.ts": 3636, - "5201-array-sort-keyed-records.ts": 3559, - "5202-array-sort-keyed-lookalikes.ts": 3148, - "5203-typed-array-sort-default.ts": 6169, - "5204-typed-array-sort-comparators.ts": 4152, - "521-map-number-keys.ts": 2529, - "5210-process-memory-usage.ts": 3044, - "5211-process-identity.ts": 2815, - "5212-perf-marks-measures.ts": 2925, - "5213-perf-timing-errors.ts": 3203, - "5214-perf-entry-inspect.ts": 3164, - "5215-perf-timing-validation.js": 4384, - "5216-perf-spread-arguments.js": 3711, - "5217-perf-spread-typed.ts": 3324, - "522-map-foreach.ts": 2813, - "5220-url-parse-warnings.ts": 2906, - "5221-url-parse-shapes.ts": 2400, - "5222-url-parse-hosts.ts": 2972, - "5223-url-parse-query.ts": 2190, - "5224-url-format-objects.ts": 2681, - "5225-url-format-whatwg.ts": 2885, - "5226-url-resolve.ts": 2184, - "5227-url-legacy-dependency/main.ts": 3291, - "5228-url-domain-conversion.ts": 2624, - "5229-url-legacy-errors.cjs": 3698, - "523-map-ref-values.ts": 2904, - "5230-inline-union-fields.ts": 2318, - "5231-inline-union-field-kinds.ts": 3614, - "5232-inline-union-fields-dynamic.ts": 3502, - "5233-inline-union-fields-shapes.ts": 3338, - "5234-inline-union-class-fields.ts": 4285, - "5235-inline-union-fields-publish.ts": 2840, - "5236-inline-union-unchecked-reads.ts": 1998, - "5237-inline-union-frame-objects.ts": 2284, - "524-map-cycles.ts": 3272, - "5240-event-target-subclass.ts": 3668, - "5241-event-subclass.ts": 4201, - "5242-event-target-subclass-hierarchy.ts": 2218, - "5243-event-target-subclass-dynamic.ts": 2613, - "5244-event-target-subclass.js": 3715, - "5245-event-target-subclass-signals.ts": 3077, - "5246-event-target-subclass-listener-throw.ts": 2770, - "5247-event-target-subclass-lifetimes.ts": 3603, - "5248-event-target-subclass-warnings.ts": 2743, - "5249-event-target-subclass-unconstructed.ts": 1632, - "525-map-rc-stress.ts": 3853, + "4471-unassigned-field-reads.ts": 3063, + "4476-string-ascii-header-fact.ts": 3053, + "4477-buffer-write-ascii-runs.ts": 1845, + "4478-string-large-index-reads.ts": 2385, + "4481-array-optional-push.ts": 2921, + "4482-instanceof-static-class-optional.ts": 2110, + "4483-array-splice-statement.ts": 3260, + "4484-array-length-reset.ts": 2963, + "4485-array-splice-optional-item.ts": 3033, + "4486-array-field-element-borrows.ts": 2099, + "4487-array-literal-optional-values.ts": 2387, + "4520-optional-guard-narrowing.ts": 3290, + "4521-array-callback-element-presence.ts": 4205, + "4522-captured-parameter-lifetimes.ts": 3072, + "4523-array-pop-removal.ts": 2939, + "4524-array-callback-supertype-params.ts": 4250, + "4541-nullable-wrap-borrows.ts": 2850, + "4542-preserving-call-borrows.ts": 3298, + "4543-walk-borrowed-locals.ts": 3324, + "4544-checked-cast-aliases.ts": 2878, + "4545-borrowed-returns.ts": 3935, + "4546-rebound-borrowed-params.ts": 2128, + "4560-field-store-borrowed-receivers.ts": 3268, + "4561-virtual-borrowed-parameters.ts": 2119, + "4562-string-self-concat-move.ts": 2875, + "4563-array-read-projection-receivers.ts": 2961, + "4564-literal-choice-strings.ts": 3091, + "4568-for-of-hole-elements.ts": 3194, + "4569-shorthand-missing-elements.ts": 2799, + "4570-map-lookup-default-record.ts": 2885, + "4591-weak-keys-union-records.ts": 3283, + "4592-cycle-const-from-import/main.ts": 2283, + "4593-weak-keys-empty-objects.ts": 1759, + "4594-union-class-field-mixed-types.ts": 3165, + "4595-union-class-field-optional-receiver.ts": 2742, + "4596-error-subclass-int-fields.ts": 2574, + "4596-tdz-nullable-forward-capture.ts": 3762, + "4597-callback-field-method-name.ts": 3397, + "4598-live-array-ref-element-access.ts": 4852, + "4598-map-set-clear-reuse.ts": 4729, + "4598-os-available-parallelism.ts": 2510, + "4598-publish-constructor-stores.ts": 1852, + "4599-construction-only-field-borrows.ts": 3236, + "4600-construction-only-fields-dynamic-writes.ts": 3072, + "4601-cycle-holders.ts": 2734, + "4602-constructor-escape-order.ts": 2610, + "4610-array-ext-dyn-refresh.ts": 2862, + "4620-optional-chain-borrowed-receivers.ts": 3224, + "4621-edge-preserving-callees/main.ts": 3365, + "4630-contract-int32.ts": 2754, + "4630-reference-write-call-arguments.ts": 3053, + "4631-contract-nothrow.ts": 2070, + "4631-reference-write-aliases.ts": 2695, + "4632-contract-immutable.ts": 2863, + "4632-reference-write-loops-and-walks.ts": 3098, + "4633-contract-program-lifetime.ts": 3689, + "4633-reference-write-callbacks-returns.ts": 3144, + "4634-contract-program-lifetime-publish.ts": 4904, + "4634-optional-element-borrowed-returns.ts": 2709, + "4640-bitwise-identity-ranges.ts": 2778, + "4641-nothrow-try-catch.ts": 2708, + "4642-acyclic-contract.ts": 3288, + "4650-stale-property-narrowing.ts": 3851, + "4651-map-string-get-entry.ts": 3371, + "4652-stale-closure-binding-narrowing.ts": 3495, + "4660-typed-rest-spread-forwarding.ts": 2766, + "4671-scoped-array-read-borrows.ts": 3085, + "4690-cycle-bypass-long-lived.ts": 2735, + "4691-publish-constructor-self-alias.ts": 3219, + "4692-borrowed-result-mutating-callees.ts": 2601, + "4720-cold-throw-paths.ts": 3390, + "4721-integer-induction-numbers.ts": 2467, + "4730-touint32-large-magnitudes.ts": 3097, + "4731-string-mixed-ascii-slices.ts": 2704, + "4732-buffer-write-utf16le-runs.ts": 1998, + "4733-typed-array-read-compares.ts": 3234, + "4750-map-string-absent-filter.ts": 3594, + "4751-string-search-multibyte-needles.ts": 2725, + "4795-published-untyped-member-reads.ts": 3268, + "4806-uint32-loop-accumulators.ts": 3231, + "4810-union-identity-retags.ts": 4620, + "4811-union-retag-checked-cast.ts": 3091, + "4812-int32-wrapping-sums.ts": 3463, + "4813-typed-array-read-equality-bindings.ts": 4674, + "4820-sort-comparator-lent-arguments.ts": 4000, + "4821-callback-lent-arguments.ts": 2333, + "4822-stable-capture-reads.ts": 2409, + "4823-array-store-receivers.ts": 2969, + "4830-typed-teardown-chains.ts": 2905, + "4831-cycle-bypass-probe-windows.ts": 2840, + "4840-array-hole-free-prefix.ts": 2459, + "4860-int32-local-storage.ts": 4170, + "4870-array-pipeline-fusion.ts": 7346, + "4871-array-pipeline-analytics.ts": 4533, + "4872-array-pipeline-temporaries.ts": 7994, + "4875-stream-consumers-array-buffer.ts": 3281, + "4876-array-buffer-inspect.ts": 2814, + "4880-await-call-turn-order.ts": 1921, + "4881-await-call-exceptions.ts": 3225, + "4882-await-call-request-chain.ts": 3022, + "4883-await-values-and-hops.ts": 2825, + "4884-await-call-unhandled-sibling.ts": 2163, + "4885-await-call-checkpoints.ts": 2954, + "4890-regex-literal-sites.ts": 3163, + "4891-regex-plain-text-patterns.ts": 2001, + "4892-regex-exec-read-captures.ts": 3652, + "4900-bigint-division-cross-check.ts": 3357, + "4900-console-instances.ts": 3637, + "4901-bigint-radix-text.ts": 2779, + "4901-console-instance-errors.ts": 3196, + "4902-bigint-compound-assign.ts": 1706, + "4903-bigint-fixed-width.ts": 3128, + "4904-bigint-large-products.ts": 3340, + "4905-bigint-fixed-width-fusion.ts": 3031, + "4906-bigint-small-value-trees.ts": 3759, + "4907-bigint-random-trees.ts": 5188, + "4910-hole-free-prefix-upkeep.ts": 3084, + "4920-string-literal-switch.ts": 3310, + "4930-typed-record-reflection.ts": 4737, + "4931-typed-data-generic-walks.ts": 4118, + "4932-typed-json-unknown.ts": 3475, + "4940-async-return-adoption.ts": 3491, + "4941-async-return-adoption-try.ts": 3096, + "4942-async-return-adoption-values.ts": 2964, + "4943-async-return-adoption-interleaved.ts": 2876, + "4950-regex-compiled-captures.ts": 4852, + "4951-regex-compiled-last-index.ts": 2706, + "4952-regex-compiled-anchors-classes.ts": 2724, + "4953-regex-compiled-backtracking.ts": 4297, + "4954-regex-log-report.ts": 3687, + "4955-regex-compiled-differential.ts": 13757, + "4970-int32-call-abi.ts": 3580, + "4980-generator-early-exit-finally.ts": 3050, + "4981-generator-delegation-iterables.ts": 4127, + "4982-generator-sent-values.ts": 2957, + "4983-generator-reuse-iterables.ts": 3475, + "4984-generator-exceptions.ts": 3390, + "4985-generator-lazy-pipeline.ts": 3419, + "4986-generator-default-channels.ts": 3152, + "4987-generator-closures-methods.ts": 3151, + "4988-generator-async-interplay.ts": 2316, + "4989-generator-step-drives.ts": 3427, + "4990-lone-surrogates.ts": 3491, + "4991-lone-surrogate-halves.ts": 3293, + "4992-lone-surrogate-search.ts": 2456, + "4993-lone-surrogate-json.ts": 3728, + "4994-lone-surrogate-uri.ts": 1777, + "4995-lone-surrogate-regex.ts": 2799, + "4996-lone-surrogate-stdio.ts": 3100, + "4997-lone-surrogate-stdout-patch.js": 1716, + "4998-lone-surrogate-buffers.ts": 3414, + "4999-lone-surrogate-io.ts": 2886, + "500-array-basics.ts": 2955, + "501-array-push-pop.ts": 1902, + "5010-lifetime-region-generations.ts": 3477, + "5011-lifetime-region-outside-references.ts": 2843, + "5012-lifetime-region-shapes.ts": 4150, + "5013-lifetime-region-async.ts": 3814, + "5014-lifetime-region-nesting.ts": 2997, + "5015-lifetime-region-publish.ts": 2741, + "5016-lifetime-region-weak-keys.ts": 3235, + "5017-lifetime-region-cycles.ts": 3057, + "5018-lifetime-region-hierarchies.ts": 4043, + "5019-lifetime-region-values.ts": 2895, + "502-array-for-of.ts": 2808, + "5020-lifetime-region-large.ts": 3808, + "5021-lifetime-region-opaque-holders.ts": 3422, + "5022-lifetime-region-workers.ts": 2531, + "503-array-functions.ts": 2837, + "504-array-rc-stress.ts": 2722, + "5040-promise-all-race-turns.ts": 3860, + "5041-promise-all-turns.js": 3644, + "5042-async-generator-return-promise.ts": 3304, + "5043-async-generator-return-forms.ts": 3190, + "5045-generator-delegation-typed-next.ts": 3751, + "5046-generator-delegation-return-throw.ts": 2749, + "5047-generator-delegation-iterables-typed.ts": 4798, + "5048-generator-delegation-async.ts": 3315, + "5049-generator-delegation-edges.ts": 3539, + "5050-inherited-in-membership.ts": 3427, + "5051-typed-record-prototypes.ts": 2418, + "5052-class-for-in-unknown.ts": 3692, + "5053-json-replacer-arrays.ts": 3781, + "5054-required-field-delete.ts": 2108, + "5055-object-create-record-literal.ts": 2773, + "5056-generator-in-unknown.ts": 2634, + "5060-child-fork-exit-after-messages/main.ts": 2129, + "5061-child-fork-local-disconnect/main.ts": 3136, + "5062-child-fork-message-before-eof/main.ts": 3024, + "5065-global-increment-initializers.ts": 2900, + "5066-global-compound-updates.ts": 3224, + "5067-global-updates-in-functions.ts": 2208, + "5068-global-var-let-const-updates.ts": 2542, + "5069-global-update-modules/main.ts": 1962, + "5070-optional-read-bindings.ts": 2623, + "5071-optional-chain-scalars.ts": 2743, + "5072-optional-nullish-ternary.ts": 2840, + "5073-optional-results.ts": 3242, + "5074-optional-pop-shift.ts": 2144, + "5075-optional-reads-unchecked/main.ts": 3167, + "5076-optional-escapes.ts": 2155, + "5080-boolean-array-storage.ts": 4783, + "5081-boolean-array-dynamic-views.ts": 2550, + "5085-promise-allsettled-turns.ts": 4142, + "5086-promise-any-turns.ts": 3722, + "5087-promise-allsettled-any-dyn.js": 5509, + "5088-promise-combinator-thenables.js": 4706, + "5089-promise-settled-records.ts": 3855, + "5090-generator-finished-result-value.ts": 2787, + "5091-generator-delegation-arrays-strings.ts": 4059, + "5092-generator-delegation-sets-maps.ts": 3822, + "5095-console-count-group.ts": 3219, + "5096-console-assert-dir.ts": 3665, + "5097-console-table.ts": 2407, + "5098-console-time-warnings.ts": 5609, + "5099-console-methods-dynamic.cjs": 3155, + "510-array-map-filter-foreach.ts": 2313, + "511-array-indexof-includes.ts": 2884, + "5110-var-hoisting-early-reads.ts": 2759, + "5111-var-hoisting-closures-classes.ts": 2869, + "5112-var-hoisting-function-scope.ts": 2697, + "5113-tdz-let-const-class.ts": 2402, + "5114-var-hoisting-js.js": 2192, + "5115-regex-replace-compiled.ts": 2826, + "5116-regex-capture-reads.ts": 3329, + "5117-regex-log-report-spans.ts": 3686, + "5118-regex-replace-char-chains.ts": 2917, + "512-array-join-chains.ts": 1729, + "5120-frame-records.ts": 2763, + "5121-frame-objects.ts": 2346, + "5122-frame-result-slots.ts": 3086, + "5123-frame-reassigned.ts": 2807, + "5124-frame-objects-control.ts": 2789, + "5125-frame-mutating-methods.ts": 2122, + "5126-frame-returned-params.ts": 2597, + "5127-frame-loop-bindings.ts": 2498, + "513-array-methods-rc-stress.ts": 3202, + "5130-event-target-dispatch.js": 4435, + "5131-event-target-listener-errors.js": 1856, + "5132-event-target-typed.ts": 2296, + "5133-abort-signal-event-target.ts": 3474, + "5134-events-error-monitor.ts": 2972, + "5135-event-target-warnings.js": 2909, + "5136-events-error-monitor-string-name.ts": 2529, + "5137-events-error-monitor-computed-name.js": 3132, + "5138-events-error-monitor-shared-listener.ts": 2744, + "5139-event-target-listener-throw.ts": 2800, + "514-array-find-some-every.ts": 3281, + "5140-os-host-facts.ts": 3044, + "5141-os-constants.ts": 3300, + "5142-path-parse-format.ts": 2224, + "5145-path-matches-glob-basics.ts": 2906, + "5146-path-matches-glob-braces.ts": 5151, + "5147-path-matches-glob-extglob.ts": 2798, + "5148-path-matches-glob-classes.ts": 2450, + "5149-path-matches-glob-win32.ts": 3351, + "515-array-flatmap.ts": 3014, + "5150-small-array-inline-slots.ts": 3873, + "5155-cycle-header-types.ts": 3715, + "516-array-reduce.ts": 3532, + "5160-field-callback-receiver.ts": 3321, + "5161-field-callback-receiver-escape.ts": 2766, + "5162-field-method-reference-receiver.ts": 2634, + "5163-field-callback-receiver.cjs": 3329, + "5164-worker-field-callback-receiver.ts": 3447, + "5165-interface-method-dispatch.ts": 3406, + "5166-interface-method-values.ts": 4300, + "5167-interface-method-order.ts": 3903, + "5168-interface-method-hierarchy.ts": 5186, + "5169-interface-method-chains.ts": 2434, + "517-array-hof-index-args.ts": 3100, + "5170-string-scan-eviction.ts": 1929, + "5171-lone-surrogate-replace-seams.ts": 2824, + "5175-forin-typed-as-unknown.ts": 2364, + "5176-object-keys-typed-as-unknown.ts": 1967, + "5177-forin-dynamic-objects.ts": 2917, + "5178-forin-keys-js.js": 3039, + "5179-forin-typed-shapes.ts": 3389, + "518-array-sort.ts": 3117, + "518-promise-void-union-callbacks.ts": 2562, + "5180-interface-arrays.ts": 3202, + "5181-interface-array-methods.ts": 6982, + "5182-interface-array-boundaries.ts": 3287, + "5183-interface-property-reads.ts": 3238, + "5184-interface-property-objects.ts": 3177, + "5185-util-inherits.cjs": 3654, + "5186-util-inherits.ts": 3139, + "5187-util-deprecate.cjs": 2383, + "5188-util-deprecate-flags.cjs": 2907, + "5189-util-deprecate.ts": 2180, + "519-array-from-length.ts": 2896, + "519-promise-union-await-values.ts": 2702, + "5190-util-callbackify.cjs": 3059, + "5191-util-callbackify.ts": 3126, + "5192-util-debuglog.cjs": 3809, + "5193-util-debuglog.ts": 2614, + "5194-process-emit-warning-tick.cjs": 2394, + "5195-object-entries-typed-as-unknown.ts": 3883, + "5196-object-values-typed-as-unknown.ts": 3399, + "5197-object-entries-dynamic-objects.ts": 3397, + "5198-object-entries-values-js.js": 2635, + "5199-object-entries-identity.ts": 3121, + "520-map-basics.ts": 2823, + "5200-array-sort-keyed-numbers.ts": 4287, + "5201-array-sort-keyed-records.ts": 4564, + "5202-array-sort-keyed-lookalikes.ts": 3516, + "5203-typed-array-sort-default.ts": 6009, + "5204-typed-array-sort-comparators.ts": 4333, + "521-map-number-keys.ts": 2785, + "5210-process-memory-usage.ts": 2299, + "5211-process-identity.ts": 3103, + "5212-perf-marks-measures.ts": 3829, + "5213-perf-timing-errors.ts": 3477, + "5214-perf-entry-inspect.ts": 4088, + "5215-perf-timing-validation.js": 3386, + "5216-perf-spread-arguments.js": 4128, + "5217-perf-spread-typed.ts": 3454, + "522-map-foreach.ts": 2702, + "5220-url-parse-warnings.ts": 2881, + "5221-url-parse-shapes.ts": 1930, + "5222-url-parse-hosts.ts": 3064, + "5223-url-parse-query.ts": 3104, + "5224-url-format-objects.ts": 3496, + "5225-url-format-whatwg.ts": 2608, + "5226-url-resolve.ts": 2695, + "5227-url-legacy-dependency/main.ts": 2825, + "5228-url-domain-conversion.ts": 2843, + "5229-url-legacy-errors.cjs": 3833, + "523-map-ref-values.ts": 3192, + "5230-inline-union-fields.ts": 2629, + "5231-inline-union-field-kinds.ts": 2513, + "5232-inline-union-fields-dynamic.ts": 3917, + "5233-inline-union-fields-shapes.ts": 3689, + "5234-inline-union-class-fields.ts": 3417, + "5235-inline-union-fields-publish.ts": 2910, + "5236-inline-union-unchecked-reads.ts": 2919, + "5237-inline-union-frame-objects.ts": 2775, + "524-map-cycles.ts": 2820, + "5240-event-target-subclass.ts": 4712, + "5241-event-subclass.ts": 3442, + "5242-event-target-subclass-hierarchy.ts": 3429, + "5243-event-target-subclass-dynamic.ts": 3827, + "5244-event-target-subclass.js": 3772, + "5245-event-target-subclass-signals.ts": 3197, + "5246-event-target-subclass-listener-throw.ts": 1982, + "5247-event-target-subclass-lifetimes.ts": 4315, + "5248-event-target-subclass-warnings.ts": 2798, + "5249-event-target-subclass-unconstructed.ts": 2600, + "525-map-rc-stress.ts": 2751, "5250-cipher-aes-gcm.ts": 6095, "5251-cipher-aes-cbc.ts": 3544, "5252-cipher-aes-ctr.ts": 2536, @@ -1702,45 +1702,45 @@ "5257-cipher-vectors.ts": 3374, "5258-cipher-handles.js": 2798, "5259-cipher-chunked.ts": 3781, - "526-set-basics.ts": 1919, - "5260-record-unknown-identity.ts": 2937, - "5261-optional-field-identity.ts": 2860, - "5262-record-unknown-many.ts": 2984, - "527-set-foreach.ts": 3210, - "5270-url-parse-no-deprecation.cjs": 3158, - "5271-url-parse-throw-deprecation.cjs": 2975, - "5275-http-end-callback-order.ts": 2389, - "5276-style-text-hex-colors.cjs": 2820, - "5277-fs-read-file-buffer-option.cjs": 2710, - "5278-host-null-bytes.cjs": 2114, - "5279-search-params-null-init.cjs": 1781, - "528-set-seeded.ts": 2610, - "5285-blob-construct.ts": 2681, - "5286-blob-readers.ts": 3079, - "5287-blob-inspect.ts": 3817, - "5288-blob-validation.js": 3803, - "5289-blob-read-order.ts": 2829, - "529-map-seeded.ts": 2574, - "5290-blob-dynamic.js": 2354, - "5295-readline-promises-question.ts": 3709, - "5296-readline-lines.ts": 2760, - "5297-readline-callback-events.cjs": 2472, - "5298-readline-abort.cjs": 2757, - "5299-readline-stdin.ts": 3087, - "530-record-arrays.ts": 2787, - "5300-stream-add-abort-signal.ts": 3027, - "5301-stream-add-abort-signal-errors.cjs": 2717, - "5302-stream-promises-options.ts": 3120, - "5303-stream-finished-callback-opts.cjs": 2705, - "5305-json-stringify-typed-arrays.ts": 3153, - "531-record-array-hofs.ts": 2832, - "5315-map-iterate-after-front-deletes.ts": 3911, - "5316-map-lru-eviction.ts": 2782, - "5317-map-iterate-while-mutating.ts": 2769, - "5318-set-iterate-after-deletes.ts": 2291, - "5319-map-iteration-values.ts": 2689, - "532-record-arrays-rc-stress.ts": 2437, - "5320-map-iterate-across-compaction.ts": 3526, + "526-set-basics.ts": 2514, + "5260-record-unknown-identity.ts": 3342, + "5261-optional-field-identity.ts": 2813, + "5262-record-unknown-many.ts": 2768, + "527-set-foreach.ts": 2947, + "5270-url-parse-no-deprecation.cjs": 3204, + "5271-url-parse-throw-deprecation.cjs": 3229, + "5275-http-end-callback-order.ts": 3224, + "5276-style-text-hex-colors.cjs": 2193, + "5277-fs-read-file-buffer-option.cjs": 1864, + "5278-host-null-bytes.cjs": 2972, + "5279-search-params-null-init.cjs": 1662, + "528-set-seeded.ts": 1937, + "5285-blob-construct.ts": 3802, + "5286-blob-readers.ts": 2609, + "5287-blob-inspect.ts": 2930, + "5288-blob-validation.js": 4282, + "5289-blob-read-order.ts": 3276, + "529-map-seeded.ts": 2575, + "5290-blob-dynamic.js": 3409, + "5295-readline-promises-question.ts": 2860, + "5296-readline-lines.ts": 3085, + "5297-readline-callback-events.cjs": 2092, + "5298-readline-abort.cjs": 3384, + "5299-readline-stdin.ts": 2909, + "530-record-arrays.ts": 3090, + "5300-stream-add-abort-signal.ts": 2505, + "5301-stream-add-abort-signal-errors.cjs": 3168, + "5302-stream-promises-options.ts": 2812, + "5303-stream-finished-callback-opts.cjs": 2840, + "5305-json-stringify-typed-arrays.ts": 4425, + "531-record-array-hofs.ts": 3107, + "5315-map-iterate-after-front-deletes.ts": 3372, + "5316-map-lru-eviction.ts": 2980, + "5317-map-iterate-while-mutating.ts": 3025, + "5318-set-iterate-after-deletes.ts": 2325, + "5319-map-iteration-values.ts": 2767, + "532-record-arrays-rc-stress.ts": 2605, + "5320-map-iterate-across-compaction.ts": 3341, "5321-integer-closed-arithmetic-loops.ts": 2935, "5321-json-parse-cycles.ts": 2739, "5322-integer-variable-step-loops.ts": 2732, @@ -1749,29 +1749,29 @@ "5323-int32-nonnegative-slot-facts.ts": 2925, "5324-int32-initializer-locals.ts": 2126, "5324-structured-clone-documents.ts": 3093, - "5325-record-boundary-returns.ts": 1763, - "5326-record-boundary-params.ts": 2634, - "5327-record-boundary-identity.ts": 2323, - "5328-record-boundary-open.ts": 2561, - "5329-record-boundary-recursion.ts": 2680, - "533-array-element-cycles.ts": 2932, - "5330-record-boundary-fields.ts": 1977, - "5331-record-boundary-methods.ts": 3130, + "5325-record-boundary-returns.ts": 2952, + "5326-record-boundary-params.ts": 3045, + "5327-record-boundary-identity.ts": 2913, + "5328-record-boundary-open.ts": 2787, + "5329-record-boundary-recursion.ts": 2543, + "533-array-element-cycles.ts": 2595, + "5330-record-boundary-fields.ts": 2690, + "5331-record-boundary-methods.ts": 2941, "5332-int32-narrowed-slot-facts.ts": 3036, "5333-integer-guarded-while-counters.ts": 2907, - "5333-record-boundary-nullable-argument.ts": 3012, - "5334-fetch-mentions-without-calls.ts": 2532, + "5333-record-boundary-nullable-argument.ts": 3066, + "5334-fetch-mentions-without-calls.ts": 2537, "5335-stream-operators-values.ts": 3463, - "5335-top-level-await-pending-exit-code.ts": 1919, + "5335-top-level-await-pending-exit-code.ts": 2626, "5336-stream-operators-promise-timing.ts": 3056, - "5336-top-level-await-pending-exit-listener.ts": 3734, - "5337-dc-subscriber-throw-next-tick.cjs": 2604, + "5336-top-level-await-pending-exit-listener.ts": 2547, + "5337-dc-subscriber-throw-next-tick.cjs": 2655, "5337-stream-operators-concurrency.ts": 2539, - "5338-js-tdz-function-element.js": 2562, + "5338-js-tdz-function-element.js": 2247, "5338-stream-operators-checks.cjs": 3619, - "5339-array-buffer-constructor.js": 2502, + "5339-array-buffer-constructor.js": 3106, "5339-stream-for-await-hops.ts": 2525, - "534-record-width-subtyping.ts": 2615, + "534-record-width-subtyping.ts": 2764, "5340-readable-from-options.ts": 3427, "5341-compound-any-operand.ts": 3571, "5341-generator-callback-params.ts": 3696, @@ -1787,28 +1787,28 @@ "5343-stream-compose-edges.ts": 3167, "5344-json-parse-undeclared-keys.ts": 4016, "5344-stream-pipeline-timing.ts": 3216, - "5345-object-values-for-of-unknown.ts": 3008, - "5346-object-values-length-dynamic.ts": 3055, - "5347-object-values-loop-control.ts": 3030, - "5348-object-values-for-of-js.js": 2732, - "5349-object-entries-values-optional.ts": 2083, - "535-object-statics.ts": 2312, - "5350-object-values-wide-record.ts": 2790, - "5351-object-values-methods-index.ts": 3275, + "5345-object-values-for-of-unknown.ts": 2662, + "5346-object-values-length-dynamic.ts": 3253, + "5347-object-values-loop-control.ts": 3534, + "5348-object-values-for-of-js.js": 3133, + "5349-object-entries-values-optional.ts": 3434, + "535-object-statics.ts": 3684, + "5350-object-values-wide-record.ts": 3383, + "5351-object-values-methods-index.ts": 4044, "5352-final-field-loop-reads.ts": 2982, "5353-captured-const-values.ts": 3255, "5354-captured-const-tdz.ts": 1913, "5355-captured-function-declarations.ts": 2960, "5356-captured-tdz-ordering.ts": 2164, "5357-init-only-module-bindings.ts": 3203, - "536-map-seed-array.ts": 2712, - "5360-array-sort-comparator-calls.ts": 3175, - "5361-array-sort-inconsistent-comparators.ts": 3161, - "5362-array-sort-comparator-throws.ts": 2896, - "5363-array-sort-comparator-writes.ts": 6813, - "5364-array-sort-union-and-boolean-elements.ts": 8514, - "5365-array-sort-dynamic-values.js": 2402, - "537-map-iter-drains.ts": 2867, + "536-map-seed-array.ts": 2803, + "5360-array-sort-comparator-calls.ts": 2961, + "5361-array-sort-inconsistent-comparators.ts": 2659, + "5362-array-sort-comparator-throws.ts": 2991, + "5363-array-sort-comparator-writes.ts": 5900, + "5364-array-sort-union-and-boolean-elements.ts": 10497, + "5365-array-sort-dynamic-values.js": 3189, + "537-map-iter-drains.ts": 2987, "5370-zlib-stream-roundtrip.ts": 3454, "5371-zlib-stream-chunking.cjs": 3925, "5372-zlib-stream-errors.cjs": 2700, @@ -1819,29 +1819,29 @@ "5377-zlib-stream-backpressure.cjs": 3427, "5378-zlib-sync-options.cjs": 2176, "5379-zlib-callback-options.ts": 3566, - "538-map-set-for-of.ts": 2756, - "5390-interface-loop-element-lifetimes.ts": 2999, - "5391-interface-dispatch-hierarchies.ts": 3168, - "5392-interface-receiver-bindings.ts": 2015, - "5393-interface-array-holes.ts": 2530, - "5394-interface-implementers.ts": 2992, - "5395-locale-compare-ascii.ts": 3026, - "5396-locale-compare-latin.ts": 3119, - "5397-locale-compare-sorting.ts": 3179, - "540-tuples-basics.ts": 2776, - "5400-json-parse-typed-keys.ts": 3131, - "5405-buffer-arraybuffer-window.ts": 2729, - "5406-util-types-keys.ts": 2747, - "5407-http-header-field-limit.ts": 2785, - "5408-http-unread-request-end.ts": 3226, - "5409-http-held-request-body.ts": 3218, - "541-ref-array-json.ts": 3099, - "5410-inspect-class-values.ts": 1875, - "5411-inspect-class-hierarchies.ts": 2712, - "5412-inspect-dynamic-collections.ts": 2792, - "5413-inspect-class-values.cjs": 3020, + "538-map-set-for-of.ts": 2976, + "5390-interface-loop-element-lifetimes.ts": 3153, + "5391-interface-dispatch-hierarchies.ts": 3899, + "5392-interface-receiver-bindings.ts": 3131, + "5393-interface-array-holes.ts": 3093, + "5394-interface-implementers.ts": 3579, + "5395-locale-compare-ascii.ts": 2963, + "5396-locale-compare-latin.ts": 1885, + "5397-locale-compare-sorting.ts": 3156, + "540-tuples-basics.ts": 2555, + "5400-json-parse-typed-keys.ts": 3448, + "5405-buffer-arraybuffer-window.ts": 3039, + "5406-util-types-keys.ts": 2823, + "5407-http-header-field-limit.ts": 3316, + "5408-http-unread-request-end.ts": 3667, + "5409-http-held-request-body.ts": 2506, + "541-ref-array-json.ts": 2521, + "5410-inspect-class-values.ts": 2528, + "5411-inspect-class-hierarchies.ts": 3094, + "5412-inspect-dynamic-collections.ts": 3071, + "5413-inspect-class-values.cjs": 3263, "5415-zlib-dynamic-inputs.cjs": 2520, - "542-union-element-arrays.ts": 2846, + "542-union-element-arrays.ts": 2223, "5420-readable-from-generators.ts": 3661, "5421-readable-from-generators.cjs": 3036, "5422-stream-async-push-wakeup.ts": 3138, @@ -1852,43 +1852,43 @@ "5427-pipeline-generator-backpressure.ts": 2729, "5428-pipeline-generator-stages.cjs": 3499, "5429-pipeline-generator-buffers.ts": 3223, - "5430-dyn-number-string-boxes.ts": 3059, - "5435-crypto-hash-algorithms.ts": 2030, - "5436-crypto-hash-names.js": 2098, - "5437-crypto-hmac-algorithms.ts": 2699, - "5438-crypto-kdf-digests.ts": 2741, - "5439-crypto-kdf-callbacks.js": 2685, - "5440-crypto-hash-encodings.js": 4004, - "5441-crypto-hash-output-length.ts": 3671, - "5442-crypto-random-values.ts": 3947, - "5443-crypto-random-arguments.js": 3548, - "5444-crypto-timing-safe-equal.js": 3213, - "5445-crypto-secret-key-objects.ts": 3869, - "5445-stream-buffer-chunks.ts": 2881, - "5446-crypto-secret-key-errors.js": 3035, - "5446-stream-buffer-chunks-dynamic.js": 2859, - "5447-fs-readdir-order.ts": 2639, - "5448-fs-glob-patterns.ts": 2837, - "5449-fs-glob-options.ts": 3025, - "5450-fs-glob-validation.js": 3327, - "5451-fs-promises-glob.ts": 3059, - "5452-fs-glob-callback.ts": 2936, - "5455-power-of-two-remainder.ts": 2837, - "5456-remainder-large-integer-dividends.ts": 2786, - "5457-lcg-modulus.ts": 1426, - "5458-fractional-remainder.ts": 1394, - "5460-locale-compare-contractions.ts": 2979, - "5461-locale-compare-equivalents.ts": 2661, - "5462-locale-compare-probe-sweep.ts": 3400, - "5463-locale-compare-combining-letters.ts": 2733, - "5464-locale-compare-fractions.ts": 2833, + "5430-dyn-number-string-boxes.ts": 3048, + "5435-crypto-hash-algorithms.ts": 2461, + "5436-crypto-hash-names.js": 3064, + "5437-crypto-hmac-algorithms.ts": 3107, + "5438-crypto-kdf-digests.ts": 3109, + "5439-crypto-kdf-callbacks.js": 2368, + "5440-crypto-hash-encodings.js": 4093, + "5441-crypto-hash-output-length.ts": 3652, + "5442-crypto-random-values.ts": 4190, + "5443-crypto-random-arguments.js": 3529, + "5444-crypto-timing-safe-equal.js": 3508, + "5445-crypto-secret-key-objects.ts": 3186, + "5445-stream-buffer-chunks.ts": 3012, + "5446-crypto-secret-key-errors.js": 3785, + "5446-stream-buffer-chunks-dynamic.js": 3127, + "5447-fs-readdir-order.ts": 2143, + "5448-fs-glob-patterns.ts": 3113, + "5449-fs-glob-options.ts": 3649, + "5450-fs-glob-validation.js": 2855, + "5451-fs-promises-glob.ts": 3569, + "5452-fs-glob-callback.ts": 2885, + "5455-power-of-two-remainder.ts": 3093, + "5456-remainder-large-integer-dividends.ts": 2991, + "5457-lcg-modulus.ts": 2871, + "5458-fractional-remainder.ts": 2988, + "5460-locale-compare-contractions.ts": 2881, + "5461-locale-compare-equivalents.ts": 2942, + "5462-locale-compare-probe-sweep.ts": 2752, + "5463-locale-compare-combining-letters.ts": 3006, + "5464-locale-compare-fractions.ts": 2946, "5465-dyn-index-read-arrays.ts": 3424, "5466-dyn-index-read-special.ts": 2632, - "5470-strip-vt-osc.cjs": 2497, - "5471-strip-vt-csi.cjs": 2651, - "5472-strip-vt-random.cjs": 2375, - "5473-strip-vt-unterminated.cjs": 3521, - "5474-strip-vt-surrogates.ts": 2534, + "5470-strip-vt-osc.cjs": 2376, + "5471-strip-vt-csi.cjs": 2167, + "5472-strip-vt-random.cjs": 3001, + "5473-strip-vt-unterminated.cjs": 3560, + "5474-strip-vt-surrogates.ts": 3301, "5510-assert-error-properties.js": 3653, "5511-assert-error-class.ts": 3637, "5512-assert-error-options.js": 3115, @@ -1909,20 +1909,20 @@ "5530-buffer-pool.ts": 3971, "5531-buffer-pool-first-slab.ts": 5569, "5532-buffer-pool-first-slab-untyped.mjs": 40038, - "5540-fs-callback-forms.cjs": 3233, - "5541-fs-stats-fields.cjs": 3564, - "5542-fs-promises-parity.cjs": 3940, - "5543-fs-promises-typed.ts": 1655, - "5544-fs-opendir.cjs": 3024, - "5545-fs-options-encoding.cjs": 2994, + "5540-fs-callback-forms.cjs": 3631, + "5541-fs-stats-fields.cjs": 3800, + "5542-fs-promises-parity.cjs": 3962, + "5543-fs-promises-typed.ts": 2212, + "5544-fs-opendir.cjs": 3332, + "5545-fs-options-encoding.cjs": 4482, "5546-fs-read-stream.cjs": 4502, "5547-fs-write-stream.cjs": 5101, - "5548-fs-callback-arguments.cjs": 4041, - "5549-fs-callback-option-checks.cjs": 3738, - "5550-locale-compare-ascii-words.ts": 2509, - "5551-array-search-references.ts": 3475, - "5552-string-appends.ts": 2703, - "5553-string-append-char-code.ts": 2870, + "5548-fs-callback-arguments.cjs": 4306, + "5549-fs-callback-option-checks.cjs": 4187, + "5550-locale-compare-ascii-words.ts": 2669, + "5551-array-search-references.ts": 3663, + "5552-string-appends.ts": 3195, + "5553-string-append-char-code.ts": 2446, "5554-fs-streams-typed.ts": 3785, "5555-fs-callback-turns.cjs": 3093, "5555-http-server-close-keep-alive.ts": 7242, @@ -1935,15 +1935,15 @@ "5562-https-verify-errors.ts": 3494, "5563-http-keep-alive-timeout.ts": 11607, "5564-http-request-signal.ts": 3916, - "5565-fs-dirent-untyped.mjs": 2600, - "5566-fs-dirent-dyn-boundaries/main.mjs": 2607, + "5565-fs-dirent-untyped.mjs": 3810, + "5566-fs-dirent-dyn-boundaries/main.mjs": 3533, "5567-fs-cpsync.ts": 3626, "5568-fs-cp-errors.js": 3163, "5569-fs-cp-symlinks.ts": 3704, "5570-fs-cp-async.ts": 3480, "5571-fs-cp-deep.ts": 4934, - "5585-record-results-inlined.ts": 2922, - "5595-net-ref-unref.ts": 2593, + "5585-record-results-inlined.ts": 3154, + "5595-net-ref-unref.ts": 2641, "5600-dyn-cycle-self.ts": 2124, "5601-dyn-cycle-mutual.ts": 3279, "5602-dyn-cycle-arrays.ts": 2568, @@ -1974,13 +1974,13 @@ "5630-promisify-zlib.ts": 1934, "5631-promisify-crypto.ts": 2200, "5632-promisify-dns.ts": 1700, - "5644-net-socket-addresses.ts": 2220, - "5645-net-socket-callbacks.ts": 2442, - "5646-net-server-connections.ts": 2389, - "5647-net-is-ip.ts": 2776, - "5648-dns-lookup-forms.ts": 2992, - "5649-dns-service-servers.ts": 2712, - "5650-dns-lookup-errors-untyped.cjs": 2822, + "5644-net-socket-addresses.ts": 3275, + "5645-net-socket-callbacks.ts": 3377, + "5646-net-server-connections.ts": 2448, + "5647-net-is-ip.ts": 2731, + "5648-dns-lookup-forms.ts": 3763, + "5649-dns-service-servers.ts": 2892, + "5650-dns-lookup-errors-untyped.cjs": 2811, "5651-tls-socket-protocol.ts": 3198, "5652-http-client-trailer-overflow.ts": 2916, "5653-net-socket-read-ahead.ts": 4816, @@ -1993,7 +1993,7 @@ "5664-tls-client-identity.ts": 2704, "5674-union-instanceof-array-arms.ts": 3663, "5680-array-growth-after-copy.ts": 3726, - "5681-array-pop-and-length.ts": 3754, + "5681-array-pop-and-length.ts": 4270, "5682-publish-wide-objects.ts": 3077, "5700-cycle-release-retained.ts": 2148, "5701-cycle-release-old-edges.ts": 2696, @@ -2054,36 +2054,36 @@ "5795-worker-message-port-batches.ts": 2254, "5796-worker-message-channel.cjs": 3566, "5797-worker-message-port-transfer.ts": 3180, - "5800-broadcast-channel.ts": 2899, - "5801-broadcast-channel.cjs": 2727, - "5802-broadcast-channel-workers.ts": 2809, - "5803-worker-environment-data.ts": 2748, - "5804-worker-environment-data.cjs": 2469, - "5805-worker-receive-message-parent-port.ts": 2839, - "5806-worker-resource-limits.ts": 3153, - "5807-worker-error-values.ts": 3304, - "5808-worker-unhandled-rejections.ts": 3430, - "5809-process-exit-and-rejections.cjs": 3294, - "5810-mock-method-records.ts": 3976, - "5811-mock-tracker-restore.ts": 3698, - "5812-dyn-box-async-fields.ts": 3522, - "5813-mock-timers-module.ts": 3766, - "5814-mock-timers-date.ts": 3760, + "5800-broadcast-channel.ts": 3206, + "5801-broadcast-channel.cjs": 3035, + "5802-broadcast-channel-workers.ts": 3120, + "5803-worker-environment-data.ts": 3113, + "5804-worker-environment-data.cjs": 3000, + "5805-worker-receive-message-parent-port.ts": 3259, + "5806-worker-resource-limits.ts": 3191, + "5807-worker-error-values.ts": 3239, + "5808-worker-unhandled-rejections.ts": 3439, + "5809-process-exit-and-rejections.cjs": 3393, + "5810-mock-method-records.ts": 3670, + "5811-mock-tracker-restore.ts": 3216, + "5812-dyn-box-async-fields.ts": 2941, + "5813-mock-timers-module.ts": 3052, + "5814-mock-timers-date.ts": 3365, "5830-timers-promises-signal.ts": 3771, - "5831-util-types-brands.ts": 3347, - "5832-util-types-brands-dynamic.js": 3250, - "5833-url-search-params-iterators.ts": 2678, - "5834-url-search-params-iterators-dynamic.mjs": 2696, - "5835-util-format-integer-specifiers.ts": 2534, - "5836-url-search-params-tuple-pairs.ts": 2118, - "5837-util-format-json-circular.ts": 3117, - "5838-qs-stringify-bigint.ts": 2207, + "5831-util-types-brands.ts": 3300, + "5832-util-types-brands-dynamic.js": 3811, + "5833-url-search-params-iterators.ts": 3578, + "5834-url-search-params-iterators-dynamic.mjs": 3566, + "5835-util-format-integer-specifiers.ts": 2544, + "5836-url-search-params-tuple-pairs.ts": 2830, + "5837-util-format-json-circular.ts": 2387, + "5838-qs-stringify-bigint.ts": 3072, "5839-timers-promises-scheduler.ts": 2609, "5840-promise-with-resolvers-js.js": 2922, - "5841-json-typed-dyn-members.ts": 5467, - "5842-qs-parse-null-prototype.ts": 1774, - "5843-qs-parse-null-prototype-js.mjs": 1559, - "5844-date-unknown-values.ts": 3969, + "5841-json-typed-dyn-members.ts": 3536, + "5842-qs-parse-null-prototype.ts": 3138, + "5843-qs-parse-null-prototype-js.mjs": 2658, + "5844-date-unknown-values.ts": 3255, "5845-groupby-null-prototype.ts": 3675, "5846-events-esm-default-max.ts": 2633, "5847-events-cjs-default-max.cjs": 2823, @@ -2095,45 +2095,45 @@ "5854-array-from-async.ts": 3165, "5855-array-from-async-js.js": 3186, "5856-error-is-error.ts": 3631, - "5857-regexp-unicode-sets.ts": 3350, - "5858-disposable-stack.ts": 3050, - "5859-disposable-stack-js.js": 3100, + "5857-regexp-unicode-sets.ts": 2021, + "5858-disposable-stack.ts": 4753, + "5859-disposable-stack-js.js": 3636, "5860-url-ipv4-hosts.ts": 3030, - "5870-worker-thread-names.ts": 3106, - "5871-worker-untransferable.cjs": 2786, + "5870-worker-thread-names.ts": 3457, + "5871-worker-untransferable.cjs": 2368, "5872-readline-positional-create-interface.mjs": 2993, "5873-readline-promises-namespace.cjs": 2951, - "5874-worker-stdio-streams.ts": 2839, - "5875-worker-stdout-pipe.cjs": 2740, - "5879-worker-stdin.ts": 3158, + "5874-worker-stdio-streams.ts": 2974, + "5875-worker-stdout-pipe.cjs": 3115, + "5879-worker-stdin.ts": 3644, "5880-emitter-leak-warning-delivery.ts": 2660, - "5881-inspect-weak-collections.ts": 2615, - "5882-string-decoder-runtime-encoding.ts": 2541, - "5883-os-set-priority.ts": 2380, - "5884-inspect-layout-options.ts": 3108, + "5881-inspect-weak-collections.ts": 2621, + "5882-string-decoder-runtime-encoding.ts": 2742, + "5883-os-set-priority.ts": 2927, + "5884-inspect-layout-options.ts": 3552, "5885-events-max-listener-helpers.ts": 3645, - "5886-inspect-dates.ts": 2559, - "5887-inspect-typed-arrays.ts": 3448, - "5888-inspect-sorted.ts": 2998, + "5886-inspect-dates.ts": 2931, + "5887-inspect-typed-arrays.ts": 2476, + "5888-inspect-sorted.ts": 3227, "5889-timers-scheduler-signal.ts": 2549, "5890-while-string-length-counters.ts": 3080, "5892-buffer-write-utf16le-runs.ts": 3098, - "5900-float16-array.ts": 3000, - "5901-float16-array-js.js": 2900, - "5904-async-generator-completion.ts": 2950, - "5905-array-from-async-generator.ts": 2750, - "5906-array-from-async-generator-js.js": 2950, + "5900-float16-array.ts": 3586, + "5901-float16-array-js.js": 3449, + "5904-async-generator-completion.ts": 5816, + "5905-array-from-async-generator.ts": 2793, + "5906-array-from-async-generator-js.js": 3377, "5907-regex-groups-match-rows.ts": 3150, - "5910-set-prototype-of-primitive-object-kinds.ts": 2719, - "5911-dyn-class-to-primitive.ts": 2850, - "5912-dyn-class-conversion-methods.ts": 3251, - "5913-prototype-type-error-messages.ts": 2484, - "5914-dyn-in-class-prototype-members.ts": 3169, - "5915-dyn-error-string-conversions.ts": 3200, + "5910-set-prototype-of-primitive-object-kinds.ts": 2148, + "5911-dyn-class-to-primitive.ts": 6231, + "5912-dyn-class-conversion-methods.ts": 4317, + "5913-prototype-type-error-messages.ts": 2831, + "5914-dyn-in-class-prototype-members.ts": 2811, + "5915-dyn-error-string-conversions.ts": 3158, "5920-promise-try-args.ts": 3150, "5921-promise-try-args-js.js": 2112, - "5922-matchall-groups-callbacks.ts": 3650, - "5923-matchall-groups-js.js": 3970, + "5922-matchall-groups-callbacks.ts": 4259, + "5923-matchall-groups-js.js": 4523, "5924-js-literal-identity.js": 3064, "5925-class-view-identity-observers.ts": 2653, "5926-class-view-switch-js.js": 1690, @@ -2150,7 +2150,7 @@ "5936-checked-js-class-types.js": 2384, "5937-override-narrowed-union-returns.ts": 3039, "5938-object-literal-computed-keys-keep-methods.ts": 3195, - "5939-js-let-object-reassigned-wider.js": 1945, + "5939-js-let-object-reassigned-wider.js": 2362, "5940-callback-helper-specialization.ts": 3130, "5941-callback-specialization-recursion.ts": 3996, "5942-callback-specialization-throws.ts": 2908, @@ -2158,2534 +2158,2534 @@ "5944-js-fields-read-before-assignment.js": 4247, "5945-local-class-observed-methods.ts": 5063, "5946-nested-record-field-optional-writes.ts": 6045, - "5950-tuple-predicate-methods.ts": 5990, - "5951-result-never-widening.ts": 4710, + "5950-tuple-predicate-methods.ts": 3865, + "5951-result-never-widening.ts": 3022, "5952-record-missing-keys.ts": 6090, "5953-nan-coded-method-returns.ts": 4100, - "5955-any-promise-methods.js": 3940, - "5956-erased-generic-members.ts": 6730, - "5958-asserted-union-receiver.ts": 2430, - "5959-date-to-json.ts": 3330, - "5960-generic-mapped-types.ts": 2540, - "5970-net-connect-host-name.ts": 2400, - "5971-buffer-chunks-to-string.ts": 2700, - "5972-net-set-encoding-listeners.ts": 2550, - "5974-typeof-module-exports.cjs": 2000, + "5955-any-promise-methods.js": 3111, + "5956-erased-generic-members.ts": 5669, + "5958-asserted-union-receiver.ts": 1929, + "5959-date-to-json.ts": 2922, + "5960-generic-mapped-types.ts": 3167, + "5970-net-connect-host-name.ts": 1992, + "5971-buffer-chunks-to-string.ts": 3183, + "5972-net-set-encoding-listeners.ts": 2129, + "5974-typeof-module-exports.cjs": 2008, "5975-zlib-class-values.ts": 2800, - "5990-worker-uncloneable.mjs": 3283, - "5991-worker-async-dispose.mjs": 5699, - "5992-worker-thread-name-lifetime.mjs": 2687, + "5990-worker-uncloneable.mjs": 3202, + "5991-worker-async-dispose.mjs": 5853, + "5992-worker-thread-name-lifetime.mjs": 2058, "5993-array-length-loop-resizing.ts": 3187, "5994-array-length-sparse-loops.ts": 3292, "5995-array-dense-loop-boundaries.ts": 2596, - "600-closures-basic.ts": 2349, - "601-closures-loops.ts": 1788, - "602-closures-identity-recursion.ts": 2372, - "6020-class-extends-function-constructor.js": 4300, + "600-closures-basic.ts": 2637, + "601-closures-loops.ts": 2250, + "602-closures-identity-recursion.ts": 2821, + "6020-class-extends-function-constructor.js": 3026, "6021-asserted-literal-union-arm.ts": 3400, - "603-closures-rc-stress.ts": 1832, - "604-closures-for-of.ts": 2639, - "605-closures-forward-capture-tdz.ts": 3277, - "700-classes-basic.ts": 2530, - "701-classes-composition.ts": 2357, - "702-classes-this-capture.ts": 2140, - "703-classes-rc-stress.ts": 2186, - "710-inheritance-basics.ts": 2728, - "711-inheritance-dispatch.ts": 2360, - "712-inheritance-instanceof.ts": 2715, - "713-inheritance-rc-stress.ts": 2448, - "720-accessors-basics.ts": 2562, - "721-accessors-eval-order.ts": 2406, - "722-accessors-inheritance.ts": 2543, - "723-accessors-rc-stress.ts": 2054, - "750-cycle-closure-box.ts": 2227, - "751-cycle-records-mutual.ts": 2118, - "752-cycle-classes.ts": 2207, - "753-cycle-owned-arrays.ts": 2148, - "754-cycle-external-ref.ts": 2118, - "755-cycle-async-promise.ts": 2303, - "756-cycle-inheritance.ts": 2162, - "757-cycle-cross-generation.ts": 2893, - "762-any-boundary.ts": 2310, - "764-any-async.ts": 2553, - "765-any-optional-chain.ts": 2593, - "766-any-union-boundary.ts": 3292, - "767-string-literal-keys.ts": 2238, - "768-any-uninitialized.ts": 2264, - "800-switch-basics.ts": 2244, - "801-switch-lazy-tests.ts": 2610, - "802-switch-loops.ts": 2329, - "803-switch-rc-stress.ts": 2314, - "804-switch-braced-blocks.ts": 2594, - "810-do-while.ts": 2658, - "820-multi-decl.ts": 2315, - "830-let-uninitialized.ts": 2519, - "900-records-basics.ts": 2736, - "901-records-eval-order.ts": 2544, - "902-records-functions-closures.ts": 2645, - "903-records-rc-stress.ts": 2871, - "904-records-optional-fields.ts": 1801, - "905-records-optional-rc-stress.ts": 2425, - "906-records-utility-types.ts": 2878, - "907-records-utility-generics.ts": 2738, - "908-records-index-signatures.ts": 2545, - "909-records-index-json.ts": 2019, - "910-records-index-rc-stress.ts": 1878, - "911-records-index-dot-access.ts": 3510, - "912-unknown-slots.ts": 2427, - "913-records-index-iteration.ts": 3462, - "914-records-from-entries.ts": 3129, - "915-unknown-tostring-eq.ts": 3072, - "916-unknown-bytes.ts": 2767, - "917-record-array-index-dot.ts": 2445, - "950-modules-basic/main.ts": 2473, - "951-modules-diamond/main.ts": 1969, - "952-modules-cross/main.ts": 2427, - "953-modules-default/main.ts": 2409, - "954-modules-reexport/main.ts": 2586, - "957-builtins-namespace.ts": 2102, - "960-generics-basics.ts": 2487, - "961-generics-recursion.ts": 2589, - "962-generics-closures.ts": 2098, - "963-generics-modules/main.ts": 2726, - "964-generics-rc-stress.ts": 2825, - "965-generics-async.ts": 2802, - "965-unions-retag.ts": 2772, - "966-unions-retag-rc-stress.ts": 2336, - "967-record-field-widening.ts": 2097, - "969-unions-arm-matrix.ts": 2419, - "970-unions-basics.ts": 2692, - "971-unions-switch.ts": 2491, - "972-unions-nested.ts": 3069, - "973-unions-rc-stress.ts": 2478, - "974-unions-modules/main.ts": 2052, - "975-unions-undefined.ts": 2811, - "976-unions-null.ts": 2344, - "977-unions-unit-rc-stress.ts": 2013, - "978-unions-nullish.ts": 2330, - "979-unions-optional-chaining.ts": 2341, - "980-exceptions-basics.ts": 1988, - "981-exceptions-values.ts": 2615, - "982-exceptions-rc-stress.ts": 2259, - "983-exceptions-control-flow.ts": 2004, - "984-exceptions-finally.ts": 2140, - "985-exceptions-call-chains.ts": 2787, - "986-exceptions-uncaught.ts": 2529, - "987-exceptions-result-unions.ts": 2390, - "990-process-basics.ts": 2623, - "991-process-exit.ts": 2155, - "992-fs-roundtrip.ts": 2680, - "993-fs-readdir.ts": 2781, - "994-fs-errors.ts": 2322, - "995-fs-uncaught.ts": 2134, - "996-fs-rc-stress.ts": 2214, - "997-fs-modules/main.ts": 2230, - "998-process-env.ts": 2196, - "abstract-property-dispatch.ts": 2956, - "arguments-arrow-capture.mjs": 2802, - "arguments-reexport/main.ts": 2655, - "array-argument-lifetimes-exits.ts": 2164, - "array-argument-lifetimes-mutation.ts": 2547, - "array-argument-lifetimes-strings.ts": 2738, - "array-argument-lifetimes-values.ts": 3081, - "array-buffer-conversions.js": 1978, - "array-buffer-storage.ts": 3147, - "array-checked-callback-results.mjs": 3053, - "array-checked-constructor.js": 3001, - "array-concat-widening.ts": 2947, + "603-closures-rc-stress.ts": 2800, + "604-closures-for-of.ts": 1980, + "605-closures-forward-capture-tdz.ts": 2765, + "700-classes-basic.ts": 1650, + "701-classes-composition.ts": 2262, + "702-classes-this-capture.ts": 1945, + "703-classes-rc-stress.ts": 2498, + "710-inheritance-basics.ts": 1936, + "711-inheritance-dispatch.ts": 2643, + "712-inheritance-instanceof.ts": 2608, + "713-inheritance-rc-stress.ts": 2855, + "720-accessors-basics.ts": 2703, + "721-accessors-eval-order.ts": 2000, + "722-accessors-inheritance.ts": 2558, + "723-accessors-rc-stress.ts": 2721, + "750-cycle-closure-box.ts": 2521, + "751-cycle-records-mutual.ts": 2024, + "752-cycle-classes.ts": 2646, + "753-cycle-owned-arrays.ts": 2810, + "754-cycle-external-ref.ts": 2655, + "755-cycle-async-promise.ts": 2228, + "756-cycle-inheritance.ts": 2657, + "757-cycle-cross-generation.ts": 2901, + "762-any-boundary.ts": 2854, + "764-any-async.ts": 2890, + "765-any-optional-chain.ts": 2394, + "766-any-union-boundary.ts": 2672, + "767-string-literal-keys.ts": 2479, + "768-any-uninitialized.ts": 2844, + "800-switch-basics.ts": 2758, + "801-switch-lazy-tests.ts": 2588, + "802-switch-loops.ts": 1780, + "803-switch-rc-stress.ts": 2015, + "804-switch-braced-blocks.ts": 2537, + "810-do-while.ts": 1969, + "820-multi-decl.ts": 1629, + "830-let-uninitialized.ts": 2899, + "900-records-basics.ts": 2778, + "901-records-eval-order.ts": 2686, + "902-records-functions-closures.ts": 2628, + "903-records-rc-stress.ts": 2550, + "904-records-optional-fields.ts": 3083, + "905-records-optional-rc-stress.ts": 2791, + "906-records-utility-types.ts": 1783, + "907-records-utility-generics.ts": 2604, + "908-records-index-signatures.ts": 2041, + "909-records-index-json.ts": 3081, + "910-records-index-rc-stress.ts": 2746, + "911-records-index-dot-access.ts": 3174, + "912-unknown-slots.ts": 2915, + "913-records-index-iteration.ts": 3669, + "914-records-from-entries.ts": 3427, + "915-unknown-tostring-eq.ts": 3373, + "916-unknown-bytes.ts": 2791, + "917-record-array-index-dot.ts": 2745, + "950-modules-basic/main.ts": 2721, + "951-modules-diamond/main.ts": 1492, + "952-modules-cross/main.ts": 1431, + "953-modules-default/main.ts": 2552, + "954-modules-reexport/main.ts": 2362, + "957-builtins-namespace.ts": 2216, + "960-generics-basics.ts": 2982, + "961-generics-recursion.ts": 2893, + "962-generics-closures.ts": 2684, + "963-generics-modules/main.ts": 2595, + "964-generics-rc-stress.ts": 3029, + "965-generics-async.ts": 3085, + "965-unions-retag.ts": 2457, + "966-unions-retag-rc-stress.ts": 2098, + "967-record-field-widening.ts": 2939, + "969-unions-arm-matrix.ts": 2998, + "970-unions-basics.ts": 2779, + "971-unions-switch.ts": 2261, + "972-unions-nested.ts": 2825, + "973-unions-rc-stress.ts": 2576, + "974-unions-modules/main.ts": 2186, + "975-unions-undefined.ts": 2396, + "976-unions-null.ts": 2274, + "977-unions-unit-rc-stress.ts": 2486, + "978-unions-nullish.ts": 2487, + "979-unions-optional-chaining.ts": 2987, + "980-exceptions-basics.ts": 2385, + "981-exceptions-values.ts": 2867, + "982-exceptions-rc-stress.ts": 1550, + "983-exceptions-control-flow.ts": 2778, + "984-exceptions-finally.ts": 2144, + "985-exceptions-call-chains.ts": 3115, + "986-exceptions-uncaught.ts": 2615, + "987-exceptions-result-unions.ts": 1576, + "990-process-basics.ts": 2148, + "991-process-exit.ts": 2021, + "992-fs-roundtrip.ts": 2662, + "993-fs-readdir.ts": 2790, + "994-fs-errors.ts": 2954, + "995-fs-uncaught.ts": 2485, + "996-fs-rc-stress.ts": 2801, + "997-fs-modules/main.ts": 1791, + "998-process-env.ts": 2322, + "abstract-property-dispatch.ts": 3676, + "arguments-arrow-capture.mjs": 2969, + "arguments-reexport/main.ts": 2670, + "array-argument-lifetimes-exits.ts": 3229, + "array-argument-lifetimes-mutation.ts": 2355, + "array-argument-lifetimes-strings.ts": 2875, + "array-argument-lifetimes-values.ts": 3135, + "array-buffer-conversions.js": 2768, + "array-buffer-storage.ts": 2184, + "array-checked-callback-results.mjs": 3207, + "array-checked-constructor.js": 2168, + "array-concat-widening.ts": 3084, "array-deque-unshift.ts": 3209, - "array-element-compound-updates.ts": 3325, - "array-fill-unit-values.ts": 2281, - "array-from-checked.js": 3228, - "array-from-value.mjs": 2658, - "array-isarray-value/main.js": 2180, - "array-numeric-own-keys.ts": 2770, - "array-optional-number-write-index.ts": 2584, - "array-primitive-ordering.ts": 3806, + "array-element-compound-updates.ts": 4339, + "array-fill-unit-values.ts": 2510, + "array-from-checked.js": 4274, + "array-from-value.mjs": 3224, + "array-isarray-value/main.js": 2742, + "array-numeric-own-keys.ts": 1884, + "array-optional-number-write-index.ts": 2617, + "array-primitive-ordering.ts": 2544, "array-queue-head-room.ts": 3344, - "array-read-helper-effects.ts": 3223, - "array-refined-storage.ts": 3132, - "array-sort-dense-effects.ts": 2813, - "array-sort-dense-values.ts": 3705, - "array-sort-holes-published.ts": 6604, - "array-sort-runs.ts": 5713, - "array-sort-runtime-comparator.ts": 5050, - "array-sort-unknown-comparator.ts": 1888, - "array-storage-transitions.ts": 3122, - "array-truncate-reuse.ts": 2475, - "async-backend-factory.mjs": 2638, - "async-local-typed-results.ts": 2579, - "atomics-integer-operations.ts": 3320, - "bigint-checked-casts.ts": 2572, - "bigint-checked-storage.js": 3519, - "bigint-union-conversion.ts": 2774, - "boxed-error-rethrows.mjs": 2034, - "buffer-codec-boundaries.ts": 3206, - "buffer-primitive-predicate.ts": 2712, - "builtin-prototype-method-values.mjs": 3158, - "byte-loop-bounds.ts": 2922, - "byte-number-pipeline.ts": 2738, - "byte-record-windows.ts": 2668, - "call-lifetimes-argument-order.ts": 1933, - "call-lifetimes-control-flow.ts": 2653, - "call-lifetimes-owned-boundaries.ts": 2979, - "call-lifetimes-projections.ts": 3011, - "call-lifetimes-union-values.ts": 2366, - "call-lifetimes-virtual-optionals.ts": 2747, - "callable-module-members.mjs": 2647, - "callable-properties.mjs": 3266, - "callable-property-cycles.js": 2241, - "callable-reexport/main.ts": 2809, - "captured-class-refinement.ts": 2580, - "catch-capture.ts": 2050, - "caught-class-identity.ts": 3173, - "caught-standalone-class.ts": 2858, - "caught-system-error-fields.ts": 2612, + "array-read-helper-effects.ts": 2217, + "array-refined-storage.ts": 2827, + "array-sort-dense-effects.ts": 3621, + "array-sort-dense-values.ts": 3004, + "array-sort-holes-published.ts": 7729, + "array-sort-runs.ts": 4117, + "array-sort-runtime-comparator.ts": 4714, + "array-sort-unknown-comparator.ts": 2824, + "array-storage-transitions.ts": 3984, + "array-truncate-reuse.ts": 2234, + "async-backend-factory.mjs": 1807, + "async-local-typed-results.ts": 2185, + "atomics-integer-operations.ts": 2603, + "bigint-checked-casts.ts": 2636, + "bigint-checked-storage.js": 3528, + "bigint-union-conversion.ts": 2763, + "boxed-error-rethrows.mjs": 2627, + "buffer-codec-boundaries.ts": 2453, + "buffer-primitive-predicate.ts": 2183, + "builtin-prototype-method-values.mjs": 3361, + "byte-loop-bounds.ts": 3029, + "byte-number-pipeline.ts": 3197, + "byte-record-windows.ts": 2142, + "call-lifetimes-argument-order.ts": 2451, + "call-lifetimes-control-flow.ts": 2879, + "call-lifetimes-owned-boundaries.ts": 3007, + "call-lifetimes-projections.ts": 1722, + "call-lifetimes-union-values.ts": 2751, + "call-lifetimes-virtual-optionals.ts": 3153, + "callable-module-members.mjs": 2485, + "callable-properties.mjs": 3432, + "callable-property-cycles.js": 3096, + "callable-reexport/main.ts": 3039, + "captured-class-refinement.ts": 3032, + "catch-capture.ts": 2928, + "caught-class-identity.ts": 2572, + "caught-standalone-class.ts": 3034, + "caught-system-error-fields.ts": 2540, "checked-addition.js": 2460, - "checked-any-addition.ts": 2551, - "checked-array-assignment.ts": 2273, - "checked-array-flat/main.ts": 2256, - "checked-bitwise/main.js": 2560, - "checked-builder-cycles.js": 3055, - "checked-byte-storage/main.ts": 3171, - "checked-callback-options.ts": 2385, - "checked-class-descriptors.mjs": 3021, - "checked-class-factory.mjs": 2266, - "checked-collection-iterators.ts": 2906, - "checked-collection-symbol-methods.ts": 2575, - "checked-dispatch-input-lifetimes.js": 3038, - "checked-increment/main.js": 2332, - "checked-inherited-fields.ts": 2382, - "checked-iterator-consumption.js": 3603, - "checked-numeric-arithmetic.js": 2783, - "checked-object-module-alias.js": 2898, - "checked-optional-calls.mjs": 2763, - "checked-promise-recovery.ts": 2689, - "checked-proxy-callback/main.ts": 2754, - "checked-record-constructor.ts": 2506, - "checked-renderer-defaults.js": 2308, - "checked-rest-function-adapters.js": 2312, - "checked-storage-transitions.js": 2557, - "checked-symbol-array.ts": 1859, - "checked-value-input-lifetimes.ts": 2728, - "class-accessor-returned-function.js": 2068, - "class-array-optional-return.ts": 2589, - "class-bracket-method-calls.js": 2833, - "class-brand-overload.js": 2700, - "class-callback-replacement.js": 3640, - "class-callback-storage.ts": 3803, - "class-checked-composites.ts": 2846, - "class-checked-upcast.ts": 2625, - "class-collection-insertion.ts": 3901, - "class-computed-presence.ts": 3018, - "class-computed-symbols.js": 3495, - "class-covariant-returns.ts": 3069, - "class-curried-factory.mjs": 3062, - "class-data-descriptors.js": 3732, - "class-factory-inherited-statics.mjs": 2710, - "class-factory-parameter-base.mjs": 2492, - "class-factory-record-base.mjs": 4680, - "class-factory-recursive-statics.mjs": 2820, - "class-factory-static-members.mjs": 2990, - "class-function-base/main.js": 2706, - "class-instance-constructor.js": 2628, - "class-interface-protocols.ts": 3911, - "class-interface-refinements.ts": 2967, - "class-json-checked.ts": 2638, - "class-local-function-base.mjs": 2970, - "class-method-spreads.ts": 3142, - "class-narrowed-views.ts": 2862, - "class-property-call-values.mjs": 3343, - "class-prototype-data.js": 3393, - "class-prototype-descriptor-copy.mjs": 3870, - "class-specialized-computed-base.mjs": 3439, - "class-static-data.js": 2153, - "class-subclass-assertions.ts": 2814, - "class-super-surplus-spread.mjs": 2024, - "class-symbol-accessors.ts": 2458, - "class-symbol-cache.mjs": 2883, - "class-value-constructor-exceptions.ts": 2222, + "checked-any-addition.ts": 2597, + "checked-array-assignment.ts": 1938, + "checked-array-flat/main.ts": 2376, + "checked-bitwise/main.js": 2931, + "checked-builder-cycles.js": 2124, + "checked-byte-storage/main.ts": 2136, + "checked-callback-options.ts": 2655, + "checked-class-descriptors.mjs": 3730, + "checked-class-factory.mjs": 2259, + "checked-collection-iterators.ts": 3189, + "checked-collection-symbol-methods.ts": 2758, + "checked-dispatch-input-lifetimes.js": 3290, + "checked-increment/main.js": 2209, + "checked-inherited-fields.ts": 1885, + "checked-iterator-consumption.js": 3562, + "checked-numeric-arithmetic.js": 2775, + "checked-object-module-alias.js": 2993, + "checked-optional-calls.mjs": 2857, + "checked-promise-recovery.ts": 2965, + "checked-proxy-callback/main.ts": 2460, + "checked-record-constructor.ts": 2536, + "checked-renderer-defaults.js": 2974, + "checked-rest-function-adapters.js": 2402, + "checked-storage-transitions.js": 3227, + "checked-symbol-array.ts": 2138, + "checked-value-input-lifetimes.ts": 2968, + "class-accessor-returned-function.js": 2548, + "class-array-optional-return.ts": 2505, + "class-bracket-method-calls.js": 3232, + "class-brand-overload.js": 2772, + "class-callback-replacement.js": 4256, + "class-callback-storage.ts": 3103, + "class-checked-composites.ts": 2644, + "class-checked-upcast.ts": 2728, + "class-collection-insertion.ts": 4030, + "class-computed-presence.ts": 3380, + "class-computed-symbols.js": 2436, + "class-covariant-returns.ts": 3091, + "class-curried-factory.mjs": 3427, + "class-data-descriptors.js": 3815, + "class-factory-inherited-statics.mjs": 3016, + "class-factory-parameter-base.mjs": 3162, + "class-factory-record-base.mjs": 5127, + "class-factory-recursive-statics.mjs": 2561, + "class-factory-static-members.mjs": 3200, + "class-function-base/main.js": 3392, + "class-instance-constructor.js": 3735, + "class-interface-protocols.ts": 5264, + "class-interface-refinements.ts": 2054, + "class-json-checked.ts": 2470, + "class-local-function-base.mjs": 3094, + "class-method-spreads.ts": 4098, + "class-narrowed-views.ts": 1811, + "class-property-call-values.mjs": 3042, + "class-prototype-data.js": 2959, + "class-prototype-descriptor-copy.mjs": 3884, + "class-specialized-computed-base.mjs": 3695, + "class-static-data.js": 2083, + "class-subclass-assertions.ts": 2716, + "class-super-surplus-spread.mjs": 3129, + "class-symbol-accessors.ts": 2288, + "class-symbol-cache.mjs": 3599, + "class-value-constructor-exceptions.ts": 2725, "closed-virtual-dispatch-modules/main.ts": 2752, "closed-virtual-dispatch.ts": 3200, - "closure-nullable-union-return.ts": 2472, - "closure-union-locals.ts": 2465, - "collection-array-cycles.ts": 2552, - "collection-array-maps.ts": 3481, - "collection-array-missing.ts": 2873, - "collection-array-sets.ts": 3383, - "collection-copy-identities.ts": 2585, - "collection-data-unions.ts": 2565, - "collection-ingestion-mappers.ts": 3262, - "collection-ingestion-protocol/main.ts": 3814, - "collection-ingestion-references.ts": 3375, - "collection-ingestion.ts": 3053, - "collection-storage-copies.ts": 3096, - "collection-value-keys.ts": 3176, - "compound-field-receivers.ts": 2272, - "compound-presence-guards.ts": 3094, - "conditional-tuple-destructuring.ts": 2487, - "console-imports.cjs": 2314, - "console-native-value.js": 2165, - "const-enum-module-cycle/main.ts": 2618, - "constant-callback-dispatch.ts": 2539, - "constant-module-globals/main.ts": 2455, - "constant-number-remainders.ts": 2350, - "constructed-class-dispatch.ts": 3014, - "contextual-array-union-write.ts": 5379, - "contextual-return-layouts.ts": 2919, - "counted-loop-numbers.ts": 2515, - "counted-loop-storage.ts": 2556, - "crypto-hash-optional-input.ts": 2860, - "cycle-generations-long-lived.ts": 2691, - "cycle-growth-yield.ts": 2929, - "date-checked-native.js": 2323, - "declared-index-spread.ts": 2660, - "deep-reference-teardown.ts": 3136, - "default-undefined-parameters.ts": 2589, - "deferred-field-updates.ts": 2347, - "deferred-registry-many.ts": 2661, - "derived-numeric-updates.ts": 1907, - "destructure-call-assignment.js": 2267, - "destructure-inferred-row-defaults.js": 2538, - "destructure-union-arrays.ts": 2379, - "dynamic-function-descriptors.js": 2763, - "error-cause-writes.js": 2954, - "error-inherited-message.mjs": 2631, - "error-inherited-name.mjs": 2285, - "error-property-writes.mjs": 2636, - "error-prototype-tostring.js": 3155, - "error-stack-frames.ts": 2206, - "error-stack-limit.ts": 2510, - "error-tostring-overrides.ts": 2305, - "error-values-inspect.ts": 2398, - "exact-index-round-trip.ts": 2801, - "expression-runtime-values.ts": 2027, - "fiber-switch-stress.ts": 2898, - "fiberless-async-ordering.ts": 2908, - "fiberless-async-unhandled.ts": 2133, - "field-assignment-values.ts": 2107, - "file-handle-values.ts": 2357, - "file-read-storage.ts": 2439, - "file-url-percent-decoding.ts": 2222, - "final-field-borrows.ts": 2890, - "for-multiple-bindings.ts": 2286, - "for-multiple-lexical-bindings.ts": 2283, - "for-of-checked-iterator.js": 3511, - "for-of-subclass-elements.ts": 2219, - "forward-generic-signatures.ts": 2294, - "fresh-array-union-layout.js": 2480, - "frozen-checked-dictionaries.mjs": 2629, - "fs-native-realpath.ts": 2351, + "closure-nullable-union-return.ts": 2492, + "closure-union-locals.ts": 2959, + "collection-array-cycles.ts": 3095, + "collection-array-maps.ts": 3559, + "collection-array-missing.ts": 3686, + "collection-array-sets.ts": 3501, + "collection-copy-identities.ts": 2360, + "collection-data-unions.ts": 3003, + "collection-ingestion-mappers.ts": 2535, + "collection-ingestion-protocol/main.ts": 3823, + "collection-ingestion-references.ts": 2342, + "collection-ingestion.ts": 3093, + "collection-storage-copies.ts": 2080, + "collection-value-keys.ts": 2956, + "compound-field-receivers.ts": 1671, + "compound-presence-guards.ts": 3200, + "conditional-tuple-destructuring.ts": 2750, + "console-imports.cjs": 1673, + "console-native-value.js": 2807, + "const-enum-module-cycle/main.ts": 2704, + "constant-callback-dispatch.ts": 1960, + "constant-module-globals/main.ts": 1705, + "constant-number-remainders.ts": 2349, + "constructed-class-dispatch.ts": 3130, + "contextual-array-union-write.ts": 6681, + "contextual-return-layouts.ts": 3422, + "counted-loop-numbers.ts": 2709, + "counted-loop-storage.ts": 2965, + "crypto-hash-optional-input.ts": 2865, + "cycle-generations-long-lived.ts": 2572, + "cycle-growth-yield.ts": 3019, + "date-checked-native.js": 2742, + "declared-index-spread.ts": 3806, + "deep-reference-teardown.ts": 3156, + "default-undefined-parameters.ts": 2963, + "deferred-field-updates.ts": 1865, + "deferred-registry-many.ts": 3051, + "derived-numeric-updates.ts": 1958, + "destructure-call-assignment.js": 2640, + "destructure-inferred-row-defaults.js": 2122, + "destructure-union-arrays.ts": 2784, + "dynamic-function-descriptors.js": 2749, + "error-cause-writes.js": 2022, + "error-inherited-message.mjs": 2684, + "error-inherited-name.mjs": 2378, + "error-property-writes.mjs": 2676, + "error-prototype-tostring.js": 3103, + "error-stack-frames.ts": 2531, + "error-stack-limit.ts": 2338, + "error-tostring-overrides.ts": 2421, + "error-values-inspect.ts": 2394, + "exact-index-round-trip.ts": 2708, + "expression-runtime-values.ts": 2672, + "fiber-switch-stress.ts": 2404, + "fiberless-async-ordering.ts": 2698, + "fiberless-async-unhandled.ts": 2605, + "field-assignment-values.ts": 2753, + "file-handle-values.ts": 2888, + "file-read-storage.ts": 3335, + "file-url-percent-decoding.ts": 1678, + "final-field-borrows.ts": 2810, + "for-multiple-bindings.ts": 2621, + "for-multiple-lexical-bindings.ts": 2696, + "for-of-checked-iterator.js": 2735, + "for-of-subclass-elements.ts": 2538, + "forward-generic-signatures.ts": 1734, + "fresh-array-union-layout.js": 2661, + "frozen-checked-dictionaries.mjs": 2513, + "fs-native-realpath.ts": 2900, "fs-null-byte-paths-js.cjs": 2166, "fs-null-byte-paths.ts": 3560, - "fs-read-encodings.ts": 2505, + "fs-read-encodings.ts": 2192, "fs-read-utf8-edges.ts": 3494, "fs-read-utf8-handle-forms.ts": 1894, - "fs-remove-readonly.ts": 2354, - "fs-write-string-bytes-union.ts": 2286, - "function-apply-value.mjs": 2558, - "function-constructor-global.mjs": 1848, - "function-constructor-kinds/main.js": 2532, - "function-custom-prototype.js": 2604, - "function-custom-to-string.mjs": 2607, - "function-object-assign.js": 2509, - "function-own-prototype/main.js": 2423, - "generator-checked-protocol.ts": 2631, - "generator-checked-return.js": 2326, - "generator-custom-delegation/main.ts": 3343, - "generator-default-return-pattern.ts": 2653, - "generator-delegation-values.ts": 2368, - "generator-inferred-date.js": 2465, - "generator-mixed-checked-channels.ts": 2662, - "generator-untyped-consumer/main.ts": 2958, - "generic-base-specializations.ts": 2073, - "generic-binding-ownership.ts": 2817, - "generic-class-js-functions/main.ts": 2051, - "generic-class-recovery.ts": 2415, - "generic-namespace-factories/main.ts": 2073, - "generic-nullable-collections.ts": 2677, - "generic-pattern-bindings.ts": 2698, - "generic-record-index.ts": 2753, - "generic-visitor-void.ts": 2405, + "fs-remove-readonly.ts": 2005, + "fs-write-string-bytes-union.ts": 2781, + "function-apply-value.mjs": 2795, + "function-constructor-global.mjs": 2338, + "function-constructor-kinds/main.js": 3030, + "function-custom-prototype.js": 2801, + "function-custom-to-string.mjs": 1937, + "function-object-assign.js": 1754, + "function-own-prototype/main.js": 2470, + "generator-checked-protocol.ts": 2909, + "generator-checked-return.js": 3084, + "generator-custom-delegation/main.ts": 5038, + "generator-default-return-pattern.ts": 2685, + "generator-delegation-values.ts": 1962, + "generator-inferred-date.js": 3181, + "generator-mixed-checked-channels.ts": 2887, + "generator-untyped-consumer/main.ts": 2216, + "generic-base-specializations.ts": 2930, + "generic-binding-ownership.ts": 2565, + "generic-class-js-functions/main.ts": 2055, + "generic-class-recovery.ts": 2723, + "generic-namespace-factories/main.ts": 2103, + "generic-nullable-collections.ts": 2282, + "generic-pattern-bindings.ts": 2536, + "generic-record-index.ts": 2488, + "generic-visitor-void.ts": 2848, "global-accumulator-loops.ts": 2271, - "global-error-subclasses.ts": 1773, - "global-runtime-probes.js": 2288, - "global-stored-probes.js": 2726, - "global-string-cache/main.js": 1889, - "global-symbol-cache/main.js": 3399, - "guarded-native-iterables.ts": 2496, - "heap-input-aliases.ts": 2746, - "heap-input-collections.ts": 2558, - "in-array-runtime-index.ts": 2579, - "indexed-assignment-values.js": 2971, - "indexed-assignment-values.ts": 1852, - "indexed-element-field-reads.ts": 2452, - "inferred-array-assignment-values.mjs": 2352, - "inferred-class-default.mjs": 2460, - "inferred-compound-values.mjs": 2473, - "inferred-conditional-class.mjs": 2635, - "inferred-error-fields.js": 2509, - "inferred-map-patterns.mjs": 2353, - "inferred-method-override.js": 2137, - "inferred-partial-destructuring.mjs": 2205, - "inferred-primitive-properties.mjs": 2135, - "inferred-record-return.mjs": 1793, - "inferred-recursive-record.mjs": 1833, - "inferred-undefined-field.mjs": 1777, - "input-lifetime-intervals.ts": 2714, - "input-lifetimes-modules/main.ts": 3258, - "instanceof-class-record-union.ts": 2400, - "integer-flow-arithmetic.ts": 3652, - "integer-loop-forms.ts": 2368, - "integer-view-control.ts": 1809, - "integer-view-numbers.ts": 2394, - "integer-view-storage.ts": 2439, - "intl-grapheme-conformance/main.ts": 3718, - "intl-grapheme.ts": 2449, - "iterator-typed-returns.ts": 3400, - "js-abort-portable.js": 2829, - "js-array-constructor.js": 3163, - "js-array-default-buffer.js": 2537, - "js-array-iterators.js": 2559, - "js-arrow-bind.cjs": 3343, - "js-buffer-callback-brand.cjs": 2262, - "js-callable-proxy.js": 3516, - "js-chained-native-results.mjs": 2641, - "js-checked-array-iterator.js": 2670, - "js-checked-array-reference.js": 2270, - "js-checked-number-negation.mjs": 1915, - "js-checked-sort-result.js": 2373, - "js-child-error-listener.cjs": 2357, - "js-cjs-callable-snapshots/main.cjs": 1981, - "js-class-added-parameters.js": 2472, - "js-class-checked-overrides.js": 2571, - "js-class-computed-fields.js": 1830, - "js-class-enumeration.js": 3296, - "js-class-field-accessor-override.js": 2567, - "js-class-fluent-overrides.js": 2822, - "js-class-late-method-values.js": 2309, - "js-class-member-dispatch.js": 3016, - "js-class-return-shapes.js": 2231, - "js-class-shadowed-methods.js": 2942, - "js-class-stored-method-receiver.js": 2382, - "js-class-subclass-properties.js": 3695, - "js-class-symbol-spread.cjs": 2704, - "js-computed-prototype-additions.js": 3142, - "js-constructor-returned-callable.js": 2605, - "js-constructor-spread.js": 2289, - "js-dataview-dispatch.js": 2273, - "js-declared-fields.cjs": 3263, - "js-default-listener-arguments.cjs": 2549, - "js-default-options/main.ts": 3044, - "js-deferred-field-initializers.js": 2121, - "js-deferred-registry-effects.js": 2381, - "js-derived-constructor-hoisting.js": 1805, - "js-dormant-array-write.js": 1888, - "js-dormant-overrides.js": 2569, - "js-expando-records.js": 2454, - "js-implicit-call-results.js": 3064, - "js-inferred-callback-exports/main.js": 3830, - "js-inferred-class-array-return.js": 2570, - "js-inferred-object-values.js": 2380, - "js-inherited-field-storage.js": 3121, - "js-inherited-parameter-abi.js": 2210, - "js-iterable-spread.js": 2950, - "js-loose-dynamic-primitives.js": 1960, - "js-map-object-seeds.js": 2610, - "js-member-increment.js": 2926, - "js-module-function-values.js": 2014, - "js-mutable-null-members.js": 2370, - "js-nested-native-descriptors.js": 2412, - "js-normalize-dispatch.js": 2793, - "js-nullish-inherited-fields.mjs": 2710, - "js-object-receiver-storage.js": 2613, - "js-object-returning-constructors.mjs": 2186, - "js-object-shared-arrays.js": 2465, - "js-omitted-typed-arguments.js": 2236, - "js-open-binding-writes.js": 1787, - "js-optional-class-fields.js": 2266, - "js-optional-member-call.js": 1883, - "js-primitive-union-addition.js": 2256, - "js-promise-all-values.js": 3079, - "js-promise-catch-handler.js": 1749, - "js-promise-finally-order.js": 1913, - "js-promise-pending-reactions.js": 2644, - "js-prototype-host-boundary.js": 2224, - "js-reflect-receivers.js": 3119, - "js-regex-record-captures.js": 2010, - "js-scalar-iterables.js": 2477, - "js-shared-method-dispatch.js": 2033, - "js-specialized-field-method.js": 2335, - "js-static-accessors.js": 2520, - "js-static-method-values.js": 2194, - "js-static-registries.cjs": 2703, - "js-super-accessor-initialization.js": 2100, - "js-uninitialized-native-fields.js": 2180, - "json-guarded-map-values.ts": 2374, - "json-output-bulk.ts": 2827, - "json-runtime-options.mjs": 1997, - "json-stringify-value.js": 2563, - "json-typed-parse-direct.ts": 2355, + "global-error-subclasses.ts": 1850, + "global-runtime-probes.js": 3085, + "global-stored-probes.js": 3029, + "global-string-cache/main.js": 2487, + "global-symbol-cache/main.js": 2631, + "guarded-native-iterables.ts": 2969, + "heap-input-aliases.ts": 2864, + "heap-input-collections.ts": 2900, + "in-array-runtime-index.ts": 3065, + "indexed-assignment-values.js": 2826, + "indexed-assignment-values.ts": 1639, + "indexed-element-field-reads.ts": 1506, + "inferred-array-assignment-values.mjs": 2520, + "inferred-class-default.mjs": 2339, + "inferred-compound-values.mjs": 2708, + "inferred-conditional-class.mjs": 2429, + "inferred-error-fields.js": 2383, + "inferred-map-patterns.mjs": 2476, + "inferred-method-override.js": 2284, + "inferred-partial-destructuring.mjs": 1972, + "inferred-primitive-properties.mjs": 2268, + "inferred-record-return.mjs": 2543, + "inferred-recursive-record.mjs": 2822, + "inferred-undefined-field.mjs": 2615, + "input-lifetime-intervals.ts": 2188, + "input-lifetimes-modules/main.ts": 2672, + "instanceof-class-record-union.ts": 2441, + "integer-flow-arithmetic.ts": 1990, + "integer-loop-forms.ts": 2426, + "integer-view-control.ts": 2085, + "integer-view-numbers.ts": 2088, + "integer-view-storage.ts": 2560, + "intl-grapheme-conformance/main.ts": 4354, + "intl-grapheme.ts": 1787, + "iterator-typed-returns.ts": 2556, + "js-abort-portable.js": 3289, + "js-array-constructor.js": 3326, + "js-array-default-buffer.js": 2785, + "js-array-iterators.js": 2367, + "js-arrow-bind.cjs": 3832, + "js-buffer-callback-brand.cjs": 2996, + "js-callable-proxy.js": 3619, + "js-chained-native-results.mjs": 2794, + "js-checked-array-iterator.js": 2235, + "js-checked-array-reference.js": 3562, + "js-checked-number-negation.mjs": 2819, + "js-checked-sort-result.js": 2743, + "js-child-error-listener.cjs": 2228, + "js-cjs-callable-snapshots/main.cjs": 2256, + "js-class-added-parameters.js": 2567, + "js-class-checked-overrides.js": 2547, + "js-class-computed-fields.js": 2943, + "js-class-enumeration.js": 3714, + "js-class-field-accessor-override.js": 3000, + "js-class-fluent-overrides.js": 2749, + "js-class-late-method-values.js": 2358, + "js-class-member-dispatch.js": 3594, + "js-class-return-shapes.js": 3435, + "js-class-shadowed-methods.js": 3639, + "js-class-stored-method-receiver.js": 2943, + "js-class-subclass-properties.js": 3662, + "js-class-symbol-spread.cjs": 2503, + "js-computed-prototype-additions.js": 2456, + "js-constructor-returned-callable.js": 2517, + "js-constructor-spread.js": 3593, + "js-dataview-dispatch.js": 2188, + "js-declared-fields.cjs": 4540, + "js-default-listener-arguments.cjs": 2448, + "js-default-options/main.ts": 3104, + "js-deferred-field-initializers.js": 2710, + "js-deferred-registry-effects.js": 2361, + "js-derived-constructor-hoisting.js": 2306, + "js-dormant-array-write.js": 2104, + "js-dormant-overrides.js": 1741, + "js-expando-records.js": 2473, + "js-implicit-call-results.js": 2893, + "js-inferred-callback-exports/main.js": 4125, + "js-inferred-class-array-return.js": 2816, + "js-inferred-object-values.js": 2369, + "js-inherited-field-storage.js": 3308, + "js-inherited-parameter-abi.js": 2238, + "js-iterable-spread.js": 2086, + "js-loose-dynamic-primitives.js": 2810, + "js-map-object-seeds.js": 2592, + "js-member-increment.js": 3352, + "js-module-function-values.js": 2994, + "js-mutable-null-members.js": 2723, + "js-nested-native-descriptors.js": 2548, + "js-normalize-dispatch.js": 2929, + "js-nullish-inherited-fields.mjs": 2189, + "js-object-receiver-storage.js": 2175, + "js-object-returning-constructors.mjs": 2945, + "js-object-shared-arrays.js": 2935, + "js-omitted-typed-arguments.js": 2736, + "js-open-binding-writes.js": 2167, + "js-optional-class-fields.js": 3219, + "js-optional-member-call.js": 3110, + "js-primitive-union-addition.js": 2549, + "js-promise-all-values.js": 3527, + "js-promise-catch-handler.js": 2649, + "js-promise-finally-order.js": 2445, + "js-promise-pending-reactions.js": 2595, + "js-prototype-host-boundary.js": 2723, + "js-reflect-receivers.js": 3391, + "js-regex-record-captures.js": 3115, + "js-scalar-iterables.js": 2746, + "js-shared-method-dispatch.js": 2796, + "js-specialized-field-method.js": 2049, + "js-static-accessors.js": 3053, + "js-static-method-values.js": 2375, + "js-static-registries.cjs": 2790, + "js-super-accessor-initialization.js": 2104, + "js-uninitialized-native-fields.js": 1764, + "json-guarded-map-values.ts": 3144, + "json-output-bulk.ts": 2572, + "json-runtime-options.mjs": 2583, + "json-stringify-value.js": 2182, + "json-typed-parse-direct.ts": 3644, "json-typed-parse-index-signatures.ts": 4122, "json-typed-parse-optional-members.ts": 3273, "json-typed-parse-union-members.ts": 3078, - "literal-switch-dispatch.ts": 2500, - "live-reference-shared-converters.ts": 2552, - "llvm-read-receiver-lifetime.ts": 2343, - "local-class-call-spreads.js": 3208, - "local-class-declaration.ts": 2486, - "local-class-evaluation.ts": 2605, - "local-class-inheritance.ts": 2327, - "local-class-lifetimes.ts": 2376, - "local-class-namespace/main.js": 2940, - "local-class-prototype-data.js": 2781, - "local-class-specialization.js": 2399, - "local-class-unknown.ts": 2443, - "local-class-values.ts": 1784, - "local-union-storage.ts": 2967, - "locale-compare-root-order.ts": 2518, - "logical-assignment-dynamic.js": 2592, - "logical-assignment-values.ts": 2497, - "logical-runtime-optional-record.ts": 2944, - "loop-reference-lifetimes.ts": 2542, - "map-checked-boundary/main.ts": 2629, - "map-checked-seed.js": 3013, + "literal-switch-dispatch.ts": 2252, + "live-reference-shared-converters.ts": 3470, + "llvm-read-receiver-lifetime.ts": 3118, + "local-class-call-spreads.js": 2490, + "local-class-declaration.ts": 2302, + "local-class-evaluation.ts": 2915, + "local-class-inheritance.ts": 2396, + "local-class-lifetimes.ts": 2780, + "local-class-namespace/main.js": 3248, + "local-class-prototype-data.js": 3273, + "local-class-specialization.js": 2054, + "local-class-unknown.ts": 1964, + "local-class-values.ts": 2059, + "local-union-storage.ts": 2500, + "locale-compare-root-order.ts": 2609, + "logical-assignment-dynamic.js": 2892, + "logical-assignment-values.ts": 2287, + "logical-runtime-optional-record.ts": 2390, + "loop-reference-lifetimes.ts": 2959, + "map-checked-boundary/main.ts": 2651, + "map-checked-seed.js": 1821, "map-get-set-fusion.ts": 3131, - "map-number-keys-dense.ts": 2562, - "map-read-lifetimes-exits.ts": 2227, - "map-read-lifetimes.ts": 2725, - "map-seeds-and-spreads.ts": 2719, - "map-typed-array-values.ts": 2850, - "math-function-values.js": 2367, - "missing-read-lambda-results.ts": 2379, - "missing-read-narrowed-storage.ts": 2498, - "missing-read-number-conversions.ts": 2181, - "module-byte-loops.ts": 2636, - "module-fallback-functions/main.js": 2148, - "narrowed-nullish-values.ts": 2410, - "native-any-timer-callback.ts": 1834, - "native-array-borrowed-find-last.js": 2515, - "native-array-borrowed-slice.js": 2404, - "native-array-copying-methods.js": 2076, - "native-array-fill-copywithin.js": 2636, - "native-array-frozen-noops.js": 2476, - "native-array-index-boundaries.js": 1913, - "native-array-integrity.js": 2429, - "native-array-length.js": 2568, - "native-array-named-properties.js": 2390, - "native-array-prototype/main.js": 2161, - "native-array-read-lifetimes.ts": 2771, - "native-array-reduce-find-last.js": 2375, - "native-array-search-from-index.js": 1823, - "native-array-splice-coercion.js": 2296, - "native-array-splice-flat.js": 1933, - "native-buffer-coercion.js": 2389, - "native-callback-dispatch.ts": 3007, - "native-class-array-boundaries.ts": 2676, - "native-class-cache.js": 3391, - "native-class-properties.cjs": 3541, - "native-class-property-cycles.cjs": 2291, - "native-class-property-order.cjs": 1867, - "native-class-type-predicates.ts": 2386, - "native-factory-records.js": 2851, - "native-method-values.js": 2903, - "native-method-values.ts": 2495, - "native-npm-imports/main.ts": 2716, - "native-object-descriptors.js": 2717, - "native-object-for-in-minimal.js": 2536, - "native-object-property-attributes.js": 3149, - "native-object-prototype.js": 3180, - "native-property-names.ts": 1827, - "native-proxy-env.js": 3519, - "native-worker-arena-reuse.ts": 4699, - "native-worker-bounded-errors.ts": 2268, - "native-worker-buffer-consumers.ts": 2531, - "native-worker-cancel-hot.ts": 2446, - "native-worker-class-fields.ts": 2650, - "native-worker-clone-errors.ts": 2347, - "native-worker-commonjs.cjs": 2188, - "native-worker-delayed-messages.ts": 3114, - "native-worker-discarded-heaps.ts": 4430, - "native-worker-environment.ts": 3538, - "native-worker-error.ts": 2810, - "native-worker-exception-state.ts": 3938, - "native-worker-exit-listeners.ts": 2965, - "native-worker-io.ts": 3018, - "native-worker-loop-cancellation.ts": 2773, - "native-worker-message-graphs.ts": 2440, - "native-worker-messages.ts": 2911, - "native-worker-poll-exceptions.ts": 2706, - "native-worker-port-lifetime.ts": 3175, - "native-worker-process-exit.ts": 2168, - "native-worker-publish-classes.ts": 2797, - "native-worker-publish-refusals.ts": 2330, - "native-worker-published-graphs.ts": 3411, - "native-worker-references.ts": 2156, - "native-worker-roots/main.ts": 2962, - "native-worker-shared-views.ts": 2377, - "native-worker-stack-overflow.ts": 2443, - "native-worker-terminate-exception-state.ts": 3368, - "native-worker-terminate-loop.ts": 1929, - "native-worker-terminate-recursion.ts": 2935, - "native-worker-terminate-suspended.ts": 2843, - "native-worker-terminate-tested-loops.ts": 3082, - "native-worker-terminate-wait.ts": 2267, - "native-worker-typed-arrays.ts": 2361, - "nested-map-cycles.ts": 2306, - "nested-map-values.ts": 2038, - "never-returning-calls.ts": 2680, - "next-tick-commonjs-entry.cjs": 1924, - "node24-buffer-encoding-errors.ts": 2742, - "node24-buffer-encoding.ts": 2822, - "node24-crypto-kdf-errors.ts": 2607, - "node24-crypto-kdf-options.ts": 1925, - "node24-crypto-kdf.ts": 3401, - "node24-crypto-sha2.ts": 2336, - "node24-deep-equality-properties.js": 2551, - "node24-deep-equality.cjs": 2373, - "node24-deep-equality.ts": 3193, - "node24-env-files-errors.ts": 2555, - "node24-env-files.ts": 2556, - "node24-env-imports.cjs": 2518, - "node24-env-parse-errors.ts": 2083, - "node24-env-parse.ts": 2189, - "node24-esm-metadata/main.mjs": 2257, - "node24-file-url-buffer.ts": 1904, - "node24-file-url-errors.js": 2838, - "node24-file-url-options.ts": 2563, - "node24-fs-links-callbacks.cjs": 2964, - "node24-fs-links-errors.cjs": 2795, - "node24-fs-links-options.cjs": 3096, - "node24-fs-links-promise-errors.cjs": 2481, - "node24-fs-links-promises.ts": 2014, - "node24-fs-links.ts": 3060, - "node24-fs-statfs-callbacks.cjs": 2761, - "node24-fs-statfs-errors.cjs": 3068, - "node24-fs-statfs-options.cjs": 2927, - "node24-fs-statfs.ts": 2192, - "node24-fs-timestamps-callbacks.cjs": 2865, - "node24-fs-timestamps-errors.cjs": 2733, - "node24-fs-timestamps-promises.ts": 2476, - "node24-fs-timestamps-symlinks.ts": 2406, - "node24-fs-timestamps.ts": 2758, - "node24-no-error-assertions-coercion.js": 2950, - "node24-no-error-assertions.cjs": 2361, - "node24-no-error-assertions.ts": 2895, - "node24-parseargs.js": 3512, - "node24-string-decoder.ts": 2569, - "node24-style-text-environment.js": 2370, - "node24-style-text-validation.js": 2999, - "node24-style-text.cjs": 1883, - "node24-style-text.ts": 2102, - "node24-system-error-validation.js": 2003, - "node24-system-errors.cjs": 2247, - "node24-system-errors.ts": 2302, - "node24-text-codec-properties.ts": 2178, - "node24-text-encode-into.ts": 2427, - "node24-text-utilities-coercion.js": 2867, - "node24-text-utilities-validation.js": 1874, - "node24-text-utilities.cjs": 2132, - "node24-text-utilities.ts": 2215, - "node24-url-authority-coercion.js": 2529, - "node24-url-authority.ts": 2720, - "node24-url-factories.ts": 2586, - "node24-url-factory-errors.ts": 1931, - "node24-url-mutation-coercion.js": 2518, - "node24-url-mutation.ts": 2194, - "node24-util-types.cjs": 3057, - "node24-util-types.js": 1900, - "node24-util-types.ts": 2935, - "non-null-class-iteration.ts": 2350, - "nonnull-element-arguments.ts": 2545, - "nonnull-forwarded-class-values.ts": 2532, - "nullable-object-extension.mjs": 1922, - "nullish-asserted-class-arms.ts": 2485, - "nullish-assignment-values.ts": 1745, - "nullish-long-chain.ts": 2326, - "number-parse-statics.ts": 2443, - "number-predicates-unknown.ts": 2375, - "numeric-call-specialization.ts": 2588, - "object-enumeration-array-reads.ts": 1967, - "object-from-checked-entries.js": 2542, - "object-inherited-to-string.js": 2670, - "object-key-indexes.js": 2753, - "object-prototype-identity.mjs": 2064, - "object-reexport/main.js": 2482, - "object-spread-computed.ts": 2578, - "opentui-byte-queue.js": 2802, - "optional-callback-arity.ts": 2348, - "optional-class-flows.ts": 2247, - "optional-element-defaults.ts": 2052, - "optional-flag-comparisons.ts": 2527, - "optional-native-callables.js": 2309, - "optional-node-list-iteration.ts": 2316, - "optional-string-index/main.ts": 2950, - "path-to-file-url-options.ts": 2299, - "performance-presence.ts": 2043, - "primitive-and-function-descriptors.js": 2222, - "primitive-union-string.ts": 2856, - "process-builtin-values.js": 2616, - "process-constrained-memory.ts": 2105, - "process-env-computed-keys.js": 2252, - "process-hrtime.js": 2596, - "process-named-signals.cjs": 2604, - "process-uncaught-handler-throws.cjs": 2306, - "process-uncaught-loop.cjs": 2320, - "process-uncaught-module.mjs": 1832, - "process-uncaught-monitor.cjs": 2077, - "process-uncaught-rejection.cjs": 2431, - "process-uncaught-sync.cjs": 2425, - "process-version-pin.ts": 2418, - "process-versions-storage.ts": 2051, - "projected-collection-lifetimes.ts": 2409, - "promise-checked-rejections.ts": 1985, - "promise-resolve-void.ts": 2341, - "prototype-method-overrides.mjs": 4870, - "prototype-named-data-records.ts": 2513, + "map-number-keys-dense.ts": 2480, + "map-read-lifetimes-exits.ts": 2004, + "map-read-lifetimes.ts": 2956, + "map-seeds-and-spreads.ts": 2807, + "map-typed-array-values.ts": 2864, + "math-function-values.js": 2704, + "missing-read-lambda-results.ts": 2964, + "missing-read-narrowed-storage.ts": 2975, + "missing-read-number-conversions.ts": 2247, + "module-byte-loops.ts": 2710, + "module-fallback-functions/main.js": 2953, + "narrowed-nullish-values.ts": 2689, + "native-any-timer-callback.ts": 2256, + "native-array-borrowed-find-last.js": 2331, + "native-array-borrowed-slice.js": 2738, + "native-array-copying-methods.js": 2547, + "native-array-fill-copywithin.js": 2422, + "native-array-frozen-noops.js": 1940, + "native-array-index-boundaries.js": 1855, + "native-array-integrity.js": 3078, + "native-array-length.js": 2779, + "native-array-named-properties.js": 2991, + "native-array-prototype/main.js": 1536, + "native-array-read-lifetimes.ts": 3338, + "native-array-reduce-find-last.js": 2328, + "native-array-search-from-index.js": 2430, + "native-array-splice-coercion.js": 2633, + "native-array-splice-flat.js": 2555, + "native-buffer-coercion.js": 2993, + "native-callback-dispatch.ts": 3551, + "native-class-array-boundaries.ts": 2938, + "native-class-cache.js": 4207, + "native-class-properties.cjs": 3301, + "native-class-property-cycles.cjs": 2085, + "native-class-property-order.cjs": 2417, + "native-class-type-predicates.ts": 2597, + "native-factory-records.js": 2167, + "native-method-values.js": 3675, + "native-method-values.ts": 2504, + "native-npm-imports/main.ts": 3572, + "native-object-descriptors.js": 2795, + "native-object-for-in-minimal.js": 2689, + "native-object-property-attributes.js": 2700, + "native-object-prototype.js": 2600, + "native-property-names.ts": 2409, + "native-proxy-env.js": 3746, + "native-worker-arena-reuse.ts": 4764, + "native-worker-bounded-errors.ts": 3072, + "native-worker-buffer-consumers.ts": 2989, + "native-worker-cancel-hot.ts": 2633, + "native-worker-class-fields.ts": 3458, + "native-worker-clone-errors.ts": 2734, + "native-worker-commonjs.cjs": 2159, + "native-worker-delayed-messages.ts": 2169, + "native-worker-discarded-heaps.ts": 5523, + "native-worker-environment.ts": 3190, + "native-worker-error.ts": 2740, + "native-worker-exception-state.ts": 4140, + "native-worker-exit-listeners.ts": 2056, + "native-worker-io.ts": 2596, + "native-worker-loop-cancellation.ts": 2554, + "native-worker-message-graphs.ts": 3182, + "native-worker-messages.ts": 2651, + "native-worker-poll-exceptions.ts": 3212, + "native-worker-port-lifetime.ts": 3033, + "native-worker-process-exit.ts": 2692, + "native-worker-publish-classes.ts": 4065, + "native-worker-publish-refusals.ts": 3039, + "native-worker-published-graphs.ts": 3663, + "native-worker-references.ts": 2640, + "native-worker-roots/main.ts": 3080, + "native-worker-shared-views.ts": 3041, + "native-worker-stack-overflow.ts": 2862, + "native-worker-terminate-exception-state.ts": 3985, + "native-worker-terminate-loop.ts": 2725, + "native-worker-terminate-recursion.ts": 3128, + "native-worker-terminate-suspended.ts": 2867, + "native-worker-terminate-tested-loops.ts": 3161, + "native-worker-terminate-wait.ts": 1905, + "native-worker-typed-arrays.ts": 2971, + "nested-map-cycles.ts": 2802, + "nested-map-values.ts": 3022, + "never-returning-calls.ts": 2411, + "next-tick-commonjs-entry.cjs": 2251, + "node24-buffer-encoding-errors.ts": 2393, + "node24-buffer-encoding.ts": 2789, + "node24-crypto-kdf-errors.ts": 2833, + "node24-crypto-kdf-options.ts": 2131, + "node24-crypto-kdf.ts": 4066, + "node24-crypto-sha2.ts": 1593, + "node24-deep-equality-properties.js": 2924, + "node24-deep-equality.cjs": 2596, + "node24-deep-equality.ts": 3235, + "node24-env-files-errors.ts": 2781, + "node24-env-files.ts": 2586, + "node24-env-imports.cjs": 1729, + "node24-env-parse-errors.ts": 2642, + "node24-env-parse.ts": 2636, + "node24-esm-metadata/main.mjs": 2627, + "node24-file-url-buffer.ts": 2669, + "node24-file-url-errors.js": 2467, + "node24-file-url-options.ts": 3030, + "node24-fs-links-callbacks.cjs": 3015, + "node24-fs-links-errors.cjs": 2843, + "node24-fs-links-options.cjs": 3229, + "node24-fs-links-promise-errors.cjs": 2844, + "node24-fs-links-promises.ts": 2107, + "node24-fs-links.ts": 1958, + "node24-fs-statfs-callbacks.cjs": 2203, + "node24-fs-statfs-errors.cjs": 2705, + "node24-fs-statfs-options.cjs": 2846, + "node24-fs-statfs.ts": 2174, + "node24-fs-timestamps-callbacks.cjs": 2972, + "node24-fs-timestamps-errors.cjs": 1969, + "node24-fs-timestamps-promises.ts": 2959, + "node24-fs-timestamps-symlinks.ts": 2931, + "node24-fs-timestamps.ts": 1989, + "node24-no-error-assertions-coercion.js": 3207, + "node24-no-error-assertions.cjs": 1972, + "node24-no-error-assertions.ts": 2214, + "node24-parseargs.js": 4158, + "node24-string-decoder.ts": 2635, + "node24-style-text-environment.js": 2062, + "node24-style-text-validation.js": 3237, + "node24-style-text.cjs": 2491, + "node24-style-text.ts": 2829, + "node24-system-error-validation.js": 2660, + "node24-system-errors.cjs": 2361, + "node24-system-errors.ts": 2897, + "node24-text-codec-properties.ts": 2383, + "node24-text-encode-into.ts": 2992, + "node24-text-utilities-coercion.js": 2902, + "node24-text-utilities-validation.js": 2997, + "node24-text-utilities.cjs": 2432, + "node24-text-utilities.ts": 1910, + "node24-url-authority-coercion.js": 2861, + "node24-url-authority.ts": 2689, + "node24-url-factories.ts": 1863, + "node24-url-factory-errors.ts": 1955, + "node24-url-mutation-coercion.js": 2400, + "node24-url-mutation.ts": 2663, + "node24-util-types.cjs": 3712, + "node24-util-types.js": 2869, + "node24-util-types.ts": 3395, + "non-null-class-iteration.ts": 2220, + "nonnull-element-arguments.ts": 2568, + "nonnull-forwarded-class-values.ts": 2603, + "nullable-object-extension.mjs": 2408, + "nullish-asserted-class-arms.ts": 2116, + "nullish-assignment-values.ts": 2517, + "nullish-long-chain.ts": 2430, + "number-parse-statics.ts": 1887, + "number-predicates-unknown.ts": 1974, + "numeric-call-specialization.ts": 2627, + "object-enumeration-array-reads.ts": 2586, + "object-from-checked-entries.js": 2775, + "object-inherited-to-string.js": 2674, + "object-key-indexes.js": 2909, + "object-prototype-identity.mjs": 2317, + "object-reexport/main.js": 2625, + "object-spread-computed.ts": 2429, + "opentui-byte-queue.js": 3139, + "optional-callback-arity.ts": 2294, + "optional-class-flows.ts": 2613, + "optional-element-defaults.ts": 2793, + "optional-flag-comparisons.ts": 2714, + "optional-native-callables.js": 2344, + "optional-node-list-iteration.ts": 2344, + "optional-string-index/main.ts": 2788, + "path-to-file-url-options.ts": 2568, + "performance-presence.ts": 2450, + "primitive-and-function-descriptors.js": 2677, + "primitive-union-string.ts": 1777, + "process-builtin-values.js": 3974, + "process-constrained-memory.ts": 1850, + "process-env-computed-keys.js": 2019, + "process-hrtime.js": 2975, + "process-named-signals.cjs": 2191, + "process-uncaught-handler-throws.cjs": 2460, + "process-uncaught-loop.cjs": 2411, + "process-uncaught-module.mjs": 1942, + "process-uncaught-monitor.cjs": 1718, + "process-uncaught-rejection.cjs": 2645, + "process-uncaught-sync.cjs": 2436, + "process-version-pin.ts": 1717, + "process-versions-storage.ts": 2502, + "projected-collection-lifetimes.ts": 2791, + "promise-checked-rejections.ts": 2434, + "promise-resolve-void.ts": 2330, + "prototype-method-overrides.mjs": 4995, + "prototype-named-data-records.ts": 2858, "rc-last-use-moves.ts": 2819, "rc-private-array-writes.ts": 2121, - "record-field-presence.ts": 3025, - "record-key-order.ts": 2807, - "record-optional-json-presence.ts": 2623, - "record-presence-copies.ts": 2693, - "record-presence-delete-json.ts": 2748, - "record-unchecked-read-presence.ts": 2103, - "record-unknown-values.ts": 3450, - "reflect-own-keys.mjs": 2583, - "reflect-record-union-keys.mjs": 2454, - "reflect-typed-record-keys.ts": 1855, - "regex-callback-replacements.ts": 2492, - "regex-callback-values.js": 2733, - "regex-checked-casts.ts": 2350, - "regex-checked-storage.js": 2669, - "regex-exec-long-subject.ts": 4533, + "record-field-presence.ts": 3356, + "record-key-order.ts": 2943, + "record-optional-json-presence.ts": 2861, + "record-presence-copies.ts": 2372, + "record-presence-delete-json.ts": 3243, + "record-unchecked-read-presence.ts": 2717, + "record-unknown-values.ts": 3976, + "reflect-own-keys.mjs": 2238, + "reflect-record-union-keys.mjs": 2626, + "reflect-typed-record-keys.ts": 2852, + "regex-callback-replacements.ts": 2111, + "regex-callback-values.js": 2464, + "regex-checked-casts.ts": 2160, + "regex-checked-storage.js": 2310, + "regex-exec-long-subject.ts": 4567, "regex-exec-result-arrays.ts": 3123, "regex-fs-text-surfaces.ts": 2847, - "regex-input-lifetimes.ts": 2535, - "regex-native-matcher.ts": 3683, - "regex-optional-captures.ts": 2606, - "regex-optional-templates.ts": 2338, - "regex-split-captures.ts": 2583, - "regex-text-paths.ts": 2889, - "regexp-constructor-repeat.ts": 2351, - "regexp-optional-constructor.ts": 2315, - "regexp-string-coercion.js": 1897, - "renderer-export-dictionaries.js": 2582, - "renderer-null-state.js": 2185, - "renderer-specializations.js": 2653, - "repeat-and-typed-read-errors.ts": 2751, - "rest-optional-array-arguments.ts": 2671, - "rest-optional-elements.ts": 2289, - "return-void-through-finally.ts": 2486, - "runtime-optional-string-flows.ts": 2406, - "scalar-string-slices.ts": 2175, - "set-checked-methods.js": 2631, - "set-checked-storage.ts": 2064, - "set-iterator-seed-references.ts": 2863, - "set-iterator-seeds.ts": 2896, - "set-optional-seeds.ts": 2121, - "small-collection-transitions.ts": 2645, + "regex-input-lifetimes.ts": 2221, + "regex-native-matcher.ts": 4414, + "regex-optional-captures.ts": 3043, + "regex-optional-templates.ts": 2695, + "regex-split-captures.ts": 2413, + "regex-text-paths.ts": 3078, + "regexp-constructor-repeat.ts": 2829, + "regexp-optional-constructor.ts": 2162, + "regexp-string-coercion.js": 2219, + "renderer-export-dictionaries.js": 2331, + "renderer-null-state.js": 1751, + "renderer-specializations.js": 2860, + "repeat-and-typed-read-errors.ts": 2689, + "rest-optional-array-arguments.ts": 2219, + "rest-optional-elements.ts": 2503, + "return-void-through-finally.ts": 2582, + "runtime-optional-string-flows.ts": 2381, + "scalar-string-slices.ts": 2256, + "set-checked-methods.js": 2598, + "set-checked-storage.ts": 2088, + "set-iterator-seed-references.ts": 2454, + "set-iterator-seeds.ts": 3016, + "set-optional-seeds.ts": 2563, + "small-collection-transitions.ts": 2967, "speculative-integer-globals.ts": 2480, "speculative-integer-loops.ts": 3219, "speculative-integer-reads.ts": 2852, - "stack-depth-async-bodies.ts": 1910, - "stack-overflow-async.ts": 2447, - "stack-overflow-caught.ts": 2424, - "stack-overflow-finally.ts": 2613, - "stack-overflow-shapes.ts": 2534, - "stack-overflow-uncaught.ts": 2317, + "stack-depth-async-bodies.ts": 2421, + "stack-overflow-async.ts": 1922, + "stack-overflow-caught.ts": 2542, + "stack-overflow-finally.ts": 2607, + "stack-overflow-shapes.ts": 3083, + "stack-overflow-uncaught.ts": 2465, "stackless-async-concurrency.ts": 2441, "stackless-async-context.ts": 2934, "stackless-async-exceptions.ts": 2936, "stackless-async-ordering.ts": 2618, "stackless-async-unhandled.ts": 2477, - "static-field-updates/main.ts": 2050, - "static-method-receivers.ts": 2243, - "stdio-values.mjs": 2578, - "stdio-write-errors.mjs": 1977, - "stdio-write-overrides.mjs": 2495, - "stored-native-builtins.js": 2831, - "stored-object-helpers.js": 2747, + "static-field-updates/main.ts": 2461, + "static-method-receivers.ts": 1849, + "stdio-values.mjs": 2236, + "stdio-write-errors.mjs": 2342, + "stdio-write-overrides.mjs": 2002, + "stored-native-builtins.js": 2708, + "stored-object-helpers.js": 2808, "stream-dynamic-entry-kinds.cjs": 3015, "stream-dynamic-entry-kinds.ts": 1582, "stream-encoded-from-entries.cjs": 3058, "stream-encoded-from-entries.ts": 2590, - "string-char-code-integer-loops.ts": 2495, - "string-code-points.ts": 1970, - "string-concat-number-parts.ts": 2044, - "string-construction-order.ts": 2502, + "string-char-code-integer-loops.ts": 2802, + "string-code-points.ts": 2658, + "string-concat-number-parts.ts": 2339, + "string-construction-order.ts": 2902, "string-field-append.ts": 3251, - "string-lifetimes-boundaries.ts": 2481, - "string-lifetimes-evaluation.ts": 2486, - "string-lifetimes-iteration.ts": 2043, - "string-lifetimes-operations.ts": 2490, - "string-normalize.ts": 2391, - "string-pattern-replacement.ts": 3527, - "string-scan-fast-paths.ts": 2272, - "string-split-checked-separator.mjs": 2144, - "string-split-traversal.ts": 3038, - "structural-class-properties.ts": 2610, - "structured-text-boundaries.js": 2792, - "structured-text-storage.ts": 2942, - "switch-integer-dispatch.ts": 2290, - "symbol-checked-boundary/main.ts": 2273, - "symbol-class-fields.ts": 2065, - "symbol-class-fields/main.cjs": 2595, - "symbol-class-methods/main.ts": 1855, - "symbol-fields-deferred-factory.ts": 2253, - "symbol-fields-inferred.js": 2329, - "symbol-object-properties/main.js": 2835, - "synchronous-callback-lifetimes.ts": 2768, - "terminal-stream-properties.ts": 2586, - "text-codec-values/main.ts": 2158, - "text-codec-var.ts": 2182, - "text-encode-into-boundaries.ts": 1971, - "timers-clear-many.ts": 2704, - "tuple-and-string-search.ts": 2663, - "tuple-array-union.ts": 2706, - "tuple-callback-visitation.ts": 3464, - "tuple-forof-visitation.ts": 2357, - "typed-array-bulk-conversion.mjs": 3837, - "typed-array-byte-io.js": 2552, - "typed-array-checked-index.js": 2420, - "typed-array-constructor-alias.ts": 2507, - "typed-array-constructor-identity.js": 2453, - "typed-array-constructor-union.ts": 2428, - "typed-array-constructor-values.mjs": 2571, - "typed-array-dynamic-methods.js": 2604, - "typed-array-integer-widths.ts": 2747, - "typed-array-nan-coded-reads.ts": 2921, - "typed-array-numeric-import.ts": 2450, - "typed-array-present-reads.ts": 2582, - "typed-array-reversed-storage.ts": 2168, - "typed-array-unknown.ts": 2500, - "typed-collection-iterator-references.ts": 3186, - "typed-collection-iterators.ts": 2946, - "typed-collection-views/main.ts": 2523, - "typed-index-arguments.ts": 2494, - "typed-prototype-methods.ts": 2527, - "typed-rest-callables.ts": 2391, - "typed-rest-filtered-return.ts": 2578, - "typedarray-native-inputs.js": 3104, - "typeof-checked-comparison.js": 2116, - "uint8array-sort-domains.ts": 2494, - "unicode-case-paths.ts": 2356, - "unicode-process-argv.ts": 2569, - "union-discriminant-width.ts": 2670, - "union-literal-scalar-discriminants.ts": 2869, - "union-literal-slot-conversion.ts": 2792, - "union-nested-layout-discriminant.ts": 2120, - "union-optional-semantic-identity.ts": 2455, - "union-record-clone.ts": 2790, - "union-record-structural-copy.ts": 2905, - "union-reference-comparison.ts": 2401, - "unknown-array-holes.ts": 1853, - "unknown-collections.ts": 3166, - "unknown-object-enumeration.ts": 3783, - "unknown-record-views.ts": 3243, - "url-runtime-base.ts": 2584, - "utf8-span-decoding.ts": 2564, - "util-parseargs-wrapped/main.ts": 2257, - "virtual-runtime-optional-returns.ts": 2981, - "weak-map-array-buffer.ts": 2435, - "weak-map-fresh-array.js": 2341, - "weak-map-native.js": 3068, - "weak-native-class-identity.ts": 2403, - "weak-set-native.js": 2924, - "worker-class-instance-clone.ts": 3052 + "string-lifetimes-boundaries.ts": 2858, + "string-lifetimes-evaluation.ts": 1805, + "string-lifetimes-iteration.ts": 2235, + "string-lifetimes-operations.ts": 2468, + "string-normalize.ts": 2348, + "string-pattern-replacement.ts": 1662, + "string-scan-fast-paths.ts": 2133, + "string-split-checked-separator.mjs": 2285, + "string-split-traversal.ts": 1939, + "structural-class-properties.ts": 3139, + "structured-text-boundaries.js": 3111, + "structured-text-storage.ts": 2912, + "switch-integer-dispatch.ts": 2264, + "symbol-checked-boundary/main.ts": 2800, + "symbol-class-fields.ts": 2364, + "symbol-class-fields/main.cjs": 2507, + "symbol-class-methods/main.ts": 2255, + "symbol-fields-deferred-factory.ts": 2386, + "symbol-fields-inferred.js": 2386, + "symbol-object-properties/main.js": 3085, + "synchronous-callback-lifetimes.ts": 2296, + "terminal-stream-properties.ts": 2094, + "text-codec-values/main.ts": 2338, + "text-codec-var.ts": 2708, + "text-encode-into-boundaries.ts": 2679, + "timers-clear-many.ts": 2665, + "tuple-and-string-search.ts": 2567, + "tuple-array-union.ts": 2150, + "tuple-callback-visitation.ts": 3321, + "tuple-forof-visitation.ts": 2818, + "typed-array-bulk-conversion.mjs": 4061, + "typed-array-byte-io.js": 3073, + "typed-array-checked-index.js": 2572, + "typed-array-constructor-alias.ts": 2243, + "typed-array-constructor-identity.js": 2693, + "typed-array-constructor-union.ts": 2646, + "typed-array-constructor-values.mjs": 2380, + "typed-array-dynamic-methods.js": 2112, + "typed-array-integer-widths.ts": 2661, + "typed-array-nan-coded-reads.ts": 3761, + "typed-array-numeric-import.ts": 2783, + "typed-array-present-reads.ts": 3074, + "typed-array-reversed-storage.ts": 2650, + "typed-array-unknown.ts": 2830, + "typed-collection-iterator-references.ts": 3315, + "typed-collection-iterators.ts": 3098, + "typed-collection-views/main.ts": 1720, + "typed-index-arguments.ts": 2531, + "typed-prototype-methods.ts": 3386, + "typed-rest-callables.ts": 2393, + "typed-rest-filtered-return.ts": 2745, + "typedarray-native-inputs.js": 3102, + "typeof-checked-comparison.js": 2558, + "uint8array-sort-domains.ts": 2057, + "unicode-case-paths.ts": 2222, + "unicode-process-argv.ts": 2491, + "union-discriminant-width.ts": 2970, + "union-literal-scalar-discriminants.ts": 3053, + "union-literal-slot-conversion.ts": 2820, + "union-nested-layout-discriminant.ts": 1976, + "union-optional-semantic-identity.ts": 3464, + "union-record-clone.ts": 2368, + "union-record-structural-copy.ts": 3130, + "union-reference-comparison.ts": 2882, + "unknown-array-holes.ts": 1889, + "unknown-collections.ts": 3133, + "unknown-object-enumeration.ts": 4341, + "unknown-record-views.ts": 3288, + "url-runtime-base.ts": 2471, + "utf8-span-decoding.ts": 2821, + "util-parseargs-wrapped/main.ts": 2971, + "virtual-runtime-optional-returns.ts": 3001, + "weak-map-array-buffer.ts": 1951, + "weak-map-fresh-array.js": 2498, + "weak-map-native.js": 3238, + "weak-native-class-identity.ts": 2197, + "weak-set-native.js": 2814, + "worker-class-instance-clone.ts": 3421 }, "san": { - "001-hello.ts": 38244, - "002-log-args.ts": 31270, - "100-number-format.ts": 45195, - "1000-json-stringify-basics.ts": 46332, - "1001-json-escapes-unicode.ts": 4513, - "1002-json-parse-cast.ts": 35521, - "1003-json-parse-unions.ts": 3512, - "1004-json-parse-errors.ts": 3903, - "1005-json-nested.ts": 3425, - "1006-json-fs-config.ts": 3347, - "1007-json-rc-stress.ts": 34305, - "1008-json-null-arms.ts": 3422, - "1009-json-optional-fields.ts": 4004, - "101-arithmetic.ts": 4655, - "1010-json-stringify-space.ts": 45417, - "1011-json-unknown-typeof.ts": 4001, - "102-comparisons.ts": 3774, - "1020-async-basics.ts": 3697, - "1021-async-ordering.ts": 3078, - "1022-async-exceptions.ts": 3780, - "1023-async-rc-stress.ts": 3889, - "1024-async-pending-exit.ts": 3389, - "1025-async-promise-capture.ts": 42296, - "1026-throw-promise.ts": 4482, - "1027-async-return-promise.ts": 3534, - "1028-async-return-record-literals.ts": 3843, - "1029-async-eager-chains.ts": 4890, - "103-ternary.ts": 3470, - "104-ternary-empty-arrays.ts": 7056, - "1050-comptime-tables.ts": 4643, - "1051-comptime-strings.ts": 42895, - "1052-comptime-records.ts": 44375, - "1053-comptime-json.ts": 4497, - "1054-comptime-modules/main.ts": 4326, - "110-number-radix.ts": 3100, - "111-record-entries.ts": 7961, - "1110-math-members.ts": 3457, - "1111-math-random.ts": 4321, - "1113-string-methods.ts": 23286, - "1114-string-unicode-island.ts": 45718, - "1115-parse-globals.ts": 3277, - "1116-island-static-mix.ts": 3738, - "1117-typeof-static-union.ts": 4351, - "1118-object-spread-conditional.ts": 3602, - "1119-switch-union.ts": 4833, - "112-class-descriptor-key.js": 4674, - "1121-infinity-number-tostring.ts": 4470, - "1122-any-captures.ts": 7125, - "1124-union-narrowed-retag.ts": 3484, - "113-promise-checked-exits.ts": 4562, - "114-live-record-delete.ts": 3572, - "115-array-compound.js": 6457, - "116-text-decoder-runtime.js": 33483, - "117-weak-cache-cycle.js": 5789, - "118-fs-stored-callbacks.cjs": 52946, - "119-native-patterns.js": 6101, - "1200-regex-test-basics.ts": 47554, - "1201-regex-replace.ts": 3959, - "1202-regex-substitutions.ts": 3855, - "1203-regex-split.ts": 31517, - "1204-regex-empty-unicode.ts": 4662, - "1205-regex-rc-stress.ts": 36658, - "1300-errors-basics.ts": 4354, - "1301-errors-subclass.ts": 4687, - "1302-errors-typed-catch.ts": 4229, - "1303-errors-rc-stress.ts": 3431, - "1304-errors-uncaught.ts": 3763, - "1305-errors-async-rejections.ts": 4254, - "1306-errors-runtime-instances.ts": 4140, - "1350-path-normalize-join.ts": 4224, - "1351-path-parts.ts": 4167, - "1352-path-resolve-relative.ts": 4382, - "1353-os-basics.ts": 4007, - "1354-builtin-bare-specifiers.ts": 3999, - "1355-url-parse.ts": 3346, - "1356-url-file-bridge.ts": 3553, - "1357-fsp-roundtrip.ts": 4325, - "1358-crypto-random.ts": 3398, - "1359-json-module/main.ts": 4414, - "1360-spawn-sync.ts": 4387, - "1361-spawn-events.ts": 4260, - "1362-spawn-timers.ts": 9971, - "1363-spawn-unhandled-error.ts": 3744, - "1364-union-truthiness.ts": 3907, - "1365-union-logical.ts": 4258, - "1366-union-equality.ts": 3058, - "1367-destructuring.ts": 5461, - "1368-constructor-functions.ts": 3781, - "1369-promise-union.ts": 3864, - "1370-spread.ts": 3429, - "1371-union-template-tostring.ts": 3265, - "1372-loose-null-tests.ts": 3885, - "1373-union-array-arms.ts": 3435, - "140-bitwise-operators.ts": 4527, - "1400-typedarray-basics.ts": 5395, - "1401-typedarray-slice-set.ts": 3626, - "1402-buffer-encodings.ts": 4871, - "1403-buffer-fs.ts": 4268, - "1404-zlib-crypto-bytes.ts": 5331, - "1405-bytes-unions-arrays.ts": 3838, - "1406-dataview-mp4.ts": 3661, - "1407-dataview-bounds.ts": 5553, - "1408-string-indexing.ts": 5392, - "1409-typedarray-integer-loops.ts": 4558, - "1420-number-statics.ts": 3886, - "1421-number-parse-strings.ts": 4644, - "1422-date-iso.ts": 4015, - "1423-text-codec.ts": 38476, - "1424-fs-options.ts": 3473, - "1425-stdin-tty.ts": 4093, - "1426-stdin-read.ts": 3982, - "1427-fromcharcode-lastindexof.ts": 2946, - "1428-settled-await-order.ts": 3794, - "1429-promise-catch-finally.ts": 4465, - "1430-promise-race.ts": 4414, - "1431-caught-tostring.ts": 2971, - "1432-destructured-params.ts": 3941, - "1433-filter-narrow.ts": 3907, - "1434-async-never.ts": 3465, - "1435-math-spread.ts": 3652, - "1436-default-undef-param.ts": 3877, - "1437-pad-default.ts": 3475, - "1438-promise-all.ts": 7297, - "1440-interval-basics.ts": 4144, - "1441-interval-clear-cross.ts": 7176, - "1442-interval-throw.ts": 3609, - "1443-signal-handlers.ts": 7600, - "1444-exit-listeners.ts": 4768, - "1445-exit-process-exit.ts": 5403, - "1446-exit-uncaught.ts": 4319, - "1447-stdin-closed-events.ts": 4894, - "1448-stream-columns.ts": 4014, - "1450-incdec-expression.ts": 3639, - "1451-instanceof-uint8array-unknown.ts": 3654, - "1452-return-through-finally.ts": 4057, - "1453-pmap-settled.ts": 4531, - "1454-nonnull-narrow-and-fcc-bytes.ts": 3459, - "1455-lambda-union-return-adoption.ts": 3583, - "1460-console-error-warn.ts": 3484, - "1461-process-pid-getuid-kill.ts": 3345, - "1462-exec-sync.ts": 5307, - "1463-timeout-unref.ts": 3316, - "1464-env-writes.ts": 3946, - "1465-env-value.ts": 3554, - "1466-child-containers.ts": 4064, - "1467-string-match.ts": 3329, - "1468-exec-path.ts": 3588, - "1469-remove-listener.ts": 5747, - "1470-child-lifecycle.ts": 2972, - "1471-child-unref.ts": 8472, - "1472-errno-code.ts": 3388, - "1473-promisify-execfile.ts": 5200, - "1474-string-decoder.ts": 3868, - "1475-readline-closed-stdin.ts": 3587, - "1476-assign-expression.ts": 4319, - "1477-in-expressions.ts": 3951, - "1478-promise-reject.ts": 4331, - "1479-destructuring-assign.ts": 3821, - "1480-os-network-interfaces.ts": 4186, - "1481-string-case-static.ts": 2782, - "1482-spawnsync-error.ts": 2721, - "1483-array-slice.ts": 52661, - "1520-fs-wider-surface.ts": 3691, - "1520-string-split-static.ts": 3432, - "1521-fs-lstat-lock.ts": 3409, - "1521-string-trim-pad-static.ts": 4078, - "1522-parseint-static.ts": 3461, - "1522-spawnsync-options.ts": 5773, - "1523-isnan-floor-static.ts": 3552, - "1523-spawn-options.ts": 5294, - "1524-atomics-sleep-static.ts": 4028, - "1524-catch-narrowing.ts": 2626, - "1525-child-exit-signal.ts": 3477, - "1525-unknown-typeof-validation.ts": 2889, - "1526-set-spread.ts": 3802, - "1527-logical-mixed-operands.ts": 4773, - "1528-delete-records-env.ts": 3621, - "1529-class-with-statics.ts": 3381, - "1530-array-push-variadic.ts": 2970, - "1530-spread-override-completion.ts": 2499, - "1531-delete-optional-fields.ts": 3623, - "1531-process-arch-versions.ts": 2740, - "1532-array-splice-shift.ts": 4204, - "1532-union-shared-field-read.ts": 2834, - "1533-bool-equality.ts": 4076, - "1533-path-platform-namespaces.ts": 3406, - "1534-crypto-hash-chain.ts": 4097, - "1534-union-as-arm-cast.ts": 45787, - "1535-spawn-fd-stdio.ts": 3840, - "1535-union-param-defaults.ts": 4358, - "1536-destructuring-defaults.ts": 3812, - "1536-string-array-sweep.ts": 3859, - "1537-chalk-hybrid/main.ts": 4683, - "1537-os-release-spawnsync-stdio.ts": 2674, - "1538-await-promiselike-return.ts": 2642, - "1538-math-static-scalar.ts": 3735, - "1539-readonly-set-map.ts": 3299, - "1539-unknown-truthiness.ts": 3045, - "1540-os-userinfo.ts": 4119, - "1540-void-statement.ts": 2941, - "1541-fs-readdir-dirent.ts": 5432, - "1541-union-keyed-reads.ts": 4646, - "1542-map-promise-values.ts": 33000, - "1542-record-literal-into-union.ts": 2885, - "1543-rest-destructuring.ts": 3500, - "1543-set-server-handles.ts": 6770, - "1544-dyn-json-reads.ts": 4863, - "1544-string-matchall.ts": 4770, - "1545-spread-order-and-optional.ts": 4536, - "1546-union-element-reads.ts": 4536, - "1547-computed-key-fold.ts": 3960, - "1548-boolean-condition-forms.ts": 4649, - "1549-array-isarray-unions.ts": 4084, - "1550-param-defaults-func-set.ts": 3020, - "1551-dyn-receiver-methods.ts": 3403, - "1552-exec-options-record.ts": 2877, - "1553-truthy-hof-predicates.ts": 3895, - "1554-caught-into-unknown.ts": 3417, - "1555-index-spread-into-declared.ts": 4534, - "1556-union-retag-width-arms.ts": 3587, - "1557-url-host.ts": 2566, - "1558-any-joins-and-dyn-validation.ts": 33883, - "1559-conditional-spread-index-merge.ts": 3282, - "1560-forof-homogeneous-tuples.ts": 3680, - "1561-forof-strings.ts": 2878, - "1561-promise-then.ts": 3851, - "1562-optional-chain-tails.ts": 4618, - "1562-spawn-conditional-spread.ts": 4043, - "1563-forof-iterator-projections.ts": 3930, - "1563-string-raw-fold.ts": 3100, - "1564-fs-watch.ts": 4051, - "1564-string-raw.ts": 3075, - "1565-spawn-pipe-streams.ts": 3895, - "1565-union-element-join.ts": 4167, - "1566-child-duck-interface.ts": 3875, - "1567-server-close-override.ts": 3304, - "1568-x509-fingerprint.ts": 2839, - "1569-fsp-mkdir-unlink-chmod.ts": 3012, - "1570-child-unref-kill-reffed.ts": 9046, - "1571-optional-call-tostring-tail.ts": 26380, - "1571-stdin-set-raw-mode-non-tty.ts": 4151, - "1572-promise-reject-all-tuple.ts": 4201, - "1572-x509-validity-date-gettime.ts": 3944, - "1573-promisify-execfile-env-spread.ts": 4480, - "1573-tdz-scalar-forward-capture.ts": 2862, - "1574-dyn-optional-method-number-keys.ts": 3192, - "1574-promise-all-tuple-literal.ts": 4410, - "1575-unknown-assert-into-record.ts": 3424, - "1576-width-coercions.ts": 4144, - "1577-url-hostname.ts": 4030, - "1578-exec-input-optional.ts": 4028, - "1579-matchall-index.ts": 4108, - "1580-exec-env-conditional-spread.ts": 3516, - "1581-declare-const-read.ts": 3997, - "1582-timer-sleep-resolve.ts": 4177, - "1583-loops-and-stream-captures.ts": 4450, - "1584-union-field-unassigned.ts": 3964, - "1585-union-field-conditional-ctor.ts": 3070, - "1586-derived-field-before-super-init.ts": 4073, - "1590-js-unannotated.js": 4738, - "1591-js-closures.js": 3535, - "1592-js-classes.js": 7400, - "1593-js-jsdoc-records.js": 4695, - "1594-js-async.js": 3836, - "1595-js-island-gap/main.js": 3139, - "1596-cjs-modules/main.js": 3283, - "1597-mjs-graph/main.mjs": 3605, - "1598-cjs-builtin-require/main.js": 2977, - "1599-js-uncaught-throw.js": 3196, - "1600-assert-passing.ts": 4333, - "1601-assert-fail-exit.ts": 3725, - "1602-assert-caught-error.ts": 3373, - "1603-assert-scalar-messages.ts": 5128, - "1604-assert-deep-structures.ts": 4364, - "1605-assert-import-forms.ts": 4371, - "1606-assert-strict-module.ts": 2984, - "1607-assert-throws-match.ts": 4301, - "1608-cjs-assert/main.js": 3820, - "1609-assert-async.ts": 2695, - "1610-path-win32-full.ts": 2757, - "1611-url-file-bridge-neutral.ts": 4375, - "1612-cjs-module-globals.cjs": 3706, - "1613-cjs-esm-proxy-named/main.mjs": 3290, - "1614-js-fence-dodges.cjs": 2861, - "1615-cjs-export-shapes/main.cjs": 4723, - "1616-cjs-esm-lexer-invisible/main.mjs": 2991, - "1617-cjs-esm-lexer-visible/main.mjs": 3860, - "1618-cjs-esm-poisoned-tail/main.mjs": 3236, - "1619-cjs-esm-reexport-invisible/main.mjs": 3244, - "1620-cjs-require-effects-order/main.js": 2604, - "1621-cjs-require-cache-hit/main.js": 3531, - "1622-cjs-require-conditional/main.js": 3501, - "1623-cjs-require-diamond/main.js": 4051, - "1624-cjs-require-dir-mid-file/main.js": 2658, - "1625-cjs-require-lazy-fn/main.js": 3635, - "1626-cjs-require-mjs/main.js": 2942, - "1627-mjs-import-cjs-requires/main.mjs": 3236, - "1628-checked-dynamic-builtin-args.cjs": 2968, - "1629-require-main-filename.cjs": 2826, - "1630-inspect-scalars.ts": 3908, - "1630-rmsync-retry-options.cjs": 3797, - "1631-inspect-arrays.ts": 4065, - "1632-inspect-records.ts": 4843, - "1633-inspect-map-set.ts": 3133, - "1634-inspect-classes.ts": 3805, - "1635-inspect-buffer.ts": 3530, - "1636-util-format.ts": 2945, - "1637-inspect-dyn.ts": 3297, - "1638-inspect-cjs.cjs": 3549, - "1639-versions-openssl-probe.ts": 3544, - "1640-fd-read-decode.ts": 2932, - "1641-string-search.ts": 3476, - "1642-object-fromentries-rows.ts": 3699, - "1643-metadata-dyn-return.cjs": 4074, - "1644-ee-basics.ts": 4205, - "1645-ee-extends.ts": 3512, - "1646-ee-once-remove.ts": 3828, - "1647-ee-meta-events.ts": 3673, - "1648-ee-error-event.ts": 3271, - "1649-ee-names-counts.ts": 3057, - "1650-ee-prepend.ts": 3927, - "1651-ee-max-listeners.ts": 4648, - "1652-ee-snapshot.ts": 4220, - "1653-ee-cjs.cjs": 3230, - "1654-ee-namespace.ts": 3631, - "1655-spawnsync-neutral.ts": 5393, - "1656-execsync-neutral.ts": 3546, - "1657-spawn-async-neutral.ts": 3320, - "1660-buffer-read-write-num.ts": 4303, - "1661-buffer-encodings-full.ts": 3877, - "1662-string-decoder-encodings.ts": 3423, - "1663-buffer-compare-search-fill.ts": 4770, - "1664-dyn-fn-boundary.cjs": 3405, - "1665-dyn-fn-mustcall/main.cjs": 2819, - "1666-dyn-fn-identity.ts": 2740, - "1667-dyn-fn-not-callable.cjs": 3303, - "1668-dyn-fn-throws.cjs": 3745, - "1669-symbol-identity.ts": 3617, - "1670-symbol-registry.ts": 4207, - "1671-symbol-typeof.ts": 3400, - "1672-symbol-containers.ts": 3581, - "1673-symbol-cjs.cjs": 3624, - "1674-symbol-inspect.ts": 2758, - "1676-func-array-surface.ts": 2900, - "1677-emitter-listeners.ts": 4932, - "1678-emitter-dyn-listeners.cjs": 3287, - "1679-console-dyn.js": 3576, - "1680-assert-bytes.ts": 3903, - "1681-assert-funcs.ts": 3918, - "1685-stream-readable-basics.ts": 6503, - "1686-stream-readable-paused.ts": 6965, - "1687-stream-readable-flow-control.ts": 3669, - "1688-stream-writable-basics.ts": 3711, - "1689-stream-writable-async-drain.ts": 6004, - "1690-stream-duplex.ts": 6220, - "1691-stream-transform.ts": 6193, - "1692-stream-pipe.ts": 6662, - "1693-stream-pipe-backpressure.ts": 3700, - "1694-stream-destroy.ts": 3259, - "1695-stream-props.ts": 4843, - "1696-stream-read-inside-read.ts": 3524, - "1697-stream-tick-vs-timer.ts": 3256, - "1698-stream-uncaught-error.ts": 4826, - "1699-stream-callback-shapes.ts": 3791, - "1700-mustcall-common/main.cjs": 4329, - "1701-mustcall-exit-report/main.cjs": 3995, - "1702-dyn-proto-dispatch.cjs": 4694, - "1703-arguments-rest-props.cjs": 3485, - "1710-cjs-export-class/main.js": 2945, - "1711-cjs-export-single-values/main.js": 3527, - "1712-field-incdec.ts": 3301, - "1713-js-dyn-fields.js": 3702, - "1720-assert-throws-shape.ts": 3665, - "1721-assert-throws-regex-class.ts": 3205, - "1722-assert-rejects.ts": 3941, - "1723-assert-does-not-reject.ts": 3991, - "1724-assert-iferror.ts": 2922, - "1725-assert-symbols.ts": 4117, - "1726-promise-with-resolvers.ts": 3773, - "1727-assert-throws-shape-exit.ts": 4180, - "1730-countdown-symbol-keys/main.js": 3717, - "1731-symbol-field-shapes.cjs": 4041, - "1732-symbol-field-cross-module/main.js": 3671, - "1740-stream-extends-readable.ts": 5413, - "1741-stream-extends-writable.ts": 6469, - "1742-stream-extends-duplex-transform.ts": 6437, - "1743-stream-extends-vt-dispatch.ts": 7212, - "1744-stream-set-encoding.ts": 3635, - "1745-stream-encoding-js.cjs": 2973, - "1746-stream-for-await.ts": 4707, - "1747-stream-for-await-js.cjs": 4902, - "1750-http-agent-options.ts": 7371, - "1751-options-record-stance.ts": 4112, - "1760-surplus-args-drop.cjs": 3672, - "1761-emitter-special-event-names.cjs": 5508, - "1770-assert-dyn-strict.ts": 4072, - "1771-assert-dyn-deep.ts": 3521, - "1772-assert-dyn-js.cjs": 3744, - "1773-assert-dyn-exit.ts": 3156, - "1780-http-res-surface.ts": 7173, - "1781-http-server-shapes.cjs": 3500, - "1790-computed-key-folds.ts": 3641, - "1791-searchparams-core.ts": 3206, - "1792-searchparams-encoding.ts": 3500, - "1793-searchparams-iteration.ts": 3620, - "1794-searchparams-url-live.ts": 3114, - "1795-dyn-handle-request.cjs": 6764, - "1796-dyn-handle-body.cjs": 6226, - "1797-dyn-handle-socket.cjs": 3886, - "1798-dyn-handle-typed-box.ts": 6248, - "1800-immediate-basics.ts": 3211, - "1801-immediate-handle.ts": 3455, - "1802-immediate-unref-exit.ts": 3001, - "1803-timeout-refresh.ts": 3714, - "1804-timers-module.ts": 3580, - "1805-timer-callback-args.ts": 3293, - "1806-timer-delay-trunc.ts": 3354, - "1810-stream-options-const-record.ts": 4095, - "1811-stream-option-value-callbacks.cjs": 3113, - "1812-stream-super-options-forwarding.cjs": 3239, - "1813-stream-finished.ts": 3753, - "1814-stream-pipeline.cjs": 3633, - "1815-stream-state-reads.cjs": 3723, - "1820-static-block-basics.ts": 3496, - "1821-static-block-order.ts": 3121, - "1822-static-block-js.js": 2926, - "1823-static-instance-method-names.ts": 2971, - "1824-for-of-destructuring-defaults.ts": 3389, - "1825-exhaustive-typeof-switch.ts": 2558, - "1826-settimeout-arguments-callback.js": 3292, - "1830-enum-numeric-basics.ts": 3721, - "1831-enum-string-const-reverse.ts": 3386, - "1832-enum-modules/main.ts": 3491, - "1835-var-basics.ts": 3090, - "1836-var-loop-capture.ts": 4227, - "1837-var-undefined-hoisting.ts": 3129, - "1838-var-modules/main.ts": 3442, - "1839-var-js/main.cjs": 2943, - "1840-jsdoc-import-type-only/main.js": 3153, - "1850-overload-basics.ts": 3527, - "1851-overload-return-narrowing.ts": 3485, - "1852-overload-class-members.ts": 3165, - "1853-overload-modules/main.ts": 3369, - "1854-ambient-declare-fn.ts": 3339, - "1855-ambient-declare-fn-uncaught.ts": 2825, - "1870-unit-type-values.ts": 3760, - "1871-empty-array-never.ts": 2995, - "1872-template-tostring-composite.ts": 3281, - "1880-json-declared-field-order.ts": 3669, - "1881-default-anon/main.ts": 3229, - "1882-default-cjs-interop/main.ts": 3282, - "1883-default-exports/main.ts": 3775, - "1890-ns-imports/main.ts": 3324, - "1891-ns-reexport/main.ts": 3059, - "1940-class-values-basics.ts": 3481, - "1941-class-values-registry.ts": 3018, - "1942-class-expressions.ts": 2837, - "1943-class-statics-expanded.ts": 3294, - "1944-class-values-modules/main.ts": 3634, - "1950-generic-fn-values.ts": 3713, - "1951-generic-classes-basics.ts": 3449, - "1952-generic-class-statics-values.ts": 3863, - "1953-generic-class-hierarchy.ts": 3771, - "1954-generic-modules/main.ts": 3506, - "1960-namespace-basics.ts": 3039, - "1961-namespace-nested.ts": 2879, - "1962-namespace-classes.ts": 3820, - "1963-namespace-aliases.ts": 2943, - "1964-namespace-type-only.ts": 3637, - "1965-namespace-ambient.ts": 3549, - "1966-namespace-modules/main.ts": 3116, - "1967-namespace-alias-typeonly.ts": 2879, - "1968-namespace-import-eq-snapshot.ts": 3284, - "1970-decorators-basics.ts": 3029, - "1971-decorators-rebinding.ts": 3079, - "1972-decorators-throwing.ts": 2634, - "1973-decorators-ambient.ts": 3508, - "1980-primitive-proto-statics.ts": 3768, - "1981-date-utc.ts": 3681, - "1982-freeze-resolve-passthrough.ts": 3352, - "1983-array-tuple-surfaces.ts": 3130, - "1990-labels-basics.ts": 3662, - "1991-for-in-loops.ts": 4312, - "1992-small-syntax.ts": 3036, - "200-strings.ts": 3188, - "2000-generic-methods-basic.ts": 3233, - "2001-generic-methods-generic-class.ts": 3654, - "2002-generic-methods-inheritance.ts": 3883, - "2003-generic-methods-object-literal.ts": 4002, - "2004-generic-methods-statics.ts": 2781, - "201-templates.ts": 3259, - "2010-generators-basics.ts": 2930, - "2011-generators-forof.ts": 3439, - "2012-generators-return-throw.ts": 3077, - "2013-generators-sent-values.ts": 3157, - "2014-generators-values.ts": 3230, - "2015-generators-yieldstar.ts": 2691, - "2016-generators-rc-stress.ts": 3408, - "2017-generators-async.ts": 3645, - "2018-generators-uncaught.ts": 3372, - "2019-generators-loops.ts": 3684, - "2020-generic-value-bindings.ts": 4814, - "2021-generic-value-binding-modules/main.ts": 2613, - "2022-width-index-capture.ts": 4066, - "2023-width-readonly.ts": 3988, - "2024-width-array-elems.ts": 3088, - "2025-width-union-compose.ts": 3148, - "2026-width-spread.ts": 3721, - "2030-width-nested.ts": 3956, - "2031-width-tuples.ts": 3454, - "2032-cjs-export-assigned-class-expression/main.cjs": 3771, - "2033-property-assigned-class-extends.cjs": 2857, - "2035-ternary-array-retag.cjs": 3742, - "2036-evolving-array-decl.cjs": 3733, - "2037-fn-decl-hoisting.cjs": 3504, - "2038-evolving-array-js.cjs": 4258, - "2040-any-bindings.ts": 3664, - "2040-mixin-heritage.ts": 3192, - "2041-any-params-returns.ts": 3362, - "2041-mixin-values.ts": 3893, - "2042-any-flow-loops.ts": 3770, - "2042-mixin-modules/main.ts": 3144, - "2043-any-dom-values.ts": 3779, - "2043-mixin-rc-stress.ts": 4190, - "2044-vtable-sibling-slots.ts": 4054, - "2045-objlit-accessors-basic.ts": 3443, - "2045-parameter-properties.ts": 3049, - "2046-abstract-classes.ts": 4183, - "2046-objlit-accessors-effects.ts": 3215, - "2047-objlit-accessors-shapes.ts": 3091, - "2047-optional-class-fields.ts": 4146, - "2050-dynamic-import-own-module/main.ts": 3451, - "2051-dynamic-import-then/main.ts": 3601, - "2052-dynamic-import-self.ts": 3591, - "2053-typeof-static-fold.ts": 3479, - "2054-destructuring-island-source.ts": 3225, - "2060-empty-tuple.ts": 3198, - "2070-computed-key-folds.ts": 3432, - "2071-integer-key-enumeration-order.ts": 3897, - "2072-expando-function-members.ts": 3830, - "2073-destructuring-assignment.ts": 3540, - "2074-island-destructuring.ts": 3784, - "2075-index-signature-runtime-keys.ts": 2791, - "2080-destructuring-defaults.ts": 3781, - "2081-destructuring-rest.ts": 3728, - "2082-destructuring-assignment.ts": 3505, - "2085-destructuring-heads-rest-params.ts": 3490, - "2087-destructuring-for-heads.ts": 3190, - "2090-index-signature-number-keys.ts": 2803, - "2091-index-signature-string-intersection.ts": 2723, - "2092-package-imports/main.ts": 2857, - "2093-timers-promises.ts": 4034, - "2094-diagnostics-channel.ts": 3375, - "2095-js-catch-unknown.js": 3448, - "2096-os-type.ts": 3784, - "2097-js-evolving-globals.js": 3531, - "210-string-methods.ts": 3602, - "2100-stream-default-hwm.ts": 3572, - "2101-dyn-param-defaults.ts": 2799, - "2102-empty-pattern-decls.ts": 3305, - "2105-computed-key-static-folds.ts": 3458, - "2106-comma-expressions.ts": 3662, - "211-string-unicode.ts": 2722, - "2110-top-object-types.ts": 2930, - "2111-json-stringify-unknown.ts": 2894, - "2112-array-at-findlast.ts": 3347, - "2113-string-index-methods.js": 2954, - "212-string-aliasing-append.ts": 2936, - "2120-package-self-import/main.ts": 2637, - "2121-esm-cycle-inert-backedge/main.ts": 2688, - "2123-ambient-import-crash/main.ts": 2830, - "2124-imports-field-wildcard/main.ts": 2779, - "2140-uri-component-codecs.ts": 3028, - "2160-dc-tracing-channel.cjs": 3125, - "2161-js-object-literal-identity.cjs": 3710, - "2162-js-dyn-destructure.cjs": 2745, - "2163-js-selfref-const.cjs": 4243, - "2164-js-then-dyn-handler.cjs": 4454, - "2165-js-throw-dyn.cjs": 3859, - "2166-cjs-getter-this/main.cjs": 3481, - "2170-island-array-exits.ts": 5249, - "2171-island-json-stringify.ts": 3408, - "2172-island-regexp-boundary.ts": 4656, - "2190-new-object-and-string-wrappers.ts": 2892, - "2191-uri-encoders.ts": 2460, - "2192-object-default-tostring.ts": 3152, - "2193-discarded-stdlib-reads.ts": 3436, - "2194-ambient-undef-chains.ts": 3329, - "2195-require-missing-package/main.mjs": 3396, - "2196-island-computed-key-chain.ts": 4364, - "2210-dyn-promise-crossing.cjs": 3412, - "2211-dc-trace-promise.cjs": 4496, - "2212-unhandled-rejection-listener.cjs": 3503, - "2213-async-local-storage.cjs": 3304, - "2214-dc-bind-store.cjs": 4372, - "2215-process-emit-warning-exit.cjs": 4385, - "2240-width-class-into-record.ts": 3816, - "2241-width-record-into-class.ts": 3107, - "2242-width-statics-into-record.ts": 3187, - "2243-width-assert-satisfies-shapes.ts": 3725, - "2250-tagged-templates.ts": 2802, - "2252-class-iterators.ts": 4024, - "2253-union-coercions.ts": 2969, - "2260-http2-constants.cjs": 2611, - "2280-builtin-namespace-destructure.cjs": 2964, - "2281-domexception-atob-btoa.cjs": 3116, - "2282-queue-microtask.cjs": 3672, - "2283-structured-clone.cjs": 3661, - "2284-regexp-constructor.cjs": 2921, - "2285-iferror-dyn.cjs": 2815, - "2286-dyn-object-walks.cjs": 2814, - "2300-dyn-record-spread-and-keyed-access.cjs": 3340, - "2301-cjs-export-table-dom-attach.cjs": 2994, - "2310-process-next-tick.ts": 3462, - "2311-next-tick-js-callbacks.js": 3541, - "2312-stream-underscore-assign.ts": 4210, - "2313-stream-underscore-assign-js.cjs": 3281, - "2314-process-introspection.ts": 4007, - "2320-await-unit.ts": 2773, - "2321-emitter-static-setmax.cjs": 3576, - "2322-dyn-array-sort.cjs": 2683, - "2323-timer-callback-returns.ts": 3611, - "2330-tls-server-runtime-options.cjs": 22007, - "2331-tls-server-options-typed.ts": 22550, - "2350-nan-global.ts": 3586, - "2351-async-methods.ts": 3496, - "2352-void-coercions.ts": 2875, - "2353-decorators-member-ambient.ts": 2855, - "2354-decorators-expression-ambient.ts": 2445, - "2360-tuple-to-array.ts": 3725, - "2361-assign-index-record.ts": 3918, - "2362-execsync-inherit.ts": 3204, - "2363-nullish-retag.ts": 3277, - "2364-in-runtime-key.ts": 3653, - "2365-dyn-into-island.ts": 2967, - "2366-string-well-formed.ts": 3530, - "2367-regexp-escape.ts": 3537, - "2368-set-methods.ts": 3321, - "2369-promise-try.ts": 3477, - "2370-group-by.ts": 3834, - "2371-iterator-helpers.ts": 3503, - "2380-buffer-module-named-import.ts": 3337, - "2381-builtin-default-imports.js": 3386, - "2382-cycle-two-decl/main.ts": 2540, - "2383-cycle-assertdoc/main.js": 3635, - "2384-cycle-mixed-bindings/main.ts": 2680, - "2385-builtin-reexport-facade/main.ts": 2415, - "2386-string-to-chars.ts": 3358, - "2387-tonumber-argv.ts": 3189, - "2388-tonumber-grammar-zoo.ts": 2478, - "2389-tonumber-unary-plus.ts": 3505, - "2390-dot-requires/main.cjs": 3502, - "2391-default-builtin-imports/main.ts": 3560, - "2392-block-guard-alias-scope.ts": 2811, - "2393-loop-exit-guard-narrow.ts": 3396, - "2394-loop-narrow-containment.ts": 3368, - "2395-while-cond-guard.ts": 2736, - "2396-born-narrowed-decl.ts": 3324, - "2397-branch-kill-merge.ts": 2593, - "2398-switch-arm-kill.ts": 3348, - "2399-reassign-kill-polarity.ts": 3637, - "240-stdout-write.ts": 3882, - "2400-kill-return-edge.ts": 3195, - "2401-kill-break-staging.ts": 3449, - "2402-labeled-break-kill.ts": 2813, - "2403-kill-continue-backedge.ts": 3428, - "2404-kill-throw-catch.ts": 2824, - "2405-sibling-arm-narrow.ts": 2442, - "2406-switch-clause-sibling-narrow.ts": 2665, - "2407-infinite-loop-seal.ts": 3312, - "2408-loop-terminality-reopen.ts": 3281, - "2409-loop-body-return-not-terminal.ts": 3145, - "2410-stacked-cases-terminality.ts": 3627, - "2411-exhaustive-switch-terminality.ts": 3158, - "2412-dowhile-guard-trailing-test.ts": 3265, - "2413-dowhile-kill-renarrow.ts": 2701, - "2414-dowhile-continue-kill.ts": 3317, - "2415-dowhile-break-trailing-test.ts": 3362, - "2416-spread-ternary-positions.ts": 3467, - "2417-ternary-local-inference.ts": 3368, - "2418-wrapped-ternary-arms.ts": 3310, - "2419-selector-ternary-union.ts": 3702, - "2420-nullish-null-identity.ts": 2553, - "2421-float-lane-inference.ts": 3344, - "2422-ieee-div-rem-corners.ts": 3186, - "2423-param-null-reassign.ts": 3025, - "2424-ternary-miss-first-narrowing.ts": 3552, - "2425-elseif-head-exit-narrow.ts": 3257, - "2426-default-snapshot-mutable/main.ts": 3423, - "2427-perf-hooks-now.ts": 3049, - "2428-field-redeclare-inherited.ts": 3585, - "2429-destructure-class-instance.ts": 2694, - "2430-empty-literal-unknown-field.js": 3401, - "2431-primitive-ctor-values.ts": 2884, - "2432-generic-member-fields-async.ts": 5845, - "2433-as-const-command-tables.ts": 3180, - "2434-deferred-init-fields.ts": 3249, - "2435-loose-same-kind-equality.ts": 3363, - "2440-console-inspect-args.ts": 5418, - "2441-console-process-argv.ts": 3041, - "2442-union-literal-arm-widening.ts": 2555, - "2443-union-literal-shadow-narrowing.ts": 3302, - "2444-union-literal-reducer-spread.ts": 3618, - "2445-math-minmax-nary.ts": 2645, - "2446-performance-global.ts": 3980, - "2447-island-boundary-slots/main.ts": 6217, - "2448-entries-null-arms-regex-arrays.ts": 3545, - "2450-private-instance-methods.ts": 2931, - "2451-private-fields.ts": 3694, - "2452-private-statics.ts": 2965, - "2453-private-accessors.ts": 3478, - "2454-private-generator-methods.ts": 3697, - "2455-private-brand-checks.ts": 3515, - "2456-private-async-methods.ts": 3535, - "2457-private-members.js": 2780, - "2460-qs-parse-grammar.ts": 4534, - "2461-qs-parse-options.ts": 4115, - "2462-qs-stringify.ts": 3434, - "2463-qs-escape-unescape.ts": 3311, - "2464-qs-require-forms.cjs": 2821, - "2470-mockable-module-shape.js": 2978, - "2471-record-keyed-write-hasown.js": 2970, - "2472-string-regexp-union.ts": 3393, - "2473-option-table-widths.js": 3653, - "2474-island-literal-forms.ts": 3643, - "2475-variadic-wrapper-island.js": 3606, - "2476-map-regex-values.ts": 3711, - "2480-recursive-record-tree.ts": 3376, - "2481-mutual-recursive-records.ts": 3699, - "2482-recursive-union-tree.ts": 3347, - "2483-recursive-record-cycles.ts": 2764, - "2484-json-stringify-circular.ts": 3845, - "2485-inspect-circular-refs.ts": 3694, - "2486-recursive-record-boundaries.ts": 3988, - "2487-recursive-deep-equal.ts": 3416, - "2488-ast-walker.ts": 3100, - "2490-find-miss-null-compare.ts": 3107, - "2491-strict-unit-compare-no-arm.ts": 2820, - "2492-loose-null-compare-unions.ts": 3683, - "2493-switch-unit-cases.ts": 3703, - "2494-no-arm-compare-effects.ts": 3089, - "2500-net-autosel-timeout.ts": 3775, - "2510-dyn-evolving-array-map.ts": 3265, - "2511-dyn-evolving-array-filter-foreach.ts": 2885, - "2512-dyn-evolving-array-mixed-push.ts": 3639, - "2520-private-statics-class-name-calls.ts": 3155, - "2521-private-statics-class-expression.ts": 3520, - "2522-private-statics-decorated.ts": 3673, - "2523-private-statics-aliased-class.ts": 3795, - "2530-object-destructuring-decl.ts": 2869, - "2531-array-tuple-destructuring-decl.ts": 3168, - "2532-param-destructuring-options.ts": 2906, - "2533-forof-destructuring.ts": 2840, - "2534-object-rest-decl.ts": 3199, - "2535-destructuring-assign-basics.ts": 3816, - "2536-destructuring-assign-nested.ts": 3047, - "2537-destructuring-assign-member-targets.ts": 3590, - "2538-destructuring-assign-class-source.ts": 3544, - "2539-class-instance-rest.ts": 3764, - "2540-accessor-destructuring-defaults.ts": 3201, - "2541-destructuring-eval-order.ts": 2670, - "2550-generics-keyof-pick.ts": 3947, - "2551-generics-value-aliases.ts": 3227, - "2552-generics-iface-methods.ts": 3318, - "2553-generics-signature-bindings.ts": 3442, - "2554-generics-frontier-mix.ts": 3344, - "2555-generics-keyof-writes.ts": 3448, - "2556-crypto-introspection.ts": 3351, - "2556-width-hybrid-shapes.ts": 3462, - "2557-tls-ca-store.ts": 4438, - "2557-width-field-lifts.ts": 4453, - "2558-index-signature-func-values.ts": 3590, - "2558-rejection-events.cjs": 3641, - "2559-index-signature-container-values.ts": 4066, - "2560-arraybuffer-dataview-set.ts": 3614, - "2561-object-is.ts": 3391, - "2562-intl-numberformat-en-us.ts": 3241, - "2563-stream-promises-pipeline.ts": 3490, - "2564-stream-promises-finished.ts": 2994, - "2565-stream-promises-js.cjs": 2616, - "2566-promise-reject-dyn-reason.js": 3548, - "2567-rest-spread-forward.js": 3292, - "2568-rest-spread-forward-dynamic.js": 3367, - "2569-upcast-identity.ts": 2553, - "2570-buffer-arg-validation.cjs": 5779, - "2571-searchparams-arg-validation.cjs": 3913, - "2572-readable-emitted-readable-flag.cjs": 3556, - "2573-fs-url-arg-ladders.cjs": 3502, - "2574-emitter-max-listeners-ladders.cjs": 2895, - "2575-string-destructuring-decl.ts": 3433, - "2576-string-destructuring-assign.ts": 2984, - "2577-builtin-global-destructuring.js": 3466, - "2578-jsval-into-unknown-rows.ts": 3398, - "2579-jsval-object-param-crossing.js": 3294, - "2580-jsval-routed-keyed-ops.js": 3298, - "2581-jsval-routed-calls.js": 3542, - "2582-jsval-object-statics.js": 3509, - "2582-jsval-routed-keyed-ops.js": 3136, - "2583-dyn-nullish-coalesce.js": 2976, - "2583-jsval-routed-calls.js": 2950, - "2584-jsval-object-statics.js": 3305, - "2584-union-dyn-collapse.ts": 2970, - "2585-dyn-nullish-coalesce.js": 3632, - "2585-unknown-array.ts": 3809, - "2586-object-assign-spread.js": 4084, - "2587-array-entries-forof.ts": 2633, - "2588-array-entries-chains.ts": 4097, - "2589-object-create-null.cjs": 3112, - "2590-object-create-dynamic.js": 4279, - "2591-ambient-generic-traps.ts": 3216, - "2592-ambient-trap-uncaught.ts": 3198, - "2593-generic-inert-bindings.ts": 3007, - "2594-nullish-generic-bindings.ts": 3321, - "2595-fs-arg-ladders.cjs": 3930, - "2596-net-arg-ladders.cjs": 3528, - "2597-dgram-send-ladders.cjs": 4536, - "2598-tls-arg-ladders.cjs": 4142, - "2599-stream-arg-ladders.cjs": 5465, - "2600-dyn-keyed-write-harness.js": 2800, - "2601-dyn-keyed-write-ops.js": 3269, - "2602-dyn-array-destructure.js": 3207, - "2603-island-keyed-write-dyn.js": 3608, - "2604-cycle-classes-mutual/main.ts": 3410, - "2605-cycle-three-module/main.ts": 2592, - "2606-dynamic-import-cycle/main.ts": 2445, - "2608-regex-named-groups.ts": 3896, - "2609-regex-named-replace.ts": 3215, - "2610-regex-named-matchall.ts": 3887, - "2611-regex-named-groups-js.cjs": 3523, - "2613-for-init-uninitialized-let.ts": 3167, - "2614-trap-binding-later-writes.ts": 3345, - "2615-nullish-field-record-binding.ts": 2720, - "2616-js-collect-probe-defers.js": 3534, - "2617-enum-static-field-import/main.ts": 3068, - "2618-ee-emit-override.ts": 3915, - "2619-ee-override-chain.ts": 2567, - "2620-ee-override-once-order.ts": 3439, - "2621-ee-override-error-throw.ts": 3265, - "2622-ee-override-filter.ts": 3339, - "2623-ee-job-queue.ts": 3586, - "2624-ee-override-js.cjs": 2637, - "2625-bytes-views.ts": 2847, - "2626-stream-event-names.ts": 3436, - "2627-stream-ticks-are-nextticks.ts": 4048, - "2628-stream-push-encodings.cjs": 3219, - "2629-stream-consumers.ts": 4523, - "2630-stream-consumers-errors.ts": 3353, - "2631-create-require/main.ts": 2869, - "2632-dyn-jsval-iterate.js": 3938, - "2633-island-promise-crossing.js": 3898, - "2634-stream-pipeline-arg-ladders.cjs": 2829, - "2635-trap-binding-unmappable-written.ts": 3493, - "2636-trap-binding-ambient-rooted-rewrite.ts": 3155, - "2637-create-require-bare/main.ts": 3093, - "2638-http-dyn-res-compat.cjs": 7897, - "2639-http-dyn-req-pause.cjs": 4028, - "2640-net-dyn-socket-compat.cjs": 3877, - "2641-http-agent-surface.cjs": 6286, - "2642-http-agent-maxsockets.cjs": 4681, - "2643-or-default-retag.ts": 3292, - "2644-http-client-url-argument.ts": 3256, - "2645-https-client-url-argument.ts": 24258, - "2646-top-level-await.ts": 3392, - "2647-top-level-await-modules/main.ts": 3047, - "2648-top-level-await-rejection.ts": 3150, - "2649-top-level-await-pending.ts": 3160, - "2650-top-level-await-self-import.ts": 2440, - "2651-top-level-await-pending-unhandled.ts": 2762, - "2652-top-level-await-dynamic/main.ts": 3760, - "2653-top-level-await-rejection-stops-loop.ts": 2631, - "2654-top-level-await-unrelated-rejection.ts": 2643, - "2655-top-level-await-cycle/main.ts": 3098, - "2656-top-level-await-cycle-order/main.ts": 3167, - "2657-top-level-await-cycle-dynamic/main.ts": 2957, - "2658-top-level-await-sync-completion/main.ts": 3318, - "2659-top-level-await-dynamic-cycle/main.ts": 2585, - "2660-top-level-await-cycle-rejection/main.ts": 3210, - "2661-top-level-await-dynamic-runtime-root/main.ts": 3366, - "2662-top-level-await-cycle-external-wait/main.ts": 3005, - "2663-top-level-await-dependency-errors/main.ts": 2847, - "2664-top-level-await-same-checkpoint-rejection.ts": 3116, - "2665-top-level-await-unhandled-listener-liveness.ts": 2875, - "2666-array-to-sorted.ts": 7633, - "2668-stored-number-array-iterator.ts": 3253, - "2669-array-copying-methods.ts": 3549, - "2670-uint8array-copy-iterate.ts": 3853, - "2671-array-copying-js.cjs": 3682, - "2672-http-request-response-callback.ts": 4143, - "2673-top-level-await-implicit-module.ts": 3247, - "2674-top-level-for-await-implicit-module.ts": 3134, - "2675-create-require-nested-esm.js": 2364, - "2675-process-self-reexec.ts": 2727, - "2676-indexed-read-strict-equality.ts": 2731, - "2676-record-clone-overrides.ts": 2957, - "2676-top-level-await-ambiguous/main.ts": 2732, - "2677-runtime-optional-closure.ts": 4013, - "2677-top-level-await-module-scope/main.ts": 3413, - "2678-date-instances.ts": 2682, - "2678-large-string-sparse-index.ts": 3695, - "2678-util-parseargs.ts": 6509, - "2679-util-parseargs-cjs.cjs": 4674, - "2680-util-parseargs-default.ts": 2968, - "2681-util-parseargs-dynamic.js": 4805, - "2682-fs-rename.ts": 3870, - "2683-filter-truthy-predicate.ts": 3057, - "2683-fs-rename-js.cjs": 3194, - "2684-filter-no-predicate-dyn.cjs": 2886, - "2684-fs-rename-abort.ts": 4187, - "2685-array-unshift-reverse.ts": 3336, - "2685-fs-write-sync.ts": 3018, - "2686-fs-file-handle.ts": 4533, - "2687-fsp-write-file-options.ts": 3468, - "2687-process-write-args.ts": 4056, - "2688-fs-stats-disk-fields.ts": 3885, - "2689-http-server-timeout-properties.ts": 3928, - "2690-https-server-timeout-option.ts": 21635, - "2691-retained-lowering-record-order.ts": 4394, - "2692-inline-record-assert-index.ts": 4260, - "2692-string-accumulation.ts": 2769, - "2693-math-constants.ts": 2825, - "2700-array-sort-complexity.ts": 3067, - "2700-http-static-trailers.ts": 3428, - "2700-wasi-core.ts": 3839, - "2701-array-sort-snapshot.ts": 3995, - "2701-http-static-trailer-wire.ts": 3237, - "2701-import-meta/main.mjs": 2794, - "2702-http-static-trailer-end.ts": 3525, - "2702-type-import-link-static/main.ts": 3217, - "2702-uint8array-to-sorted.ts": 3838, - "2703-array-sparse-sort.ts": 7138, - "2703-type-import-link-static-reexport/main.ts": 2989, - "2704-array-sparse-to-sorted.ts": 7251, - "2704-type-import-link-static-success/main.ts": 3249, - "2705-array-sparse-sort-append.ts": 6240, - "2705-type-import-link-dynamic/main.ts": 2760, - "2706-array-search-missing-needle.ts": 3091, - "2706-type-import-link-dynamic-success/main.ts": 3330, - "2707-array-search-huge-sparse.ts": 45179, - "2707-type-import-link-static-default-reexport/main.ts": 2758, - "2708-type-import-link-dynamic/main.ts": 4132, - "2720-array-read-parity.ts": 3456, - "2721-array-nested-missing-receiver.ts": 3322, - "2750-array-sparse-foundation.ts": 3816, - "2751-buffer-concat-sparse-list.ts": 3043, - "2752-array-optional-stores.ts": 3548, - "2753-array-optional-method-values.ts": 3422, - "2754-array-property-undefined.ts": 3456, - "2755-array-optional-literal-forwarding.ts": 3507, - "2780-array-parity-composition.ts": 9748, - "2781-array-missing-value-escape.ts": 2984, - "2782-array-sparse-callbacks.ts": 3368, - "2783-array-defaults-rest.ts": 3426, - "2784-array-reduce-missing-result.ts": 2920, - "2785-array-missing-destructuring.ts": 4220, - "2786-array-sparse-serialization.ts": 3688, - "2787-array-missing-string-arithmetic.ts": 2565, - "2788-array-missing-builtin-conversions.ts": 2767, - "2789-array-missing-optional-tostring.ts": 3009, - "2790-dynamic-import-self-name/main.ts": 3621, - "2791-record-optional-keys.ts": 3660, - "2792-record-optional-spread-entries.ts": 3741, - "2793-union-conversion-identity-capture.ts": 3519, - "2794-array-generic-callback-values.ts": 2842, - "2795-array-optional-typedarray-source.ts": 29642, - "2796-array-sparse-class-value-instanceof.ts": 4014, - "2800-array-expression-consumers.ts": 2964, - "2801-array-switch-consumers.ts": 3634, - "2820-array-missing-method-receivers.ts": 3219, - "2821-array-optional-numeric-comparisons.ts": 3648, - "2830-cjs-require-self-name/main.cjs": 2817, - "2840-finally-completions.ts": 2484, - "2841-using-sync.ts": 3654, - "2842-await-using.ts": 3139, - "2843-using-suppressed-error.ts": 3369, - "2844-node-disposable-resources.ts": 3909, - "2845-for-using-of.ts": 3562, - "2846-generator-using.ts": 3676, - "2850-async-generators-protocol.ts": 4224, - "2851-async-generators-values.ts": 3418, - "2852-timers-promises-interval.ts": 3999, - "2854-leading-bom-literals.ts": 3644, - "2855-searchparams-sort-complexity.ts": 2896, - "2856-dynamic-any-local-operators.ts": 3122, - "2857-branded-primitives.ts": 2535, - "2858-import-meta-resolve/main.mjs": 2803, - "2859-import-meta-resolve-dynamic/main.mjs": 2791, - "2860-require-resolve/main.cjs": 3416, - "2861-readable-iterator-close.ts": 3965, - "2862-web-readable-async-iteration.ts": 48807, - "2863-class-async-iterator.ts": 3227, - "2864-array-class-method-receivers.ts": 2404, - "2865-cjs-process-alias.cjs": 3403, - "2866-dyn-switch.ts": 2311, - "2867-array-shift-length.js": 3507, - "2868-empty-record-promise-presence.js": 2925, - "2869-nullish-mixed-lazy.ts": 2958, - "2870-and-dropped-truthy-arm.ts": 2834, - "2871-optional-promise-to-unknown.ts": 3267, - "2872-unobserved-dynamic-event.ts": 3355, - "2873-optional-receiver-loop-lifetime.js": 3047, - "2874-nullable-callback-field-cycle.js": 3534, - "2875-evolving-let-read-before-write.js": 2810, - "2876-class-unknown-roundtrip.ts": 3764, - "2877-child-unknown-roundtrip.ts": 2785, - "2878-class-private-unknown.cjs": 3352, - "2880-cjs-module-graph/main.cjs": 3782, - "2890-crypto-static-utility.ts": 2826, - "2891-json-record-key-escapes.ts": 3816, - "2892-windows-console-unicode.ts": 3563, - "2893-child-stdin-duplex.ts": 3578, - "2894-child-stdin-backpressure.ts": 3536, - "2895-child-stdin-write-after-end.ts": 3038, - "2896-child-stdin-write-after-finish.ts": 3391, - "2897-child-stdin-destroy.ts": 3563, - "2898-child-stdin-spawn-failure.ts": 3036, - "2899-nested-mutual-recursion.ts": 3350, - "2900-float64array-static.ts": 3865, - "2900-void-conditional-arrow.ts": 2828, - "2901-bigint-core.ts": 3440, - "2902-bigint-bytes.ts": 2684, - "2903-bigint-storage.ts": 3029, - "2904-bigint-errors.ts": 3660, - "2905-bigint-edges.ts": 3424, - "2906-bigint-wasi-width.ts": 3017, - "2910-overloaded-callable-alias.ts": 3175, - "2911-execfile-callback.ts": 3152, - "2912-execfile-callback-options.ts": 3514, - "2912-promisify-fs-readfile.ts": 3307, - "2913-builtin-callable-alias.ts": 4333, - "2914-fixed-tuple-call-spread.ts": 3657, - "2915-path-function-values.ts": 2684, - "2916-path-function-values-cjs.ts": 3544, - "2917-builtin-callable-widths.ts": 3312, - "2918-builtin-callable-widths-cjs.ts": 4040, - "2919-fs-function-values.ts": 4214, - "2920-fs-promises-function-values.ts": 2447, - "2921-zlib-callbacks.ts": 4192, - "2922-dyn-bitwise-not.cjs": 2704, - "2923-cjs-factory-export/main.cjs": 3106, - "2930-union-receiver-calls.ts": 3700, - "2931-union-dynamic-field-call.js": 3466, - "2932-create-require-program/main.ts": 3686, - "2933-static-dynamic-import/main.ts": 3405, - "2934-static-import-stored.ts": 2381, - "2935-module-namespace-values/main.ts": 3289, - "2936-static-loose-equality.ts": 3642, - "2937-bitwise-hot-loop.ts": 3298, - "2938-fs-sync-overloads.cjs": 2598, - "2939-child-shell-text.ts": 2919, - "2940-date-parse.ts": 3171, - "2940-fsp-realpath.ts": 3497, - "2941-fsp-lstat-identity.ts": 3608, - "2941-process-exit-code.ts": 3007, - "2942-fsp-readdir-dirent.ts": 3744, - "2942-process-exit-code-override.ts": 2479, - "2943-process-exit-code-invalid.ts": 3225, - "2944-process-exit-code-wrap.ts": 3249, - "2945-url-origin-username.ts": 2371, - "2946-child-fork-ipc/main.ts": 4191, - "2946-url-port-hash.ts": 2720, - "2947-set-readonly-seeds.ts": 3363, - "2948-child-fork-eof-callback/main.ts": 3691, - "2948-stdio-callback-record.ts": 3021, - "2949-child-fork-default/main.mjs": 3752, - "2949-url-password.ts": 3268, - "2950-fs-descriptor-publication.ts": 3039, - "2951-math-static-analytic.ts": 2897, - "2952-math-static-remaining.ts": 3708, - "2953-http-header-validation.ts": 2926, - "2954-http-outgoing-headers.ts": 3568, - "2955-http-static-state.ts": 3392, - "2956-http-static-informational.ts": 3156, - "2957-http-static-response-controls.ts": 3011, - "2961-emitter-computed-names.cjs": 3061, - "2962-emitter-computed-optional.ts": 3117, - "2963-child-fork-dispatch/main.ts": 3069, - "2964-indexed-compound.ts": 4283, - "2966-numeric-array-read-fusion.ts": 2881, - "2967-numeric-array-read-lifetime.ts": 3327, - "2968-numeric-array-borrow.ts": 3624, - "2969-scalar-record-results.ts": 3705, - "2970-constant-numeric-tables.ts": 3396, - "2971-constant-table-modules/main.ts": 2786, - "2972-http-static-distinct-snapshots.ts": 3464, - "2972-math-receiver-borrow.ts": 4257, - "2973-http-static-agent.ts": 3844, - "2973-integer-bitwise-arithmetic.ts": 3703, - "2974-array-search-from-index.ts": 120829, - "2974-http-static-module-values.ts": 5733, - "2974-numeric-remainder.ts": 3749, - "2975-bigint-default-radix.ts": 2671, - "2975-http-static-client-controls.ts": 3229, - "2976-http-static-incoming-state.ts": 3560, - "2976-json-stringify-no-arguments.js": 3221, - "2977-http-static-incoming-timeout.ts": 3554, - "2977-nested-array-binding-defaults.js": 3145, - "2978-http-static-client-timeout.ts": 3607, - "2978-regexp-optional-subject.js": 3504, - "2979-array-search-mixed-needles.js": 2692, - "2979-http-static-server-timeout.ts": 3769, - "2980-http-static-server-timeout-default.ts": 3050, - "2980-string-position-arguments.js": 3269, - "2981-http-static-events.ts": 2644, - "2981-string-optional-positions.ts": 2494, - "2982-http-static-close-all.ts": 2737, - "2982-string-position-coercion-order.js": 3410, - "2983-http-static-close-idle.ts": 3031, - "2984-http-static-close-upgrade.ts": 3101, - "2985-http-static-message-destroy.ts": 3632, - "2986-http-static-client-socket-finish.ts": 2911, - "2987-http-static-timeout-errors.ts": 3301, - "2988-http-static-client-abort.ts": 2940, - "2989-http-static-response-timeout-handled.ts": 3640, - "2990-http-static-request-timeout-handled.ts": 3597, - "2991-array-indexed-equality.ts": 3696, - "2992-stream-rows.ts": 3357, - "2993-fiber-stack-lifetimes.ts": 3545, - "2994-fromcharcode-scalar.ts": 3381, - "2995-math-hyperbolic.ts": 3225, - "2996-math-near-one.ts": 2714, - "2997-math-integer-float.ts": 3635, - "300-if-else.ts": 2510, - "3001-caught-typeof-object.js": 3444, - "3002-promise-then-two.ts": 3645, - "301-while.ts": 3200, - "302-for.ts": 2865, - "3020-string-last-index-position.ts": 3627, - "3021-buffer-union-narrow-callback.ts": 3829, - "3022-string-affix-positions.ts": 3463, - "3023-string-affix-position-coercion.js": 3644, - "3024-string-number-narrow-for-in.ts": 3394, - "3025-string-search-position-coercion.js": 3367, - "3026-array-last-index-of.js": 2868, - "3027-array-last-index-of-records.ts": 3472, - "3028-string-search-dynamic-needle.js": 2934, - "3029-string-search-union-needle.js": 3701, - "303-break-continue.ts": 2701, - "3030-array-search-no-arg.js": 3806, - "3031-array-relative-index-coercion.js": 3498, - "3031-string-last-index-search-value.js": 2610, - "3032-string-search-value.js": 3067, - "3033-string-search-needle-coercion.js": 3292, - "3034-arguments-with-parameters.js": 2687, - "3035-string-positioned-search-value.js": 3575, - "3036-string-object-search-value.js": 2688, - "3037-number-nullish-conversion.js": 3018, - "3038-number-scalar-unions.ts": 2381, - "3039-string-repeat-count.js": 2336, - "304-compound-incdec.ts": 3307, - "3040-string-prototype-call.js": 3584, - "3041-string-prototype-object-call.js": 3163, - "3042-string-padding-coercion.js": 3486, - "3043-string-split-arguments.js": 3038, - "3044-array-slice-splice-positions.js": 3582, - "3045-array-indexed-mutation.js": 4003, - "3046-array-indexed-ref-identity.ts": 2594, - "3047-object-prototype-tag.js": 5012, - "3048-object-own-prototype.ts": 4080, - "3049-array-flat-depth.ts": 3414, - "305-truthiness.ts": 2664, - "3050-array-splice-insert.ts": 2966, - "3051-array-join-default.ts": 3468, - "3052-array-construction.ts": 4201, - "3053-array-construction-js.js": 2937, - "3054-dynamic-abort-record.ts": 25141, - "3055-default-builtin-nodenext/main.ts": 2702, - "3056-default-builtin-bundler/main.ts": 3487, - "3057-default-builtin-nodenext-dynamic/main.ts": 2447, - "3058-optional-array-chain-join.ts": 3991, - "3059-arguments-property-names.ts": 2550, - "3061-concurrent-fiber-stacks.ts": 3788, - "3062-runtime-optional-record-guards.ts": 3181, - "3063-runtime-optional-class-guards.ts": 3568, - "3064-installed-entry-imports/main.ts": 2606, - "3065-installed-entry-js/main.js": 3045, - "3066-source-debugging/main.ts": 3383, - "3067-cjs-function-export-require/main.cjs": 2939, - "3068-debug-variables/main.ts": 2618, - "3068-url-checked-identity.ts": 3006, - "3069-set-checked-seed.js": 3140, - "3069-tuple-spread.ts": 3376, - "3070-checked-object-accessors.js": 3573, - "3070-collection-views.ts": 3175, - "3071-checked-specialization-narrowing.js": 3321, - "3071-map-contextual-record-seeds.ts": 4329, - "3072-optional-union-receivers.ts": 3610, - "3072-weak-process-streams.js": 2918, - "3073-optional-callable-module.js": 3300, - "3073-union-keyed-reads.ts": 3869, - "3074-discriminated-intersections.ts": 3384, - "3075-recursive-contextual-literals.ts": 4502, - "3076-nullish-record-defaults.ts": 3009, - "3077-optional-union-array-reads.ts": 3992, - "3078-forward-mutable-captures.ts": 3466, - "3079-forward-mutable-tdz.ts": 3489, - "3080-exhaustive-never-bindings.ts": 3664, - "3081-recursive-array-destinations.ts": 3893, - "3082-forward-write-unwind.ts": 3471, - "3083-set-string-seed.ts": 3139, - "3084-record-own-membership.ts": 2971, - "3085-conditional-record-construction.ts": 3822, - "3086-error-constructor-options.ts": 3660, - "3087-error-options-lifetime.ts": 2905, - "3088-array-wide-callbacks.ts": 3195, - "3089-array-find-narrowing.ts": 4220, - "3090-json-discriminated-records.ts": 3463, - "3091-json-recursive-discriminants.ts": 3555, - "3092-number-union-predicates.ts": 2884, - "3093-error-option-data.ts": 2574, - "3094-json-replacer-traversal.ts": 3823, - "3095-json-reviver-traversal.ts": 3825, - "3096-json-callback-nonfinite.ts": 3620, - "3097-json-callback-reentrancy.ts": 2760, - "3098-json-callback-space.ts": 3696, - "3099-json-callback-functions.ts": 4108, - "3100-json-callback-holder.js": 3675, - "3101-json-callback-bytes.ts": 3250, - "3102-json-unknown-fields.ts": 2925, - "3103-scalar-record-nested-control-flow.ts": 3592, - "3104-native-analysis-tables-loops.ts": 3494, - "3105-nullable-collections.ts": 3244, - "3106-mixed-insertion-spreads.ts": 4146, - "3107-nullable-collection-lifetimes.ts": 3486, - "3108-for-await-sync-arrays.js": 4312, - "3108-identity-map-keys.ts": 3894, - "3109-destructuring-unknown-defaults.js": 3234, - "3109-identity-union-collections.ts": 3977, - "3110-builtin-error-families.ts": 3250, - "3110-identity-collection-mutation.ts": 3825, - "3111-identity-collection-cycles.ts": 3640, - "3112-union-switch-control-flow.ts": 2681, - "3113-union-array-removal.ts": 3778, - "3114-union-record-field-write.ts": 3884, - "3115-zlib-static-compression-levels.ts": 4085, - "3116-sequence-expression-lifetimes.ts": 3245, - "3117-unknown-switch-control-flow.ts": 3706, - "3118-recursive-union-spread.ts": 3476, - "3119-runtime-optional-spread.ts": 4508, - "3120-dynamic-property-descriptors.js": 3228, - "3120-generator-method-loop-bindings.ts": 3222, - "3120-ir-nonfinite-numbers.ts": 3251, - "3121-compound-assignment-values.js": 3525, - "3121-dynamic-accessor-descriptors.js": 4470, - "3122-dynamic-delete-descriptors.cjs": 3353, - "3122-dynamic-delete-descriptors.js": 3300, - "3122-js-async-class-methods.js": 3524, - "3123-destructured-global-tdz.js": 3896, - "3124-array-prototype-borrow.js": 4000, - "3125-regex-global-match.ts": 2889, - "3126-js-number-radix/main.ts": 3491, - "3127-spawn-runtime-options.ts": 3338, - "3128-regex-last-index.ts": 3768, - "3129-js-token-union/main.ts": 3461, - "3130-child-generic-streams.ts": 3435, - "3131-child-rest-listeners.js": 3280, - "3132-child-generic-stream-completion.ts": 6821, - "3133-text-decoder-streaming.ts": 32031, - "3134-fs-vectors.ts": 3621, - "3135-fs-file-handle-controls.ts": 3152, - "3136-fs-file-handle-options.ts": 4992, - "3137-fs-vector-callbacks.cjs": 3636, - "3138-array-large-storage.ts": 5104, - "3139-regex-native-deep-alternatives.ts": 38096, - "3140-array-dense-access.ts": 4712, - "3141-map-string-key-hash.ts": 3358, - "3150-integer-remainder.ts": 3568, - "3151-array-push-writes.ts": 3892, - "3170-number-conversion-fast-paths.ts": 2663, - "3171-method-census-data-writes.ts": 4253, - "400-fib.ts": 3919, - "401-mutual-recursion.ts": 2844, - "402-string-functions.ts": 3081, - "403-void-and-params.ts": 3112, - "4030-runtime-object-truthiness.ts": 3275, - "4031-event-emitter-long-tuples.ts": 3646, - "4032-inline-rc-fast-paths.ts": 4866, - "404-rc-stress.ts": 2781, - "4040-adapted-function-identity.ts": 3610, - "4041-adapted-function-properties.ts": 3413, - "4042-object-is-union-subclass.ts": 2746, - "4043-nonnull-missing-element.ts": 3815, - "4044-adapted-callback-modules/main.ts": 2918, - "4045-optional-element-projections.ts": 4182, - "4046-captured-parameter-values.ts": 4191, - "4047-captured-parameter-rebinding.ts": 2867, - "405-params-optional.ts": 2408, - "406-params-defaults.ts": 2614, - "4060-cycle-shared-instance/main.ts": 2758, - "4060-stack-union-reads.ts": 4386, - "4061-cycle-evaluation-order/main.ts": 3229, - "4061-nullable-ref-fields.ts": 6151, - "4062-cycle-tdz-read/main.ts": 3056, - "4063-cycle-hoisted-calls/main.ts": 3238, - "4064-cycle-classes-after-init/main.ts": 2548, - "4065-cycle-init-throws/main.ts": 2955, - "4066-cycle-top-level-tdz/main.ts": 3040, - "4067-dynamic-import-cycle-tdz/main.ts": 3004, - "407-params-rest.ts": 3335, - "408-params-ctors-inheritance.ts": 3021, - "4080-optional-read-presence-tests.ts": 3095, - "4080-string-index-bounds.ts": 3083, - "4081-hoisted-function-tdz.ts": 3193, - "4081-string-index-unproven.ts": 3273, - "4082-hoisted-function-tdz-uncaught.ts": 2845, - "4083-dynamic-import-failure/main.ts": 3748, - "4084-record-optional-field-copies.ts": 4118, - "4085-generator-loop-close.ts": 3638, - "4086-optional-capture-defaults.ts": 3227, - "4088-class-static-tdz.ts": 3234, - "4089-class-wrapper-tdz.js": 3393, - "409-params-async-generics.ts": 2742, - "4090-computed-key-tdz.js": 2796, - "4091-class-evaluation-deferred.ts": 3464, - "410-params-rc-stress.ts": 3461, - "4140-array-callback-split-visit.ts": 7289, - "4141-array-callback-ambient-receiver/main.ts": 3100, - "4142-array-callback-factories.ts": 4541, - "4143-union-refinement-intersection-arms.ts": 3822, - "420-dead-strip-modules/main.ts": 3118, - "4290-acyclic-immutable-trees.ts": 3580, - "4291-acyclic-constructor-escapes.ts": 3039, - "4292-acyclic-readonly-bypass.ts": 4316, - "4293-acyclic-dynamic-writes.ts": 3268, - "4294-console-line-sizes.ts": 6986, - "4295-console-template-parts.ts": 3358, - "4296-console-glued-long-parts.ts": 3290, - "4410-inline-object-allocation.ts": 3305, - "4411-nullable-ref-values.ts": 5301, - "4412-nullable-record-values.ts": 5088, - "4413-cycle-old-late-death.ts": 4012, - "4413-nullable-null-and-undefined.ts": 4328, - "4414-cycle-old-weak-keys.ts": 4005, - "4414-nullable-string-values.ts": 5044, - "4415-identity-borrowed-operands.ts": 3101, - "4415-nullable-container-values.ts": 4932, - "4431-exception-pending-contexts.ts": 3487, - "4432-checked-downcast-failures.ts": 3971, - "4451-int32-field-storage.ts": 3668, - "4452-int32-field-dynamic-writes.ts": 4531, - "4453-int32-closed-locals.ts": 2786, + "001-hello.ts": 47467, + "002-log-args.ts": 4723, + "100-number-format.ts": 49913, + "1000-json-stringify-basics.ts": 49071, + "1001-json-escapes-unicode.ts": 5167, + "1002-json-parse-cast.ts": 48226, + "1003-json-parse-unions.ts": 5247, + "1004-json-parse-errors.ts": 4196, + "1005-json-nested.ts": 8262, + "1006-json-fs-config.ts": 36095, + "1007-json-rc-stress.ts": 30487, + "1008-json-null-arms.ts": 48758, + "1009-json-optional-fields.ts": 3469, + "101-arithmetic.ts": 49638, + "1010-json-stringify-space.ts": 48585, + "1011-json-unknown-typeof.ts": 52058, + "102-comparisons.ts": 47851, + "1020-async-basics.ts": 4722, + "1021-async-ordering.ts": 4973, + "1022-async-exceptions.ts": 49732, + "1023-async-rc-stress.ts": 6131, + "1024-async-pending-exit.ts": 48202, + "1025-async-promise-capture.ts": 3959, + "1026-throw-promise.ts": 4948, + "1027-async-return-promise.ts": 4908, + "1028-async-return-record-literals.ts": 4271, + "1029-async-eager-chains.ts": 3619, + "103-ternary.ts": 5182, + "104-ternary-empty-arrays.ts": 7669, + "1050-comptime-tables.ts": 4897, + "1051-comptime-strings.ts": 47107, + "1052-comptime-records.ts": 39735, + "1053-comptime-json.ts": 5104, + "1054-comptime-modules/main.ts": 48253, + "110-number-radix.ts": 3792, + "111-record-entries.ts": 7069, + "1110-math-members.ts": 5365, + "1111-math-random.ts": 4260, + "1113-string-methods.ts": 54370, + "1114-string-unicode-island.ts": 52372, + "1115-parse-globals.ts": 3948, + "1116-island-static-mix.ts": 42223, + "1117-typeof-static-union.ts": 4732, + "1118-object-spread-conditional.ts": 39126, + "1119-switch-union.ts": 28754, + "112-class-descriptor-key.js": 39424, + "1121-infinity-number-tostring.ts": 4725, + "1122-any-captures.ts": 7404, + "1124-union-narrowed-retag.ts": 6000, + "113-promise-checked-exits.ts": 3453, + "114-live-record-delete.ts": 4924, + "115-array-compound.js": 5191, + "116-text-decoder-runtime.js": 46050, + "117-weak-cache-cycle.js": 5083, + "118-fs-stored-callbacks.cjs": 56960, + "119-native-patterns.js": 8396, + "1200-regex-test-basics.ts": 52932, + "1201-regex-replace.ts": 57037, + "1202-regex-substitutions.ts": 57467, + "1203-regex-split.ts": 3335, + "1204-regex-empty-unicode.ts": 42721, + "1205-regex-rc-stress.ts": 4531, + "1300-errors-basics.ts": 4518, + "1301-errors-subclass.ts": 4955, + "1302-errors-typed-catch.ts": 4560, + "1303-errors-rc-stress.ts": 3938, + "1304-errors-uncaught.ts": 4101, + "1305-errors-async-rejections.ts": 3614, + "1306-errors-runtime-instances.ts": 4054, + "1350-path-normalize-join.ts": 3568, + "1351-path-parts.ts": 4963, + "1352-path-resolve-relative.ts": 4503, + "1353-os-basics.ts": 4704, + "1354-builtin-bare-specifiers.ts": 4189, + "1355-url-parse.ts": 3863, + "1356-url-file-bridge.ts": 4207, + "1357-fsp-roundtrip.ts": 4886, + "1358-crypto-random.ts": 4050, + "1359-json-module/main.ts": 3853, + "1360-spawn-sync.ts": 4896, + "1361-spawn-events.ts": 3844, + "1362-spawn-timers.ts": 9749, + "1363-spawn-unhandled-error.ts": 5302, + "1364-union-truthiness.ts": 4307, + "1365-union-logical.ts": 4482, + "1366-union-equality.ts": 4253, + "1367-destructuring.ts": 5033, + "1368-constructor-functions.ts": 4831, + "1369-promise-union.ts": 3513, + "1370-spread.ts": 3969, + "1371-union-template-tostring.ts": 4126, + "1372-loose-null-tests.ts": 4513, + "1373-union-array-arms.ts": 3764, + "140-bitwise-operators.ts": 5173, + "1400-typedarray-basics.ts": 5411, + "1401-typedarray-slice-set.ts": 6335, + "1402-buffer-encodings.ts": 3500, + "1403-buffer-fs.ts": 7777, + "1404-zlib-crypto-bytes.ts": 6742, + "1405-bytes-unions-arrays.ts": 3762, + "1406-dataview-mp4.ts": 4549, + "1407-dataview-bounds.ts": 3820, + "1408-string-indexing.ts": 4530, + "1409-typedarray-integer-loops.ts": 4694, + "1420-number-statics.ts": 2928, + "1421-number-parse-strings.ts": 4454, + "1422-date-iso.ts": 3607, + "1423-text-codec.ts": 45738, + "1424-fs-options.ts": 3565, + "1425-stdin-tty.ts": 3853, + "1426-stdin-read.ts": 4250, + "1427-fromcharcode-lastindexof.ts": 3449, + "1428-settled-await-order.ts": 3904, + "1429-promise-catch-finally.ts": 6712, + "1430-promise-race.ts": 5576, + "1431-caught-tostring.ts": 4594, + "1432-destructured-params.ts": 5133, + "1433-filter-narrow.ts": 5015, + "1434-async-never.ts": 4402, + "1435-math-spread.ts": 4605, + "1436-default-undef-param.ts": 3807, + "1437-pad-default.ts": 3436, + "1438-promise-all.ts": 7568, + "1440-interval-basics.ts": 4290, + "1441-interval-clear-cross.ts": 7227, + "1442-interval-throw.ts": 4291, + "1443-signal-handlers.ts": 9442, + "1444-exit-listeners.ts": 5858, + "1445-exit-process-exit.ts": 5492, + "1446-exit-uncaught.ts": 4521, + "1447-stdin-closed-events.ts": 5005, + "1448-stream-columns.ts": 4280, + "1450-incdec-expression.ts": 3444, + "1451-instanceof-uint8array-unknown.ts": 4098, + "1452-return-through-finally.ts": 4660, + "1453-pmap-settled.ts": 7068, + "1454-nonnull-narrow-and-fcc-bytes.ts": 4716, + "1455-lambda-union-return-adoption.ts": 4826, + "1460-console-error-warn.ts": 4457, + "1461-process-pid-getuid-kill.ts": 4447, + "1462-exec-sync.ts": 4723, + "1463-timeout-unref.ts": 3720, + "1464-env-writes.ts": 4414, + "1465-env-value.ts": 4722, + "1466-child-containers.ts": 3465, + "1467-string-match.ts": 3798, + "1468-exec-path.ts": 4492, + "1469-remove-listener.ts": 6954, + "1470-child-lifecycle.ts": 4162, + "1471-child-unref.ts": 8772, + "1472-errno-code.ts": 5205, + "1473-promisify-execfile.ts": 5324, + "1474-string-decoder.ts": 4470, + "1475-readline-closed-stdin.ts": 55374, + "1476-assign-expression.ts": 4697, + "1477-in-expressions.ts": 3393, + "1478-promise-reject.ts": 4340, + "1479-destructuring-assign.ts": 4907, + "1480-os-network-interfaces.ts": 5202, + "1481-string-case-static.ts": 5232, + "1482-spawnsync-error.ts": 4518, + "1483-array-slice.ts": 47847, + "1520-fs-wider-surface.ts": 4261, + "1520-string-split-static.ts": 3932, + "1521-fs-lstat-lock.ts": 4472, + "1521-string-trim-pad-static.ts": 3262, + "1522-parseint-static.ts": 4734, + "1522-spawnsync-options.ts": 5888, + "1523-isnan-floor-static.ts": 4375, + "1523-spawn-options.ts": 4320, + "1524-atomics-sleep-static.ts": 4175, + "1524-catch-narrowing.ts": 4322, + "1525-child-exit-signal.ts": 4107, + "1525-unknown-typeof-validation.ts": 4804, + "1526-set-spread.ts": 5272, + "1527-logical-mixed-operands.ts": 3380, + "1528-delete-records-env.ts": 26816, + "1529-class-with-statics.ts": 3554, + "1530-array-push-variadic.ts": 4410, + "1530-spread-override-completion.ts": 4642, + "1531-delete-optional-fields.ts": 4468, + "1531-process-arch-versions.ts": 4294, + "1532-array-splice-shift.ts": 4135, + "1532-union-shared-field-read.ts": 3539, + "1533-bool-equality.ts": 3797, + "1533-path-platform-namespaces.ts": 4105, + "1534-crypto-hash-chain.ts": 4243, + "1534-union-as-arm-cast.ts": 3852, + "1535-spawn-fd-stdio.ts": 3827, + "1535-union-param-defaults.ts": 3756, + "1536-destructuring-defaults.ts": 4441, + "1536-string-array-sweep.ts": 4773, + "1537-chalk-hybrid/main.ts": 4555, + "1537-os-release-spawnsync-stdio.ts": 3030, + "1538-await-promiselike-return.ts": 4081, + "1538-math-static-scalar.ts": 2688, + "1539-readonly-set-map.ts": 4386, + "1539-unknown-truthiness.ts": 4573, + "1540-os-userinfo.ts": 4277, + "1540-void-statement.ts": 3770, + "1541-fs-readdir-dirent.ts": 5970, + "1541-union-keyed-reads.ts": 5137, + "1542-map-promise-values.ts": 3680, + "1542-record-literal-into-union.ts": 4161, + "1543-rest-destructuring.ts": 5386, + "1543-set-server-handles.ts": 8749, + "1544-dyn-json-reads.ts": 5370, + "1544-string-matchall.ts": 4375, + "1545-spread-order-and-optional.ts": 4546, + "1546-union-element-reads.ts": 50679, + "1547-computed-key-fold.ts": 5436, + "1548-boolean-condition-forms.ts": 3960, + "1549-array-isarray-unions.ts": 3329, + "1550-param-defaults-func-set.ts": 3161, + "1551-dyn-receiver-methods.ts": 6009, + "1552-exec-options-record.ts": 3255, + "1553-truthy-hof-predicates.ts": 4287, + "1554-caught-into-unknown.ts": 3533, + "1555-index-spread-into-declared.ts": 4772, + "1556-union-retag-width-arms.ts": 4319, + "1557-url-host.ts": 4070, + "1558-any-joins-and-dyn-validation.ts": 54305, + "1559-conditional-spread-index-merge.ts": 2926, + "1560-forof-homogeneous-tuples.ts": 32566, + "1561-forof-strings.ts": 3862, + "1561-promise-then.ts": 4850, + "1562-optional-chain-tails.ts": 4960, + "1562-spawn-conditional-spread.ts": 3616, + "1563-forof-iterator-projections.ts": 4225, + "1563-string-raw-fold.ts": 4244, + "1564-fs-watch.ts": 5142, + "1564-string-raw.ts": 4078, + "1565-spawn-pipe-streams.ts": 4189, + "1565-union-element-join.ts": 3622, + "1566-child-duck-interface.ts": 4142, + "1567-server-close-override.ts": 8728, + "1568-x509-fingerprint.ts": 3542, + "1569-fsp-mkdir-unlink-chmod.ts": 4083, + "1570-child-unref-kill-reffed.ts": 9583, + "1571-optional-call-tostring-tail.ts": 28217, + "1571-stdin-set-raw-mode-non-tty.ts": 3839, + "1572-promise-reject-all-tuple.ts": 4539, + "1572-x509-validity-date-gettime.ts": 4354, + "1573-promisify-execfile-env-spread.ts": 5359, + "1573-tdz-scalar-forward-capture.ts": 4394, + "1574-dyn-optional-method-number-keys.ts": 4461, + "1574-promise-all-tuple-literal.ts": 5082, + "1575-unknown-assert-into-record.ts": 4680, + "1576-width-coercions.ts": 4595, + "1577-url-hostname.ts": 3199, + "1578-exec-input-optional.ts": 3688, + "1579-matchall-index.ts": 4163, + "1580-exec-env-conditional-spread.ts": 3992, + "1581-declare-const-read.ts": 3904, + "1582-timer-sleep-resolve.ts": 5122, + "1583-loops-and-stream-captures.ts": 2955, + "1584-union-field-unassigned.ts": 4202, + "1585-union-field-conditional-ctor.ts": 4837, + "1586-derived-field-before-super-init.ts": 3740, + "1590-js-unannotated.js": 5105, + "1591-js-closures.js": 4745, + "1592-js-classes.js": 5879, + "1593-js-jsdoc-records.js": 4650, + "1594-js-async.js": 4426, + "1595-js-island-gap/main.js": 26477, + "1596-cjs-modules/main.js": 3160, + "1597-mjs-graph/main.mjs": 4960, + "1598-cjs-builtin-require/main.js": 3030, + "1599-js-uncaught-throw.js": 4259, + "1600-assert-passing.ts": 4325, + "1601-assert-fail-exit.ts": 4804, + "1602-assert-caught-error.ts": 5361, + "1603-assert-scalar-messages.ts": 4806, + "1604-assert-deep-structures.ts": 6023, + "1605-assert-import-forms.ts": 5339, + "1606-assert-strict-module.ts": 4600, + "1607-assert-throws-match.ts": 4414, + "1608-cjs-assert/main.js": 5188, + "1609-assert-async.ts": 4729, + "1610-path-win32-full.ts": 2755, + "1611-url-file-bridge-neutral.ts": 3733, + "1612-cjs-module-globals.cjs": 4516, + "1613-cjs-esm-proxy-named/main.mjs": 4105, + "1614-js-fence-dodges.cjs": 5207, + "1615-cjs-export-shapes/main.cjs": 5553, + "1616-cjs-esm-lexer-invisible/main.mjs": 3099, + "1617-cjs-esm-lexer-visible/main.mjs": 4087, + "1618-cjs-esm-poisoned-tail/main.mjs": 2476, + "1619-cjs-esm-reexport-invisible/main.mjs": 3415, + "1620-cjs-require-effects-order/main.js": 2713, + "1621-cjs-require-cache-hit/main.js": 3783, + "1622-cjs-require-conditional/main.js": 3828, + "1623-cjs-require-diamond/main.js": 3626, + "1624-cjs-require-dir-mid-file/main.js": 2336, + "1625-cjs-require-lazy-fn/main.js": 3015, + "1626-cjs-require-mjs/main.js": 2250, + "1627-mjs-import-cjs-requires/main.mjs": 2873, + "1628-checked-dynamic-builtin-args.cjs": 3077, + "1629-require-main-filename.cjs": 3479, + "1630-inspect-scalars.ts": 3977, + "1630-rmsync-retry-options.cjs": 3932, + "1631-inspect-arrays.ts": 5457, + "1632-inspect-records.ts": 4882, + "1633-inspect-map-set.ts": 4086, + "1634-inspect-classes.ts": 5725, + "1635-inspect-buffer.ts": 5155, + "1636-util-format.ts": 5015, + "1637-inspect-dyn.ts": 4071, + "1638-inspect-cjs.cjs": 3892, + "1639-versions-openssl-probe.ts": 4020, + "1640-fd-read-decode.ts": 4014, + "1641-string-search.ts": 21121, + "1642-object-fromentries-rows.ts": 4097, + "1643-metadata-dyn-return.cjs": 56433, + "1644-ee-basics.ts": 3623, + "1645-ee-extends.ts": 5009, + "1646-ee-once-remove.ts": 3768, + "1647-ee-meta-events.ts": 3840, + "1648-ee-error-event.ts": 2892, + "1649-ee-names-counts.ts": 4454, + "1650-ee-prepend.ts": 2707, + "1651-ee-max-listeners.ts": 4174, + "1652-ee-snapshot.ts": 5505, + "1653-ee-cjs.cjs": 4390, + "1654-ee-namespace.ts": 4636, + "1655-spawnsync-neutral.ts": 6342, + "1656-execsync-neutral.ts": 4702, + "1657-spawn-async-neutral.ts": 4011, + "1660-buffer-read-write-num.ts": 4936, + "1661-buffer-encodings-full.ts": 4916, + "1662-string-decoder-encodings.ts": 4639, + "1663-buffer-compare-search-fill.ts": 4818, + "1664-dyn-fn-boundary.cjs": 3636, + "1665-dyn-fn-mustcall/main.cjs": 4145, + "1666-dyn-fn-identity.ts": 3840, + "1667-dyn-fn-not-callable.cjs": 2882, + "1668-dyn-fn-throws.cjs": 3462, + "1669-symbol-identity.ts": 4719, + "1670-symbol-registry.ts": 4117, + "1671-symbol-typeof.ts": 5887, + "1672-symbol-containers.ts": 4625, + "1673-symbol-cjs.cjs": 6028, + "1674-symbol-inspect.ts": 4649, + "1676-func-array-surface.ts": 3616, + "1677-emitter-listeners.ts": 5664, + "1678-emitter-dyn-listeners.cjs": 6093, + "1679-console-dyn.js": 4398, + "1680-assert-bytes.ts": 3589, + "1681-assert-funcs.ts": 4450, + "1685-stream-readable-basics.ts": 8176, + "1686-stream-readable-paused.ts": 8142, + "1687-stream-readable-flow-control.ts": 6069, + "1688-stream-writable-basics.ts": 9377, + "1689-stream-writable-async-drain.ts": 7873, + "1690-stream-duplex.ts": 8422, + "1691-stream-transform.ts": 6383, + "1692-stream-pipe.ts": 5114, + "1693-stream-pipe-backpressure.ts": 3801, + "1694-stream-destroy.ts": 3612, + "1695-stream-props.ts": 8560, + "1696-stream-read-inside-read.ts": 4132, + "1697-stream-tick-vs-timer.ts": 7129, + "1698-stream-uncaught-error.ts": 4025, + "1699-stream-callback-shapes.ts": 4137, + "1700-mustcall-common/main.cjs": 4739, + "1701-mustcall-exit-report/main.cjs": 4788, + "1702-dyn-proto-dispatch.cjs": 4406, + "1703-arguments-rest-props.cjs": 3234, + "1710-cjs-export-class/main.js": 4152, + "1711-cjs-export-single-values/main.js": 3547, + "1712-field-incdec.ts": 3906, + "1713-js-dyn-fields.js": 5278, + "1720-assert-throws-shape.ts": 4205, + "1721-assert-throws-regex-class.ts": 3161, + "1722-assert-rejects.ts": 4021, + "1723-assert-does-not-reject.ts": 4049, + "1724-assert-iferror.ts": 3854, + "1725-assert-symbols.ts": 3165, + "1726-promise-with-resolvers.ts": 2792, + "1727-assert-throws-shape-exit.ts": 4670, + "1730-countdown-symbol-keys/main.js": 3893, + "1731-symbol-field-shapes.cjs": 4357, + "1732-symbol-field-cross-module/main.js": 4117, + "1740-stream-extends-readable.ts": 5412, + "1741-stream-extends-writable.ts": 7703, + "1742-stream-extends-duplex-transform.ts": 8664, + "1743-stream-extends-vt-dispatch.ts": 7746, + "1744-stream-set-encoding.ts": 3694, + "1745-stream-encoding-js.cjs": 3919, + "1746-stream-for-await.ts": 6732, + "1747-stream-for-await-js.cjs": 11913, + "1750-http-agent-options.ts": 7010, + "1751-options-record-stance.ts": 4331, + "1760-surplus-args-drop.cjs": 3419, + "1761-emitter-special-event-names.cjs": 3326, + "1770-assert-dyn-strict.ts": 4129, + "1771-assert-dyn-deep.ts": 4621, + "1772-assert-dyn-js.cjs": 3690, + "1773-assert-dyn-exit.ts": 3870, + "1780-http-res-surface.ts": 7391, + "1781-http-server-shapes.cjs": 11204, + "1790-computed-key-folds.ts": 3769, + "1791-searchparams-core.ts": 2566, + "1792-searchparams-encoding.ts": 3926, + "1793-searchparams-iteration.ts": 3839, + "1794-searchparams-url-live.ts": 3667, + "1795-dyn-handle-request.cjs": 7469, + "1796-dyn-handle-body.cjs": 4708, + "1797-dyn-handle-socket.cjs": 6317, + "1798-dyn-handle-typed-box.ts": 12433, + "1800-immediate-basics.ts": 3461, + "1801-immediate-handle.ts": 2828, + "1802-immediate-unref-exit.ts": 3773, + "1803-timeout-refresh.ts": 2890, + "1804-timers-module.ts": 4324, + "1805-timer-callback-args.ts": 4084, + "1806-timer-delay-trunc.ts": 3166, + "1810-stream-options-const-record.ts": 3962, + "1811-stream-option-value-callbacks.cjs": 3964, + "1812-stream-super-options-forwarding.cjs": 8384, + "1813-stream-finished.ts": 5772, + "1814-stream-pipeline.cjs": 8091, + "1815-stream-state-reads.cjs": 7977, + "1820-static-block-basics.ts": 3028, + "1821-static-block-order.ts": 2726, + "1822-static-block-js.js": 4178, + "1823-static-instance-method-names.ts": 2438, + "1824-for-of-destructuring-defaults.ts": 3053, + "1825-exhaustive-typeof-switch.ts": 3216, + "1826-settimeout-arguments-callback.js": 2649, + "1830-enum-numeric-basics.ts": 3631, + "1831-enum-string-const-reverse.ts": 3353, + "1832-enum-modules/main.ts": 3697, + "1835-var-basics.ts": 3553, + "1836-var-loop-capture.ts": 3991, + "1837-var-undefined-hoisting.ts": 3692, + "1838-var-modules/main.ts": 2987, + "1839-var-js/main.cjs": 3074, + "1840-jsdoc-import-type-only/main.js": 3723, + "1850-overload-basics.ts": 3730, + "1851-overload-return-narrowing.ts": 3097, + "1852-overload-class-members.ts": 4001, + "1853-overload-modules/main.ts": 4277, + "1854-ambient-declare-fn.ts": 2860, + "1855-ambient-declare-fn-uncaught.ts": 4252, + "1870-unit-type-values.ts": 3913, + "1871-empty-array-never.ts": 2656, + "1872-template-tostring-composite.ts": 3669, + "1880-json-declared-field-order.ts": 5166, + "1881-default-anon/main.ts": 3155, + "1882-default-cjs-interop/main.ts": 4152, + "1883-default-exports/main.ts": 4005, + "1890-ns-imports/main.ts": 4423, + "1891-ns-reexport/main.ts": 2975, + "1940-class-values-basics.ts": 2991, + "1941-class-values-registry.ts": 4395, + "1942-class-expressions.ts": 4086, + "1943-class-statics-expanded.ts": 3500, + "1944-class-values-modules/main.ts": 3932, + "1950-generic-fn-values.ts": 4360, + "1951-generic-classes-basics.ts": 4948, + "1952-generic-class-statics-values.ts": 4310, + "1953-generic-class-hierarchy.ts": 3171, + "1954-generic-modules/main.ts": 3610, + "1960-namespace-basics.ts": 3656, + "1961-namespace-nested.ts": 4076, + "1962-namespace-classes.ts": 3740, + "1963-namespace-aliases.ts": 3282, + "1964-namespace-type-only.ts": 3064, + "1965-namespace-ambient.ts": 3659, + "1966-namespace-modules/main.ts": 4077, + "1967-namespace-alias-typeonly.ts": 2697, + "1968-namespace-import-eq-snapshot.ts": 2527, + "1970-decorators-basics.ts": 4151, + "1971-decorators-rebinding.ts": 2897, + "1972-decorators-throwing.ts": 2556, + "1973-decorators-ambient.ts": 3932, + "1980-primitive-proto-statics.ts": 4096, + "1981-date-utc.ts": 3463, + "1982-freeze-resolve-passthrough.ts": 4042, + "1983-array-tuple-surfaces.ts": 4356, + "1990-labels-basics.ts": 3887, + "1991-for-in-loops.ts": 5008, + "1992-small-syntax.ts": 3829, + "200-strings.ts": 3521, + "2000-generic-methods-basic.ts": 4027, + "2001-generic-methods-generic-class.ts": 3431, + "2002-generic-methods-inheritance.ts": 3737, + "2003-generic-methods-object-literal.ts": 4544, + "2004-generic-methods-statics.ts": 3642, + "201-templates.ts": 2558, + "2010-generators-basics.ts": 3652, + "2011-generators-forof.ts": 3852, + "2012-generators-return-throw.ts": 3950, + "2013-generators-sent-values.ts": 4017, + "2014-generators-values.ts": 4246, + "2015-generators-yieldstar.ts": 3908, + "2016-generators-rc-stress.ts": 4275, + "2017-generators-async.ts": 2845, + "2018-generators-uncaught.ts": 3328, + "2019-generators-loops.ts": 3191, + "2020-generic-value-bindings.ts": 5274, + "2021-generic-value-binding-modules/main.ts": 3546, + "2022-width-index-capture.ts": 4336, + "2023-width-readonly.ts": 3104, + "2024-width-array-elems.ts": 3482, + "2025-width-union-compose.ts": 4076, + "2026-width-spread.ts": 3943, + "2030-width-nested.ts": 4567, + "2031-width-tuples.ts": 2753, + "2032-cjs-export-assigned-class-expression/main.cjs": 4056, + "2033-property-assigned-class-extends.cjs": 3174, + "2035-ternary-array-retag.cjs": 4091, + "2036-evolving-array-decl.cjs": 3778, + "2037-fn-decl-hoisting.cjs": 2776, + "2038-evolving-array-js.cjs": 4351, + "2040-any-bindings.ts": 3377, + "2040-mixin-heritage.ts": 3511, + "2041-any-params-returns.ts": 3626, + "2041-mixin-values.ts": 4380, + "2042-any-flow-loops.ts": 3135, + "2042-mixin-modules/main.ts": 4398, + "2043-any-dom-values.ts": 3973, + "2043-mixin-rc-stress.ts": 3648, + "2044-vtable-sibling-slots.ts": 3788, + "2045-objlit-accessors-basic.ts": 3867, + "2045-parameter-properties.ts": 4798, + "2046-abstract-classes.ts": 5738, + "2046-objlit-accessors-effects.ts": 3922, + "2047-objlit-accessors-shapes.ts": 3974, + "2047-optional-class-fields.ts": 5957, + "2050-dynamic-import-own-module/main.ts": 4276, + "2051-dynamic-import-then/main.ts": 3569, + "2052-dynamic-import-self.ts": 2505, + "2053-typeof-static-fold.ts": 3591, + "2054-destructuring-island-source.ts": 4039, + "2060-empty-tuple.ts": 3547, + "2070-computed-key-folds.ts": 5392, + "2071-integer-key-enumeration-order.ts": 4114, + "2072-expando-function-members.ts": 3911, + "2073-destructuring-assignment.ts": 3331, + "2074-island-destructuring.ts": 2722, + "2075-index-signature-runtime-keys.ts": 2808, + "2080-destructuring-defaults.ts": 4723, + "2081-destructuring-rest.ts": 3815, + "2082-destructuring-assignment.ts": 4463, + "2085-destructuring-heads-rest-params.ts": 3370, + "2087-destructuring-for-heads.ts": 3817, + "2090-index-signature-number-keys.ts": 3307, + "2091-index-signature-string-intersection.ts": 4503, + "2092-package-imports/main.ts": 3209, + "2093-timers-promises.ts": 4576, + "2094-diagnostics-channel.ts": 5184, + "2095-js-catch-unknown.js": 3505, + "2096-os-type.ts": 3468, + "2097-js-evolving-globals.js": 3426, + "210-string-methods.ts": 3239, + "2100-stream-default-hwm.ts": 4068, + "2101-dyn-param-defaults.ts": 4169, + "2102-empty-pattern-decls.ts": 3916, + "2105-computed-key-static-folds.ts": 3626, + "2106-comma-expressions.ts": 4728, + "211-string-unicode.ts": 3897, + "2110-top-object-types.ts": 3438, + "2111-json-stringify-unknown.ts": 3888, + "2112-array-at-findlast.ts": 3424, + "2113-string-index-methods.js": 3570, + "212-string-aliasing-append.ts": 3570, + "2120-package-self-import/main.ts": 3971, + "2121-esm-cycle-inert-backedge/main.ts": 2650, + "2123-ambient-import-crash/main.ts": 3746, + "2124-imports-field-wildcard/main.ts": 2731, + "2140-uri-component-codecs.ts": 3381, + "2160-dc-tracing-channel.cjs": 4690, + "2161-js-object-literal-identity.cjs": 4257, + "2162-js-dyn-destructure.cjs": 3551, + "2163-js-selfref-const.cjs": 4654, + "2164-js-then-dyn-handler.cjs": 5156, + "2165-js-throw-dyn.cjs": 3523, + "2166-cjs-getter-this/main.cjs": 3882, + "2170-island-array-exits.ts": 3858, + "2171-island-json-stringify.ts": 3712, + "2172-island-regexp-boundary.ts": 3327, + "2190-new-object-and-string-wrappers.ts": 2850, + "2191-uri-encoders.ts": 2942, + "2192-object-default-tostring.ts": 3177, + "2193-discarded-stdlib-reads.ts": 3355, + "2194-ambient-undef-chains.ts": 3563, + "2195-require-missing-package/main.mjs": 4117, + "2196-island-computed-key-chain.ts": 3932, + "2210-dyn-promise-crossing.cjs": 5102, + "2211-dc-trace-promise.cjs": 4621, + "2212-unhandled-rejection-listener.cjs": 4270, + "2213-async-local-storage.cjs": 4068, + "2214-dc-bind-store.cjs": 5707, + "2215-process-emit-warning-exit.cjs": 4386, + "2240-width-class-into-record.ts": 3665, + "2241-width-record-into-class.ts": 3361, + "2242-width-statics-into-record.ts": 3708, + "2243-width-assert-satisfies-shapes.ts": 3967, + "2250-tagged-templates.ts": 3434, + "2252-class-iterators.ts": 4459, + "2253-union-coercions.ts": 2359, + "2260-http2-constants.cjs": 3538, + "2280-builtin-namespace-destructure.cjs": 3057, + "2281-domexception-atob-btoa.cjs": 3389, + "2282-queue-microtask.cjs": 5820, + "2283-structured-clone.cjs": 4600, + "2284-regexp-constructor.cjs": 3741, + "2285-iferror-dyn.cjs": 2861, + "2286-dyn-object-walks.cjs": 3243, + "2300-dyn-record-spread-and-keyed-access.cjs": 2809, + "2301-cjs-export-table-dom-attach.cjs": 2887, + "2310-process-next-tick.ts": 4130, + "2311-next-tick-js-callbacks.js": 4068, + "2312-stream-underscore-assign.ts": 6594, + "2313-stream-underscore-assign-js.cjs": 4269, + "2314-process-introspection.ts": 3297, + "2320-await-unit.ts": 3657, + "2321-emitter-static-setmax.cjs": 4316, + "2322-dyn-array-sort.cjs": 3658, + "2323-timer-callback-returns.ts": 4288, + "2330-tls-server-runtime-options.cjs": 57265, + "2331-tls-server-options-typed.ts": 24831, + "2350-nan-global.ts": 3780, + "2351-async-methods.ts": 4037, + "2352-void-coercions.ts": 4230, + "2353-decorators-member-ambient.ts": 3783, + "2354-decorators-expression-ambient.ts": 3425, + "2360-tuple-to-array.ts": 4066, + "2361-assign-index-record.ts": 3954, + "2362-execsync-inherit.ts": 3811, + "2363-nullish-retag.ts": 4019, + "2364-in-runtime-key.ts": 3905, + "2365-dyn-into-island.ts": 4006, + "2366-string-well-formed.ts": 2861, + "2367-regexp-escape.ts": 3081, + "2368-set-methods.ts": 3869, + "2369-promise-try.ts": 4228, + "2370-group-by.ts": 4759, + "2371-iterator-helpers.ts": 4028, + "2380-buffer-module-named-import.ts": 3715, + "2381-builtin-default-imports.js": 3602, + "2382-cycle-two-decl/main.ts": 2942, + "2383-cycle-assertdoc/main.js": 2814, + "2384-cycle-mixed-bindings/main.ts": 2985, + "2385-builtin-reexport-facade/main.ts": 2368, + "2386-string-to-chars.ts": 3688, + "2387-tonumber-argv.ts": 4524, + "2388-tonumber-grammar-zoo.ts": 3447, + "2389-tonumber-unary-plus.ts": 3631, + "2390-dot-requires/main.cjs": 3823, + "2391-default-builtin-imports/main.ts": 4261, + "2392-block-guard-alias-scope.ts": 3432, + "2393-loop-exit-guard-narrow.ts": 4204, + "2394-loop-narrow-containment.ts": 3545, + "2395-while-cond-guard.ts": 3342, + "2396-born-narrowed-decl.ts": 3204, + "2397-branch-kill-merge.ts": 2872, + "2398-switch-arm-kill.ts": 2478, + "2399-reassign-kill-polarity.ts": 3975, + "240-stdout-write.ts": 3714, + "2400-kill-return-edge.ts": 2788, + "2401-kill-break-staging.ts": 3266, + "2402-labeled-break-kill.ts": 3546, + "2403-kill-continue-backedge.ts": 3341, + "2404-kill-throw-catch.ts": 3390, + "2405-sibling-arm-narrow.ts": 3636, + "2406-switch-clause-sibling-narrow.ts": 3321, + "2407-infinite-loop-seal.ts": 3706, + "2408-loop-terminality-reopen.ts": 3556, + "2409-loop-body-return-not-terminal.ts": 2952, + "2410-stacked-cases-terminality.ts": 2785, + "2411-exhaustive-switch-terminality.ts": 2898, + "2412-dowhile-guard-trailing-test.ts": 3018, + "2413-dowhile-kill-renarrow.ts": 3619, + "2414-dowhile-continue-kill.ts": 3030, + "2415-dowhile-break-trailing-test.ts": 3541, + "2416-spread-ternary-positions.ts": 3398, + "2417-ternary-local-inference.ts": 2779, + "2418-wrapped-ternary-arms.ts": 3414, + "2419-selector-ternary-union.ts": 2916, + "2420-nullish-null-identity.ts": 2738, + "2421-float-lane-inference.ts": 3483, + "2422-ieee-div-rem-corners.ts": 3493, + "2423-param-null-reassign.ts": 2469, + "2424-ternary-miss-first-narrowing.ts": 2704, + "2425-elseif-head-exit-narrow.ts": 3239, + "2426-default-snapshot-mutable/main.ts": 3047, + "2427-perf-hooks-now.ts": 3594, + "2428-field-redeclare-inherited.ts": 3306, + "2429-destructure-class-instance.ts": 3925, + "2430-empty-literal-unknown-field.js": 3247, + "2431-primitive-ctor-values.ts": 4135, + "2432-generic-member-fields-async.ts": 4525, + "2433-as-const-command-tables.ts": 4328, + "2434-deferred-init-fields.ts": 3024, + "2435-loose-same-kind-equality.ts": 3478, + "2440-console-inspect-args.ts": 5890, + "2441-console-process-argv.ts": 3753, + "2442-union-literal-arm-widening.ts": 3136, + "2443-union-literal-shadow-narrowing.ts": 3135, + "2444-union-literal-reducer-spread.ts": 2966, + "2445-math-minmax-nary.ts": 3844, + "2446-performance-global.ts": 3708, + "2447-island-boundary-slots/main.ts": 4610, + "2448-entries-null-arms-regex-arrays.ts": 4797, + "2450-private-instance-methods.ts": 4126, + "2451-private-fields.ts": 3682, + "2452-private-statics.ts": 3833, + "2453-private-accessors.ts": 3714, + "2454-private-generator-methods.ts": 4326, + "2455-private-brand-checks.ts": 2955, + "2456-private-async-methods.ts": 4273, + "2457-private-members.js": 3893, + "2460-qs-parse-grammar.ts": 5096, + "2461-qs-parse-options.ts": 3628, + "2462-qs-stringify.ts": 4992, + "2463-qs-escape-unescape.ts": 3734, + "2464-qs-require-forms.cjs": 4220, + "2470-mockable-module-shape.js": 2876, + "2471-record-keyed-write-hasown.js": 4081, + "2472-string-regexp-union.ts": 2606, + "2473-option-table-widths.js": 4586, + "2474-island-literal-forms.ts": 4522, + "2475-variadic-wrapper-island.js": 3845, + "2476-map-regex-values.ts": 3182, + "2480-recursive-record-tree.ts": 3879, + "2481-mutual-recursive-records.ts": 3675, + "2482-recursive-union-tree.ts": 3577, + "2483-recursive-record-cycles.ts": 3205, + "2484-json-stringify-circular.ts": 3643, + "2485-inspect-circular-refs.ts": 3845, + "2486-recursive-record-boundaries.ts": 2991, + "2487-recursive-deep-equal.ts": 4100, + "2488-ast-walker.ts": 4477, + "2490-find-miss-null-compare.ts": 3671, + "2491-strict-unit-compare-no-arm.ts": 3227, + "2492-loose-null-compare-unions.ts": 3901, + "2493-switch-unit-cases.ts": 3674, + "2494-no-arm-compare-effects.ts": 3403, + "2500-net-autosel-timeout.ts": 3482, + "2510-dyn-evolving-array-map.ts": 3667, + "2511-dyn-evolving-array-filter-foreach.ts": 4096, + "2512-dyn-evolving-array-mixed-push.ts": 4423, + "2520-private-statics-class-name-calls.ts": 3265, + "2521-private-statics-class-expression.ts": 3750, + "2522-private-statics-decorated.ts": 3195, + "2523-private-statics-aliased-class.ts": 3584, + "2530-object-destructuring-decl.ts": 3283, + "2531-array-tuple-destructuring-decl.ts": 4032, + "2532-param-destructuring-options.ts": 4645, + "2533-forof-destructuring.ts": 4187, + "2534-object-rest-decl.ts": 4358, + "2535-destructuring-assign-basics.ts": 3621, + "2536-destructuring-assign-nested.ts": 3573, + "2537-destructuring-assign-member-targets.ts": 3272, + "2538-destructuring-assign-class-source.ts": 3962, + "2539-class-instance-rest.ts": 4142, + "2540-accessor-destructuring-defaults.ts": 3446, + "2541-destructuring-eval-order.ts": 3928, + "2550-generics-keyof-pick.ts": 3409, + "2551-generics-value-aliases.ts": 3346, + "2552-generics-iface-methods.ts": 3488, + "2553-generics-signature-bindings.ts": 3749, + "2554-generics-frontier-mix.ts": 3794, + "2555-generics-keyof-writes.ts": 3364, + "2556-crypto-introspection.ts": 3435, + "2556-width-hybrid-shapes.ts": 4079, + "2557-tls-ca-store.ts": 3530, + "2557-width-field-lifts.ts": 4176, + "2558-index-signature-func-values.ts": 4225, + "2558-rejection-events.cjs": 3844, + "2559-index-signature-container-values.ts": 4449, + "2560-arraybuffer-dataview-set.ts": 3087, + "2561-object-is.ts": 4355, + "2562-intl-numberformat-en-us.ts": 3901, + "2563-stream-promises-pipeline.ts": 3564, + "2564-stream-promises-finished.ts": 6034, + "2565-stream-promises-js.cjs": 4473, + "2566-promise-reject-dyn-reason.js": 3377, + "2567-rest-spread-forward.js": 3534, + "2568-rest-spread-forward-dynamic.js": 4104, + "2569-upcast-identity.ts": 3496, + "2570-buffer-arg-validation.cjs": 5910, + "2571-searchparams-arg-validation.cjs": 4428, + "2572-readable-emitted-readable-flag.cjs": 3512, + "2573-fs-url-arg-ladders.cjs": 3763, + "2574-emitter-max-listeners-ladders.cjs": 3689, + "2575-string-destructuring-decl.ts": 4712, + "2576-string-destructuring-assign.ts": 3735, + "2577-builtin-global-destructuring.js": 4445, + "2578-jsval-into-unknown-rows.ts": 3828, + "2579-jsval-object-param-crossing.js": 3036, + "2580-jsval-routed-keyed-ops.js": 3956, + "2581-jsval-routed-calls.js": 3809, + "2582-jsval-object-statics.js": 3967, + "2582-jsval-routed-keyed-ops.js": 2714, + "2583-dyn-nullish-coalesce.js": 3955, + "2583-jsval-routed-calls.js": 4033, + "2584-jsval-object-statics.js": 3852, + "2584-union-dyn-collapse.ts": 3199, + "2585-dyn-nullish-coalesce.js": 4086, + "2585-unknown-array.ts": 3037, + "2586-object-assign-spread.js": 4129, + "2587-array-entries-forof.ts": 3963, + "2588-array-entries-chains.ts": 4778, + "2589-object-create-null.cjs": 3994, + "2590-object-create-dynamic.js": 3840, + "2591-ambient-generic-traps.ts": 3572, + "2592-ambient-trap-uncaught.ts": 3517, + "2593-generic-inert-bindings.ts": 3984, + "2594-nullish-generic-bindings.ts": 3028, + "2595-fs-arg-ladders.cjs": 6103, + "2596-net-arg-ladders.cjs": 3811, + "2597-dgram-send-ladders.cjs": 4888, + "2598-tls-arg-ladders.cjs": 26930, + "2599-stream-arg-ladders.cjs": 6141, + "2600-dyn-keyed-write-harness.js": 2931, + "2601-dyn-keyed-write-ops.js": 2148, + "2602-dyn-array-destructure.js": 2954, + "2603-island-keyed-write-dyn.js": 2848, + "2604-cycle-classes-mutual/main.ts": 3417, + "2605-cycle-three-module/main.ts": 3678, + "2606-dynamic-import-cycle/main.ts": 3530, + "2608-regex-named-groups.ts": 4497, + "2609-regex-named-replace.ts": 3665, + "2610-regex-named-matchall.ts": 3003, + "2611-regex-named-groups-js.cjs": 4787, + "2613-for-init-uninitialized-let.ts": 3768, + "2614-trap-binding-later-writes.ts": 2989, + "2615-nullish-field-record-binding.ts": 3529, + "2616-js-collect-probe-defers.js": 3466, + "2617-enum-static-field-import/main.ts": 3293, + "2618-ee-emit-override.ts": 3565, + "2619-ee-override-chain.ts": 3727, + "2620-ee-override-once-order.ts": 4249, + "2621-ee-override-error-throw.ts": 3855, + "2622-ee-override-filter.ts": 3910, + "2623-ee-job-queue.ts": 3743, + "2624-ee-override-js.cjs": 3084, + "2625-bytes-views.ts": 3970, + "2626-stream-event-names.ts": 4359, + "2627-stream-ticks-are-nextticks.ts": 7617, + "2628-stream-push-encodings.cjs": 3343, + "2629-stream-consumers.ts": 4441, + "2630-stream-consumers-errors.ts": 5041, + "2631-create-require/main.ts": 3703, + "2632-dyn-jsval-iterate.js": 3831, + "2633-island-promise-crossing.js": 5160, + "2634-stream-pipeline-arg-ladders.cjs": 3923, + "2635-trap-binding-unmappable-written.ts": 3043, + "2636-trap-binding-ambient-rooted-rewrite.ts": 3569, + "2637-create-require-bare/main.ts": 2767, + "2638-http-dyn-res-compat.cjs": 8125, + "2639-http-dyn-req-pause.cjs": 8808, + "2640-net-dyn-socket-compat.cjs": 4119, + "2641-http-agent-surface.cjs": 8974, + "2642-http-agent-maxsockets.cjs": 7586, + "2643-or-default-retag.ts": 3938, + "2644-http-client-url-argument.ts": 8788, + "2645-https-client-url-argument.ts": 5188, + "2646-top-level-await.ts": 3543, + "2647-top-level-await-modules/main.ts": 3228, + "2648-top-level-await-rejection.ts": 3718, + "2649-top-level-await-pending.ts": 3680, + "2650-top-level-await-self-import.ts": 3580, + "2651-top-level-await-pending-unhandled.ts": 3616, + "2652-top-level-await-dynamic/main.ts": 3624, + "2653-top-level-await-rejection-stops-loop.ts": 3405, + "2654-top-level-await-unrelated-rejection.ts": 3746, + "2655-top-level-await-cycle/main.ts": 3633, + "2656-top-level-await-cycle-order/main.ts": 3581, + "2657-top-level-await-cycle-dynamic/main.ts": 3334, + "2658-top-level-await-sync-completion/main.ts": 3454, + "2659-top-level-await-dynamic-cycle/main.ts": 2695, + "2660-top-level-await-cycle-rejection/main.ts": 3883, + "2661-top-level-await-dynamic-runtime-root/main.ts": 3717, + "2662-top-level-await-cycle-external-wait/main.ts": 3322, + "2663-top-level-await-dependency-errors/main.ts": 4049, + "2664-top-level-await-same-checkpoint-rejection.ts": 4075, + "2665-top-level-await-unhandled-listener-liveness.ts": 3625, + "2666-array-to-sorted.ts": 8369, + "2668-stored-number-array-iterator.ts": 3915, + "2669-array-copying-methods.ts": 4422, + "2670-uint8array-copy-iterate.ts": 4692, + "2671-array-copying-js.cjs": 3615, + "2672-http-request-response-callback.ts": 3326, + "2673-top-level-await-implicit-module.ts": 2622, + "2674-top-level-for-await-implicit-module.ts": 3487, + "2675-create-require-nested-esm.js": 3107, + "2675-process-self-reexec.ts": 3537, + "2676-indexed-read-strict-equality.ts": 3497, + "2676-record-clone-overrides.ts": 3652, + "2676-top-level-await-ambiguous/main.ts": 3641, + "2677-runtime-optional-closure.ts": 4530, + "2677-top-level-await-module-scope/main.ts": 3142, + "2678-date-instances.ts": 4477, + "2678-large-string-sparse-index.ts": 3931, + "2678-util-parseargs.ts": 7627, + "2679-util-parseargs-cjs.cjs": 4984, + "2680-util-parseargs-default.ts": 2670, + "2681-util-parseargs-dynamic.js": 3233, + "2682-fs-rename.ts": 4087, + "2683-filter-truthy-predicate.ts": 4348, + "2683-fs-rename-js.cjs": 2621, + "2684-filter-no-predicate-dyn.cjs": 3942, + "2684-fs-rename-abort.ts": 3403, + "2685-array-unshift-reverse.ts": 3942, + "2685-fs-write-sync.ts": 4263, + "2686-fs-file-handle.ts": 6233, + "2687-fsp-write-file-options.ts": 3951, + "2687-process-write-args.ts": 2844, + "2688-fs-stats-disk-fields.ts": 4789, + "2689-http-server-timeout-properties.ts": 3279, + "2690-https-server-timeout-option.ts": 56311, + "2691-retained-lowering-record-order.ts": 5946, + "2692-inline-record-assert-index.ts": 3857, + "2692-string-accumulation.ts": 3602, + "2693-math-constants.ts": 3816, + "2700-array-sort-complexity.ts": 3912, + "2700-http-static-trailers.ts": 6657, + "2700-wasi-core.ts": 3863, + "2701-array-sort-snapshot.ts": 3906, + "2701-http-static-trailer-wire.ts": 3412, + "2701-import-meta/main.mjs": 4097, + "2702-http-static-trailer-end.ts": 8433, + "2702-type-import-link-static/main.ts": 2947, + "2702-uint8array-to-sorted.ts": 3549, + "2703-array-sparse-sort.ts": 8716, + "2703-type-import-link-static-reexport/main.ts": 3510, + "2704-array-sparse-to-sorted.ts": 8447, + "2704-type-import-link-static-success/main.ts": 3172, + "2705-array-sparse-sort-append.ts": 7740, + "2705-type-import-link-dynamic/main.ts": 3687, + "2706-array-search-missing-needle.ts": 3192, + "2706-type-import-link-dynamic-success/main.ts": 4191, + "2707-array-search-huge-sparse.ts": 48438, + "2707-type-import-link-static-default-reexport/main.ts": 3502, + "2708-type-import-link-dynamic/main.ts": 3358, + "2720-array-read-parity.ts": 3686, + "2721-array-nested-missing-receiver.ts": 2904, + "2750-array-sparse-foundation.ts": 3895, + "2751-buffer-concat-sparse-list.ts": 3589, + "2752-array-optional-stores.ts": 3503, + "2753-array-optional-method-values.ts": 2814, + "2754-array-property-undefined.ts": 2681, + "2755-array-optional-literal-forwarding.ts": 3614, + "2780-array-parity-composition.ts": 12116, + "2781-array-missing-value-escape.ts": 3458, + "2782-array-sparse-callbacks.ts": 3870, + "2783-array-defaults-rest.ts": 3473, + "2784-array-reduce-missing-result.ts": 3973, + "2785-array-missing-destructuring.ts": 4123, + "2786-array-sparse-serialization.ts": 4457, + "2787-array-missing-string-arithmetic.ts": 3381, + "2788-array-missing-builtin-conversions.ts": 3415, + "2789-array-missing-optional-tostring.ts": 2621, + "2790-dynamic-import-self-name/main.ts": 3399, + "2791-record-optional-keys.ts": 3271, + "2792-record-optional-spread-entries.ts": 4055, + "2793-union-conversion-identity-capture.ts": 4295, + "2794-array-generic-callback-values.ts": 3662, + "2795-array-optional-typedarray-source.ts": 38684, + "2796-array-sparse-class-value-instanceof.ts": 3585, + "2800-array-expression-consumers.ts": 3265, + "2801-array-switch-consumers.ts": 4057, + "2820-array-missing-method-receivers.ts": 3301, + "2821-array-optional-numeric-comparisons.ts": 2316, + "2830-cjs-require-self-name/main.cjs": 3030, + "2840-finally-completions.ts": 3523, + "2841-using-sync.ts": 3234, + "2842-await-using.ts": 3418, + "2843-using-suppressed-error.ts": 3352, + "2844-node-disposable-resources.ts": 5430, + "2845-for-using-of.ts": 3355, + "2846-generator-using.ts": 3702, + "2850-async-generators-protocol.ts": 4747, + "2851-async-generators-values.ts": 4111, + "2852-timers-promises-interval.ts": 3376, + "2854-leading-bom-literals.ts": 2675, + "2855-searchparams-sort-complexity.ts": 2462, + "2856-dynamic-any-local-operators.ts": 3959, + "2857-branded-primitives.ts": 3738, + "2858-import-meta-resolve/main.mjs": 2597, + "2859-import-meta-resolve-dynamic/main.mjs": 2565, + "2860-require-resolve/main.cjs": 3076, + "2861-readable-iterator-close.ts": 3422, + "2862-web-readable-async-iteration.ts": 55094, + "2863-class-async-iterator.ts": 3586, + "2864-array-class-method-receivers.ts": 4152, + "2865-cjs-process-alias.cjs": 3499, + "2866-dyn-switch.ts": 3318, + "2867-array-shift-length.js": 3797, + "2868-empty-record-promise-presence.js": 3592, + "2869-nullish-mixed-lazy.ts": 3886, + "2870-and-dropped-truthy-arm.ts": 3748, + "2871-optional-promise-to-unknown.ts": 3966, + "2872-unobserved-dynamic-event.ts": 3095, + "2873-optional-receiver-loop-lifetime.js": 3310, + "2874-nullable-callback-field-cycle.js": 4239, + "2875-evolving-let-read-before-write.js": 2007, + "2876-class-unknown-roundtrip.ts": 3485, + "2877-child-unknown-roundtrip.ts": 3462, + "2878-class-private-unknown.cjs": 3481, + "2880-cjs-module-graph/main.cjs": 4418, + "2890-crypto-static-utility.ts": 3693, + "2891-json-record-key-escapes.ts": 3227, + "2892-windows-console-unicode.ts": 3154, + "2893-child-stdin-duplex.ts": 3517, + "2894-child-stdin-backpressure.ts": 4232, + "2895-child-stdin-write-after-end.ts": 3755, + "2896-child-stdin-write-after-finish.ts": 4128, + "2897-child-stdin-destroy.ts": 2592, + "2898-child-stdin-spawn-failure.ts": 3984, + "2899-nested-mutual-recursion.ts": 3524, + "2900-float64array-static.ts": 2647, + "2900-void-conditional-arrow.ts": 3544, + "2901-bigint-core.ts": 3085, + "2902-bigint-bytes.ts": 3574, + "2903-bigint-storage.ts": 4190, + "2904-bigint-errors.ts": 3820, + "2905-bigint-edges.ts": 3695, + "2906-bigint-wasi-width.ts": 3566, + "2910-overloaded-callable-alias.ts": 2729, + "2911-execfile-callback.ts": 3798, + "2912-execfile-callback-options.ts": 3803, + "2912-promisify-fs-readfile.ts": 3648, + "2913-builtin-callable-alias.ts": 5737, + "2914-fixed-tuple-call-spread.ts": 3851, + "2915-path-function-values.ts": 4013, + "2916-path-function-values-cjs.ts": 3957, + "2917-builtin-callable-widths.ts": 3640, + "2918-builtin-callable-widths-cjs.ts": 3701, + "2919-fs-function-values.ts": 3810, + "2920-fs-promises-function-values.ts": 3724, + "2921-zlib-callbacks.ts": 5492, + "2922-dyn-bitwise-not.cjs": 3645, + "2923-cjs-factory-export/main.cjs": 3645, + "2930-union-receiver-calls.ts": 4841, + "2931-union-dynamic-field-call.js": 3975, + "2932-create-require-program/main.ts": 4060, + "2933-static-dynamic-import/main.ts": 3736, + "2934-static-import-stored.ts": 3490, + "2935-module-namespace-values/main.ts": 3371, + "2936-static-loose-equality.ts": 4954, + "2937-bitwise-hot-loop.ts": 3448, + "2938-fs-sync-overloads.cjs": 3181, + "2939-child-shell-text.ts": 4371, + "2940-date-parse.ts": 3212, + "2940-fsp-realpath.ts": 3484, + "2941-fsp-lstat-identity.ts": 3903, + "2941-process-exit-code.ts": 3406, + "2942-fsp-readdir-dirent.ts": 4202, + "2942-process-exit-code-override.ts": 3082, + "2943-process-exit-code-invalid.ts": 3479, + "2944-process-exit-code-wrap.ts": 3266, + "2945-url-origin-username.ts": 2899, + "2946-child-fork-ipc/main.ts": 4761, + "2946-url-port-hash.ts": 2865, + "2947-set-readonly-seeds.ts": 3446, + "2948-child-fork-eof-callback/main.ts": 3476, + "2948-stdio-callback-record.ts": 3365, + "2949-child-fork-default/main.mjs": 3332, + "2949-url-password.ts": 3628, + "2950-fs-descriptor-publication.ts": 3569, + "2951-math-static-analytic.ts": 3919, + "2952-math-static-remaining.ts": 3652, + "2953-http-header-validation.ts": 7274, + "2954-http-outgoing-headers.ts": 9450, + "2955-http-static-state.ts": 6516, + "2956-http-static-informational.ts": 6092, + "2957-http-static-response-controls.ts": 6929, + "2961-emitter-computed-names.cjs": 4004, + "2962-emitter-computed-optional.ts": 2860, + "2963-child-fork-dispatch/main.ts": 3483, + "2964-indexed-compound.ts": 4204, + "2966-numeric-array-read-fusion.ts": 4381, + "2967-numeric-array-read-lifetime.ts": 3892, + "2968-numeric-array-borrow.ts": 3610, + "2969-scalar-record-results.ts": 4035, + "2970-constant-numeric-tables.ts": 2720, + "2971-constant-table-modules/main.ts": 3311, + "2972-http-static-distinct-snapshots.ts": 4474, + "2972-math-receiver-borrow.ts": 4401, + "2973-http-static-agent.ts": 3997, + "2973-integer-bitwise-arithmetic.ts": 3629, + "2974-array-search-from-index.ts": 116997, + "2974-http-static-module-values.ts": 7598, + "2974-numeric-remainder.ts": 3511, + "2975-bigint-default-radix.ts": 3179, + "2975-http-static-client-controls.ts": 3852, + "2976-http-static-incoming-state.ts": 8478, + "2976-json-stringify-no-arguments.js": 3354, + "2977-http-static-incoming-timeout.ts": 3463, + "2977-nested-array-binding-defaults.js": 2952, + "2978-http-static-client-timeout.ts": 4066, + "2978-regexp-optional-subject.js": 2771, + "2979-array-search-mixed-needles.js": 3599, + "2979-http-static-server-timeout.ts": 3821, + "2980-http-static-server-timeout-default.ts": 3238, + "2980-string-position-arguments.js": 3754, + "2981-http-static-events.ts": 3579, + "2981-string-optional-positions.ts": 3623, + "2982-http-static-close-all.ts": 2800, + "2982-string-position-coercion-order.js": 4005, + "2983-http-static-close-idle.ts": 3208, + "2984-http-static-close-upgrade.ts": 3773, + "2985-http-static-message-destroy.ts": 3787, + "2986-http-static-client-socket-finish.ts": 3574, + "2987-http-static-timeout-errors.ts": 3533, + "2988-http-static-client-abort.ts": 4341, + "2989-http-static-response-timeout-handled.ts": 3444, + "2990-http-static-request-timeout-handled.ts": 3719, + "2991-array-indexed-equality.ts": 3650, + "2992-stream-rows.ts": 3551, + "2993-fiber-stack-lifetimes.ts": 3792, + "2994-fromcharcode-scalar.ts": 4459, + "2995-math-hyperbolic.ts": 3860, + "2996-math-near-one.ts": 3086, + "2997-math-integer-float.ts": 3955, + "300-if-else.ts": 3194, + "3001-caught-typeof-object.js": 4263, + "3002-promise-then-two.ts": 4357, + "301-while.ts": 3525, + "302-for.ts": 3433, + "3020-string-last-index-position.ts": 3282, + "3021-buffer-union-narrow-callback.ts": 3951, + "3022-string-affix-positions.ts": 2990, + "3023-string-affix-position-coercion.js": 3327, + "3024-string-number-narrow-for-in.ts": 3695, + "3025-string-search-position-coercion.js": 3055, + "3026-array-last-index-of.js": 3971, + "3027-array-last-index-of-records.ts": 3174, + "3028-string-search-dynamic-needle.js": 3488, + "3029-string-search-union-needle.js": 2317, + "303-break-continue.ts": 3497, + "3030-array-search-no-arg.js": 3148, + "3031-array-relative-index-coercion.js": 4248, + "3031-string-last-index-search-value.js": 2998, + "3032-string-search-value.js": 3484, + "3033-string-search-needle-coercion.js": 3256, + "3034-arguments-with-parameters.js": 3316, + "3035-string-positioned-search-value.js": 3436, + "3036-string-object-search-value.js": 3562, + "3037-number-nullish-conversion.js": 3657, + "3038-number-scalar-unions.ts": 2371, + "3039-string-repeat-count.js": 3353, + "304-compound-incdec.ts": 3802, + "3040-string-prototype-call.js": 4850, + "3041-string-prototype-object-call.js": 3234, + "3042-string-padding-coercion.js": 3916, + "3043-string-split-arguments.js": 3976, + "3044-array-slice-splice-positions.js": 4465, + "3045-array-indexed-mutation.js": 3477, + "3046-array-indexed-ref-identity.ts": 3717, + "3047-object-prototype-tag.js": 7241, + "3048-object-own-prototype.ts": 2902, + "3049-array-flat-depth.ts": 4100, + "305-truthiness.ts": 3370, + "3050-array-splice-insert.ts": 4056, + "3051-array-join-default.ts": 3538, + "3052-array-construction.ts": 4542, + "3053-array-construction-js.js": 3392, + "3054-dynamic-abort-record.ts": 30732, + "3055-default-builtin-nodenext/main.ts": 3399, + "3056-default-builtin-bundler/main.ts": 3748, + "3057-default-builtin-nodenext-dynamic/main.ts": 3727, + "3058-optional-array-chain-join.ts": 3025, + "3059-arguments-property-names.ts": 3619, + "3061-concurrent-fiber-stacks.ts": 4083, + "3062-runtime-optional-record-guards.ts": 4619, + "3063-runtime-optional-class-guards.ts": 4458, + "3064-installed-entry-imports/main.ts": 2755, + "3065-installed-entry-js/main.js": 2496, + "3066-source-debugging/main.ts": 3345, + "3067-cjs-function-export-require/main.cjs": 3584, + "3068-debug-variables/main.ts": 2803, + "3068-url-checked-identity.ts": 3525, + "3069-set-checked-seed.js": 3730, + "3069-tuple-spread.ts": 3638, + "3070-checked-object-accessors.js": 3937, + "3070-collection-views.ts": 3112, + "3071-checked-specialization-narrowing.js": 4666, + "3071-map-contextual-record-seeds.ts": 3637, + "3072-optional-union-receivers.ts": 4348, + "3072-weak-process-streams.js": 3937, + "3073-optional-callable-module.js": 3783, + "3073-union-keyed-reads.ts": 3349, + "3074-discriminated-intersections.ts": 3833, + "3075-recursive-contextual-literals.ts": 4956, + "3076-nullish-record-defaults.ts": 3537, + "3077-optional-union-array-reads.ts": 4192, + "3078-forward-mutable-captures.ts": 4709, + "3079-forward-mutable-tdz.ts": 4069, + "3080-exhaustive-never-bindings.ts": 3678, + "3081-recursive-array-destinations.ts": 3824, + "3082-forward-write-unwind.ts": 3698, + "3083-set-string-seed.ts": 3916, + "3084-record-own-membership.ts": 4502, + "3085-conditional-record-construction.ts": 4272, + "3086-error-constructor-options.ts": 2549, + "3087-error-options-lifetime.ts": 3996, + "3088-array-wide-callbacks.ts": 4379, + "3089-array-find-narrowing.ts": 4095, + "3090-json-discriminated-records.ts": 4621, + "3091-json-recursive-discriminants.ts": 4799, + "3092-number-union-predicates.ts": 3661, + "3093-error-option-data.ts": 3834, + "3094-json-replacer-traversal.ts": 3366, + "3095-json-reviver-traversal.ts": 3492, + "3096-json-callback-nonfinite.ts": 3652, + "3097-json-callback-reentrancy.ts": 4051, + "3098-json-callback-space.ts": 4000, + "3099-json-callback-functions.ts": 4355, + "3100-json-callback-holder.js": 4131, + "3101-json-callback-bytes.ts": 4053, + "3102-json-unknown-fields.ts": 3096, + "3103-scalar-record-nested-control-flow.ts": 3773, + "3104-native-analysis-tables-loops.ts": 3270, + "3105-nullable-collections.ts": 3945, + "3106-mixed-insertion-spreads.ts": 4363, + "3107-nullable-collection-lifetimes.ts": 4026, + "3108-for-await-sync-arrays.js": 5613, + "3108-identity-map-keys.ts": 3552, + "3109-destructuring-unknown-defaults.js": 3464, + "3109-identity-union-collections.ts": 4940, + "3110-builtin-error-families.ts": 3056, + "3110-identity-collection-mutation.ts": 4022, + "3111-identity-collection-cycles.ts": 4287, + "3112-union-switch-control-flow.ts": 3956, + "3113-union-array-removal.ts": 4360, + "3114-union-record-field-write.ts": 3442, + "3115-zlib-static-compression-levels.ts": 5168, + "3116-sequence-expression-lifetimes.ts": 4189, + "3117-unknown-switch-control-flow.ts": 4180, + "3118-recursive-union-spread.ts": 3041, + "3119-runtime-optional-spread.ts": 3381, + "3120-dynamic-property-descriptors.js": 2965, + "3120-generator-method-loop-bindings.ts": 4201, + "3120-ir-nonfinite-numbers.ts": 4055, + "3121-compound-assignment-values.js": 3508, + "3121-dynamic-accessor-descriptors.js": 5206, + "3122-dynamic-delete-descriptors.cjs": 3618, + "3122-dynamic-delete-descriptors.js": 3463, + "3122-js-async-class-methods.js": 3826, + "3123-destructured-global-tdz.js": 3445, + "3124-array-prototype-borrow.js": 4427, + "3125-regex-global-match.ts": 2948, + "3126-js-number-radix/main.ts": 3569, + "3127-spawn-runtime-options.ts": 3489, + "3128-regex-last-index.ts": 4225, + "3129-js-token-union/main.ts": 4007, + "3130-child-generic-streams.ts": 4070, + "3131-child-rest-listeners.js": 3532, + "3132-child-generic-stream-completion.ts": 11386, + "3133-text-decoder-streaming.ts": 19582, + "3134-fs-vectors.ts": 4100, + "3135-fs-file-handle-controls.ts": 5084, + "3136-fs-file-handle-options.ts": 5319, + "3137-fs-vector-callbacks.cjs": 4121, + "3138-array-large-storage.ts": 5662, + "3139-regex-native-deep-alternatives.ts": 37923, + "3140-array-dense-access.ts": 5683, + "3141-map-string-key-hash.ts": 3292, + "3150-integer-remainder.ts": 4041, + "3151-array-push-writes.ts": 4409, + "3170-number-conversion-fast-paths.ts": 3918, + "3171-method-census-data-writes.ts": 4678, + "400-fib.ts": 3649, + "401-mutual-recursion.ts": 2468, + "402-string-functions.ts": 3526, + "403-void-and-params.ts": 3277, + "4030-runtime-object-truthiness.ts": 4681, + "4031-event-emitter-long-tuples.ts": 3970, + "4032-inline-rc-fast-paths.ts": 6135, + "404-rc-stress.ts": 3734, + "4040-adapted-function-identity.ts": 4226, + "4041-adapted-function-properties.ts": 3785, + "4042-object-is-union-subclass.ts": 3204, + "4043-nonnull-missing-element.ts": 4658, + "4044-adapted-callback-modules/main.ts": 3502, + "4045-optional-element-projections.ts": 4551, + "4046-captured-parameter-values.ts": 4678, + "4047-captured-parameter-rebinding.ts": 3804, + "405-params-optional.ts": 3480, + "406-params-defaults.ts": 3673, + "4060-cycle-shared-instance/main.ts": 2973, + "4060-stack-union-reads.ts": 3684, + "4061-cycle-evaluation-order/main.ts": 3762, + "4061-nullable-ref-fields.ts": 5610, + "4062-cycle-tdz-read/main.ts": 3351, + "4063-cycle-hoisted-calls/main.ts": 3608, + "4064-cycle-classes-after-init/main.ts": 3570, + "4065-cycle-init-throws/main.ts": 3220, + "4066-cycle-top-level-tdz/main.ts": 2340, + "4067-dynamic-import-cycle-tdz/main.ts": 3378, + "407-params-rest.ts": 3809, + "408-params-ctors-inheritance.ts": 4026, + "4080-optional-read-presence-tests.ts": 3072, + "4080-string-index-bounds.ts": 2694, + "4081-hoisted-function-tdz.ts": 4427, + "4081-string-index-unproven.ts": 3902, + "4082-hoisted-function-tdz-uncaught.ts": 2748, + "4083-dynamic-import-failure/main.ts": 3742, + "4084-record-optional-field-copies.ts": 4621, + "4085-generator-loop-close.ts": 4491, + "4086-optional-capture-defaults.ts": 2947, + "4088-class-static-tdz.ts": 3366, + "4089-class-wrapper-tdz.js": 2781, + "409-params-async-generics.ts": 4252, + "4090-computed-key-tdz.js": 3408, + "4091-class-evaluation-deferred.ts": 2828, + "410-params-rc-stress.ts": 2917, + "4140-array-callback-split-visit.ts": 6798, + "4141-array-callback-ambient-receiver/main.ts": 3870, + "4142-array-callback-factories.ts": 4472, + "4143-union-refinement-intersection-arms.ts": 4107, + "420-dead-strip-modules/main.ts": 2681, + "4290-acyclic-immutable-trees.ts": 3286, + "4291-acyclic-constructor-escapes.ts": 3619, + "4292-acyclic-readonly-bypass.ts": 4006, + "4293-acyclic-dynamic-writes.ts": 3787, + "4294-console-line-sizes.ts": 5430, + "4295-console-template-parts.ts": 3102, + "4296-console-glued-long-parts.ts": 4254, + "4410-inline-object-allocation.ts": 4263, + "4411-nullable-ref-values.ts": 5324, + "4412-nullable-record-values.ts": 4337, + "4413-cycle-old-late-death.ts": 3017, + "4413-nullable-null-and-undefined.ts": 4035, + "4414-cycle-old-weak-keys.ts": 3820, + "4414-nullable-string-values.ts": 5821, + "4415-identity-borrowed-operands.ts": 4327, + "4415-nullable-container-values.ts": 5953, + "4431-exception-pending-contexts.ts": 5399, + "4432-checked-downcast-failures.ts": 4507, + "4451-int32-field-storage.ts": 5079, + "4452-int32-field-dynamic-writes.ts": 4478, + "4453-int32-closed-locals.ts": 3221, "4454-int32-field-reflection-reads.ts": 4583, "4455-live-view-reads-without-stores.ts": 4961, - "4471-unassigned-field-reads.ts": 3896, - "4476-string-ascii-header-fact.ts": 3522, - "4477-buffer-write-ascii-runs.ts": 3321, - "4478-string-large-index-reads.ts": 4146, - "4481-array-optional-push.ts": 3259, - "4482-instanceof-static-class-optional.ts": 3786, - "4483-array-splice-statement.ts": 4036, - "4484-array-length-reset.ts": 2849, - "4485-array-splice-optional-item.ts": 3817, - "4486-array-field-element-borrows.ts": 2903, - "4487-array-literal-optional-values.ts": 3145, - "4520-optional-guard-narrowing.ts": 2774, - "4521-array-callback-element-presence.ts": 5601, - "4522-captured-parameter-lifetimes.ts": 3907, - "4523-array-pop-removal.ts": 3769, - "4524-array-callback-supertype-params.ts": 4594, - "4541-nullable-wrap-borrows.ts": 3939, - "4542-preserving-call-borrows.ts": 3361, - "4543-walk-borrowed-locals.ts": 3633, - "4544-checked-cast-aliases.ts": 3723, - "4545-borrowed-returns.ts": 4116, - "4546-rebound-borrowed-params.ts": 2930, - "4560-field-store-borrowed-receivers.ts": 4438, - "4561-virtual-borrowed-parameters.ts": 3634, - "4562-string-self-concat-move.ts": 2703, - "4563-array-read-projection-receivers.ts": 3601, - "4564-literal-choice-strings.ts": 3137, - "4568-for-of-hole-elements.ts": 3387, - "4569-shorthand-missing-elements.ts": 3958, - "4570-map-lookup-default-record.ts": 3112, - "4591-weak-keys-union-records.ts": 3556, - "4592-cycle-const-from-import/main.ts": 3467, - "4593-weak-keys-empty-objects.ts": 2938, - "4594-union-class-field-mixed-types.ts": 4040, - "4595-union-class-field-optional-receiver.ts": 3379, - "4596-error-subclass-int-fields.ts": 3559, - "4596-tdz-nullable-forward-capture.ts": 4676, - "4597-callback-field-method-name.ts": 4014, - "4598-live-array-ref-element-access.ts": 8384, - "4598-map-set-clear-reuse.ts": 4224, - "4598-os-available-parallelism.ts": 3815, - "4598-publish-constructor-stores.ts": 3618, - "4599-construction-only-field-borrows.ts": 3619, - "4600-construction-only-fields-dynamic-writes.ts": 3184, - "4601-cycle-holders.ts": 3348, - "4602-constructor-escape-order.ts": 3674, - "4610-array-ext-dyn-refresh.ts": 4598, - "4620-optional-chain-borrowed-receivers.ts": 3411, - "4621-edge-preserving-callees/main.ts": 3288, - "4630-contract-int32.ts": 2810, - "4630-reference-write-call-arguments.ts": 3333, - "4631-contract-nothrow.ts": 3196, - "4631-reference-write-aliases.ts": 4264, - "4632-contract-immutable.ts": 3449, - "4632-reference-write-loops-and-walks.ts": 3791, - "4633-contract-program-lifetime.ts": 4644, - "4633-reference-write-callbacks-returns.ts": 4024, - "4634-contract-program-lifetime-publish.ts": 42618, - "4634-optional-element-borrowed-returns.ts": 3411, - "4640-bitwise-identity-ranges.ts": 3713, - "4641-nothrow-try-catch.ts": 3056, - "4642-acyclic-contract.ts": 4040, - "4650-stale-property-narrowing.ts": 3665, - "4651-map-string-get-entry.ts": 3369, - "4652-stale-closure-binding-narrowing.ts": 3504, - "4660-typed-rest-spread-forwarding.ts": 3148, - "4671-scoped-array-read-borrows.ts": 3020, - "4690-cycle-bypass-long-lived.ts": 5374, - "4691-publish-constructor-self-alias.ts": 38620, - "4692-borrowed-result-mutating-callees.ts": 3592, - "4720-cold-throw-paths.ts": 4339, - "4721-integer-induction-numbers.ts": 3854, - "4730-touint32-large-magnitudes.ts": 3431, - "4731-string-mixed-ascii-slices.ts": 4436, - "4732-buffer-write-utf16le-runs.ts": 4084, - "4733-typed-array-read-compares.ts": 3240, - "4750-map-string-absent-filter.ts": 3584, - "4751-string-search-multibyte-needles.ts": 3227, - "4795-published-untyped-member-reads.ts": 3450, - "4806-uint32-loop-accumulators.ts": 3543, - "4810-union-identity-retags.ts": 34911, - "4811-union-retag-checked-cast.ts": 3044, - "4812-int32-wrapping-sums.ts": 3457, - "4813-typed-array-read-equality-bindings.ts": 4853, - "4820-sort-comparator-lent-arguments.ts": 3579, - "4821-callback-lent-arguments.ts": 4210, - "4822-stable-capture-reads.ts": 3094, - "4823-array-store-receivers.ts": 3774, - "4830-typed-teardown-chains.ts": 3908, - "4831-cycle-bypass-probe-windows.ts": 6157, - "4840-array-hole-free-prefix.ts": 3932, - "4860-int32-local-storage.ts": 5136, - "4870-array-pipeline-fusion.ts": 6645, - "4871-array-pipeline-analytics.ts": 4575, - "4872-array-pipeline-temporaries.ts": 10635, - "4875-stream-consumers-array-buffer.ts": 4120, - "4876-array-buffer-inspect.ts": 2819, - "4880-await-call-turn-order.ts": 3872, - "4881-await-call-exceptions.ts": 3027, - "4882-await-call-request-chain.ts": 2730, - "4883-await-values-and-hops.ts": 3412, - "4884-await-call-unhandled-sibling.ts": 3410, - "4885-await-call-checkpoints.ts": 2703, - "4890-regex-literal-sites.ts": 3712, - "4891-regex-plain-text-patterns.ts": 3018, - "4892-regex-exec-read-captures.ts": 4130, - "4900-bigint-division-cross-check.ts": 3763, - "4900-console-instances.ts": 4286, - "4901-bigint-radix-text.ts": 3099, - "4901-console-instance-errors.ts": 3171, - "4902-bigint-compound-assign.ts": 3431, - "4903-bigint-fixed-width.ts": 3707, - "4904-bigint-large-products.ts": 3972, - "4905-bigint-fixed-width-fusion.ts": 3443, - "4906-bigint-small-value-trees.ts": 4875, - "4907-bigint-random-trees.ts": 5277, - "4910-hole-free-prefix-upkeep.ts": 4073, - "4920-string-literal-switch.ts": 3607, - "4930-typed-record-reflection.ts": 4869, - "4931-typed-data-generic-walks.ts": 5228, - "4932-typed-json-unknown.ts": 3250, - "4940-async-return-adoption.ts": 4405, - "4941-async-return-adoption-try.ts": 3533, - "4942-async-return-adoption-values.ts": 4824, - "4943-async-return-adoption-interleaved.ts": 3851, - "4950-regex-compiled-captures.ts": 5146, - "4951-regex-compiled-last-index.ts": 4316, - "4952-regex-compiled-anchors-classes.ts": 3149, - "4953-regex-compiled-backtracking.ts": 3822, - "4954-regex-log-report.ts": 4449, - "4955-regex-compiled-differential.ts": 20102, - "4970-int32-call-abi.ts": 3029, - "4980-generator-early-exit-finally.ts": 3262, - "4981-generator-delegation-iterables.ts": 5306, - "4982-generator-sent-values.ts": 3649, - "4983-generator-reuse-iterables.ts": 4023, - "4984-generator-exceptions.ts": 4220, - "4985-generator-lazy-pipeline.ts": 3164, - "4986-generator-default-channels.ts": 3434, - "4987-generator-closures-methods.ts": 3505, - "4988-generator-async-interplay.ts": 2790, - "4989-generator-step-drives.ts": 3509, - "4990-lone-surrogates.ts": 3213, - "4991-lone-surrogate-halves.ts": 4020, - "4992-lone-surrogate-search.ts": 3375, - "4993-lone-surrogate-json.ts": 3473, - "4994-lone-surrogate-uri.ts": 3848, - "4995-lone-surrogate-regex.ts": 4302, - "4996-lone-surrogate-stdio.ts": 2592, - "4997-lone-surrogate-stdout-patch.js": 3072, - "4998-lone-surrogate-buffers.ts": 3134, - "4999-lone-surrogate-io.ts": 3225, - "500-array-basics.ts": 2886, - "501-array-push-pop.ts": 2682, - "5010-lifetime-region-generations.ts": 4147, - "5011-lifetime-region-outside-references.ts": 3407, - "5012-lifetime-region-shapes.ts": 4861, - "5013-lifetime-region-async.ts": 3124, - "5014-lifetime-region-nesting.ts": 3259, - "5015-lifetime-region-publish.ts": 27669, - "5016-lifetime-region-weak-keys.ts": 2554, - "5017-lifetime-region-cycles.ts": 3105, - "5018-lifetime-region-hierarchies.ts": 4007, - "5019-lifetime-region-values.ts": 2888, - "502-array-for-of.ts": 3621, - "5020-lifetime-region-large.ts": 4812, - "5021-lifetime-region-opaque-holders.ts": 3957, - "5022-lifetime-region-workers.ts": 38841, - "503-array-functions.ts": 2982, - "504-array-rc-stress.ts": 3289, - "5040-promise-all-race-turns.ts": 4439, - "5041-promise-all-turns.js": 3708, - "5042-async-generator-return-promise.ts": 3292, - "5043-async-generator-return-forms.ts": 3922, - "5045-generator-delegation-typed-next.ts": 4740, - "5046-generator-delegation-return-throw.ts": 3192, - "5047-generator-delegation-iterables-typed.ts": 4558, - "5048-generator-delegation-async.ts": 3457, - "5049-generator-delegation-edges.ts": 3057, - "5050-inherited-in-membership.ts": 4297, - "5051-typed-record-prototypes.ts": 3534, - "5052-class-for-in-unknown.ts": 3663, - "5053-json-replacer-arrays.ts": 4093, - "5054-required-field-delete.ts": 3619, - "5055-object-create-record-literal.ts": 3237, - "5056-generator-in-unknown.ts": 3060, - "5060-child-fork-exit-after-messages/main.ts": 3584, - "5061-child-fork-local-disconnect/main.ts": 4277, - "5062-child-fork-message-before-eof/main.ts": 3570, - "5065-global-increment-initializers.ts": 2946, - "5066-global-compound-updates.ts": 3425, - "5067-global-updates-in-functions.ts": 3465, - "5068-global-var-let-const-updates.ts": 3395, - "5069-global-update-modules/main.ts": 3167, - "5070-optional-read-bindings.ts": 3316, - "5071-optional-chain-scalars.ts": 3214, - "5072-optional-nullish-ternary.ts": 2900, - "5073-optional-results.ts": 3751, - "5074-optional-pop-shift.ts": 3099, - "5075-optional-reads-unchecked/main.ts": 3754, - "5076-optional-escapes.ts": 3593, - "5080-boolean-array-storage.ts": 7564, - "5081-boolean-array-dynamic-views.ts": 3915, - "5085-promise-allsettled-turns.ts": 4557, - "5086-promise-any-turns.ts": 3994, - "5087-promise-allsettled-any-dyn.js": 5205, - "5088-promise-combinator-thenables.js": 5007, - "5089-promise-settled-records.ts": 4859, - "5090-generator-finished-result-value.ts": 3648, - "5091-generator-delegation-arrays-strings.ts": 3362, - "5092-generator-delegation-sets-maps.ts": 4496, - "5095-console-count-group.ts": 3356, - "5096-console-assert-dir.ts": 3645, - "5097-console-table.ts": 3255, - "5098-console-time-warnings.ts": 7324, - "5099-console-methods-dynamic.cjs": 3314, - "510-array-map-filter-foreach.ts": 3232, - "511-array-indexof-includes.ts": 3286, - "5110-var-hoisting-early-reads.ts": 4048, - "5111-var-hoisting-closures-classes.ts": 2474, - "5112-var-hoisting-function-scope.ts": 3383, - "5113-tdz-let-const-class.ts": 3628, - "5114-var-hoisting-js.js": 3550, - "5115-regex-replace-compiled.ts": 3344, - "5116-regex-capture-reads.ts": 3874, - "5117-regex-log-report-spans.ts": 3719, - "5118-regex-replace-char-chains.ts": 3632, - "512-array-join-chains.ts": 3268, - "5120-frame-records.ts": 3221, - "5121-frame-objects.ts": 3861, - "5122-frame-result-slots.ts": 3008, - "5123-frame-reassigned.ts": 3589, - "5124-frame-objects-control.ts": 3184, - "5125-frame-mutating-methods.ts": 3607, - "5126-frame-returned-params.ts": 3362, - "5127-frame-loop-bindings.ts": 4392, - "513-array-methods-rc-stress.ts": 3208, - "5130-event-target-dispatch.js": 4958, - "5131-event-target-listener-errors.js": 4558, - "5132-event-target-typed.ts": 5171, - "5133-abort-signal-event-target.ts": 22917, - "5134-events-error-monitor.ts": 3499, - "5135-event-target-warnings.js": 9058, - "5136-events-error-monitor-string-name.ts": 3057, - "5137-events-error-monitor-computed-name.js": 4052, - "5138-events-error-monitor-shared-listener.ts": 2466, - "5139-event-target-listener-throw.ts": 2925, - "514-array-find-some-every.ts": 3925, - "5140-os-host-facts.ts": 3438, - "5141-os-constants.ts": 2815, - "5142-path-parse-format.ts": 3808, - "5145-path-matches-glob-basics.ts": 3287, - "5146-path-matches-glob-braces.ts": 4987, - "5147-path-matches-glob-extglob.ts": 3938, - "5148-path-matches-glob-classes.ts": 3973, - "5149-path-matches-glob-win32.ts": 3835, - "515-array-flatmap.ts": 3688, - "5150-small-array-inline-slots.ts": 4419, - "5155-cycle-header-types.ts": 38708, - "516-array-reduce.ts": 4017, - "5160-field-callback-receiver.ts": 3678, - "5161-field-callback-receiver-escape.ts": 2857, - "5162-field-method-reference-receiver.ts": 2944, - "5163-field-callback-receiver.cjs": 3655, - "5164-worker-field-callback-receiver.ts": 30046, - "5165-interface-method-dispatch.ts": 2969, - "5166-interface-method-values.ts": 4129, - "5167-interface-method-order.ts": 3988, - "5168-interface-method-hierarchy.ts": 4483, - "5169-interface-method-chains.ts": 3336, - "517-array-hof-index-args.ts": 3024, - "5170-string-scan-eviction.ts": 3285, - "5171-lone-surrogate-replace-seams.ts": 3558, - "5175-forin-typed-as-unknown.ts": 4230, - "5176-object-keys-typed-as-unknown.ts": 3721, - "5177-forin-dynamic-objects.ts": 2893, - "5178-forin-keys-js.js": 2555, - "5179-forin-typed-shapes.ts": 4446, - "518-array-sort.ts": 3134, - "518-promise-void-union-callbacks.ts": 2401, - "5180-interface-arrays.ts": 3230, - "5181-interface-array-methods.ts": 11973, - "5182-interface-array-boundaries.ts": 3847, - "5183-interface-property-reads.ts": 3799, - "5184-interface-property-objects.ts": 3828, - "5185-util-inherits.cjs": 5041, - "5186-util-inherits.ts": 4542, - "5187-util-deprecate.cjs": 5818, - "5188-util-deprecate-flags.cjs": 4078, - "5189-util-deprecate.ts": 3798, - "519-array-from-length.ts": 2988, - "519-promise-union-await-values.ts": 3664, - "5190-util-callbackify.cjs": 5115, - "5191-util-callbackify.ts": 4367, - "5192-util-debuglog.cjs": 5096, - "5193-util-debuglog.ts": 4056, - "5194-process-emit-warning-tick.cjs": 2761, - "5195-object-entries-typed-as-unknown.ts": 3177, - "5196-object-values-typed-as-unknown.ts": 4077, - "5197-object-entries-dynamic-objects.ts": 4742, - "5198-object-entries-values-js.js": 3089, - "5199-object-entries-identity.ts": 3679, - "520-map-basics.ts": 3767, - "5200-array-sort-keyed-numbers.ts": 4618, - "5201-array-sort-keyed-records.ts": 5422, - "5202-array-sort-keyed-lookalikes.ts": 4034, - "5203-typed-array-sort-default.ts": 7941, - "5204-typed-array-sort-comparators.ts": 4085, - "521-map-number-keys.ts": 3317, - "5210-process-memory-usage.ts": 3262, - "5211-process-identity.ts": 3448, - "5212-perf-marks-measures.ts": 4026, - "5213-perf-timing-errors.ts": 4151, - "5214-perf-entry-inspect.ts": 4315, - "5215-perf-timing-validation.js": 2982, - "5216-perf-spread-arguments.js": 3745, - "5217-perf-spread-typed.ts": 4057, - "522-map-foreach.ts": 2964, - "5220-url-parse-warnings.ts": 4859, - "5221-url-parse-shapes.ts": 3814, - "5222-url-parse-hosts.ts": 3398, - "5223-url-parse-query.ts": 2653, - "5224-url-format-objects.ts": 5550, - "5225-url-format-whatwg.ts": 5213, - "5226-url-resolve.ts": 2600, - "5227-url-legacy-dependency/main.ts": 5803, - "5228-url-domain-conversion.ts": 4876, - "5229-url-legacy-errors.cjs": 5195, - "523-map-ref-values.ts": 4321, - "5230-inline-union-fields.ts": 3644, - "5231-inline-union-field-kinds.ts": 4871, - "5232-inline-union-fields-dynamic.ts": 3887, - "5233-inline-union-fields-shapes.ts": 4145, - "5234-inline-union-class-fields.ts": 3244, - "5235-inline-union-fields-publish.ts": 3360, - "5236-inline-union-unchecked-reads.ts": 3108, - "5237-inline-union-frame-objects.ts": 2533, - "524-map-cycles.ts": 3943, - "5240-event-target-subclass.ts": 5571, - "5241-event-subclass.ts": 4311, - "5242-event-target-subclass-hierarchy.ts": 4079, - "5243-event-target-subclass-dynamic.ts": 3528, - "5244-event-target-subclass.js": 4645, - "5245-event-target-subclass-signals.ts": 9410, - "5246-event-target-subclass-listener-throw.ts": 3995, - "5247-event-target-subclass-lifetimes.ts": 5991, - "5248-event-target-subclass-warnings.ts": 4513, - "5249-event-target-subclass-unconstructed.ts": 2679, - "525-map-rc-stress.ts": 2764, + "4471-unassigned-field-reads.ts": 4391, + "4476-string-ascii-header-fact.ts": 4538, + "4477-buffer-write-ascii-runs.ts": 4115, + "4478-string-large-index-reads.ts": 4211, + "4481-array-optional-push.ts": 3640, + "4482-instanceof-static-class-optional.ts": 2991, + "4483-array-splice-statement.ts": 5079, + "4484-array-length-reset.ts": 3655, + "4485-array-splice-optional-item.ts": 4264, + "4486-array-field-element-borrows.ts": 3950, + "4487-array-literal-optional-values.ts": 5139, + "4520-optional-guard-narrowing.ts": 4441, + "4521-array-callback-element-presence.ts": 6451, + "4522-captured-parameter-lifetimes.ts": 3198, + "4523-array-pop-removal.ts": 4334, + "4524-array-callback-supertype-params.ts": 5586, + "4541-nullable-wrap-borrows.ts": 4310, + "4542-preserving-call-borrows.ts": 4231, + "4543-walk-borrowed-locals.ts": 3976, + "4544-checked-cast-aliases.ts": 4280, + "4545-borrowed-returns.ts": 4524, + "4546-rebound-borrowed-params.ts": 4010, + "4560-field-store-borrowed-receivers.ts": 3877, + "4561-virtual-borrowed-parameters.ts": 4633, + "4562-string-self-concat-move.ts": 3881, + "4563-array-read-projection-receivers.ts": 4188, + "4564-literal-choice-strings.ts": 4026, + "4568-for-of-hole-elements.ts": 4432, + "4569-shorthand-missing-elements.ts": 4672, + "4570-map-lookup-default-record.ts": 3777, + "4591-weak-keys-union-records.ts": 3889, + "4592-cycle-const-from-import/main.ts": 2581, + "4593-weak-keys-empty-objects.ts": 3813, + "4594-union-class-field-mixed-types.ts": 7147, + "4595-union-class-field-optional-receiver.ts": 3827, + "4596-error-subclass-int-fields.ts": 3477, + "4596-tdz-nullable-forward-capture.ts": 3990, + "4597-callback-field-method-name.ts": 4176, + "4598-live-array-ref-element-access.ts": 9941, + "4598-map-set-clear-reuse.ts": 5807, + "4598-os-available-parallelism.ts": 3624, + "4598-publish-constructor-stores.ts": 3208, + "4599-construction-only-field-borrows.ts": 5064, + "4600-construction-only-fields-dynamic-writes.ts": 3234, + "4601-cycle-holders.ts": 3389, + "4602-constructor-escape-order.ts": 3798, + "4610-array-ext-dyn-refresh.ts": 4533, + "4620-optional-chain-borrowed-receivers.ts": 4161, + "4621-edge-preserving-callees/main.ts": 4709, + "4630-contract-int32.ts": 4369, + "4630-reference-write-call-arguments.ts": 4010, + "4631-contract-nothrow.ts": 4027, + "4631-reference-write-aliases.ts": 4138, + "4632-contract-immutable.ts": 3925, + "4632-reference-write-loops-and-walks.ts": 4126, + "4633-contract-program-lifetime.ts": 5198, + "4633-reference-write-callbacks-returns.ts": 4361, + "4634-contract-program-lifetime-publish.ts": 51728, + "4634-optional-element-borrowed-returns.ts": 3758, + "4640-bitwise-identity-ranges.ts": 4521, + "4641-nothrow-try-catch.ts": 3856, + "4642-acyclic-contract.ts": 4836, + "4650-stale-property-narrowing.ts": 5065, + "4651-map-string-get-entry.ts": 3204, + "4652-stale-closure-binding-narrowing.ts": 4161, + "4660-typed-rest-spread-forwarding.ts": 2965, + "4671-scoped-array-read-borrows.ts": 4639, + "4690-cycle-bypass-long-lived.ts": 6384, + "4691-publish-constructor-self-alias.ts": 43679, + "4692-borrowed-result-mutating-callees.ts": 4134, + "4720-cold-throw-paths.ts": 3925, + "4721-integer-induction-numbers.ts": 3986, + "4730-touint32-large-magnitudes.ts": 3378, + "4731-string-mixed-ascii-slices.ts": 3992, + "4732-buffer-write-utf16le-runs.ts": 4419, + "4733-typed-array-read-compares.ts": 3723, + "4750-map-string-absent-filter.ts": 4339, + "4751-string-search-multibyte-needles.ts": 2934, + "4795-published-untyped-member-reads.ts": 4864, + "4806-uint32-loop-accumulators.ts": 4131, + "4810-union-identity-retags.ts": 45852, + "4811-union-retag-checked-cast.ts": 3777, + "4812-int32-wrapping-sums.ts": 4491, + "4813-typed-array-read-equality-bindings.ts": 5104, + "4820-sort-comparator-lent-arguments.ts": 4547, + "4821-callback-lent-arguments.ts": 4044, + "4822-stable-capture-reads.ts": 3520, + "4823-array-store-receivers.ts": 3708, + "4830-typed-teardown-chains.ts": 5155, + "4831-cycle-bypass-probe-windows.ts": 6539, + "4840-array-hole-free-prefix.ts": 5312, + "4860-int32-local-storage.ts": 5193, + "4870-array-pipeline-fusion.ts": 9277, + "4871-array-pipeline-analytics.ts": 4466, + "4872-array-pipeline-temporaries.ts": 8037, + "4875-stream-consumers-array-buffer.ts": 4195, + "4876-array-buffer-inspect.ts": 3460, + "4880-await-call-turn-order.ts": 3196, + "4881-await-call-exceptions.ts": 3913, + "4882-await-call-request-chain.ts": 3966, + "4883-await-values-and-hops.ts": 3305, + "4884-await-call-unhandled-sibling.ts": 3775, + "4885-await-call-checkpoints.ts": 3389, + "4890-regex-literal-sites.ts": 4481, + "4891-regex-plain-text-patterns.ts": 4954, + "4892-regex-exec-read-captures.ts": 5836, + "4900-bigint-division-cross-check.ts": 4132, + "4900-console-instances.ts": 3398, + "4901-bigint-radix-text.ts": 4240, + "4901-console-instance-errors.ts": 4118, + "4902-bigint-compound-assign.ts": 3348, + "4903-bigint-fixed-width.ts": 4053, + "4904-bigint-large-products.ts": 4084, + "4905-bigint-fixed-width-fusion.ts": 4866, + "4906-bigint-small-value-trees.ts": 4495, + "4907-bigint-random-trees.ts": 6985, + "4910-hole-free-prefix-upkeep.ts": 3869, + "4920-string-literal-switch.ts": 3948, + "4930-typed-record-reflection.ts": 6446, + "4931-typed-data-generic-walks.ts": 6005, + "4932-typed-json-unknown.ts": 4690, + "4940-async-return-adoption.ts": 4747, + "4941-async-return-adoption-try.ts": 4808, + "4942-async-return-adoption-values.ts": 4525, + "4943-async-return-adoption-interleaved.ts": 4076, + "4950-regex-compiled-captures.ts": 5853, + "4951-regex-compiled-last-index.ts": 4237, + "4952-regex-compiled-anchors-classes.ts": 2970, + "4953-regex-compiled-backtracking.ts": 4881, + "4954-regex-log-report.ts": 4017, + "4955-regex-compiled-differential.ts": 17656, + "4970-int32-call-abi.ts": 4034, + "4980-generator-early-exit-finally.ts": 4293, + "4981-generator-delegation-iterables.ts": 4701, + "4982-generator-sent-values.ts": 3850, + "4983-generator-reuse-iterables.ts": 4013, + "4984-generator-exceptions.ts": 3941, + "4985-generator-lazy-pipeline.ts": 5191, + "4986-generator-default-channels.ts": 4218, + "4987-generator-closures-methods.ts": 3564, + "4988-generator-async-interplay.ts": 4129, + "4989-generator-step-drives.ts": 3945, + "4990-lone-surrogates.ts": 4283, + "4991-lone-surrogate-halves.ts": 3965, + "4992-lone-surrogate-search.ts": 4450, + "4993-lone-surrogate-json.ts": 4533, + "4994-lone-surrogate-uri.ts": 3275, + "4995-lone-surrogate-regex.ts": 4305, + "4996-lone-surrogate-stdio.ts": 3980, + "4997-lone-surrogate-stdout-patch.js": 3708, + "4998-lone-surrogate-buffers.ts": 3397, + "4999-lone-surrogate-io.ts": 4183, + "500-array-basics.ts": 3681, + "501-array-push-pop.ts": 3744, + "5010-lifetime-region-generations.ts": 4361, + "5011-lifetime-region-outside-references.ts": 3723, + "5012-lifetime-region-shapes.ts": 5352, + "5013-lifetime-region-async.ts": 4836, + "5014-lifetime-region-nesting.ts": 4098, + "5015-lifetime-region-publish.ts": 44284, + "5016-lifetime-region-weak-keys.ts": 4090, + "5017-lifetime-region-cycles.ts": 2993, + "5018-lifetime-region-hierarchies.ts": 4448, + "5019-lifetime-region-values.ts": 4593, + "502-array-for-of.ts": 3697, + "5020-lifetime-region-large.ts": 6810, + "5021-lifetime-region-opaque-holders.ts": 3221, + "5022-lifetime-region-workers.ts": 43902, + "503-array-functions.ts": 3221, + "504-array-rc-stress.ts": 3902, + "5040-promise-all-race-turns.ts": 3963, + "5041-promise-all-turns.js": 3961, + "5042-async-generator-return-promise.ts": 4464, + "5043-async-generator-return-forms.ts": 3956, + "5045-generator-delegation-typed-next.ts": 4940, + "5046-generator-delegation-return-throw.ts": 4744, + "5047-generator-delegation-iterables-typed.ts": 5495, + "5048-generator-delegation-async.ts": 4004, + "5049-generator-delegation-edges.ts": 3818, + "5050-inherited-in-membership.ts": 2952, + "5051-typed-record-prototypes.ts": 4128, + "5052-class-for-in-unknown.ts": 4437, + "5053-json-replacer-arrays.ts": 4585, + "5054-required-field-delete.ts": 3565, + "5055-object-create-record-literal.ts": 3433, + "5056-generator-in-unknown.ts": 3552, + "5060-child-fork-exit-after-messages/main.ts": 4059, + "5061-child-fork-local-disconnect/main.ts": 3921, + "5062-child-fork-message-before-eof/main.ts": 5311, + "5065-global-increment-initializers.ts": 3409, + "5066-global-compound-updates.ts": 3878, + "5067-global-updates-in-functions.ts": 3060, + "5068-global-var-let-const-updates.ts": 3099, + "5069-global-update-modules/main.ts": 3105, + "5070-optional-read-bindings.ts": 3986, + "5071-optional-chain-scalars.ts": 4053, + "5072-optional-nullish-ternary.ts": 3786, + "5073-optional-results.ts": 3653, + "5074-optional-pop-shift.ts": 3809, + "5075-optional-reads-unchecked/main.ts": 4486, + "5076-optional-escapes.ts": 3781, + "5080-boolean-array-storage.ts": 9389, + "5081-boolean-array-dynamic-views.ts": 5005, + "5085-promise-allsettled-turns.ts": 5227, + "5086-promise-any-turns.ts": 4926, + "5087-promise-allsettled-any-dyn.js": 5648, + "5088-promise-combinator-thenables.js": 6097, + "5089-promise-settled-records.ts": 4902, + "5090-generator-finished-result-value.ts": 3980, + "5091-generator-delegation-arrays-strings.ts": 4920, + "5092-generator-delegation-sets-maps.ts": 5655, + "5095-console-count-group.ts": 4543, + "5096-console-assert-dir.ts": 3659, + "5097-console-table.ts": 4019, + "5098-console-time-warnings.ts": 7779, + "5099-console-methods-dynamic.cjs": 4211, + "510-array-map-filter-foreach.ts": 3693, + "511-array-indexof-includes.ts": 2587, + "5110-var-hoisting-early-reads.ts": 3722, + "5111-var-hoisting-closures-classes.ts": 3558, + "5112-var-hoisting-function-scope.ts": 3736, + "5113-tdz-let-const-class.ts": 3427, + "5114-var-hoisting-js.js": 2426, + "5115-regex-replace-compiled.ts": 4045, + "5116-regex-capture-reads.ts": 3563, + "5117-regex-log-report-spans.ts": 3810, + "5118-regex-replace-char-chains.ts": 3242, + "512-array-join-chains.ts": 3887, + "5120-frame-records.ts": 4007, + "5121-frame-objects.ts": 3950, + "5122-frame-result-slots.ts": 3225, + "5123-frame-reassigned.ts": 3642, + "5124-frame-objects-control.ts": 2980, + "5125-frame-mutating-methods.ts": 3316, + "5126-frame-returned-params.ts": 3759, + "5127-frame-loop-bindings.ts": 4535, + "513-array-methods-rc-stress.ts": 3991, + "5130-event-target-dispatch.js": 5194, + "5131-event-target-listener-errors.js": 5170, + "5132-event-target-typed.ts": 5485, + "5133-abort-signal-event-target.ts": 30480, + "5134-events-error-monitor.ts": 3910, + "5135-event-target-warnings.js": 38892, + "5136-events-error-monitor-string-name.ts": 3923, + "5137-events-error-monitor-computed-name.js": 4432, + "5138-events-error-monitor-shared-listener.ts": 3642, + "5139-event-target-listener-throw.ts": 4714, + "514-array-find-some-every.ts": 3747, + "5140-os-host-facts.ts": 4713, + "5141-os-constants.ts": 3991, + "5142-path-parse-format.ts": 3463, + "5145-path-matches-glob-basics.ts": 4364, + "5146-path-matches-glob-braces.ts": 5382, + "5147-path-matches-glob-extglob.ts": 3804, + "5148-path-matches-glob-classes.ts": 3686, + "5149-path-matches-glob-win32.ts": 4358, + "515-array-flatmap.ts": 4323, + "5150-small-array-inline-slots.ts": 4485, + "5155-cycle-header-types.ts": 32161, + "516-array-reduce.ts": 4410, + "5160-field-callback-receiver.ts": 4515, + "5161-field-callback-receiver-escape.ts": 3931, + "5162-field-method-reference-receiver.ts": 3961, + "5163-field-callback-receiver.cjs": 4008, + "5164-worker-field-callback-receiver.ts": 43587, + "5165-interface-method-dispatch.ts": 4146, + "5166-interface-method-values.ts": 5178, + "5167-interface-method-order.ts": 4344, + "5168-interface-method-hierarchy.ts": 5405, + "5169-interface-method-chains.ts": 5047, + "517-array-hof-index-args.ts": 3899, + "5170-string-scan-eviction.ts": 2657, + "5171-lone-surrogate-replace-seams.ts": 3047, + "5175-forin-typed-as-unknown.ts": 3918, + "5176-object-keys-typed-as-unknown.ts": 2645, + "5177-forin-dynamic-objects.ts": 3654, + "5178-forin-keys-js.js": 2761, + "5179-forin-typed-shapes.ts": 3622, + "518-array-sort.ts": 4004, + "518-promise-void-union-callbacks.ts": 3964, + "5180-interface-arrays.ts": 4400, + "5181-interface-array-methods.ts": 13672, + "5182-interface-array-boundaries.ts": 3272, + "5183-interface-property-reads.ts": 4146, + "5184-interface-property-objects.ts": 3495, + "5185-util-inherits.cjs": 6043, + "5186-util-inherits.ts": 6829, + "5187-util-deprecate.cjs": 6304, + "5188-util-deprecate-flags.cjs": 4852, + "5189-util-deprecate.ts": 5176, + "519-array-from-length.ts": 4670, + "519-promise-union-await-values.ts": 3522, + "5190-util-callbackify.cjs": 4881, + "5191-util-callbackify.ts": 5163, + "5192-util-debuglog.cjs": 5490, + "5193-util-debuglog.ts": 3737, + "5194-process-emit-warning-tick.cjs": 4043, + "5195-object-entries-typed-as-unknown.ts": 3294, + "5196-object-values-typed-as-unknown.ts": 4153, + "5197-object-entries-dynamic-objects.ts": 4163, + "5198-object-entries-values-js.js": 3223, + "5199-object-entries-identity.ts": 4287, + "520-map-basics.ts": 3177, + "5200-array-sort-keyed-numbers.ts": 5498, + "5201-array-sort-keyed-records.ts": 6386, + "5202-array-sort-keyed-lookalikes.ts": 3643, + "5203-typed-array-sort-default.ts": 7538, + "5204-typed-array-sort-comparators.ts": 5252, + "521-map-number-keys.ts": 3394, + "5210-process-memory-usage.ts": 2806, + "5211-process-identity.ts": 3698, + "5212-perf-marks-measures.ts": 4803, + "5213-perf-timing-errors.ts": 4464, + "5214-perf-entry-inspect.ts": 4525, + "5215-perf-timing-validation.js": 4263, + "5216-perf-spread-arguments.js": 4935, + "5217-perf-spread-typed.ts": 3571, + "522-map-foreach.ts": 2998, + "5220-url-parse-warnings.ts": 5276, + "5221-url-parse-shapes.ts": 5152, + "5222-url-parse-hosts.ts": 5614, + "5223-url-parse-query.ts": 5852, + "5224-url-format-objects.ts": 5092, + "5225-url-format-whatwg.ts": 5939, + "5226-url-resolve.ts": 4968, + "5227-url-legacy-dependency/main.ts": 5444, + "5228-url-domain-conversion.ts": 2782, + "5229-url-legacy-errors.cjs": 6339, + "523-map-ref-values.ts": 3549, + "5230-inline-union-fields.ts": 4686, + "5231-inline-union-field-kinds.ts": 4192, + "5232-inline-union-fields-dynamic.ts": 4074, + "5233-inline-union-fields-shapes.ts": 4531, + "5234-inline-union-class-fields.ts": 4699, + "5235-inline-union-fields-publish.ts": 3783, + "5236-inline-union-unchecked-reads.ts": 3109, + "5237-inline-union-frame-objects.ts": 2338, + "524-map-cycles.ts": 3268, + "5240-event-target-subclass.ts": 5177, + "5241-event-subclass.ts": 5478, + "5242-event-target-subclass-hierarchy.ts": 4631, + "5243-event-target-subclass-dynamic.ts": 4520, + "5244-event-target-subclass.js": 5329, + "5245-event-target-subclass-signals.ts": 33048, + "5246-event-target-subclass-listener-throw.ts": 3829, + "5247-event-target-subclass-lifetimes.ts": 6504, + "5248-event-target-subclass-warnings.ts": 4300, + "5249-event-target-subclass-unconstructed.ts": 4427, + "525-map-rc-stress.ts": 3704, "5250-cipher-aes-gcm.ts": 7929, "5251-cipher-aes-cbc.ts": 15678, "5252-cipher-aes-ctr.ts": 26018, @@ -4696,45 +4696,45 @@ "5257-cipher-vectors.ts": 18839, "5258-cipher-handles.js": 21996, "5259-cipher-chunked.ts": 21780, - "526-set-basics.ts": 2480, - "5260-record-unknown-identity.ts": 3505, - "5261-optional-field-identity.ts": 3914, - "5262-record-unknown-many.ts": 3839, - "527-set-foreach.ts": 3683, - "5270-url-parse-no-deprecation.cjs": 4076, - "5271-url-parse-throw-deprecation.cjs": 3487, - "5275-http-end-callback-order.ts": 3028, - "5276-style-text-hex-colors.cjs": 4502, - "5277-fs-read-file-buffer-option.cjs": 2635, - "5278-host-null-bytes.cjs": 16385, - "5279-search-params-null-init.cjs": 2915, - "528-set-seeded.ts": 3643, - "5285-blob-construct.ts": 3124, - "5286-blob-readers.ts": 3309, - "5287-blob-inspect.ts": 2504, - "5288-blob-validation.js": 3775, - "5289-blob-read-order.ts": 3614, - "529-map-seeded.ts": 3331, - "5290-blob-dynamic.js": 2674, - "5295-readline-promises-question.ts": 2401, - "5296-readline-lines.ts": 3088, - "5297-readline-callback-events.cjs": 2975, - "5298-readline-abort.cjs": 6980, - "5299-readline-stdin.ts": 3836, - "530-record-arrays.ts": 3125, - "5300-stream-add-abort-signal.ts": 7154, - "5301-stream-add-abort-signal-errors.cjs": 7763, - "5302-stream-promises-options.ts": 8927, - "5303-stream-finished-callback-opts.cjs": 7119, - "5305-json-stringify-typed-arrays.ts": 4254, - "531-record-array-hofs.ts": 3609, - "5315-map-iterate-after-front-deletes.ts": 2759, - "5316-map-lru-eviction.ts": 3688, - "5317-map-iterate-while-mutating.ts": 3035, - "5318-set-iterate-after-deletes.ts": 2543, - "5319-map-iteration-values.ts": 4062, - "532-record-arrays-rc-stress.ts": 2708, - "5320-map-iterate-across-compaction.ts": 2736, + "526-set-basics.ts": 3497, + "5260-record-unknown-identity.ts": 3759, + "5261-optional-field-identity.ts": 3633, + "5262-record-unknown-many.ts": 4065, + "527-set-foreach.ts": 3282, + "5270-url-parse-no-deprecation.cjs": 4123, + "5271-url-parse-throw-deprecation.cjs": 5457, + "5275-http-end-callback-order.ts": 4317, + "5276-style-text-hex-colors.cjs": 4489, + "5277-fs-read-file-buffer-option.cjs": 3576, + "5278-host-null-bytes.cjs": 8285, + "5279-search-params-null-init.cjs": 3511, + "528-set-seeded.ts": 3372, + "5285-blob-construct.ts": 4331, + "5286-blob-readers.ts": 3684, + "5287-blob-inspect.ts": 4285, + "5288-blob-validation.js": 4292, + "5289-blob-read-order.ts": 3682, + "529-map-seeded.ts": 3677, + "5290-blob-dynamic.js": 4399, + "5295-readline-promises-question.ts": 3697, + "5296-readline-lines.ts": 3534, + "5297-readline-callback-events.cjs": 3926, + "5298-readline-abort.cjs": 12732, + "5299-readline-stdin.ts": 4774, + "530-record-arrays.ts": 3665, + "5300-stream-add-abort-signal.ts": 34654, + "5301-stream-add-abort-signal-errors.cjs": 12589, + "5302-stream-promises-options.ts": 13246, + "5303-stream-finished-callback-opts.cjs": 9506, + "5305-json-stringify-typed-arrays.ts": 5926, + "531-record-array-hofs.ts": 3761, + "5315-map-iterate-after-front-deletes.ts": 3399, + "5316-map-lru-eviction.ts": 4060, + "5317-map-iterate-while-mutating.ts": 3994, + "5318-set-iterate-after-deletes.ts": 3956, + "5319-map-iteration-values.ts": 4002, + "532-record-arrays-rc-stress.ts": 3024, + "5320-map-iterate-across-compaction.ts": 4445, "5321-integer-closed-arithmetic-loops.ts": 3363, "5321-json-parse-cycles.ts": 3162, "5322-integer-variable-step-loops.ts": 3747, @@ -4743,29 +4743,29 @@ "5323-int32-nonnegative-slot-facts.ts": 3657, "5324-int32-initializer-locals.ts": 2946, "5324-structured-clone-documents.ts": 4653, - "5325-record-boundary-returns.ts": 3046, - "5326-record-boundary-params.ts": 2989, - "5327-record-boundary-identity.ts": 3529, - "5328-record-boundary-open.ts": 3718, - "5329-record-boundary-recursion.ts": 3361, - "533-array-element-cycles.ts": 3118, - "5330-record-boundary-fields.ts": 3048, - "5331-record-boundary-methods.ts": 2560, + "5325-record-boundary-returns.ts": 3627, + "5326-record-boundary-params.ts": 3878, + "5327-record-boundary-identity.ts": 2625, + "5328-record-boundary-open.ts": 3032, + "5329-record-boundary-recursion.ts": 3600, + "533-array-element-cycles.ts": 3019, + "5330-record-boundary-fields.ts": 3682, + "5331-record-boundary-methods.ts": 3949, "5332-int32-narrowed-slot-facts.ts": 3391, "5333-integer-guarded-while-counters.ts": 3537, - "5333-record-boundary-nullable-argument.ts": 3100, - "5334-fetch-mentions-without-calls.ts": 4032, + "5333-record-boundary-nullable-argument.ts": 4003, + "5334-fetch-mentions-without-calls.ts": 3134, "5335-stream-operators-values.ts": 5552, - "5335-top-level-await-pending-exit-code.ts": 2383, + "5335-top-level-await-pending-exit-code.ts": 3309, "5336-stream-operators-promise-timing.ts": 3761, - "5336-top-level-await-pending-exit-listener.ts": 2814, - "5337-dc-subscriber-throw-next-tick.cjs": 3273, + "5336-top-level-await-pending-exit-listener.ts": 4072, + "5337-dc-subscriber-throw-next-tick.cjs": 4314, "5337-stream-operators-concurrency.ts": 9296, - "5338-js-tdz-function-element.js": 3733, + "5338-js-tdz-function-element.js": 2718, "5338-stream-operators-checks.cjs": 4825, - "5339-array-buffer-constructor.js": 2884, + "5339-array-buffer-constructor.js": 3399, "5339-stream-for-await-hops.ts": 5761, - "534-record-width-subtyping.ts": 3530, + "534-record-width-subtyping.ts": 3917, "5340-readable-from-options.ts": 4100, "5341-compound-any-operand.ts": 4139, "5341-generator-callback-params.ts": 4032, @@ -4781,28 +4781,28 @@ "5343-stream-compose-edges.ts": 8761, "5344-json-parse-undeclared-keys.ts": 4683, "5344-stream-pipeline-timing.ts": 3627, - "5345-object-values-for-of-unknown.ts": 4013, - "5346-object-values-length-dynamic.ts": 3930, - "5347-object-values-loop-control.ts": 3598, - "5348-object-values-for-of-js.js": 2760, - "5349-object-entries-values-optional.ts": 3370, - "535-object-statics.ts": 2862, - "5350-object-values-wide-record.ts": 3272, - "5351-object-values-methods-index.ts": 3637, + "5345-object-values-for-of-unknown.ts": 3893, + "5346-object-values-length-dynamic.ts": 4302, + "5347-object-values-loop-control.ts": 3777, + "5348-object-values-for-of-js.js": 3584, + "5349-object-entries-values-optional.ts": 3677, + "535-object-statics.ts": 4668, + "5350-object-values-wide-record.ts": 4386, + "5351-object-values-methods-index.ts": 3615, "5352-final-field-loop-reads.ts": 3880, "5353-captured-const-values.ts": 4470, "5354-captured-const-tdz.ts": 3331, "5355-captured-function-declarations.ts": 3574, "5356-captured-tdz-ordering.ts": 3626, "5357-init-only-module-bindings.ts": 3698, - "536-map-seed-array.ts": 3237, - "5360-array-sort-comparator-calls.ts": 4265, - "5361-array-sort-inconsistent-comparators.ts": 4181, - "5362-array-sort-comparator-throws.ts": 2826, - "5363-array-sort-comparator-writes.ts": 10362, - "5364-array-sort-union-and-boolean-elements.ts": 14300, - "5365-array-sort-dynamic-values.js": 2919, - "537-map-iter-drains.ts": 3050, + "536-map-seed-array.ts": 3057, + "5360-array-sort-comparator-calls.ts": 4503, + "5361-array-sort-inconsistent-comparators.ts": 4396, + "5362-array-sort-comparator-throws.ts": 3173, + "5363-array-sort-comparator-writes.ts": 12179, + "5364-array-sort-union-and-boolean-elements.ts": 14770, + "5365-array-sort-dynamic-values.js": 4175, + "537-map-iter-drains.ts": 3108, "5370-zlib-stream-roundtrip.ts": 6069, "5371-zlib-stream-chunking.cjs": 3999, "5372-zlib-stream-errors.cjs": 4377, @@ -4813,29 +4813,29 @@ "5377-zlib-stream-backpressure.cjs": 5428, "5378-zlib-sync-options.cjs": 5415, "5379-zlib-callback-options.ts": 5768, - "538-map-set-for-of.ts": 3029, - "5390-interface-loop-element-lifetimes.ts": 3566, - "5391-interface-dispatch-hierarchies.ts": 3731, - "5392-interface-receiver-bindings.ts": 3061, - "5393-interface-array-holes.ts": 2702, - "5394-interface-implementers.ts": 3603, - "5395-locale-compare-ascii.ts": 3587, - "5396-locale-compare-latin.ts": 4291, - "5397-locale-compare-sorting.ts": 3576, - "540-tuples-basics.ts": 3420, - "5400-json-parse-typed-keys.ts": 3141, - "5405-buffer-arraybuffer-window.ts": 3036, - "5406-util-types-keys.ts": 2954, - "5407-http-header-field-limit.ts": 3052, - "5408-http-unread-request-end.ts": 3992, - "5409-http-held-request-body.ts": 3771, - "541-ref-array-json.ts": 3761, - "5410-inspect-class-values.ts": 3124, - "5411-inspect-class-hierarchies.ts": 2423, - "5412-inspect-dynamic-collections.ts": 3042, - "5413-inspect-class-values.cjs": 3217, + "538-map-set-for-of.ts": 3575, + "5390-interface-loop-element-lifetimes.ts": 4065, + "5391-interface-dispatch-hierarchies.ts": 4925, + "5392-interface-receiver-bindings.ts": 3293, + "5393-interface-array-holes.ts": 3549, + "5394-interface-implementers.ts": 4320, + "5395-locale-compare-ascii.ts": 4299, + "5396-locale-compare-latin.ts": 3694, + "5397-locale-compare-sorting.ts": 4218, + "540-tuples-basics.ts": 3768, + "5400-json-parse-typed-keys.ts": 4494, + "5405-buffer-arraybuffer-window.ts": 3875, + "5406-util-types-keys.ts": 4065, + "5407-http-header-field-limit.ts": 2684, + "5408-http-unread-request-end.ts": 4832, + "5409-http-held-request-body.ts": 4395, + "541-ref-array-json.ts": 4658, + "5410-inspect-class-values.ts": 4013, + "5411-inspect-class-hierarchies.ts": 3695, + "5412-inspect-dynamic-collections.ts": 2565, + "5413-inspect-class-values.cjs": 4189, "5415-zlib-dynamic-inputs.cjs": 3913, - "542-union-element-arrays.ts": 2812, + "542-union-element-arrays.ts": 4031, "5420-readable-from-generators.ts": 5476, "5421-readable-from-generators.cjs": 3700, "5422-stream-async-push-wakeup.ts": 4528, @@ -4846,43 +4846,43 @@ "5427-pipeline-generator-backpressure.ts": 3689, "5428-pipeline-generator-stages.cjs": 5519, "5429-pipeline-generator-buffers.ts": 4449, - "5430-dyn-number-string-boxes.ts": 3930, - "5435-crypto-hash-algorithms.ts": 3451, - "5436-crypto-hash-names.js": 3185, - "5437-crypto-hmac-algorithms.ts": 3269, - "5438-crypto-kdf-digests.ts": 3099, - "5439-crypto-kdf-callbacks.js": 4398, - "5440-crypto-hash-encodings.js": 4908, - "5441-crypto-hash-output-length.ts": 3959, - "5442-crypto-random-values.ts": 4791, - "5443-crypto-random-arguments.js": 3724, - "5444-crypto-timing-safe-equal.js": 4074, - "5445-crypto-secret-key-objects.ts": 4784, - "5445-stream-buffer-chunks.ts": 5661, - "5446-crypto-secret-key-errors.js": 3275, - "5446-stream-buffer-chunks-dynamic.js": 5780, - "5447-fs-readdir-order.ts": 3355, - "5448-fs-glob-patterns.ts": 3298, - "5449-fs-glob-options.ts": 3827, - "5450-fs-glob-validation.js": 4321, - "5451-fs-promises-glob.ts": 3074, - "5452-fs-glob-callback.ts": 3887, - "5455-power-of-two-remainder.ts": 4228, - "5456-remainder-large-integer-dividends.ts": 3551, - "5457-lcg-modulus.ts": 2909, - "5458-fractional-remainder.ts": 2650, - "5460-locale-compare-contractions.ts": 3201, - "5461-locale-compare-equivalents.ts": 3410, - "5462-locale-compare-probe-sweep.ts": 4164, - "5463-locale-compare-combining-letters.ts": 3755, - "5464-locale-compare-fractions.ts": 3312, + "5430-dyn-number-string-boxes.ts": 3851, + "5435-crypto-hash-algorithms.ts": 4090, + "5436-crypto-hash-names.js": 3513, + "5437-crypto-hmac-algorithms.ts": 3873, + "5438-crypto-kdf-digests.ts": 4076, + "5439-crypto-kdf-callbacks.js": 3741, + "5440-crypto-hash-encodings.js": 5108, + "5441-crypto-hash-output-length.ts": 5257, + "5442-crypto-random-values.ts": 4596, + "5443-crypto-random-arguments.js": 4093, + "5444-crypto-timing-safe-equal.js": 3904, + "5445-crypto-secret-key-objects.ts": 3885, + "5445-stream-buffer-chunks.ts": 4371, + "5446-crypto-secret-key-errors.js": 3542, + "5446-stream-buffer-chunks-dynamic.js": 5530, + "5447-fs-readdir-order.ts": 3865, + "5448-fs-glob-patterns.ts": 3617, + "5449-fs-glob-options.ts": 4047, + "5450-fs-glob-validation.js": 4514, + "5451-fs-promises-glob.ts": 4041, + "5452-fs-glob-callback.ts": 3311, + "5455-power-of-two-remainder.ts": 3496, + "5456-remainder-large-integer-dividends.ts": 3106, + "5457-lcg-modulus.ts": 3217, + "5458-fractional-remainder.ts": 3231, + "5460-locale-compare-contractions.ts": 4279, + "5461-locale-compare-equivalents.ts": 4168, + "5462-locale-compare-probe-sweep.ts": 5118, + "5463-locale-compare-combining-letters.ts": 4089, + "5464-locale-compare-fractions.ts": 3465, "5465-dyn-index-read-arrays.ts": 2910, "5466-dyn-index-read-special.ts": 3472, - "5470-strip-vt-osc.cjs": 2708, - "5471-strip-vt-csi.cjs": 3038, - "5472-strip-vt-random.cjs": 2850, - "5473-strip-vt-unterminated.cjs": 4462, - "5474-strip-vt-surrogates.ts": 3554, + "5470-strip-vt-osc.cjs": 2950, + "5471-strip-vt-csi.cjs": 3252, + "5472-strip-vt-random.cjs": 3939, + "5473-strip-vt-unterminated.cjs": 4153, + "5474-strip-vt-surrogates.ts": 3689, "5510-assert-error-properties.js": 3848, "5511-assert-error-class.ts": 3354, "5512-assert-error-options.js": 3961, @@ -4903,20 +4903,20 @@ "5530-buffer-pool.ts": 4954, "5531-buffer-pool-first-slab.ts": 4419, "5532-buffer-pool-first-slab-untyped.mjs": 156958, - "5540-fs-callback-forms.cjs": 3079, - "5541-fs-stats-fields.cjs": 4039, - "5542-fs-promises-parity.cjs": 3312, - "5543-fs-promises-typed.ts": 2944, - "5544-fs-opendir.cjs": 3622, - "5545-fs-options-encoding.cjs": 3497, + "5540-fs-callback-forms.cjs": 5033, + "5541-fs-stats-fields.cjs": 5031, + "5542-fs-promises-parity.cjs": 3782, + "5543-fs-promises-typed.ts": 4425, + "5544-fs-opendir.cjs": 4598, + "5545-fs-options-encoding.cjs": 3812, "5546-fs-read-stream.cjs": 4053, "5547-fs-write-stream.cjs": 5026, - "5548-fs-callback-arguments.cjs": 3905, - "5549-fs-callback-option-checks.cjs": 3471, - "5550-locale-compare-ascii-words.ts": 2824, - "5551-array-search-references.ts": 3964, - "5552-string-appends.ts": 3653, - "5553-string-append-char-code.ts": 3292, + "5548-fs-callback-arguments.cjs": 3447, + "5549-fs-callback-option-checks.cjs": 4220, + "5550-locale-compare-ascii-words.ts": 3391, + "5551-array-search-references.ts": 4559, + "5552-string-appends.ts": 3836, + "5553-string-append-char-code.ts": 3220, "5554-fs-streams-typed.ts": 4826, "5555-fs-callback-turns.cjs": 4160, "5555-http-server-close-keep-alive.ts": 16562, @@ -4929,15 +4929,15 @@ "5562-https-verify-errors.ts": 5339, "5563-http-keep-alive-timeout.ts": 18223, "5564-http-request-signal.ts": 6038, - "5565-fs-dirent-untyped.mjs": 2898, - "5566-fs-dirent-dyn-boundaries/main.mjs": 3333, + "5565-fs-dirent-untyped.mjs": 4190, + "5566-fs-dirent-dyn-boundaries/main.mjs": 4370, "5567-fs-cpsync.ts": 4231, "5568-fs-cp-errors.js": 4710, "5569-fs-cp-symlinks.ts": 3975, "5570-fs-cp-async.ts": 4871, "5571-fs-cp-deep.ts": 4651, - "5585-record-results-inlined.ts": 3681, - "5595-net-ref-unref.ts": 3036, + "5585-record-results-inlined.ts": 3799, + "5595-net-ref-unref.ts": 2930, "5600-dyn-cycle-self.ts": 2377, "5601-dyn-cycle-mutual.ts": 3087, "5602-dyn-cycle-arrays.ts": 3074, @@ -4968,13 +4968,13 @@ "5630-promisify-zlib.ts": 3777, "5631-promisify-crypto.ts": 2600, "5632-promisify-dns.ts": 2000, - "5644-net-socket-addresses.ts": 2393, - "5645-net-socket-callbacks.ts": 2060, - "5646-net-server-connections.ts": 2755, - "5647-net-is-ip.ts": 2560, - "5648-dns-lookup-forms.ts": 3416, - "5649-dns-service-servers.ts": 4916, - "5650-dns-lookup-errors-untyped.cjs": 3889, + "5644-net-socket-addresses.ts": 3299, + "5645-net-socket-callbacks.ts": 4363, + "5646-net-server-connections.ts": 4089, + "5647-net-is-ip.ts": 3406, + "5648-dns-lookup-forms.ts": 4891, + "5649-dns-service-servers.ts": 4574, + "5650-dns-lookup-errors-untyped.cjs": 4634, "5651-tls-socket-protocol.ts": 4232, "5652-http-client-trailer-overflow.ts": 3846, "5653-net-socket-read-ahead.ts": 5725, @@ -4987,7 +4987,7 @@ "5664-tls-client-identity.ts": 5675, "5674-union-instanceof-array-arms.ts": 4342, "5680-array-growth-after-copy.ts": 5326, - "5681-array-pop-and-length.ts": 3216, + "5681-array-pop-and-length.ts": 4603, "5682-publish-wide-objects.ts": 2847, "5700-cycle-release-retained.ts": 2881, "5701-cycle-release-old-edges.ts": 2910, @@ -5048,36 +5048,36 @@ "5795-worker-message-port-batches.ts": 3502, "5796-worker-message-channel.cjs": 4995, "5797-worker-message-port-transfer.ts": 23371, - "5800-broadcast-channel.ts": 28374, - "5801-broadcast-channel.cjs": 27251, - "5802-broadcast-channel-workers.ts": 27251, - "5803-worker-environment-data.ts": 29298, - "5804-worker-environment-data.cjs": 26404, - "5805-worker-receive-message-parent-port.ts": 30268, - "5806-worker-resource-limits.ts": 29711, - "5807-worker-error-values.ts": 35248, - "5808-worker-unhandled-rejections.ts": 33209, - "5809-process-exit-and-rejections.cjs": 30261, - "5810-mock-method-records.ts": 6363, - "5811-mock-tracker-restore.ts": 4503, - "5812-dyn-box-async-fields.ts": 5278, - "5813-mock-timers-module.ts": 4227, - "5814-mock-timers-date.ts": 17708, + "5800-broadcast-channel.ts": 4829, + "5801-broadcast-channel.cjs": 36650, + "5802-broadcast-channel-workers.ts": 3203, + "5803-worker-environment-data.ts": 6261, + "5804-worker-environment-data.cjs": 3356, + "5805-worker-receive-message-parent-port.ts": 3933, + "5806-worker-resource-limits.ts": 22085, + "5807-worker-error-values.ts": 5689, + "5808-worker-unhandled-rejections.ts": 6775, + "5809-process-exit-and-rejections.cjs": 38724, + "5810-mock-method-records.ts": 6060, + "5811-mock-tracker-restore.ts": 5297, + "5812-dyn-box-async-fields.ts": 4153, + "5813-mock-timers-module.ts": 3845, + "5814-mock-timers-date.ts": 10489, "5830-timers-promises-signal.ts": 5868, - "5831-util-types-brands.ts": 4380, - "5832-util-types-brands-dynamic.js": 3658, - "5833-url-search-params-iterators.ts": 5339, - "5834-url-search-params-iterators-dynamic.mjs": 3797, - "5835-util-format-integer-specifiers.ts": 2768, - "5836-url-search-params-tuple-pairs.ts": 3193, - "5837-util-format-json-circular.ts": 3408, - "5838-qs-stringify-bigint.ts": 3519, + "5831-util-types-brands.ts": 3846, + "5832-util-types-brands-dynamic.js": 3912, + "5833-url-search-params-iterators.ts": 3034, + "5834-url-search-params-iterators-dynamic.mjs": 3877, + "5835-util-format-integer-specifiers.ts": 2899, + "5836-url-search-params-tuple-pairs.ts": 2897, + "5837-util-format-json-circular.ts": 2745, + "5838-qs-stringify-bigint.ts": 2868, "5839-timers-promises-scheduler.ts": 3136, "5840-promise-with-resolvers-js.js": 2701, - "5841-json-typed-dyn-members.ts": 3238, - "5842-qs-parse-null-prototype.ts": 7077, - "5843-qs-parse-null-prototype-js.mjs": 5395, - "5844-date-unknown-values.ts": 4543, + "5841-json-typed-dyn-members.ts": 4508, + "5842-qs-parse-null-prototype.ts": 3749, + "5843-qs-parse-null-prototype-js.mjs": 3308, + "5844-date-unknown-values.ts": 3966, "5845-groupby-null-prototype.ts": 3946, "5846-events-esm-default-max.ts": 3102, "5847-events-cjs-default-max.cjs": 3039, @@ -5089,45 +5089,45 @@ "5854-array-from-async.ts": 4644, "5855-array-from-async-js.js": 3880, "5856-error-is-error.ts": 3947, - "5857-regexp-unicode-sets.ts": 3900, - "5858-disposable-stack.ts": 3750, - "5859-disposable-stack-js.js": 3600, + "5857-regexp-unicode-sets.ts": 3156, + "5858-disposable-stack.ts": 4000, + "5859-disposable-stack-js.js": 4197, "5860-url-ipv4-hosts.ts": 3379, - "5870-worker-thread-names.ts": 31697, - "5871-worker-untransferable.cjs": 27481, + "5870-worker-thread-names.ts": 5388, + "5871-worker-untransferable.cjs": 38904, "5872-readline-positional-create-interface.mjs": 4683, "5873-readline-promises-namespace.cjs": 3786, - "5874-worker-stdio-streams.ts": 27801, - "5875-worker-stdout-pipe.cjs": 31391, - "5879-worker-stdin.ts": 33232, + "5874-worker-stdio-streams.ts": 8408, + "5875-worker-stdout-pipe.cjs": 36125, + "5879-worker-stdin.ts": 56815, "5880-emitter-leak-warning-delivery.ts": 3928, - "5881-inspect-weak-collections.ts": 2915, - "5882-string-decoder-runtime-encoding.ts": 3854, - "5883-os-set-priority.ts": 3417, - "5884-inspect-layout-options.ts": 3596, + "5881-inspect-weak-collections.ts": 3161, + "5882-string-decoder-runtime-encoding.ts": 3686, + "5883-os-set-priority.ts": 2593, + "5884-inspect-layout-options.ts": 3958, "5885-events-max-listener-helpers.ts": 3524, - "5886-inspect-dates.ts": 2736, - "5887-inspect-typed-arrays.ts": 2997, - "5888-inspect-sorted.ts": 2861, + "5886-inspect-dates.ts": 3606, + "5887-inspect-typed-arrays.ts": 3660, + "5888-inspect-sorted.ts": 2960, "5889-timers-scheduler-signal.ts": 3671, "5890-while-string-length-counters.ts": 3347, "5892-buffer-write-utf16le-runs.ts": 3722, - "5900-float16-array.ts": 3750, - "5901-float16-array-js.js": 3700, - "5904-async-generator-completion.ts": 3800, - "5905-array-from-async-generator.ts": 3500, - "5906-array-from-async-generator-js.js": 3750, + "5900-float16-array.ts": 3748, + "5901-float16-array-js.js": 3979, + "5904-async-generator-completion.ts": 6741, + "5905-array-from-async-generator.ts": 4080, + "5906-array-from-async-generator-js.js": 3999, "5907-regex-groups-match-rows.ts": 3750, - "5910-set-prototype-of-primitive-object-kinds.ts": 5033, - "5911-dyn-class-to-primitive.ts": 4732, - "5912-dyn-class-conversion-methods.ts": 4424, - "5913-prototype-type-error-messages.ts": 4068, - "5914-dyn-in-class-prototype-members.ts": 4327, - "5915-dyn-error-string-conversions.ts": 4247, + "5910-set-prototype-of-primitive-object-kinds.ts": 4285, + "5911-dyn-class-to-primitive.ts": 6260, + "5912-dyn-class-conversion-methods.ts": 4623, + "5913-prototype-type-error-messages.ts": 3542, + "5914-dyn-in-class-prototype-members.ts": 2963, + "5915-dyn-error-string-conversions.ts": 2860, "5920-promise-try-args.ts": 2731, "5921-promise-try-args-js.js": 2533, - "5922-matchall-groups-callbacks.ts": 5960, - "5923-matchall-groups-js.js": 6650, + "5922-matchall-groups-callbacks.ts": 4812, + "5923-matchall-groups-js.js": 4191, "5924-js-literal-identity.js": 2661, "5925-class-view-identity-observers.ts": 2640, "5926-class-view-switch-js.js": 2843, @@ -5144,7 +5144,7 @@ "5936-checked-js-class-types.js": 3902, "5937-override-narrowed-union-returns.ts": 3617, "5938-object-literal-computed-keys-keep-methods.ts": 7194, - "5939-js-let-object-reassigned-wider.js": 4436, + "5939-js-let-object-reassigned-wider.js": 3070, "5940-callback-helper-specialization.ts": 5355, "5941-callback-specialization-recursion.ts": 4385, "5942-callback-specialization-throws.ts": 3535, @@ -5152,840 +5152,840 @@ "5944-js-fields-read-before-assignment.js": 40310, "5945-local-class-observed-methods.ts": 6212, "5946-nested-record-field-optional-writes.ts": 68117, - "5950-tuple-predicate-methods.ts": 7790, - "5951-result-never-widening.ts": 6120, + "5950-tuple-predicate-methods.ts": 5999, + "5951-result-never-widening.ts": 3370, "5952-record-missing-keys.ts": 20400, "5953-nan-coded-method-returns.ts": 15600, - "5955-any-promise-methods.js": 5120, - "5956-erased-generic-members.ts": 8750, - "5958-asserted-union-receiver.ts": 3160, - "5959-date-to-json.ts": 4330, - "5960-generic-mapped-types.ts": 3300, - "5970-net-connect-host-name.ts": 2800, - "5971-buffer-chunks-to-string.ts": 3100, - "5972-net-set-encoding-listeners.ts": 3000, - "5974-typeof-module-exports.cjs": 2500, + "5955-any-promise-methods.js": 3616, + "5956-erased-generic-members.ts": 6191, + "5958-asserted-union-receiver.ts": 2929, + "5959-date-to-json.ts": 2856, + "5960-generic-mapped-types.ts": 3526, + "5970-net-connect-host-name.ts": 2998, + "5971-buffer-chunks-to-string.ts": 3483, + "5972-net-set-encoding-listeners.ts": 7935, + "5974-typeof-module-exports.cjs": 2121, "5975-zlib-class-values.ts": 4200, - "5990-worker-uncloneable.mjs": 22432, - "5991-worker-async-dispose.mjs": 25768, - "5992-worker-thread-name-lifetime.mjs": 28932, + "5990-worker-uncloneable.mjs": 37308, + "5991-worker-async-dispose.mjs": 7506, + "5992-worker-thread-name-lifetime.mjs": 44550, "5993-array-length-loop-resizing.ts": 4127, "5994-array-length-sparse-loops.ts": 2815, "5995-array-dense-loop-boundaries.ts": 4171, - "600-closures-basic.ts": 2534, - "601-closures-loops.ts": 2297, - "602-closures-identity-recursion.ts": 2427, - "6020-class-extends-function-constructor.js": 7500, + "600-closures-basic.ts": 3477, + "601-closures-loops.ts": 2866, + "602-closures-identity-recursion.ts": 3704, + "6020-class-extends-function-constructor.js": 3671, "6021-asserted-literal-union-arm.ts": 7200, - "603-closures-rc-stress.ts": 2589, - "604-closures-for-of.ts": 3514, - "605-closures-forward-capture-tdz.ts": 4638, - "700-classes-basic.ts": 2674, - "701-classes-composition.ts": 2606, - "702-classes-this-capture.ts": 2403, - "703-classes-rc-stress.ts": 3477, - "710-inheritance-basics.ts": 2972, - "711-inheritance-dispatch.ts": 2507, - "712-inheritance-instanceof.ts": 2847, - "713-inheritance-rc-stress.ts": 3484, - "720-accessors-basics.ts": 3144, - "721-accessors-eval-order.ts": 3241, - "722-accessors-inheritance.ts": 3694, - "723-accessors-rc-stress.ts": 2838, - "750-cycle-closure-box.ts": 3262, - "751-cycle-records-mutual.ts": 3163, - "752-cycle-classes.ts": 2239, - "753-cycle-owned-arrays.ts": 2204, - "754-cycle-external-ref.ts": 2593, - "755-cycle-async-promise.ts": 3154, - "756-cycle-inheritance.ts": 2213, - "757-cycle-cross-generation.ts": 3118, - "762-any-boundary.ts": 3063, - "764-any-async.ts": 3129, - "765-any-optional-chain.ts": 3899, - "766-any-union-boundary.ts": 3346, - "767-string-literal-keys.ts": 2340, - "768-any-uninitialized.ts": 2983, - "800-switch-basics.ts": 3128, - "801-switch-lazy-tests.ts": 2842, - "802-switch-loops.ts": 3486, - "803-switch-rc-stress.ts": 2321, - "804-switch-braced-blocks.ts": 3234, - "810-do-while.ts": 3326, - "820-multi-decl.ts": 2338, - "830-let-uninitialized.ts": 2579, - "900-records-basics.ts": 3473, - "901-records-eval-order.ts": 2890, - "902-records-functions-closures.ts": 3085, - "903-records-rc-stress.ts": 3146, - "904-records-optional-fields.ts": 2930, - "905-records-optional-rc-stress.ts": 2986, - "906-records-utility-types.ts": 2822, - "907-records-utility-generics.ts": 3048, - "908-records-index-signatures.ts": 2695, - "909-records-index-json.ts": 3037, - "910-records-index-rc-stress.ts": 2958, - "911-records-index-dot-access.ts": 4686, - "912-unknown-slots.ts": 3359, - "913-records-index-iteration.ts": 3265, - "914-records-from-entries.ts": 3414, - "915-unknown-tostring-eq.ts": 3349, - "916-unknown-bytes.ts": 3729, - "917-record-array-index-dot.ts": 3331, - "950-modules-basic/main.ts": 2717, - "951-modules-diamond/main.ts": 2315, - "952-modules-cross/main.ts": 2751, - "953-modules-default/main.ts": 3300, - "954-modules-reexport/main.ts": 2770, - "957-builtins-namespace.ts": 2759, - "960-generics-basics.ts": 3631, - "961-generics-recursion.ts": 3262, - "962-generics-closures.ts": 2245, - "963-generics-modules/main.ts": 2769, - "964-generics-rc-stress.ts": 3123, - "965-generics-async.ts": 3925, - "965-unions-retag.ts": 3882, - "966-unions-retag-rc-stress.ts": 3167, - "967-record-field-widening.ts": 2827, - "969-unions-arm-matrix.ts": 3297, - "970-unions-basics.ts": 3439, - "971-unions-switch.ts": 3593, - "972-unions-nested.ts": 2812, - "973-unions-rc-stress.ts": 2567, - "974-unions-modules/main.ts": 2485, - "975-unions-undefined.ts": 2505, - "976-unions-null.ts": 3528, - "977-unions-unit-rc-stress.ts": 2503, - "978-unions-nullish.ts": 2591, - "979-unions-optional-chaining.ts": 2499, - "980-exceptions-basics.ts": 2297, - "981-exceptions-values.ts": 3503, - "982-exceptions-rc-stress.ts": 3146, - "983-exceptions-control-flow.ts": 2518, - "984-exceptions-finally.ts": 2504, - "985-exceptions-call-chains.ts": 3540, - "986-exceptions-uncaught.ts": 3473, - "987-exceptions-result-unions.ts": 3527, - "990-process-basics.ts": 3510, - "991-process-exit.ts": 2297, - "992-fs-roundtrip.ts": 2694, - "993-fs-readdir.ts": 3781, - "994-fs-errors.ts": 2370, - "995-fs-uncaught.ts": 2239, - "996-fs-rc-stress.ts": 2822, - "997-fs-modules/main.ts": 2578, - "998-process-env.ts": 2181, - "abstract-property-dispatch.ts": 2739, - "arguments-arrow-capture.mjs": 3039, - "arguments-reexport/main.ts": 2635, - "array-argument-lifetimes-exits.ts": 3136, - "array-argument-lifetimes-mutation.ts": 3333, - "array-argument-lifetimes-strings.ts": 3015, - "array-argument-lifetimes-values.ts": 3223, - "array-buffer-conversions.js": 2594, - "array-buffer-storage.ts": 3699, - "array-checked-callback-results.mjs": 3402, - "array-checked-constructor.js": 3477, - "array-concat-widening.ts": 3858, + "603-closures-rc-stress.ts": 3096, + "604-closures-for-of.ts": 3045, + "605-closures-forward-capture-tdz.ts": 3323, + "700-classes-basic.ts": 2577, + "701-classes-composition.ts": 3154, + "702-classes-this-capture.ts": 2733, + "703-classes-rc-stress.ts": 3485, + "710-inheritance-basics.ts": 3238, + "711-inheritance-dispatch.ts": 3078, + "712-inheritance-instanceof.ts": 3534, + "713-inheritance-rc-stress.ts": 3301, + "720-accessors-basics.ts": 3158, + "721-accessors-eval-order.ts": 2971, + "722-accessors-inheritance.ts": 3316, + "723-accessors-rc-stress.ts": 3170, + "750-cycle-closure-box.ts": 2126, + "751-cycle-records-mutual.ts": 2363, + "752-cycle-classes.ts": 1960, + "753-cycle-owned-arrays.ts": 2692, + "754-cycle-external-ref.ts": 2903, + "755-cycle-async-promise.ts": 3043, + "756-cycle-inheritance.ts": 2972, + "757-cycle-cross-generation.ts": 2984, + "762-any-boundary.ts": 2786, + "764-any-async.ts": 3084, + "765-any-optional-chain.ts": 3008, + "766-any-union-boundary.ts": 3499, + "767-string-literal-keys.ts": 3514, + "768-any-uninitialized.ts": 3560, + "800-switch-basics.ts": 2767, + "801-switch-lazy-tests.ts": 2686, + "802-switch-loops.ts": 3125, + "803-switch-rc-stress.ts": 3547, + "804-switch-braced-blocks.ts": 2839, + "810-do-while.ts": 2218, + "820-multi-decl.ts": 3261, + "830-let-uninitialized.ts": 3097, + "900-records-basics.ts": 3422, + "901-records-eval-order.ts": 2695, + "902-records-functions-closures.ts": 3207, + "903-records-rc-stress.ts": 2631, + "904-records-optional-fields.ts": 2009, + "905-records-optional-rc-stress.ts": 2569, + "906-records-utility-types.ts": 3252, + "907-records-utility-generics.ts": 3311, + "908-records-index-signatures.ts": 3591, + "909-records-index-json.ts": 3947, + "910-records-index-rc-stress.ts": 3536, + "911-records-index-dot-access.ts": 3503, + "912-unknown-slots.ts": 3313, + "913-records-index-iteration.ts": 4350, + "914-records-from-entries.ts": 3768, + "915-unknown-tostring-eq.ts": 2630, + "916-unknown-bytes.ts": 3440, + "917-record-array-index-dot.ts": 3157, + "950-modules-basic/main.ts": 2848, + "951-modules-diamond/main.ts": 3198, + "952-modules-cross/main.ts": 3183, + "953-modules-default/main.ts": 3167, + "954-modules-reexport/main.ts": 2018, + "957-builtins-namespace.ts": 3430, + "960-generics-basics.ts": 3705, + "961-generics-recursion.ts": 2537, + "962-generics-closures.ts": 3548, + "963-generics-modules/main.ts": 2784, + "964-generics-rc-stress.ts": 3384, + "965-generics-async.ts": 2822, + "965-unions-retag.ts": 3386, + "966-unions-retag-rc-stress.ts": 2717, + "967-record-field-widening.ts": 2715, + "969-unions-arm-matrix.ts": 3012, + "970-unions-basics.ts": 2986, + "971-unions-switch.ts": 3685, + "972-unions-nested.ts": 3090, + "973-unions-rc-stress.ts": 3424, + "974-unions-modules/main.ts": 3121, + "975-unions-undefined.ts": 2840, + "976-unions-null.ts": 2783, + "977-unions-unit-rc-stress.ts": 3216, + "978-unions-nullish.ts": 3540, + "979-unions-optional-chaining.ts": 3197, + "980-exceptions-basics.ts": 3555, + "981-exceptions-values.ts": 3193, + "982-exceptions-rc-stress.ts": 2933, + "983-exceptions-control-flow.ts": 3085, + "984-exceptions-finally.ts": 3513, + "985-exceptions-call-chains.ts": 2381, + "986-exceptions-uncaught.ts": 2898, + "987-exceptions-result-unions.ts": 2879, + "990-process-basics.ts": 3199, + "991-process-exit.ts": 3081, + "992-fs-roundtrip.ts": 2369, + "993-fs-readdir.ts": 3082, + "994-fs-errors.ts": 3422, + "995-fs-uncaught.ts": 3294, + "996-fs-rc-stress.ts": 3471, + "997-fs-modules/main.ts": 2673, + "998-process-env.ts": 3051, + "abstract-property-dispatch.ts": 3176, + "arguments-arrow-capture.mjs": 3073, + "arguments-reexport/main.ts": 2672, + "array-argument-lifetimes-exits.ts": 3589, + "array-argument-lifetimes-mutation.ts": 3438, + "array-argument-lifetimes-strings.ts": 3059, + "array-argument-lifetimes-values.ts": 3883, + "array-buffer-conversions.js": 2989, + "array-buffer-storage.ts": 3822, + "array-checked-callback-results.mjs": 3408, + "array-checked-constructor.js": 3489, + "array-concat-widening.ts": 3866, "array-deque-unshift.ts": 2667, - "array-element-compound-updates.ts": 3591, - "array-fill-unit-values.ts": 2572, - "array-from-checked.js": 3097, - "array-from-value.mjs": 3428, - "array-isarray-value/main.js": 3143, - "array-numeric-own-keys.ts": 3632, - "array-optional-number-write-index.ts": 3380, - "array-primitive-ordering.ts": 3925, + "array-element-compound-updates.ts": 5084, + "array-fill-unit-values.ts": 3524, + "array-from-checked.js": 4344, + "array-from-value.mjs": 3171, + "array-isarray-value/main.js": 2914, + "array-numeric-own-keys.ts": 3622, + "array-optional-number-write-index.ts": 2652, + "array-primitive-ordering.ts": 4006, "array-queue-head-room.ts": 3597, - "array-read-helper-effects.ts": 3425, - "array-refined-storage.ts": 3909, - "array-sort-dense-effects.ts": 2917, - "array-sort-dense-values.ts": 5261, - "array-sort-holes-published.ts": 13040, - "array-sort-runs.ts": 10059, - "array-sort-runtime-comparator.ts": 5498, - "array-sort-unknown-comparator.ts": 2858, - "array-storage-transitions.ts": 2799, - "array-truncate-reuse.ts": 2407, - "async-backend-factory.mjs": 3609, - "async-local-typed-results.ts": 2487, - "atomics-integer-operations.ts": 3832, - "bigint-checked-casts.ts": 3603, - "bigint-checked-storage.js": 3992, - "bigint-union-conversion.ts": 3125, - "boxed-error-rethrows.mjs": 2646, - "buffer-codec-boundaries.ts": 3139, - "buffer-primitive-predicate.ts": 3495, - "builtin-prototype-method-values.mjs": 4297, - "byte-loop-bounds.ts": 3001, - "byte-number-pipeline.ts": 3966, - "byte-record-windows.ts": 3749, - "call-lifetimes-argument-order.ts": 2794, - "call-lifetimes-control-flow.ts": 3894, - "call-lifetimes-owned-boundaries.ts": 3881, - "call-lifetimes-projections.ts": 3082, - "call-lifetimes-union-values.ts": 3090, + "array-read-helper-effects.ts": 3562, + "array-refined-storage.ts": 4149, + "array-sort-dense-effects.ts": 4479, + "array-sort-dense-values.ts": 4819, + "array-sort-holes-published.ts": 7708, + "array-sort-runs.ts": 7566, + "array-sort-runtime-comparator.ts": 6150, + "array-sort-unknown-comparator.ts": 2544, + "array-storage-transitions.ts": 3926, + "array-truncate-reuse.ts": 3660, + "async-backend-factory.mjs": 3134, + "async-local-typed-results.ts": 3527, + "atomics-integer-operations.ts": 4356, + "bigint-checked-casts.ts": 2554, + "bigint-checked-storage.js": 3784, + "bigint-union-conversion.ts": 3322, + "boxed-error-rethrows.mjs": 2897, + "buffer-codec-boundaries.ts": 3387, + "buffer-primitive-predicate.ts": 3237, + "builtin-prototype-method-values.mjs": 3628, + "byte-loop-bounds.ts": 3700, + "byte-number-pipeline.ts": 3420, + "byte-record-windows.ts": 3513, + "call-lifetimes-argument-order.ts": 3157, + "call-lifetimes-control-flow.ts": 3596, + "call-lifetimes-owned-boundaries.ts": 3515, + "call-lifetimes-projections.ts": 2258, + "call-lifetimes-union-values.ts": 3157, "call-lifetimes-virtual-optionals.ts": 3774, - "callable-module-members.mjs": 2996, - "callable-properties.mjs": 3737, - "callable-property-cycles.js": 2394, - "callable-reexport/main.ts": 2995, - "captured-class-refinement.ts": 3815, - "catch-capture.ts": 2295, - "caught-class-identity.ts": 3893, - "caught-standalone-class.ts": 3591, - "caught-system-error-fields.ts": 3373, - "checked-addition.js": 3059, - "checked-any-addition.ts": 2638, - "checked-array-assignment.ts": 2861, - "checked-array-flat/main.ts": 2441, - "checked-bitwise/main.js": 3177, - "checked-builder-cycles.js": 3284, - "checked-byte-storage/main.ts": 3985, - "checked-callback-options.ts": 3034, - "checked-class-descriptors.mjs": 2786, - "checked-class-factory.mjs": 2348, - "checked-collection-iterators.ts": 3731, - "checked-collection-symbol-methods.ts": 3019, - "checked-dispatch-input-lifetimes.js": 3481, - "checked-increment/main.js": 2884, - "checked-inherited-fields.ts": 2756, - "checked-iterator-consumption.js": 4074, - "checked-numeric-arithmetic.js": 2874, - "checked-object-module-alias.js": 3204, - "checked-optional-calls.mjs": 2897, - "checked-promise-recovery.ts": 2819, - "checked-proxy-callback/main.ts": 3009, - "checked-record-constructor.ts": 3034, - "checked-renderer-defaults.js": 2935, - "checked-rest-function-adapters.js": 2965, - "checked-storage-transitions.js": 2510, - "checked-symbol-array.ts": 2504, - "checked-value-input-lifetimes.ts": 3033, - "class-accessor-returned-function.js": 2287, - "class-array-optional-return.ts": 3498, - "class-bracket-method-calls.js": 3071, - "class-brand-overload.js": 3526, - "class-callback-replacement.js": 3460, - "class-callback-storage.ts": 4585, - "class-checked-composites.ts": 3187, - "class-checked-upcast.ts": 3072, - "class-collection-insertion.ts": 4235, - "class-computed-presence.ts": 2974, - "class-computed-symbols.js": 3740, - "class-covariant-returns.ts": 3957, - "class-curried-factory.mjs": 4128, - "class-data-descriptors.js": 3270, - "class-factory-inherited-statics.mjs": 2538, - "class-factory-parameter-base.mjs": 2587, - "class-factory-record-base.mjs": 5836, - "class-factory-recursive-statics.mjs": 3651, - "class-factory-static-members.mjs": 3672, - "class-function-base/main.js": 2657, - "class-instance-constructor.js": 2942, - "class-interface-protocols.ts": 3713, - "class-interface-refinements.ts": 4567, - "class-json-checked.ts": 2571, - "class-local-function-base.mjs": 3643, - "class-method-spreads.ts": 3220, - "class-narrowed-views.ts": 3766, - "class-property-call-values.mjs": 3125, - "class-prototype-data.js": 4251, - "class-prototype-descriptor-copy.mjs": 3998, - "class-specialized-computed-base.mjs": 3397, - "class-static-data.js": 2157, - "class-subclass-assertions.ts": 3733, - "class-super-surplus-spread.mjs": 2301, - "class-symbol-accessors.ts": 2479, - "class-symbol-cache.mjs": 3721, - "class-value-constructor-exceptions.ts": 3210, + "callable-module-members.mjs": 3196, + "callable-properties.mjs": 3885, + "callable-property-cycles.js": 3532, + "callable-reexport/main.ts": 3427, + "captured-class-refinement.ts": 3597, + "catch-capture.ts": 2987, + "caught-class-identity.ts": 4072, + "caught-standalone-class.ts": 2672, + "caught-system-error-fields.ts": 3700, + "checked-addition.js": 3105, + "checked-any-addition.ts": 2239, + "checked-array-assignment.ts": 3049, + "checked-array-flat/main.ts": 3431, + "checked-bitwise/main.js": 3320, + "checked-builder-cycles.js": 2792, + "checked-byte-storage/main.ts": 3747, + "checked-callback-options.ts": 2687, + "checked-class-descriptors.mjs": 3712, + "checked-class-factory.mjs": 2771, + "checked-collection-iterators.ts": 3380, + "checked-collection-symbol-methods.ts": 2530, + "checked-dispatch-input-lifetimes.js": 3328, + "checked-increment/main.js": 3104, + "checked-inherited-fields.ts": 2621, + "checked-iterator-consumption.js": 4294, + "checked-numeric-arithmetic.js": 3111, + "checked-object-module-alias.js": 3420, + "checked-optional-calls.mjs": 3475, + "checked-promise-recovery.ts": 3214, + "checked-proxy-callback/main.ts": 2353, + "checked-record-constructor.ts": 3432, + "checked-renderer-defaults.js": 3283, + "checked-rest-function-adapters.js": 3083, + "checked-storage-transitions.js": 3622, + "checked-symbol-array.ts": 3310, + "checked-value-input-lifetimes.ts": 3545, + "class-accessor-returned-function.js": 3128, + "class-array-optional-return.ts": 2098, + "class-bracket-method-calls.js": 3772, + "class-brand-overload.js": 2492, + "class-callback-replacement.js": 4751, + "class-callback-storage.ts": 4435, + "class-checked-composites.ts": 2988, + "class-checked-upcast.ts": 3528, + "class-collection-insertion.ts": 3819, + "class-computed-presence.ts": 3069, + "class-computed-symbols.js": 4319, + "class-covariant-returns.ts": 2381, + "class-curried-factory.mjs": 4502, + "class-data-descriptors.js": 3422, + "class-factory-inherited-statics.mjs": 3137, + "class-factory-parameter-base.mjs": 3744, + "class-factory-record-base.mjs": 4712, + "class-factory-recursive-statics.mjs": 3419, + "class-factory-static-members.mjs": 3588, + "class-function-base/main.js": 3762, + "class-instance-constructor.js": 3074, + "class-interface-protocols.ts": 5102, + "class-interface-refinements.ts": 3720, + "class-json-checked.ts": 2934, + "class-local-function-base.mjs": 3255, + "class-method-spreads.ts": 4902, + "class-narrowed-views.ts": 3371, + "class-property-call-values.mjs": 4011, + "class-prototype-data.js": 3004, + "class-prototype-descriptor-copy.mjs": 3813, + "class-specialized-computed-base.mjs": 4267, + "class-static-data.js": 3151, + "class-subclass-assertions.ts": 3297, + "class-super-surplus-spread.mjs": 3182, + "class-symbol-accessors.ts": 3548, + "class-symbol-cache.mjs": 4032, + "class-value-constructor-exceptions.ts": 2673, "closed-virtual-dispatch-modules/main.ts": 2555, "closed-virtual-dispatch.ts": 3659, - "closure-nullable-union-return.ts": 2727, - "closure-union-locals.ts": 2878, - "collection-array-cycles.ts": 3240, - "collection-array-maps.ts": 4497, - "collection-array-missing.ts": 3865, - "collection-array-sets.ts": 3087, - "collection-copy-identities.ts": 2655, - "collection-data-unions.ts": 2993, - "collection-ingestion-mappers.ts": 3305, - "collection-ingestion-protocol/main.ts": 5059, - "collection-ingestion-references.ts": 4238, - "collection-ingestion.ts": 3626, - "collection-storage-copies.ts": 4163, - "collection-value-keys.ts": 4167, - "compound-field-receivers.ts": 2877, - "compound-presence-guards.ts": 3145, - "conditional-tuple-destructuring.ts": 3213, - "console-imports.cjs": 2893, - "console-native-value.js": 2516, - "const-enum-module-cycle/main.ts": 3456, - "constant-callback-dispatch.ts": 2916, - "constant-module-globals/main.ts": 2911, - "constant-number-remainders.ts": 2372, - "constructed-class-dispatch.ts": 3382, - "contextual-array-union-write.ts": 6417, - "contextual-return-layouts.ts": 3746, - "counted-loop-numbers.ts": 2724, - "counted-loop-storage.ts": 2302, - "crypto-hash-optional-input.ts": 3311, - "cycle-generations-long-lived.ts": 3514, - "cycle-growth-yield.ts": 3352, - "date-checked-native.js": 2676, - "declared-index-spread.ts": 2941, - "deep-reference-teardown.ts": 4427, - "default-undefined-parameters.ts": 3232, - "deferred-field-updates.ts": 3345, - "deferred-registry-many.ts": 3072, - "derived-numeric-updates.ts": 2702, - "destructure-call-assignment.js": 2978, - "destructure-inferred-row-defaults.js": 3175, - "destructure-union-arrays.ts": 3248, - "dynamic-function-descriptors.js": 2750, - "error-cause-writes.js": 3104, - "error-inherited-message.mjs": 3024, - "error-inherited-name.mjs": 2500, - "error-property-writes.mjs": 3373, - "error-prototype-tostring.js": 3874, - "error-stack-frames.ts": 2418, - "error-stack-limit.ts": 2675, - "error-tostring-overrides.ts": 3246, - "error-values-inspect.ts": 3043, - "exact-index-round-trip.ts": 3701, - "expression-runtime-values.ts": 2154, - "fiber-switch-stress.ts": 5012, - "fiberless-async-ordering.ts": 3413, - "fiberless-async-unhandled.ts": 2739, - "field-assignment-values.ts": 2662, - "file-handle-values.ts": 3133, - "file-read-storage.ts": 3685, - "file-url-percent-decoding.ts": 2659, - "final-field-borrows.ts": 3350, - "for-multiple-bindings.ts": 3223, - "for-multiple-lexical-bindings.ts": 3021, - "for-of-checked-iterator.js": 3541, - "for-of-subclass-elements.ts": 3037, - "forward-generic-signatures.ts": 2999, - "fresh-array-union-layout.js": 2679, - "frozen-checked-dictionaries.mjs": 3220, - "fs-native-realpath.ts": 2477, + "closure-nullable-union-return.ts": 3544, + "closure-union-locals.ts": 3476, + "collection-array-cycles.ts": 3864, + "collection-array-maps.ts": 4225, + "collection-array-missing.ts": 4159, + "collection-array-sets.ts": 4385, + "collection-copy-identities.ts": 2778, + "collection-data-unions.ts": 3634, + "collection-ingestion-mappers.ts": 3206, + "collection-ingestion-protocol/main.ts": 3833, + "collection-ingestion-references.ts": 3449, + "collection-ingestion.ts": 3258, + "collection-storage-copies.ts": 3108, + "collection-value-keys.ts": 4397, + "compound-field-receivers.ts": 3249, + "compound-presence-guards.ts": 2877, + "conditional-tuple-destructuring.ts": 2382, + "console-imports.cjs": 3167, + "console-native-value.js": 3394, + "const-enum-module-cycle/main.ts": 2006, + "constant-callback-dispatch.ts": 2991, + "constant-module-globals/main.ts": 2958, + "constant-number-remainders.ts": 3341, + "constructed-class-dispatch.ts": 2784, + "contextual-array-union-write.ts": 7276, + "contextual-return-layouts.ts": 3888, + "counted-loop-numbers.ts": 3637, + "counted-loop-storage.ts": 2691, + "crypto-hash-optional-input.ts": 3463, + "cycle-generations-long-lived.ts": 3441, + "cycle-growth-yield.ts": 3944, + "date-checked-native.js": 2845, + "declared-index-spread.ts": 4567, + "deep-reference-teardown.ts": 3926, + "default-undefined-parameters.ts": 3319, + "deferred-field-updates.ts": 3102, + "deferred-registry-many.ts": 3953, + "derived-numeric-updates.ts": 3389, + "destructure-call-assignment.js": 2983, + "destructure-inferred-row-defaults.js": 3512, + "destructure-union-arrays.ts": 2816, + "dynamic-function-descriptors.js": 3146, + "error-cause-writes.js": 3354, + "error-inherited-message.mjs": 3845, + "error-inherited-name.mjs": 2619, + "error-property-writes.mjs": 3158, + "error-prototype-tostring.js": 3672, + "error-stack-frames.ts": 3288, + "error-stack-limit.ts": 2624, + "error-tostring-overrides.ts": 3434, + "error-values-inspect.ts": 2196, + "exact-index-round-trip.ts": 3473, + "expression-runtime-values.ts": 3088, + "fiber-switch-stress.ts": 4040, + "fiberless-async-ordering.ts": 3692, + "fiberless-async-unhandled.ts": 2796, + "field-assignment-values.ts": 3175, + "file-handle-values.ts": 4245, + "file-read-storage.ts": 3850, + "file-url-percent-decoding.ts": 3346, + "final-field-borrows.ts": 4200, + "for-multiple-bindings.ts": 3350, + "for-multiple-lexical-bindings.ts": 2400, + "for-of-checked-iterator.js": 2766, + "for-of-subclass-elements.ts": 3269, + "forward-generic-signatures.ts": 3369, + "fresh-array-union-layout.js": 2566, + "frozen-checked-dictionaries.mjs": 3872, + "fs-native-realpath.ts": 3355, "fs-null-byte-paths-js.cjs": 2643, "fs-null-byte-paths.ts": 5975, - "fs-read-encodings.ts": 3111, + "fs-read-encodings.ts": 3730, "fs-read-utf8-edges.ts": 4190, "fs-read-utf8-handle-forms.ts": 3943, - "fs-remove-readonly.ts": 2708, - "fs-write-string-bytes-union.ts": 2772, - "function-apply-value.mjs": 2976, - "function-constructor-global.mjs": 2229, - "function-constructor-kinds/main.js": 3064, - "function-custom-prototype.js": 3165, - "function-custom-to-string.mjs": 3379, - "function-object-assign.js": 3235, - "function-own-prototype/main.js": 2539, - "generator-checked-protocol.ts": 3197, - "generator-checked-return.js": 3544, - "generator-custom-delegation/main.ts": 3611, - "generator-default-return-pattern.ts": 3352, - "generator-delegation-values.ts": 3047, - "generator-inferred-date.js": 3314, - "generator-mixed-checked-channels.ts": 3576, - "generator-untyped-consumer/main.ts": 3225, - "generic-base-specializations.ts": 2247, - "generic-binding-ownership.ts": 3517, - "generic-class-js-functions/main.ts": 2300, - "generic-class-recovery.ts": 2961, - "generic-namespace-factories/main.ts": 3104, - "generic-nullable-collections.ts": 2983, - "generic-pattern-bindings.ts": 3518, - "generic-record-index.ts": 3239, - "generic-visitor-void.ts": 3402, + "fs-remove-readonly.ts": 3417, + "fs-write-string-bytes-union.ts": 3274, + "function-apply-value.mjs": 3476, + "function-constructor-global.mjs": 3249, + "function-constructor-kinds/main.js": 3769, + "function-custom-prototype.js": 3876, + "function-custom-to-string.mjs": 3155, + "function-object-assign.js": 3527, + "function-own-prototype/main.js": 3460, + "generator-checked-protocol.ts": 2621, + "generator-checked-return.js": 3221, + "generator-custom-delegation/main.ts": 5126, + "generator-default-return-pattern.ts": 3182, + "generator-delegation-values.ts": 3197, + "generator-inferred-date.js": 3585, + "generator-mixed-checked-channels.ts": 3199, + "generator-untyped-consumer/main.ts": 3049, + "generic-base-specializations.ts": 3459, + "generic-binding-ownership.ts": 3288, + "generic-class-js-functions/main.ts": 2834, + "generic-class-recovery.ts": 3640, + "generic-namespace-factories/main.ts": 2618, + "generic-nullable-collections.ts": 3599, + "generic-pattern-bindings.ts": 3103, + "generic-record-index.ts": 3516, + "generic-visitor-void.ts": 3557, "global-accumulator-loops.ts": 3302, - "global-error-subclasses.ts": 2754, - "global-runtime-probes.js": 2804, - "global-stored-probes.js": 3113, - "global-string-cache/main.js": 2090, - "global-symbol-cache/main.js": 3628, - "guarded-native-iterables.ts": 3327, - "heap-input-aliases.ts": 3457, - "heap-input-collections.ts": 3653, - "in-array-runtime-index.ts": 3275, - "indexed-assignment-values.js": 3011, - "indexed-assignment-values.ts": 2182, - "indexed-element-field-reads.ts": 3247, - "inferred-array-assignment-values.mjs": 2906, - "inferred-class-default.mjs": 2977, - "inferred-compound-values.mjs": 2759, - "inferred-conditional-class.mjs": 3292, - "inferred-error-fields.js": 3405, - "inferred-map-patterns.mjs": 2764, - "inferred-method-override.js": 2696, - "inferred-partial-destructuring.mjs": 2539, - "inferred-primitive-properties.mjs": 2255, - "inferred-record-return.mjs": 2589, - "inferred-recursive-record.mjs": 2186, - "inferred-undefined-field.mjs": 2551, - "input-lifetime-intervals.ts": 3191, - "input-lifetimes-modules/main.ts": 3221, - "instanceof-class-record-union.ts": 3279, - "integer-flow-arithmetic.ts": 3347, - "integer-loop-forms.ts": 2940, - "integer-view-control.ts": 2093, - "integer-view-numbers.ts": 2680, - "integer-view-storage.ts": 3947, - "intl-grapheme-conformance/main.ts": 5064, - "intl-grapheme.ts": 2412, - "iterator-typed-returns.ts": 3466, - "js-abort-portable.js": 4587, - "js-array-constructor.js": 3296, - "js-array-default-buffer.js": 3604, - "js-array-iterators.js": 3215, - "js-arrow-bind.cjs": 3596, - "js-buffer-callback-brand.cjs": 3526, - "js-callable-proxy.js": 3865, - "js-chained-native-results.mjs": 3076, - "js-checked-array-iterator.js": 2790, - "js-checked-array-reference.js": 2884, - "js-checked-number-negation.mjs": 2418, - "js-checked-sort-result.js": 2906, - "js-child-error-listener.cjs": 2538, - "js-cjs-callable-snapshots/main.cjs": 2461, - "js-class-added-parameters.js": 2522, - "js-class-checked-overrides.js": 2542, - "js-class-computed-fields.js": 2281, - "js-class-enumeration.js": 3084, - "js-class-field-accessor-override.js": 3865, - "js-class-fluent-overrides.js": 3368, - "js-class-late-method-values.js": 2526, - "js-class-member-dispatch.js": 3846, - "js-class-return-shapes.js": 2639, - "js-class-shadowed-methods.js": 2891, - "js-class-stored-method-receiver.js": 2685, - "js-class-subclass-properties.js": 3775, - "js-class-symbol-spread.cjs": 3550, - "js-computed-prototype-additions.js": 3462, - "js-constructor-returned-callable.js": 3346, + "global-error-subclasses.ts": 2292, + "global-runtime-probes.js": 3435, + "global-stored-probes.js": 2946, + "global-string-cache/main.js": 2368, + "global-symbol-cache/main.js": 2737, + "guarded-native-iterables.ts": 3541, + "heap-input-aliases.ts": 3756, + "heap-input-collections.ts": 4265, + "in-array-runtime-index.ts": 3804, + "indexed-assignment-values.js": 3469, + "indexed-assignment-values.ts": 2742, + "indexed-element-field-reads.ts": 3016, + "inferred-array-assignment-values.mjs": 2506, + "inferred-class-default.mjs": 2376, + "inferred-compound-values.mjs": 2280, + "inferred-conditional-class.mjs": 3032, + "inferred-error-fields.js": 3161, + "inferred-map-patterns.mjs": 3075, + "inferred-method-override.js": 3123, + "inferred-partial-destructuring.mjs": 3133, + "inferred-primitive-properties.mjs": 2211, + "inferred-record-return.mjs": 3298, + "inferred-recursive-record.mjs": 3328, + "inferred-undefined-field.mjs": 2721, + "input-lifetime-intervals.ts": 3442, + "input-lifetimes-modules/main.ts": 3449, + "instanceof-class-record-union.ts": 3488, + "integer-flow-arithmetic.ts": 3827, + "integer-loop-forms.ts": 3201, + "integer-view-control.ts": 3231, + "integer-view-numbers.ts": 3409, + "integer-view-storage.ts": 3994, + "intl-grapheme-conformance/main.ts": 3445, + "intl-grapheme.ts": 2906, + "iterator-typed-returns.ts": 4729, + "js-abort-portable.js": 27919, + "js-array-constructor.js": 3813, + "js-array-default-buffer.js": 2697, + "js-array-iterators.js": 3607, + "js-arrow-bind.cjs": 4009, + "js-buffer-callback-brand.cjs": 3617, + "js-callable-proxy.js": 4304, + "js-chained-native-results.mjs": 2822, + "js-checked-array-iterator.js": 3340, + "js-checked-array-reference.js": 3923, + "js-checked-number-negation.mjs": 2222, + "js-checked-sort-result.js": 3358, + "js-child-error-listener.cjs": 3277, + "js-cjs-callable-snapshots/main.cjs": 2133, + "js-class-added-parameters.js": 4197, + "js-class-checked-overrides.js": 3307, + "js-class-computed-fields.js": 2995, + "js-class-enumeration.js": 4227, + "js-class-field-accessor-override.js": 3739, + "js-class-fluent-overrides.js": 3694, + "js-class-late-method-values.js": 3823, + "js-class-member-dispatch.js": 2888, + "js-class-return-shapes.js": 4179, + "js-class-shadowed-methods.js": 3019, + "js-class-stored-method-receiver.js": 3182, + "js-class-subclass-properties.js": 4548, + "js-class-symbol-spread.cjs": 3271, + "js-computed-prototype-additions.js": 3652, + "js-constructor-returned-callable.js": 3080, "js-constructor-spread.js": 3311, - "js-dataview-dispatch.js": 2423, - "js-declared-fields.cjs": 3098, - "js-default-listener-arguments.cjs": 2941, - "js-default-options/main.ts": 3442, - "js-deferred-field-initializers.js": 2409, - "js-deferred-registry-effects.js": 2980, - "js-derived-constructor-hoisting.js": 2695, - "js-dormant-array-write.js": 2014, - "js-dormant-overrides.js": 3783, - "js-expando-records.js": 2526, - "js-implicit-call-results.js": 2892, - "js-inferred-callback-exports/main.js": 3776, - "js-inferred-class-array-return.js": 3477, - "js-inferred-object-values.js": 3358, - "js-inherited-field-storage.js": 3527, - "js-inherited-parameter-abi.js": 3324, - "js-iterable-spread.js": 3504, - "js-loose-dynamic-primitives.js": 2079, - "js-map-object-seeds.js": 3322, - "js-member-increment.js": 4257, - "js-module-function-values.js": 3135, - "js-mutable-null-members.js": 2750, - "js-nested-native-descriptors.js": 2725, - "js-normalize-dispatch.js": 3264, - "js-nullish-inherited-fields.mjs": 3080, - "js-object-receiver-storage.js": 3515, - "js-object-returning-constructors.mjs": 3015, - "js-object-shared-arrays.js": 2539, - "js-omitted-typed-arguments.js": 2295, - "js-open-binding-writes.js": 1944, - "js-optional-class-fields.js": 3252, - "js-optional-member-call.js": 3095, - "js-primitive-union-addition.js": 2779, - "js-promise-all-values.js": 3443, - "js-promise-catch-handler.js": 2034, - "js-promise-finally-order.js": 2084, - "js-promise-pending-reactions.js": 3602, - "js-prototype-host-boundary.js": 4779, - "js-reflect-receivers.js": 3486, - "js-regex-record-captures.js": 2214, - "js-scalar-iterables.js": 3719, - "js-shared-method-dispatch.js": 2114, - "js-specialized-field-method.js": 3011, - "js-static-accessors.js": 3435, - "js-static-method-values.js": 3174, - "js-static-registries.cjs": 3047, - "js-super-accessor-initialization.js": 2998, - "js-uninitialized-native-fields.js": 2354, - "json-guarded-map-values.ts": 2502, - "json-output-bulk.ts": 3214, - "json-runtime-options.mjs": 2794, - "json-stringify-value.js": 2833, - "json-typed-parse-direct.ts": 3580, + "js-dataview-dispatch.js": 2584, + "js-declared-fields.cjs": 4858, + "js-default-listener-arguments.cjs": 2246, + "js-default-options/main.ts": 2763, + "js-deferred-field-initializers.js": 3209, + "js-deferred-registry-effects.js": 3112, + "js-derived-constructor-hoisting.js": 2435, + "js-dormant-array-write.js": 2504, + "js-dormant-overrides.js": 2426, + "js-expando-records.js": 2649, + "js-implicit-call-results.js": 2821, + "js-inferred-callback-exports/main.js": 4081, + "js-inferred-class-array-return.js": 3706, + "js-inferred-object-values.js": 2559, + "js-inherited-field-storage.js": 3955, + "js-inherited-parameter-abi.js": 2394, + "js-iterable-spread.js": 3349, + "js-loose-dynamic-primitives.js": 3110, + "js-map-object-seeds.js": 3942, + "js-member-increment.js": 4274, + "js-module-function-values.js": 3403, + "js-mutable-null-members.js": 2899, + "js-nested-native-descriptors.js": 3202, + "js-normalize-dispatch.js": 3282, + "js-nullish-inherited-fields.mjs": 2655, + "js-object-receiver-storage.js": 3904, + "js-object-returning-constructors.mjs": 2279, + "js-object-shared-arrays.js": 3613, + "js-omitted-typed-arguments.js": 2937, + "js-open-binding-writes.js": 2903, + "js-optional-class-fields.js": 3536, + "js-optional-member-call.js": 2325, + "js-primitive-union-addition.js": 3324, + "js-promise-all-values.js": 3699, + "js-promise-catch-handler.js": 3309, + "js-promise-finally-order.js": 3229, + "js-promise-pending-reactions.js": 3312, + "js-prototype-host-boundary.js": 3876, + "js-reflect-receivers.js": 2676, + "js-regex-record-captures.js": 3109, + "js-scalar-iterables.js": 3335, + "js-shared-method-dispatch.js": 3207, + "js-specialized-field-method.js": 3320, + "js-static-accessors.js": 3426, + "js-static-method-values.js": 3661, + "js-static-registries.cjs": 3718, + "js-super-accessor-initialization.js": 2555, + "js-uninitialized-native-fields.js": 3260, + "json-guarded-map-values.ts": 2760, + "json-output-bulk.ts": 3183, + "json-runtime-options.mjs": 3276, + "json-stringify-value.js": 3464, + "json-typed-parse-direct.ts": 4317, "json-typed-parse-index-signatures.ts": 4012, "json-typed-parse-optional-members.ts": 4377, "json-typed-parse-union-members.ts": 4357, - "literal-switch-dispatch.ts": 2951, - "live-reference-shared-converters.ts": 19276, - "llvm-read-receiver-lifetime.ts": 3803, - "local-class-call-spreads.js": 3495, - "local-class-declaration.ts": 2661, - "local-class-evaluation.ts": 3104, - "local-class-inheritance.ts": 2552, - "local-class-lifetimes.ts": 3344, - "local-class-namespace/main.js": 3630, - "local-class-prototype-data.js": 3990, - "local-class-specialization.js": 2812, - "local-class-unknown.ts": 3002, - "local-class-values.ts": 2009, - "local-union-storage.ts": 3026, - "locale-compare-root-order.ts": 3444, - "logical-assignment-dynamic.js": 3230, - "logical-assignment-values.ts": 3566, - "logical-runtime-optional-record.ts": 3322, - "loop-reference-lifetimes.ts": 3339, - "map-checked-boundary/main.ts": 2843, - "map-checked-seed.js": 2966, + "literal-switch-dispatch.ts": 2642, + "live-reference-shared-converters.ts": 5581, + "llvm-read-receiver-lifetime.ts": 3426, + "local-class-call-spreads.js": 3773, + "local-class-declaration.ts": 3293, + "local-class-evaluation.ts": 2921, + "local-class-inheritance.ts": 3273, + "local-class-lifetimes.ts": 3403, + "local-class-namespace/main.js": 4002, + "local-class-prototype-data.js": 3135, + "local-class-specialization.js": 3358, + "local-class-unknown.ts": 3386, + "local-class-values.ts": 3003, + "local-union-storage.ts": 3264, + "locale-compare-root-order.ts": 2579, + "logical-assignment-dynamic.js": 3596, + "logical-assignment-values.ts": 2685, + "logical-runtime-optional-record.ts": 3575, + "loop-reference-lifetimes.ts": 2726, + "map-checked-boundary/main.ts": 3371, + "map-checked-seed.js": 2974, "map-get-set-fusion.ts": 3516, - "map-number-keys-dense.ts": 2773, - "map-read-lifetimes-exits.ts": 2761, - "map-read-lifetimes.ts": 3024, - "map-seeds-and-spreads.ts": 3502, - "map-typed-array-values.ts": 3300, - "math-function-values.js": 2815, - "missing-read-lambda-results.ts": 3370, - "missing-read-narrowed-storage.ts": 2854, - "missing-read-number-conversions.ts": 2326, - "module-byte-loops.ts": 2961, - "module-fallback-functions/main.js": 2737, - "narrowed-nullish-values.ts": 3160, - "native-any-timer-callback.ts": 2388, - "native-array-borrowed-find-last.js": 2571, - "native-array-borrowed-slice.js": 3010, - "native-array-copying-methods.js": 3608, - "native-array-fill-copywithin.js": 2996, - "native-array-frozen-noops.js": 3132, - "native-array-index-boundaries.js": 2225, - "native-array-integrity.js": 3091, - "native-array-length.js": 2365, - "native-array-named-properties.js": 2772, - "native-array-prototype/main.js": 3257, - "native-array-read-lifetimes.ts": 3805, - "native-array-reduce-find-last.js": 2524, - "native-array-search-from-index.js": 2027, - "native-array-splice-coercion.js": 2902, - "native-array-splice-flat.js": 2702, - "native-buffer-coercion.js": 2533, - "native-callback-dispatch.ts": 3850, - "native-class-array-boundaries.ts": 3272, - "native-class-cache.js": 3290, - "native-class-properties.cjs": 4583, - "native-class-property-cycles.cjs": 2888, - "native-class-property-order.cjs": 2105, - "native-class-type-predicates.ts": 2960, - "native-factory-records.js": 3080, - "native-method-values.js": 3222, - "native-method-values.ts": 2808, - "native-npm-imports/main.ts": 2750, - "native-object-descriptors.js": 2979, - "native-object-for-in-minimal.js": 2411, - "native-object-property-attributes.js": 3057, - "native-object-prototype.js": 3409, - "native-property-names.ts": 2077, - "native-proxy-env.js": 4372, - "native-worker-arena-reuse.ts": 33854, - "native-worker-bounded-errors.ts": 2556, - "native-worker-buffer-consumers.ts": 38253, - "native-worker-cancel-hot.ts": 28908, - "native-worker-class-fields.ts": 3286, - "native-worker-clone-errors.ts": 3629, - "native-worker-commonjs.cjs": 3085, - "native-worker-delayed-messages.ts": 28752, - "native-worker-discarded-heaps.ts": 39440, - "native-worker-environment.ts": 27133, - "native-worker-error.ts": 2958, - "native-worker-exception-state.ts": 3945, - "native-worker-exit-listeners.ts": 4052, - "native-worker-io.ts": 3361, - "native-worker-loop-cancellation.ts": 2798, - "native-worker-message-graphs.ts": 2738, - "native-worker-messages.ts": 3079, - "native-worker-poll-exceptions.ts": 2575, - "native-worker-port-lifetime.ts": 3213, - "native-worker-process-exit.ts": 4104, - "native-worker-publish-classes.ts": 24713, - "native-worker-publish-refusals.ts": 2820, - "native-worker-published-graphs.ts": 3534, - "native-worker-references.ts": 3358, - "native-worker-roots/main.ts": 2808, - "native-worker-shared-views.ts": 3012, - "native-worker-stack-overflow.ts": 2597, - "native-worker-terminate-exception-state.ts": 3340, - "native-worker-terminate-loop.ts": 2222, - "native-worker-terminate-recursion.ts": 2829, - "native-worker-terminate-suspended.ts": 4348, - "native-worker-terminate-tested-loops.ts": 3576, - "native-worker-terminate-wait.ts": 3222, - "native-worker-typed-arrays.ts": 2653, - "nested-map-cycles.ts": 3041, - "nested-map-values.ts": 2382, - "never-returning-calls.ts": 2642, - "next-tick-commonjs-entry.cjs": 2624, - "node24-buffer-encoding-errors.ts": 2695, - "node24-buffer-encoding.ts": 3038, - "node24-crypto-kdf-errors.ts": 2745, - "node24-crypto-kdf-options.ts": 2029, - "node24-crypto-kdf.ts": 3632, - "node24-crypto-sha2.ts": 2849, - "node24-deep-equality-properties.js": 3355, - "node24-deep-equality.cjs": 2682, - "node24-deep-equality.ts": 4058, - "node24-env-files-errors.ts": 3202, - "node24-env-files.ts": 3044, - "node24-env-imports.cjs": 2529, - "node24-env-parse-errors.ts": 2062, - "node24-env-parse.ts": 3684, - "node24-esm-metadata/main.mjs": 2492, - "node24-file-url-buffer.ts": 2158, - "node24-file-url-errors.js": 3331, - "node24-file-url-options.ts": 2772, - "node24-fs-links-callbacks.cjs": 3549, - "node24-fs-links-errors.cjs": 2633, - "node24-fs-links-options.cjs": 3571, - "node24-fs-links-promise-errors.cjs": 2445, - "node24-fs-links-promises.ts": 2105, - "node24-fs-links.ts": 2967, - "node24-fs-statfs-callbacks.cjs": 3035, - "node24-fs-statfs-errors.cjs": 2969, - "node24-fs-statfs-options.cjs": 3557, - "node24-fs-statfs.ts": 3067, - "node24-fs-timestamps-callbacks.cjs": 3095, - "node24-fs-timestamps-errors.cjs": 3110, - "node24-fs-timestamps-promises.ts": 3573, - "node24-fs-timestamps-symlinks.ts": 3390, - "node24-fs-timestamps.ts": 3032, - "node24-no-error-assertions-coercion.js": 2850, - "node24-no-error-assertions.cjs": 2814, - "node24-no-error-assertions.ts": 4358, - "node24-parseargs.js": 5971, - "node24-string-decoder.ts": 3185, - "node24-style-text-environment.js": 4225, - "node24-style-text-validation.js": 3673, - "node24-style-text.cjs": 3476, - "node24-style-text.ts": 3037, - "node24-system-error-validation.js": 3005, - "node24-system-errors.cjs": 3631, - "node24-system-errors.ts": 2849, - "node24-text-codec-properties.ts": 30185, - "node24-text-encode-into.ts": 3601, - "node24-text-utilities-coercion.js": 3094, - "node24-text-utilities-validation.js": 2330, - "node24-text-utilities.cjs": 2768, - "node24-text-utilities.ts": 3312, - "node24-url-authority-coercion.js": 3307, - "node24-url-authority.ts": 2639, - "node24-url-factories.ts": 3240, - "node24-url-factory-errors.ts": 2819, - "node24-url-mutation-coercion.js": 2399, - "node24-url-mutation.ts": 3257, - "node24-util-types.cjs": 3263, - "node24-util-types.js": 2199, - "node24-util-types.ts": 3506, - "non-null-class-iteration.ts": 3295, - "nonnull-element-arguments.ts": 2857, - "nonnull-forwarded-class-values.ts": 3303, - "nullable-object-extension.mjs": 2652, - "nullish-asserted-class-arms.ts": 2669, - "nullish-assignment-values.ts": 2125, - "nullish-long-chain.ts": 2641, - "number-parse-statics.ts": 2471, - "number-predicates-unknown.ts": 2568, - "numeric-call-specialization.ts": 2498, - "object-enumeration-array-reads.ts": 2246, - "object-from-checked-entries.js": 3478, - "object-inherited-to-string.js": 2987, - "object-key-indexes.js": 3206, - "object-prototype-identity.mjs": 3083, - "object-reexport/main.js": 2466, - "object-spread-computed.ts": 2806, - "opentui-byte-queue.js": 3532, - "optional-callback-arity.ts": 2417, - "optional-class-flows.ts": 2497, - "optional-element-defaults.ts": 2632, - "optional-flag-comparisons.ts": 2536, - "optional-native-callables.js": 2751, - "optional-node-list-iteration.ts": 2564, - "optional-string-index/main.ts": 3419, - "path-to-file-url-options.ts": 2301, - "performance-presence.ts": 2913, - "primitive-and-function-descriptors.js": 3070, - "primitive-union-string.ts": 3434, - "process-builtin-values.js": 2781, - "process-constrained-memory.ts": 2857, - "process-env-computed-keys.js": 3185, - "process-hrtime.js": 2662, - "process-named-signals.cjs": 3171, - "process-uncaught-handler-throws.cjs": 2344, - "process-uncaught-loop.cjs": 3141, - "process-uncaught-module.mjs": 2646, - "process-uncaught-monitor.cjs": 2837, - "process-uncaught-rejection.cjs": 2664, - "process-uncaught-sync.cjs": 2858, - "process-version-pin.ts": 3005, - "process-versions-storage.ts": 2055, - "projected-collection-lifetimes.ts": 3232, - "promise-checked-rejections.ts": 2914, - "promise-resolve-void.ts": 2846, - "prototype-method-overrides.mjs": 4119, - "prototype-named-data-records.ts": 3179, + "map-number-keys-dense.ts": 3426, + "map-read-lifetimes-exits.ts": 2870, + "map-read-lifetimes.ts": 2755, + "map-seeds-and-spreads.ts": 3696, + "map-typed-array-values.ts": 3121, + "math-function-values.js": 3080, + "missing-read-lambda-results.ts": 2590, + "missing-read-narrowed-storage.ts": 3503, + "missing-read-number-conversions.ts": 3648, + "module-byte-loops.ts": 3462, + "module-fallback-functions/main.js": 3043, + "narrowed-nullish-values.ts": 2912, + "native-any-timer-callback.ts": 1952, + "native-array-borrowed-find-last.js": 2795, + "native-array-borrowed-slice.js": 3711, + "native-array-copying-methods.js": 3069, + "native-array-fill-copywithin.js": 3430, + "native-array-frozen-noops.js": 3638, + "native-array-index-boundaries.js": 2630, + "native-array-integrity.js": 3935, + "native-array-length.js": 3375, + "native-array-named-properties.js": 3404, + "native-array-prototype/main.js": 3369, + "native-array-read-lifetimes.ts": 3688, + "native-array-reduce-find-last.js": 3264, + "native-array-search-from-index.js": 3220, + "native-array-splice-coercion.js": 3281, + "native-array-splice-flat.js": 3336, + "native-buffer-coercion.js": 2766, + "native-callback-dispatch.ts": 3779, + "native-class-array-boundaries.ts": 3630, + "native-class-cache.js": 3925, + "native-class-properties.cjs": 3940, + "native-class-property-cycles.cjs": 2802, + "native-class-property-order.cjs": 3298, + "native-class-type-predicates.ts": 3174, + "native-factory-records.js": 3338, + "native-method-values.js": 4444, + "native-method-values.ts": 3470, + "native-npm-imports/main.ts": 4028, + "native-object-descriptors.js": 2892, + "native-object-for-in-minimal.js": 2799, + "native-object-property-attributes.js": 3744, + "native-object-prototype.js": 2121, + "native-property-names.ts": 2951, + "native-proxy-env.js": 4417, + "native-worker-arena-reuse.ts": 38589, + "native-worker-bounded-errors.ts": 3955, + "native-worker-buffer-consumers.ts": 3076, + "native-worker-cancel-hot.ts": 3811, + "native-worker-class-fields.ts": 3737, + "native-worker-clone-errors.ts": 3557, + "native-worker-commonjs.cjs": 3258, + "native-worker-delayed-messages.ts": 3234, + "native-worker-discarded-heaps.ts": 8633, + "native-worker-environment.ts": 2690, + "native-worker-error.ts": 2115, + "native-worker-exception-state.ts": 37223, + "native-worker-exit-listeners.ts": 4215, + "native-worker-io.ts": 4024, + "native-worker-loop-cancellation.ts": 3683, + "native-worker-message-graphs.ts": 4038, + "native-worker-messages.ts": 2850, + "native-worker-poll-exceptions.ts": 3386, + "native-worker-port-lifetime.ts": 3672, + "native-worker-process-exit.ts": 4483, + "native-worker-publish-classes.ts": 43586, + "native-worker-publish-refusals.ts": 3568, + "native-worker-published-graphs.ts": 4341, + "native-worker-references.ts": 3658, + "native-worker-roots/main.ts": 3661, + "native-worker-shared-views.ts": 3873, + "native-worker-stack-overflow.ts": 3498, + "native-worker-terminate-exception-state.ts": 4768, + "native-worker-terminate-loop.ts": 3671, + "native-worker-terminate-recursion.ts": 2944, + "native-worker-terminate-suspended.ts": 4867, + "native-worker-terminate-tested-loops.ts": 3737, + "native-worker-terminate-wait.ts": 3200, + "native-worker-typed-arrays.ts": 2972, + "nested-map-cycles.ts": 3092, + "nested-map-values.ts": 3902, + "never-returning-calls.ts": 3512, + "next-tick-commonjs-entry.cjs": 3497, + "node24-buffer-encoding-errors.ts": 2874, + "node24-buffer-encoding.ts": 2697, + "node24-crypto-kdf-errors.ts": 3771, + "node24-crypto-kdf-options.ts": 2897, + "node24-crypto-kdf.ts": 3236, + "node24-crypto-sha2.ts": 3082, + "node24-deep-equality-properties.js": 3692, + "node24-deep-equality.cjs": 4490, + "node24-deep-equality.ts": 2856, + "node24-env-files-errors.ts": 2870, + "node24-env-files.ts": 3392, + "node24-env-imports.cjs": 2365, + "node24-env-parse-errors.ts": 3439, + "node24-env-parse.ts": 3033, + "node24-esm-metadata/main.mjs": 3209, + "node24-file-url-buffer.ts": 3465, + "node24-file-url-errors.js": 3937, + "node24-file-url-options.ts": 3735, + "node24-fs-links-callbacks.cjs": 3621, + "node24-fs-links-errors.cjs": 3404, + "node24-fs-links-options.cjs": 6459, + "node24-fs-links-promise-errors.cjs": 3319, + "node24-fs-links-promises.ts": 2636, + "node24-fs-links.ts": 3567, + "node24-fs-statfs-callbacks.cjs": 2515, + "node24-fs-statfs-errors.cjs": 2787, + "node24-fs-statfs-options.cjs": 3945, + "node24-fs-statfs.ts": 3105, + "node24-fs-timestamps-callbacks.cjs": 3550, + "node24-fs-timestamps-errors.cjs": 2070, + "node24-fs-timestamps-promises.ts": 3342, + "node24-fs-timestamps-symlinks.ts": 3375, + "node24-fs-timestamps.ts": 3308, + "node24-no-error-assertions-coercion.js": 3613, + "node24-no-error-assertions.cjs": 2851, + "node24-no-error-assertions.ts": 4400, + "node24-parseargs.js": 5202, + "node24-string-decoder.ts": 3402, + "node24-style-text-environment.js": 3896, + "node24-style-text-validation.js": 3092, + "node24-style-text.cjs": 3244, + "node24-style-text.ts": 2726, + "node24-system-error-validation.js": 3065, + "node24-system-errors.cjs": 2955, + "node24-system-errors.ts": 3258, + "node24-text-codec-properties.ts": 31240, + "node24-text-encode-into.ts": 2827, + "node24-text-utilities-coercion.js": 3019, + "node24-text-utilities-validation.js": 3576, + "node24-text-utilities.cjs": 3204, + "node24-text-utilities.ts": 2533, + "node24-url-authority-coercion.js": 3364, + "node24-url-authority.ts": 3386, + "node24-url-factories.ts": 3341, + "node24-url-factory-errors.ts": 3442, + "node24-url-mutation-coercion.js": 3344, + "node24-url-mutation.ts": 3264, + "node24-util-types.cjs": 3872, + "node24-util-types.js": 3533, + "node24-util-types.ts": 2848, + "non-null-class-iteration.ts": 2837, + "nonnull-element-arguments.ts": 3131, + "nonnull-forwarded-class-values.ts": 2449, + "nullable-object-extension.mjs": 3515, + "nullish-asserted-class-arms.ts": 3564, + "nullish-assignment-values.ts": 3337, + "nullish-long-chain.ts": 4149, + "number-parse-statics.ts": 2899, + "number-predicates-unknown.ts": 2922, + "numeric-call-specialization.ts": 2677, + "object-enumeration-array-reads.ts": 3480, + "object-from-checked-entries.js": 4289, + "object-inherited-to-string.js": 3243, + "object-key-indexes.js": 3558, + "object-prototype-identity.mjs": 3385, + "object-reexport/main.js": 2771, + "object-spread-computed.ts": 3307, + "opentui-byte-queue.js": 3572, + "optional-callback-arity.ts": 3027, + "optional-class-flows.ts": 3557, + "optional-element-defaults.ts": 3575, + "optional-flag-comparisons.ts": 3414, + "optional-native-callables.js": 3002, + "optional-node-list-iteration.ts": 2230, + "optional-string-index/main.ts": 3788, + "path-to-file-url-options.ts": 2444, + "performance-presence.ts": 2497, + "primitive-and-function-descriptors.js": 3169, + "primitive-union-string.ts": 2622, + "process-builtin-values.js": 3706, + "process-constrained-memory.ts": 2749, + "process-env-computed-keys.js": 3550, + "process-hrtime.js": 2677, + "process-named-signals.cjs": 3293, + "process-uncaught-handler-throws.cjs": 2718, + "process-uncaught-loop.cjs": 2801, + "process-uncaught-module.mjs": 3158, + "process-uncaught-monitor.cjs": 3031, + "process-uncaught-rejection.cjs": 3327, + "process-uncaught-sync.cjs": 2443, + "process-version-pin.ts": 2957, + "process-versions-storage.ts": 3651, + "projected-collection-lifetimes.ts": 3241, + "promise-checked-rejections.ts": 3404, + "promise-resolve-void.ts": 3343, + "prototype-method-overrides.mjs": 4289, + "prototype-named-data-records.ts": 3466, "rc-last-use-moves.ts": 4113, "rc-private-array-writes.ts": 4261, - "record-field-presence.ts": 3698, - "record-key-order.ts": 2706, - "record-optional-json-presence.ts": 3216, - "record-presence-copies.ts": 3381, - "record-presence-delete-json.ts": 3160, - "record-unchecked-read-presence.ts": 2953, - "record-unknown-values.ts": 4095, - "reflect-own-keys.mjs": 2705, - "reflect-record-union-keys.mjs": 2815, - "reflect-typed-record-keys.ts": 2683, - "regex-callback-replacements.ts": 2631, - "regex-callback-values.js": 3741, - "regex-checked-casts.ts": 2405, - "regex-checked-storage.js": 3560, - "regex-exec-long-subject.ts": 5584, + "record-field-presence.ts": 4642, + "record-key-order.ts": 3034, + "record-optional-json-presence.ts": 3355, + "record-presence-copies.ts": 2764, + "record-presence-delete-json.ts": 2807, + "record-unchecked-read-presence.ts": 3073, + "record-unknown-values.ts": 4519, + "reflect-own-keys.mjs": 3709, + "reflect-record-union-keys.mjs": 2498, + "reflect-typed-record-keys.ts": 2697, + "regex-callback-replacements.ts": 3004, + "regex-callback-values.js": 2710, + "regex-checked-casts.ts": 3352, + "regex-checked-storage.js": 3330, + "regex-exec-long-subject.ts": 6176, "regex-exec-result-arrays.ts": 3812, "regex-fs-text-surfaces.ts": 4280, - "regex-input-lifetimes.ts": 3241, - "regex-native-matcher.ts": 3652, - "regex-optional-captures.ts": 2740, - "regex-optional-templates.ts": 2802, - "regex-split-captures.ts": 3590, - "regex-text-paths.ts": 2840, - "regexp-constructor-repeat.ts": 2602, - "regexp-optional-constructor.ts": 2950, - "regexp-string-coercion.js": 2621, - "renderer-export-dictionaries.js": 3415, - "renderer-null-state.js": 2259, - "renderer-specializations.js": 2837, - "repeat-and-typed-read-errors.ts": 3220, - "rest-optional-array-arguments.ts": 2860, - "rest-optional-elements.ts": 2445, - "return-void-through-finally.ts": 2861, - "runtime-optional-string-flows.ts": 2977, - "scalar-string-slices.ts": 2840, - "set-checked-methods.js": 3072, - "set-checked-storage.ts": 2667, - "set-iterator-seed-references.ts": 3159, - "set-iterator-seeds.ts": 3269, - "set-optional-seeds.ts": 2164, - "small-collection-transitions.ts": 3586, + "regex-input-lifetimes.ts": 3127, + "regex-native-matcher.ts": 5535, + "regex-optional-captures.ts": 3580, + "regex-optional-templates.ts": 3221, + "regex-split-captures.ts": 2939, + "regex-text-paths.ts": 3596, + "regexp-constructor-repeat.ts": 3069, + "regexp-optional-constructor.ts": 2996, + "regexp-string-coercion.js": 3263, + "renderer-export-dictionaries.js": 3616, + "renderer-null-state.js": 3037, + "renderer-specializations.js": 3634, + "repeat-and-typed-read-errors.ts": 2617, + "rest-optional-array-arguments.ts": 3777, + "rest-optional-elements.ts": 3195, + "return-void-through-finally.ts": 2410, + "runtime-optional-string-flows.ts": 3467, + "scalar-string-slices.ts": 3659, + "set-checked-methods.js": 2038, + "set-checked-storage.ts": 3153, + "set-iterator-seed-references.ts": 3637, + "set-iterator-seeds.ts": 3641, + "set-optional-seeds.ts": 3312, + "small-collection-transitions.ts": 3749, "speculative-integer-globals.ts": 3132, "speculative-integer-loops.ts": 3533, "speculative-integer-reads.ts": 3953, - "stack-depth-async-bodies.ts": 2727, - "stack-overflow-async.ts": 2942, - "stack-overflow-caught.ts": 3056, - "stack-overflow-finally.ts": 3694, - "stack-overflow-shapes.ts": 3565, - "stack-overflow-uncaught.ts": 2532, + "stack-depth-async-bodies.ts": 3272, + "stack-overflow-async.ts": 2638, + "stack-overflow-caught.ts": 2219, + "stack-overflow-finally.ts": 3033, + "stack-overflow-shapes.ts": 4491, + "stack-overflow-uncaught.ts": 2225, "stackless-async-concurrency.ts": 4361, "stackless-async-context.ts": 2699, "stackless-async-exceptions.ts": 3282, "stackless-async-ordering.ts": 3335, "stackless-async-unhandled.ts": 2784, - "static-field-updates/main.ts": 2914, - "static-method-receivers.ts": 2350, - "stdio-values.mjs": 2761, - "stdio-write-errors.mjs": 2672, - "stdio-write-overrides.mjs": 3205, - "stored-native-builtins.js": 3341, - "stored-object-helpers.js": 2959, + "static-field-updates/main.ts": 2292, + "static-method-receivers.ts": 3195, + "stdio-values.mjs": 3475, + "stdio-write-errors.mjs": 3473, + "stdio-write-overrides.mjs": 2782, + "stored-native-builtins.js": 3709, + "stored-object-helpers.js": 3602, "stream-dynamic-entry-kinds.cjs": 4557, "stream-dynamic-entry-kinds.ts": 4257, "stream-encoded-from-entries.cjs": 4266, "stream-encoded-from-entries.ts": 5622, - "string-char-code-integer-loops.ts": 2575, - "string-code-points.ts": 2460, - "string-concat-number-parts.ts": 2155, - "string-construction-order.ts": 3307, + "string-char-code-integer-loops.ts": 2285, + "string-code-points.ts": 3745, + "string-concat-number-parts.ts": 3405, + "string-construction-order.ts": 3532, "string-field-append.ts": 3568, - "string-lifetimes-boundaries.ts": 3304, - "string-lifetimes-evaluation.ts": 2835, - "string-lifetimes-iteration.ts": 2037, - "string-lifetimes-operations.ts": 2789, - "string-normalize.ts": 2348, - "string-pattern-replacement.ts": 3823, - "string-scan-fast-paths.ts": 3224, - "string-split-checked-separator.mjs": 2349, - "string-split-traversal.ts": 3258, - "structural-class-properties.ts": 2627, - "structured-text-boundaries.js": 3452, - "structured-text-storage.ts": 3201, - "switch-integer-dispatch.ts": 2387, - "symbol-checked-boundary/main.ts": 2796, - "symbol-class-fields.ts": 2814, - "symbol-class-fields/main.cjs": 2659, - "symbol-class-methods/main.ts": 1948, - "symbol-fields-deferred-factory.ts": 2721, - "symbol-fields-inferred.js": 2792, - "symbol-object-properties/main.js": 3376, - "synchronous-callback-lifetimes.ts": 2872, - "terminal-stream-properties.ts": 2946, - "text-codec-values/main.ts": 18964, - "text-codec-var.ts": 3480, - "text-encode-into-boundaries.ts": 2224, - "timers-clear-many.ts": 3073, - "tuple-and-string-search.ts": 2595, - "tuple-array-union.ts": 3305, - "tuple-callback-visitation.ts": 3801, - "tuple-forof-visitation.ts": 3276, - "typed-array-bulk-conversion.mjs": 5346, - "typed-array-byte-io.js": 41314, - "typed-array-checked-index.js": 2607, - "typed-array-constructor-alias.ts": 2778, - "typed-array-constructor-identity.js": 2769, - "typed-array-constructor-union.ts": 2366, - "typed-array-constructor-values.mjs": 3448, - "typed-array-dynamic-methods.js": 3373, - "typed-array-integer-widths.ts": 3014, - "typed-array-nan-coded-reads.ts": 4239, - "typed-array-numeric-import.ts": 3499, - "typed-array-present-reads.ts": 3561, - "typed-array-reversed-storage.ts": 2954, - "typed-array-unknown.ts": 3453, - "typed-collection-iterator-references.ts": 3531, - "typed-collection-iterators.ts": 3385, - "typed-collection-views/main.ts": 2577, - "typed-index-arguments.ts": 3036, - "typed-prototype-methods.ts": 2475, - "typed-rest-callables.ts": 2463, - "typed-rest-filtered-return.ts": 2800, - "typedarray-native-inputs.js": 3164, - "typeof-checked-comparison.js": 2913, - "uint8array-sort-domains.ts": 2505, - "unicode-case-paths.ts": 2924, - "unicode-process-argv.ts": 2793, - "union-discriminant-width.ts": 3726, - "union-literal-scalar-discriminants.ts": 3704, - "union-literal-slot-conversion.ts": 2972, - "union-nested-layout-discriminant.ts": 2841, - "union-optional-semantic-identity.ts": 3100, - "union-record-clone.ts": 3480, - "union-record-structural-copy.ts": 3563, - "union-reference-comparison.ts": 3338, - "unknown-array-holes.ts": 2088, - "unknown-collections.ts": 3765, - "unknown-object-enumeration.ts": 4219, - "unknown-record-views.ts": 3040, - "url-runtime-base.ts": 2778, - "utf8-span-decoding.ts": 2655, - "util-parseargs-wrapped/main.ts": 2482, - "virtual-runtime-optional-returns.ts": 3876, - "weak-map-array-buffer.ts": 2826, - "weak-map-fresh-array.js": 2495, - "weak-map-native.js": 3627, - "weak-native-class-identity.ts": 2943, - "weak-set-native.js": 3056, - "worker-class-instance-clone.ts": 35222 + "string-lifetimes-boundaries.ts": 2538, + "string-lifetimes-evaluation.ts": 3059, + "string-lifetimes-iteration.ts": 2631, + "string-lifetimes-operations.ts": 3387, + "string-normalize.ts": 2789, + "string-pattern-replacement.ts": 3618, + "string-scan-fast-paths.ts": 3272, + "string-split-checked-separator.mjs": 3453, + "string-split-traversal.ts": 4337, + "structural-class-properties.ts": 3247, + "structured-text-boundaries.js": 3686, + "structured-text-storage.ts": 3429, + "switch-integer-dispatch.ts": 3032, + "symbol-checked-boundary/main.ts": 3536, + "symbol-class-fields.ts": 2762, + "symbol-class-fields/main.cjs": 3297, + "symbol-class-methods/main.ts": 3256, + "symbol-fields-deferred-factory.ts": 2417, + "symbol-fields-inferred.js": 3396, + "symbol-object-properties/main.js": 3134, + "synchronous-callback-lifetimes.ts": 3731, + "terminal-stream-properties.ts": 3204, + "text-codec-values/main.ts": 34352, + "text-codec-var.ts": 32460, + "text-encode-into-boundaries.ts": 3355, + "timers-clear-many.ts": 3559, + "tuple-and-string-search.ts": 3678, + "tuple-array-union.ts": 3569, + "tuple-callback-visitation.ts": 4765, + "tuple-forof-visitation.ts": 3560, + "typed-array-bulk-conversion.mjs": 5651, + "typed-array-byte-io.js": 4933, + "typed-array-checked-index.js": 3214, + "typed-array-constructor-alias.ts": 3116, + "typed-array-constructor-identity.js": 2735, + "typed-array-constructor-union.ts": 2841, + "typed-array-constructor-values.mjs": 3638, + "typed-array-dynamic-methods.js": 3255, + "typed-array-integer-widths.ts": 3434, + "typed-array-nan-coded-reads.ts": 3804, + "typed-array-numeric-import.ts": 2396, + "typed-array-present-reads.ts": 4348, + "typed-array-reversed-storage.ts": 3192, + "typed-array-unknown.ts": 2874, + "typed-collection-iterator-references.ts": 4029, + "typed-collection-iterators.ts": 4109, + "typed-collection-views/main.ts": 3005, + "typed-index-arguments.ts": 2798, + "typed-prototype-methods.ts": 3814, + "typed-rest-callables.ts": 2881, + "typed-rest-filtered-return.ts": 3723, + "typedarray-native-inputs.js": 2740, + "typeof-checked-comparison.js": 2277, + "uint8array-sort-domains.ts": 3386, + "unicode-case-paths.ts": 3002, + "unicode-process-argv.ts": 3272, + "union-discriminant-width.ts": 3302, + "union-literal-scalar-discriminants.ts": 2833, + "union-literal-slot-conversion.ts": 4058, + "union-nested-layout-discriminant.ts": 3205, + "union-optional-semantic-identity.ts": 3833, + "union-record-clone.ts": 3862, + "union-record-structural-copy.ts": 3756, + "union-reference-comparison.ts": 2883, + "unknown-array-holes.ts": 2863, + "unknown-collections.ts": 4132, + "unknown-object-enumeration.ts": 4976, + "unknown-record-views.ts": 4014, + "url-runtime-base.ts": 3421, + "utf8-span-decoding.ts": 3446, + "util-parseargs-wrapped/main.ts": 3987, + "virtual-runtime-optional-returns.ts": 4683, + "weak-map-array-buffer.ts": 3291, + "weak-map-fresh-array.js": 2703, + "weak-map-native.js": 3899, + "weak-native-class-identity.ts": 2332, + "weak-set-native.js": 2464, + "worker-class-instance-clone.ts": 46305 } } From cd376c14f1d4f0c7da8ec70a0cef050a1ac92192 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 09:33:01 -0700 Subject: [PATCH 104/117] Refresh the corpus costs from main's newest green Linux shards Rerun scripts/ci-corpus-costs.mjs over the 120 green Linux corpus shard logs (plain and san, 20 shards each) of main CI runs 39142848734, 39142619508 and 39142079655 (307387c8e, 18c50b55d, b85dd44cd). Their Linux lanes were all green; only macOS jobs were still queued. This measures the programs added since the previous refresh, including 5770-5773, 5960-5962, 5973, 6041-6043, the CommonJS require programs 6140-6145 and 5023/5024. Coverage of current main's corpus goes from 2992/3012 (0.9934) to 3011/3012 (0.9997); the one unmeasured program, scratch-string-slices.ts, landed after those runs. Co-Authored-By: Claude Opus 5.5 --- tests/harness/corpus-costs.json | 11984 +++++++++++++++--------------- 1 file changed, 6011 insertions(+), 5973 deletions(-) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 622b64700..e4dd020cd 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1,5991 +1,6029 @@ { "note": "Milliseconds per corpus program on a GitHub-hosted ubuntu-24.04 runner: its differential plus llvm-differential case, per flavor (medians of green main runs). scripts/ci-corpus-costs.mjs refreshes it from CI logs.", "plain": { - "001-hello.ts": 3065, - "002-log-args.ts": 4101, - "100-number-format.ts": 4051, - "1000-json-stringify-basics.ts": 5187, - "1001-json-escapes-unicode.ts": 4569, - "1002-json-parse-cast.ts": 3516, - "1003-json-parse-unions.ts": 3382, - "1004-json-parse-errors.ts": 4383, - "1005-json-nested.ts": 5206, - "1006-json-fs-config.ts": 3979, - "1007-json-rc-stress.ts": 3920, - "1008-json-null-arms.ts": 3823, - "1009-json-optional-fields.ts": 4367, - "101-arithmetic.ts": 3258, - "1010-json-stringify-space.ts": 3979, - "1011-json-unknown-typeof.ts": 4108, - "102-comparisons.ts": 4061, - "1020-async-basics.ts": 3165, - "1021-async-ordering.ts": 3062, - "1022-async-exceptions.ts": 3356, - "1023-async-rc-stress.ts": 3530, - "1024-async-pending-exit.ts": 2901, - "1025-async-promise-capture.ts": 3471, - "1026-throw-promise.ts": 3173, - "1027-async-return-promise.ts": 2405, - "1028-async-return-record-literals.ts": 3561, - "1029-async-eager-chains.ts": 3698, - "103-ternary.ts": 3292, - "104-ternary-empty-arrays.ts": 4072, - "1050-comptime-tables.ts": 3518, - "1051-comptime-strings.ts": 2082, - "1052-comptime-records.ts": 3252, - "1053-comptime-json.ts": 3388, - "1054-comptime-modules/main.ts": 3286, - "110-number-radix.ts": 3749, - "111-record-entries.ts": 4017, - "1110-math-members.ts": 2615, - "1111-math-random.ts": 2691, - "1113-string-methods.ts": 3490, - "1114-string-unicode-island.ts": 2532, - "1115-parse-globals.ts": 2850, - "1116-island-static-mix.ts": 3032, - "1117-typeof-static-union.ts": 3626, - "1118-object-spread-conditional.ts": 2554, - "1119-switch-union.ts": 2726, - "112-class-descriptor-key.js": 2549, - "1121-infinity-number-tostring.ts": 3208, - "1122-any-captures.ts": 3054, - "1124-union-narrowed-retag.ts": 3578, - "113-promise-checked-exits.ts": 3586, - "114-live-record-delete.ts": 3626, - "115-array-compound.js": 3341, - "116-text-decoder-runtime.js": 2988, - "117-weak-cache-cycle.js": 2923, - "118-fs-stored-callbacks.cjs": 4172, - "119-native-patterns.js": 3825, - "1200-regex-test-basics.ts": 3353, - "1201-regex-replace.ts": 3417, - "1202-regex-substitutions.ts": 2747, - "1203-regex-split.ts": 3543, - "1204-regex-empty-unicode.ts": 3255, - "1205-regex-rc-stress.ts": 3482, - "1300-errors-basics.ts": 4832, - "1301-errors-subclass.ts": 1974, - "1302-errors-typed-catch.ts": 3160, - "1303-errors-rc-stress.ts": 3496, - "1304-errors-uncaught.ts": 2419, - "1305-errors-async-rejections.ts": 3908, - "1306-errors-runtime-instances.ts": 3226, - "1350-path-normalize-join.ts": 3294, - "1351-path-parts.ts": 3299, - "1352-path-resolve-relative.ts": 3380, - "1353-os-basics.ts": 3216, - "1354-builtin-bare-specifiers.ts": 3413, - "1355-url-parse.ts": 3188, - "1356-url-file-bridge.ts": 3020, - "1357-fsp-roundtrip.ts": 3377, - "1358-crypto-random.ts": 3134, - "1359-json-module/main.ts": 3195, - "1360-spawn-sync.ts": 3446, - "1361-spawn-events.ts": 3606, - "1362-spawn-timers.ts": 9552, - "1363-spawn-unhandled-error.ts": 3308, - "1364-union-truthiness.ts": 2872, - "1365-union-logical.ts": 3452, - "1366-union-equality.ts": 2813, - "1367-destructuring.ts": 3209, - "1368-constructor-functions.ts": 1858, - "1369-promise-union.ts": 2635, - "1370-spread.ts": 2894, - "1371-union-template-tostring.ts": 3244, - "1372-loose-null-tests.ts": 3198, - "1373-union-array-arms.ts": 3455, - "140-bitwise-operators.ts": 3457, - "1400-typedarray-basics.ts": 2651, - "1401-typedarray-slice-set.ts": 4371, - "1402-buffer-encodings.ts": 3496, - "1403-buffer-fs.ts": 3517, - "1404-zlib-crypto-bytes.ts": 3174, - "1405-bytes-unions-arrays.ts": 4083, - "1406-dataview-mp4.ts": 3511, - "1407-dataview-bounds.ts": 2861, - "1408-string-indexing.ts": 3596, - "1409-typedarray-integer-loops.ts": 3161, - "1420-number-statics.ts": 1931, - "1421-number-parse-strings.ts": 2420, - "1422-date-iso.ts": 3107, - "1423-text-codec.ts": 4835, - "1424-fs-options.ts": 3321, - "1425-stdin-tty.ts": 2403, - "1426-stdin-read.ts": 3082, - "1427-fromcharcode-lastindexof.ts": 3173, - "1428-settled-await-order.ts": 1798, - "1429-promise-catch-finally.ts": 3573, - "1430-promise-race.ts": 3479, - "1431-caught-tostring.ts": 3384, - "1432-destructured-params.ts": 2875, - "1433-filter-narrow.ts": 3756, - "1434-async-never.ts": 3046, - "1435-math-spread.ts": 2761, - "1436-default-undef-param.ts": 2349, - "1437-pad-default.ts": 3147, - "1438-promise-all.ts": 6716, - "1440-interval-basics.ts": 2538, - "1441-interval-clear-cross.ts": 6428, - "1442-interval-throw.ts": 3155, - "1443-signal-handlers.ts": 5897, - "1444-exit-listeners.ts": 2050, - "1445-exit-process-exit.ts": 3031, - "1446-exit-uncaught.ts": 3104, - "1447-stdin-closed-events.ts": 2554, - "1448-stream-columns.ts": 2939, - "1450-incdec-expression.ts": 3366, - "1451-instanceof-uint8array-unknown.ts": 3581, - "1452-return-through-finally.ts": 2366, - "1453-pmap-settled.ts": 3689, - "1454-nonnull-narrow-and-fcc-bytes.ts": 3631, - "1455-lambda-union-return-adoption.ts": 3317, - "1460-console-error-warn.ts": 2928, - "1461-process-pid-getuid-kill.ts": 2613, - "1462-exec-sync.ts": 3611, - "1463-timeout-unref.ts": 2351, - "1464-env-writes.ts": 2366, - "1465-env-value.ts": 3573, - "1466-child-containers.ts": 3261, - "1467-string-match.ts": 2763, - "1468-exec-path.ts": 1874, - "1469-remove-listener.ts": 3366, - "1470-child-lifecycle.ts": 3503, - "1471-child-unref.ts": 7428, - "1472-errno-code.ts": 3503, - "1473-promisify-execfile.ts": 3923, - "1474-string-decoder.ts": 3543, - "1475-readline-closed-stdin.ts": 2561, - "1476-assign-expression.ts": 2094, - "1477-in-expressions.ts": 2351, - "1478-promise-reject.ts": 3535, - "1479-destructuring-assign.ts": 3422, - "1480-os-network-interfaces.ts": 3878, - "1481-string-case-static.ts": 1956, - "1482-spawnsync-error.ts": 3384, - "1483-array-slice.ts": 2259, - "1520-fs-wider-surface.ts": 2338, - "1520-string-split-static.ts": 2323, - "1521-fs-lstat-lock.ts": 2828, - "1521-string-trim-pad-static.ts": 3386, - "1522-parseint-static.ts": 3245, - "1522-spawnsync-options.ts": 5207, - "1523-isnan-floor-static.ts": 2460, - "1523-spawn-options.ts": 3155, - "1524-atomics-sleep-static.ts": 3514, - "1524-catch-narrowing.ts": 3000, - "1525-child-exit-signal.ts": 3280, - "1525-unknown-typeof-validation.ts": 3939, - "1526-set-spread.ts": 3125, - "1527-logical-mixed-operands.ts": 3109, - "1528-delete-records-env.ts": 3666, - "1529-class-with-statics.ts": 2773, - "1530-array-push-variadic.ts": 2981, - "1530-spread-override-completion.ts": 2727, - "1531-delete-optional-fields.ts": 3366, - "1531-process-arch-versions.ts": 3284, - "1532-array-splice-shift.ts": 3298, - "1532-union-shared-field-read.ts": 3134, - "1533-bool-equality.ts": 2685, - "1533-path-platform-namespaces.ts": 2976, - "1534-crypto-hash-chain.ts": 3181, - "1534-union-as-arm-cast.ts": 1932, - "1535-spawn-fd-stdio.ts": 2678, - "1535-union-param-defaults.ts": 3163, - "1536-destructuring-defaults.ts": 2281, - "1536-string-array-sweep.ts": 2437, - "1537-chalk-hybrid/main.ts": 2748, - "1537-os-release-spawnsync-stdio.ts": 1762, - "1538-await-promiselike-return.ts": 3032, - "1538-math-static-scalar.ts": 3194, - "1539-readonly-set-map.ts": 2459, - "1539-unknown-truthiness.ts": 3106, - "1540-os-userinfo.ts": 3344, - "1540-void-statement.ts": 2967, - "1541-fs-readdir-dirent.ts": 3638, - "1541-union-keyed-reads.ts": 3287, - "1542-map-promise-values.ts": 2441, - "1542-record-literal-into-union.ts": 3261, - "1543-rest-destructuring.ts": 2933, - "1543-set-server-handles.ts": 1958, - "1544-dyn-json-reads.ts": 2284, - "1544-string-matchall.ts": 2886, - "1545-spread-order-and-optional.ts": 3651, - "1546-union-element-reads.ts": 3172, - "1547-computed-key-fold.ts": 3047, - "1548-boolean-condition-forms.ts": 2170, + "001-hello.ts": 4256, + "002-log-args.ts": 4431, + "100-number-format.ts": 4288, + "1000-json-stringify-basics.ts": 5132, + "1001-json-escapes-unicode.ts": 3267, + "1002-json-parse-cast.ts": 5058, + "1003-json-parse-unions.ts": 4949, + "1004-json-parse-errors.ts": 3893, + "1005-json-nested.ts": 4163, + "1006-json-fs-config.ts": 3643, + "1007-json-rc-stress.ts": 4310, + "1008-json-null-arms.ts": 3701, + "1009-json-optional-fields.ts": 5156, + "101-arithmetic.ts": 3674, + "1010-json-stringify-space.ts": 4817, + "1011-json-unknown-typeof.ts": 3898, + "102-comparisons.ts": 4171, + "1020-async-basics.ts": 2636, + "1021-async-ordering.ts": 3263, + "1022-async-exceptions.ts": 3483, + "1023-async-rc-stress.ts": 4371, + "1024-async-pending-exit.ts": 3071, + "1025-async-promise-capture.ts": 3271, + "1026-throw-promise.ts": 3956, + "1027-async-return-promise.ts": 2933, + "1028-async-return-record-literals.ts": 3384, + "1029-async-eager-chains.ts": 2879, + "103-ternary.ts": 2774, + "104-ternary-empty-arrays.ts": 3724, + "1050-comptime-tables.ts": 3691, + "1051-comptime-strings.ts": 2389, + "1052-comptime-records.ts": 3840, + "1053-comptime-json.ts": 4536, + "1054-comptime-modules/main.ts": 3656, + "110-number-radix.ts": 2382, + "111-record-entries.ts": 4655, + "1110-math-members.ts": 4248, + "1111-math-random.ts": 3457, + "1113-string-methods.ts": 3364, + "1114-string-unicode-island.ts": 3366, + "1115-parse-globals.ts": 2591, + "1116-island-static-mix.ts": 3058, + "1117-typeof-static-union.ts": 3667, + "1118-object-spread-conditional.ts": 3693, + "1119-switch-union.ts": 3739, + "112-class-descriptor-key.js": 3492, + "1121-infinity-number-tostring.ts": 3539, + "1122-any-captures.ts": 3596, + "1124-union-narrowed-retag.ts": 3745, + "113-promise-checked-exits.ts": 2180, + "114-live-record-delete.ts": 3506, + "115-array-compound.js": 2722, + "116-text-decoder-runtime.js": 3978, + "117-weak-cache-cycle.js": 2417, + "118-fs-stored-callbacks.cjs": 4105, + "119-native-patterns.js": 4047, + "1200-regex-test-basics.ts": 2828, + "1201-regex-replace.ts": 3118, + "1202-regex-substitutions.ts": 2460, + "1203-regex-split.ts": 3529, + "1204-regex-empty-unicode.ts": 2746, + "1205-regex-rc-stress.ts": 3472, + "1300-errors-basics.ts": 3642, + "1301-errors-subclass.ts": 3871, + "1302-errors-typed-catch.ts": 3598, + "1303-errors-rc-stress.ts": 2806, + "1304-errors-uncaught.ts": 2053, + "1305-errors-async-rejections.ts": 3710, + "1306-errors-runtime-instances.ts": 2540, + "1350-path-normalize-join.ts": 2427, + "1351-path-parts.ts": 2680, + "1352-path-resolve-relative.ts": 3325, + "1353-os-basics.ts": 3345, + "1354-builtin-bare-specifiers.ts": 3282, + "1355-url-parse.ts": 2902, + "1356-url-file-bridge.ts": 2530, + "1357-fsp-roundtrip.ts": 2551, + "1358-crypto-random.ts": 3328, + "1359-json-module/main.ts": 3223, + "1360-spawn-sync.ts": 3535, + "1361-spawn-events.ts": 2778, + "1362-spawn-timers.ts": 8421, + "1363-spawn-unhandled-error.ts": 2559, + "1364-union-truthiness.ts": 2999, + "1365-union-logical.ts": 3464, + "1366-union-equality.ts": 3482, + "1367-destructuring.ts": 3491, + "1368-constructor-functions.ts": 3392, + "1369-promise-union.ts": 3326, + "1370-spread.ts": 2384, + "1371-union-template-tostring.ts": 3754, + "1372-loose-null-tests.ts": 3218, + "1373-union-array-arms.ts": 4066, + "140-bitwise-operators.ts": 2496, + "1400-typedarray-basics.ts": 3520, + "1401-typedarray-slice-set.ts": 3865, + "1402-buffer-encodings.ts": 2493, + "1403-buffer-fs.ts": 2658, + "1404-zlib-crypto-bytes.ts": 2380, + "1405-bytes-unions-arrays.ts": 2532, + "1406-dataview-mp4.ts": 3915, + "1407-dataview-bounds.ts": 3752, + "1408-string-indexing.ts": 3470, + "1409-typedarray-integer-loops.ts": 2071, + "1420-number-statics.ts": 3136, + "1421-number-parse-strings.ts": 2476, + "1422-date-iso.ts": 2600, + "1423-text-codec.ts": 4597, + "1424-fs-options.ts": 3300, + "1425-stdin-tty.ts": 3063, + "1426-stdin-read.ts": 2925, + "1427-fromcharcode-lastindexof.ts": 3413, + "1428-settled-await-order.ts": 2724, + "1429-promise-catch-finally.ts": 2634, + "1430-promise-race.ts": 4554, + "1431-caught-tostring.ts": 2091, + "1432-destructured-params.ts": 3338, + "1433-filter-narrow.ts": 3904, + "1434-async-never.ts": 3174, + "1435-math-spread.ts": 3092, + "1436-default-undef-param.ts": 3956, + "1437-pad-default.ts": 3383, + "1438-promise-all.ts": 6011, + "1440-interval-basics.ts": 4575, + "1441-interval-clear-cross.ts": 6244, + "1442-interval-throw.ts": 3389, + "1443-signal-handlers.ts": 6258, + "1444-exit-listeners.ts": 3211, + "1445-exit-process-exit.ts": 3320, + "1446-exit-uncaught.ts": 2360, + "1447-stdin-closed-events.ts": 2750, + "1448-stream-columns.ts": 2209, + "1450-incdec-expression.ts": 3228, + "1451-instanceof-uint8array-unknown.ts": 2957, + "1452-return-through-finally.ts": 3660, + "1453-pmap-settled.ts": 3618, + "1454-nonnull-narrow-and-fcc-bytes.ts": 3317, + "1455-lambda-union-return-adoption.ts": 2774, + "1460-console-error-warn.ts": 3320, + "1461-process-pid-getuid-kill.ts": 3247, + "1462-exec-sync.ts": 3282, + "1463-timeout-unref.ts": 3251, + "1464-env-writes.ts": 2987, + "1465-env-value.ts": 3024, + "1466-child-containers.ts": 3422, + "1467-string-match.ts": 3346, + "1468-exec-path.ts": 2301, + "1469-remove-listener.ts": 3606, + "1470-child-lifecycle.ts": 3256, + "1471-child-unref.ts": 7451, + "1472-errno-code.ts": 3295, + "1473-promisify-execfile.ts": 2595, + "1474-string-decoder.ts": 3611, + "1475-readline-closed-stdin.ts": 3112, + "1476-assign-expression.ts": 3030, + "1477-in-expressions.ts": 2996, + "1478-promise-reject.ts": 3812, + "1479-destructuring-assign.ts": 3356, + "1480-os-network-interfaces.ts": 4196, + "1481-string-case-static.ts": 3245, + "1482-spawnsync-error.ts": 3565, + "1483-array-slice.ts": 3674, + "1520-fs-wider-surface.ts": 3471, + "1520-string-split-static.ts": 2773, + "1521-fs-lstat-lock.ts": 3726, + "1521-string-trim-pad-static.ts": 3379, + "1522-parseint-static.ts": 3352, + "1522-spawnsync-options.ts": 5275, + "1523-isnan-floor-static.ts": 3491, + "1523-spawn-options.ts": 3565, + "1524-atomics-sleep-static.ts": 3559, + "1524-catch-narrowing.ts": 3222, + "1525-child-exit-signal.ts": 3428, + "1525-unknown-typeof-validation.ts": 3170, + "1526-set-spread.ts": 3383, + "1527-logical-mixed-operands.ts": 3407, + "1528-delete-records-env.ts": 3353, + "1529-class-with-statics.ts": 2988, + "1530-array-push-variadic.ts": 3122, + "1530-spread-override-completion.ts": 2849, + "1531-delete-optional-fields.ts": 3199, + "1531-process-arch-versions.ts": 3354, + "1532-array-splice-shift.ts": 2767, + "1532-union-shared-field-read.ts": 3248, + "1533-bool-equality.ts": 3299, + "1533-path-platform-namespaces.ts": 3213, + "1534-crypto-hash-chain.ts": 3265, + "1534-union-as-arm-cast.ts": 2201, + "1535-spawn-fd-stdio.ts": 3518, + "1535-union-param-defaults.ts": 2934, + "1536-destructuring-defaults.ts": 3325, + "1536-string-array-sweep.ts": 3492, + "1537-chalk-hybrid/main.ts": 2721, + "1537-os-release-spawnsync-stdio.ts": 3013, + "1538-await-promiselike-return.ts": 3514, + "1538-math-static-scalar.ts": 2646, + "1539-readonly-set-map.ts": 2440, + "1539-unknown-truthiness.ts": 3020, + "1540-os-userinfo.ts": 2759, + "1540-void-statement.ts": 3146, + "1541-fs-readdir-dirent.ts": 3308, + "1541-union-keyed-reads.ts": 2673, + "1542-map-promise-values.ts": 3263, + "1542-record-literal-into-union.ts": 3421, + "1543-rest-destructuring.ts": 2387, + "1543-set-server-handles.ts": 3383, + "1544-dyn-json-reads.ts": 4211, + "1544-string-matchall.ts": 3589, + "1545-spread-order-and-optional.ts": 3635, + "1546-union-element-reads.ts": 3551, + "1547-computed-key-fold.ts": 3124, + "1548-boolean-condition-forms.ts": 3319, "1549-array-isarray-unions.ts": 3931, - "1550-param-defaults-func-set.ts": 2398, - "1551-dyn-receiver-methods.ts": 3835, - "1552-exec-options-record.ts": 3202, - "1553-truthy-hof-predicates.ts": 3421, - "1554-caught-into-unknown.ts": 3543, - "1555-index-spread-into-declared.ts": 3633, - "1556-union-retag-width-arms.ts": 2627, - "1557-url-host.ts": 2357, - "1558-any-joins-and-dyn-validation.ts": 3196, - "1559-conditional-spread-index-merge.ts": 3131, - "1560-forof-homogeneous-tuples.ts": 3159, - "1561-forof-strings.ts": 2864, - "1561-promise-then.ts": 2385, - "1562-optional-chain-tails.ts": 3642, - "1562-spawn-conditional-spread.ts": 3319, - "1563-forof-iterator-projections.ts": 2786, - "1563-string-raw-fold.ts": 2587, - "1564-fs-watch.ts": 3261, - "1564-string-raw.ts": 2451, - "1565-spawn-pipe-streams.ts": 3391, - "1565-union-element-join.ts": 2486, - "1566-child-duck-interface.ts": 2840, - "1567-server-close-override.ts": 3237, - "1568-x509-fingerprint.ts": 3907, - "1569-fsp-mkdir-unlink-chmod.ts": 2903, - "1570-child-unref-kill-reffed.ts": 8636, - "1571-optional-call-tostring-tail.ts": 2889, - "1571-stdin-set-raw-mode-non-tty.ts": 2975, - "1572-promise-reject-all-tuple.ts": 3556, - "1572-x509-validity-date-gettime.ts": 3310, - "1573-promisify-execfile-env-spread.ts": 2814, - "1573-tdz-scalar-forward-capture.ts": 1712, - "1574-dyn-optional-method-number-keys.ts": 3878, - "1574-promise-all-tuple-literal.ts": 2253, - "1575-unknown-assert-into-record.ts": 1861, - "1576-width-coercions.ts": 2898, - "1577-url-hostname.ts": 2901, - "1578-exec-input-optional.ts": 3273, - "1579-matchall-index.ts": 3564, - "1580-exec-env-conditional-spread.ts": 2271, - "1581-declare-const-read.ts": 3037, - "1582-timer-sleep-resolve.ts": 3206, - "1583-loops-and-stream-captures.ts": 3193, - "1584-union-field-unassigned.ts": 3119, - "1585-union-field-conditional-ctor.ts": 3101, - "1586-derived-field-before-super-init.ts": 2618, - "1590-js-unannotated.js": 2053, - "1591-js-closures.js": 2387, - "1592-js-classes.js": 4973, - "1593-js-jsdoc-records.js": 3116, - "1594-js-async.js": 2589, - "1595-js-island-gap/main.js": 3108, - "1596-cjs-modules/main.js": 3096, - "1597-mjs-graph/main.mjs": 2863, - "1598-cjs-builtin-require/main.js": 2598, - "1599-js-uncaught-throw.js": 1785, - "1600-assert-passing.ts": 3203, - "1601-assert-fail-exit.ts": 2955, - "1602-assert-caught-error.ts": 2978, - "1603-assert-scalar-messages.ts": 3055, - "1604-assert-deep-structures.ts": 3591, - "1605-assert-import-forms.ts": 2429, - "1606-assert-strict-module.ts": 3039, - "1607-assert-throws-match.ts": 2826, - "1608-cjs-assert/main.js": 3263, - "1609-assert-async.ts": 3342, - "1610-path-win32-full.ts": 2405, - "1611-url-file-bridge-neutral.ts": 2476, - "1612-cjs-module-globals.cjs": 2856, - "1613-cjs-esm-proxy-named/main.mjs": 2613, - "1614-js-fence-dodges.cjs": 1967, - "1615-cjs-export-shapes/main.cjs": 2975, - "1616-cjs-esm-lexer-invisible/main.mjs": 2660, - "1617-cjs-esm-lexer-visible/main.mjs": 3090, - "1618-cjs-esm-poisoned-tail/main.mjs": 2780, - "1619-cjs-esm-reexport-invisible/main.mjs": 2185, - "1620-cjs-require-effects-order/main.js": 1410, - "1621-cjs-require-cache-hit/main.js": 2836, - "1622-cjs-require-conditional/main.js": 2564, - "1623-cjs-require-diamond/main.js": 2652, - "1624-cjs-require-dir-mid-file/main.js": 2573, - "1625-cjs-require-lazy-fn/main.js": 2246, - "1626-cjs-require-mjs/main.js": 2951, - "1627-mjs-import-cjs-requires/main.mjs": 2683, - "1628-checked-dynamic-builtin-args.cjs": 1896, - "1629-require-main-filename.cjs": 2867, - "1630-inspect-scalars.ts": 2361, - "1630-rmsync-retry-options.cjs": 2984, - "1631-inspect-arrays.ts": 3811, - "1632-inspect-records.ts": 4779, - "1633-inspect-map-set.ts": 3008, - "1634-inspect-classes.ts": 3344, - "1635-inspect-buffer.ts": 2898, - "1636-util-format.ts": 2261, - "1637-inspect-dyn.ts": 2934, - "1638-inspect-cjs.cjs": 3133, - "1639-versions-openssl-probe.ts": 2209, - "1640-fd-read-decode.ts": 3309, - "1641-string-search.ts": 2951, - "1642-object-fromentries-rows.ts": 3231, - "1643-metadata-dyn-return.cjs": 3375, - "1644-ee-basics.ts": 3158, - "1645-ee-extends.ts": 2448, - "1646-ee-once-remove.ts": 2581, - "1647-ee-meta-events.ts": 2563, - "1648-ee-error-event.ts": 2097, - "1649-ee-names-counts.ts": 2941, - "1650-ee-prepend.ts": 3190, - "1651-ee-max-listeners.ts": 2691, - "1652-ee-snapshot.ts": 2882, - "1653-ee-cjs.cjs": 2645, - "1654-ee-namespace.ts": 2314, - "1655-spawnsync-neutral.ts": 4787, - "1656-execsync-neutral.ts": 3015, - "1657-spawn-async-neutral.ts": 3128, - "1660-buffer-read-write-num.ts": 2511, - "1661-buffer-encodings-full.ts": 3466, - "1662-string-decoder-encodings.ts": 3207, - "1663-buffer-compare-search-fill.ts": 3063, - "1664-dyn-fn-boundary.cjs": 2280, - "1665-dyn-fn-mustcall/main.cjs": 2798, - "1666-dyn-fn-identity.ts": 3303, - "1667-dyn-fn-not-callable.cjs": 2431, - "1668-dyn-fn-throws.cjs": 3052, - "1669-symbol-identity.ts": 3194, - "1670-symbol-registry.ts": 2198, - "1671-symbol-typeof.ts": 2786, - "1672-symbol-containers.ts": 2209, - "1673-symbol-cjs.cjs": 2979, - "1674-symbol-inspect.ts": 2795, - "1676-func-array-surface.ts": 2945, - "1677-emitter-listeners.ts": 4548, - "1678-emitter-dyn-listeners.cjs": 3185, - "1679-console-dyn.js": 2910, - "1680-assert-bytes.ts": 3154, - "1681-assert-funcs.ts": 1828, - "1685-stream-readable-basics.ts": 2976, - "1686-stream-readable-paused.ts": 2831, - "1687-stream-readable-flow-control.ts": 2863, - "1688-stream-writable-basics.ts": 2245, - "1689-stream-writable-async-drain.ts": 1562, - "1690-stream-duplex.ts": 3124, - "1691-stream-transform.ts": 2070, - "1692-stream-pipe.ts": 2661, - "1693-stream-pipe-backpressure.ts": 2944, - "1694-stream-destroy.ts": 2243, - "1695-stream-props.ts": 2801, - "1696-stream-read-inside-read.ts": 2398, - "1697-stream-tick-vs-timer.ts": 2703, - "1698-stream-uncaught-error.ts": 2045, - "1699-stream-callback-shapes.ts": 2523, - "1700-mustcall-common/main.cjs": 3695, - "1701-mustcall-exit-report/main.cjs": 4202, - "1702-dyn-proto-dispatch.cjs": 3277, - "1703-arguments-rest-props.cjs": 2983, - "1710-cjs-export-class/main.js": 3030, - "1711-cjs-export-single-values/main.js": 2594, - "1712-field-incdec.ts": 1845, - "1713-js-dyn-fields.js": 2654, - "1720-assert-throws-shape.ts": 2898, - "1721-assert-throws-regex-class.ts": 3751, - "1722-assert-rejects.ts": 2848, - "1723-assert-does-not-reject.ts": 3358, - "1724-assert-iferror.ts": 1705, - "1725-assert-symbols.ts": 2141, - "1726-promise-with-resolvers.ts": 2575, - "1727-assert-throws-shape-exit.ts": 2905, - "1730-countdown-symbol-keys/main.js": 2273, - "1731-symbol-field-shapes.cjs": 2895, - "1732-symbol-field-cross-module/main.js": 2678, - "1740-stream-extends-readable.ts": 2983, - "1741-stream-extends-writable.ts": 2337, - "1742-stream-extends-duplex-transform.ts": 3417, - "1743-stream-extends-vt-dispatch.ts": 2520, - "1744-stream-set-encoding.ts": 3582, - "1745-stream-encoding-js.cjs": 2993, - "1746-stream-for-await.ts": 4666, - "1747-stream-for-await-js.cjs": 3552, - "1750-http-agent-options.ts": 2667, - "1751-options-record-stance.ts": 3044, - "1760-surplus-args-drop.cjs": 2775, - "1761-emitter-special-event-names.cjs": 2427, - "1770-assert-dyn-strict.ts": 3393, - "1771-assert-dyn-deep.ts": 3639, - "1772-assert-dyn-js.cjs": 2854, - "1773-assert-dyn-exit.ts": 2368, - "1780-http-res-surface.ts": 2318, - "1781-http-server-shapes.cjs": 3339, - "1790-computed-key-folds.ts": 2833, - "1791-searchparams-core.ts": 2212, - "1792-searchparams-encoding.ts": 2305, - "1793-searchparams-iteration.ts": 3412, - "1794-searchparams-url-live.ts": 2492, - "1795-dyn-handle-request.cjs": 3337, - "1796-dyn-handle-body.cjs": 3287, - "1797-dyn-handle-socket.cjs": 2497, - "1798-dyn-handle-typed-box.ts": 2870, - "1800-immediate-basics.ts": 2802, - "1801-immediate-handle.ts": 2655, - "1802-immediate-unref-exit.ts": 2450, - "1803-timeout-refresh.ts": 2797, - "1804-timers-module.ts": 2773, - "1805-timer-callback-args.ts": 2736, - "1806-timer-delay-trunc.ts": 2060, - "1810-stream-options-const-record.ts": 2542, - "1811-stream-option-value-callbacks.cjs": 2462, - "1812-stream-super-options-forwarding.cjs": 3383, - "1813-stream-finished.ts": 2720, - "1814-stream-pipeline.cjs": 3409, - "1815-stream-state-reads.cjs": 2880, - "1820-static-block-basics.ts": 1635, - "1821-static-block-order.ts": 2551, - "1822-static-block-js.js": 2387, - "1823-static-instance-method-names.ts": 1936, - "1824-for-of-destructuring-defaults.ts": 2145, - "1825-exhaustive-typeof-switch.ts": 2973, - "1826-settimeout-arguments-callback.js": 2489, - "1830-enum-numeric-basics.ts": 2207, - "1831-enum-string-const-reverse.ts": 1943, - "1832-enum-modules/main.ts": 2350, - "1835-var-basics.ts": 2804, - "1836-var-loop-capture.ts": 3197, - "1837-var-undefined-hoisting.ts": 2836, - "1838-var-modules/main.ts": 2550, - "1839-var-js/main.cjs": 2492, - "1840-jsdoc-import-type-only/main.js": 1919, - "1850-overload-basics.ts": 2640, - "1851-overload-return-narrowing.ts": 1736, - "1852-overload-class-members.ts": 2774, - "1853-overload-modules/main.ts": 2509, - "1854-ambient-declare-fn.ts": 2603, - "1855-ambient-declare-fn-uncaught.ts": 1999, - "1870-unit-type-values.ts": 2905, - "1871-empty-array-never.ts": 2516, - "1872-template-tostring-composite.ts": 1682, - "1880-json-declared-field-order.ts": 3529, - "1881-default-anon/main.ts": 2084, - "1882-default-cjs-interop/main.ts": 2606, - "1883-default-exports/main.ts": 2612, - "1890-ns-imports/main.ts": 2704, - "1891-ns-reexport/main.ts": 2129, - "1940-class-values-basics.ts": 2668, - "1941-class-values-registry.ts": 2870, - "1942-class-expressions.ts": 2682, - "1943-class-statics-expanded.ts": 2734, - "1944-class-values-modules/main.ts": 2146, - "1950-generic-fn-values.ts": 2755, - "1951-generic-classes-basics.ts": 3235, - "1952-generic-class-statics-values.ts": 2233, - "1953-generic-class-hierarchy.ts": 2990, - "1954-generic-modules/main.ts": 2377, - "1960-namespace-basics.ts": 2728, - "1961-namespace-nested.ts": 2156, - "1962-namespace-classes.ts": 2835, - "1963-namespace-aliases.ts": 2550, - "1964-namespace-type-only.ts": 2471, - "1965-namespace-ambient.ts": 2707, - "1966-namespace-modules/main.ts": 2766, - "1967-namespace-alias-typeonly.ts": 2273, - "1968-namespace-import-eq-snapshot.ts": 2594, - "1970-decorators-basics.ts": 2916, - "1971-decorators-rebinding.ts": 2369, - "1972-decorators-throwing.ts": 2667, - "1973-decorators-ambient.ts": 2709, - "1980-primitive-proto-statics.ts": 3013, - "1981-date-utc.ts": 2644, - "1982-freeze-resolve-passthrough.ts": 3023, - "1983-array-tuple-surfaces.ts": 3232, - "1990-labels-basics.ts": 2990, - "1991-for-in-loops.ts": 3611, - "1992-small-syntax.ts": 3054, - "200-strings.ts": 1903, - "2000-generic-methods-basic.ts": 2832, - "2001-generic-methods-generic-class.ts": 2741, - "2002-generic-methods-inheritance.ts": 2972, - "2003-generic-methods-object-literal.ts": 3023, - "2004-generic-methods-statics.ts": 2292, - "201-templates.ts": 2534, - "2010-generators-basics.ts": 1525, - "2011-generators-forof.ts": 2217, - "2012-generators-return-throw.ts": 3262, - "2013-generators-sent-values.ts": 2117, - "2014-generators-values.ts": 2991, - "2015-generators-yieldstar.ts": 2892, - "2016-generators-rc-stress.ts": 2942, - "2017-generators-async.ts": 1965, - "2018-generators-uncaught.ts": 2403, - "2019-generators-loops.ts": 2116, - "2020-generic-value-bindings.ts": 3355, - "2021-generic-value-binding-modules/main.ts": 2720, - "2022-width-index-capture.ts": 2258, - "2023-width-readonly.ts": 2519, - "2024-width-array-elems.ts": 2776, - "2025-width-union-compose.ts": 3243, - "2026-width-spread.ts": 1625, - "2030-width-nested.ts": 3160, - "2031-width-tuples.ts": 2019, - "2032-cjs-export-assigned-class-expression/main.cjs": 2230, - "2033-property-assigned-class-extends.cjs": 2058, - "2035-ternary-array-retag.cjs": 2602, - "2036-evolving-array-decl.cjs": 2125, - "2037-fn-decl-hoisting.cjs": 1595, - "2038-evolving-array-js.cjs": 2965, - "2040-any-bindings.ts": 3143, - "2040-mixin-heritage.ts": 3206, - "2041-any-params-returns.ts": 2996, - "2041-mixin-values.ts": 3090, - "2042-any-flow-loops.ts": 3104, - "2042-mixin-modules/main.ts": 2762, - "2043-any-dom-values.ts": 3345, - "2043-mixin-rc-stress.ts": 2605, - "2044-vtable-sibling-slots.ts": 3123, - "2045-objlit-accessors-basic.ts": 2774, - "2045-parameter-properties.ts": 3393, - "2046-abstract-classes.ts": 2184, - "2046-objlit-accessors-effects.ts": 2948, - "2047-objlit-accessors-shapes.ts": 1767, - "2047-optional-class-fields.ts": 2566, - "2050-dynamic-import-own-module/main.ts": 2384, - "2051-dynamic-import-then/main.ts": 2679, - "2052-dynamic-import-self.ts": 2722, - "2053-typeof-static-fold.ts": 2817, - "2054-destructuring-island-source.ts": 2995, - "2060-empty-tuple.ts": 2635, - "2070-computed-key-folds.ts": 2872, - "2071-integer-key-enumeration-order.ts": 3125, - "2072-expando-function-members.ts": 2341, - "2073-destructuring-assignment.ts": 2794, - "2074-island-destructuring.ts": 2364, - "2075-index-signature-runtime-keys.ts": 2866, - "2080-destructuring-defaults.ts": 1887, - "2081-destructuring-rest.ts": 3136, - "2082-destructuring-assignment.ts": 2594, - "2085-destructuring-heads-rest-params.ts": 2973, - "2087-destructuring-for-heads.ts": 2753, - "2090-index-signature-number-keys.ts": 2175, - "2091-index-signature-string-intersection.ts": 2763, - "2092-package-imports/main.ts": 2350, - "2093-timers-promises.ts": 2872, - "2094-diagnostics-channel.ts": 2689, - "2095-js-catch-unknown.js": 2633, - "2096-os-type.ts": 1968, - "2097-js-evolving-globals.js": 2880, - "210-string-methods.ts": 2798, - "2100-stream-default-hwm.ts": 2089, - "2101-dyn-param-defaults.ts": 2260, - "2102-empty-pattern-decls.ts": 1677, - "2105-computed-key-static-folds.ts": 2815, - "2106-comma-expressions.ts": 2657, - "211-string-unicode.ts": 2741, - "2110-top-object-types.ts": 2919, - "2111-json-stringify-unknown.ts": 2401, - "2112-array-at-findlast.ts": 1741, - "2113-string-index-methods.js": 1867, - "212-string-aliasing-append.ts": 2513, - "2120-package-self-import/main.ts": 2334, - "2121-esm-cycle-inert-backedge/main.ts": 2266, - "2123-ambient-import-crash/main.ts": 2890, - "2124-imports-field-wildcard/main.ts": 2153, - "2140-uri-component-codecs.ts": 2446, - "2160-dc-tracing-channel.cjs": 2881, - "2161-js-object-literal-identity.cjs": 2928, - "2162-js-dyn-destructure.cjs": 2896, - "2163-js-selfref-const.cjs": 2717, - "2164-js-then-dyn-handler.cjs": 2572, - "2165-js-throw-dyn.cjs": 2672, - "2166-cjs-getter-this/main.cjs": 2899, - "2170-island-array-exits.ts": 2722, - "2171-island-json-stringify.ts": 2071, - "2172-island-regexp-boundary.ts": 2828, - "2190-new-object-and-string-wrappers.ts": 2625, - "2191-uri-encoders.ts": 2849, - "2192-object-default-tostring.ts": 2537, - "2193-discarded-stdlib-reads.ts": 2594, - "2194-ambient-undef-chains.ts": 1718, - "2195-require-missing-package/main.mjs": 2757, - "2196-island-computed-key-chain.ts": 2575, - "2210-dyn-promise-crossing.cjs": 2319, - "2211-dc-trace-promise.cjs": 1935, - "2212-unhandled-rejection-listener.cjs": 2879, - "2213-async-local-storage.cjs": 2883, - "2214-dc-bind-store.cjs": 2240, - "2215-process-emit-warning-exit.cjs": 3330, - "2240-width-class-into-record.ts": 2571, - "2241-width-record-into-class.ts": 2500, - "2242-width-statics-into-record.ts": 1787, - "2243-width-assert-satisfies-shapes.ts": 2738, - "2250-tagged-templates.ts": 2408, - "2252-class-iterators.ts": 3611, - "2253-union-coercions.ts": 2810, - "2260-http2-constants.cjs": 2702, - "2280-builtin-namespace-destructure.cjs": 2594, - "2281-domexception-atob-btoa.cjs": 2615, - "2282-queue-microtask.cjs": 2780, - "2283-structured-clone.cjs": 3105, - "2284-regexp-constructor.cjs": 2648, - "2285-iferror-dyn.cjs": 2717, - "2286-dyn-object-walks.cjs": 3110, - "2300-dyn-record-spread-and-keyed-access.cjs": 2464, - "2301-cjs-export-table-dom-attach.cjs": 2425, - "2310-process-next-tick.ts": 2609, - "2311-next-tick-js-callbacks.js": 2450, - "2312-stream-underscore-assign.ts": 2473, - "2313-stream-underscore-assign-js.cjs": 3017, - "2314-process-introspection.ts": 3479, - "2320-await-unit.ts": 2334, - "2321-emitter-static-setmax.cjs": 2697, - "2322-dyn-array-sort.cjs": 3014, - "2323-timer-callback-returns.ts": 3852, - "2330-tls-server-runtime-options.cjs": 2565, - "2331-tls-server-options-typed.ts": 1980, - "2350-nan-global.ts": 3180, - "2351-async-methods.ts": 2138, - "2352-void-coercions.ts": 2843, - "2353-decorators-member-ambient.ts": 3089, - "2354-decorators-expression-ambient.ts": 1841, - "2360-tuple-to-array.ts": 2335, - "2361-assign-index-record.ts": 3492, - "2362-execsync-inherit.ts": 2484, - "2363-nullish-retag.ts": 2875, - "2364-in-runtime-key.ts": 2156, - "2365-dyn-into-island.ts": 2339, - "2366-string-well-formed.ts": 2760, - "2367-regexp-escape.ts": 2791, - "2368-set-methods.ts": 3237, - "2369-promise-try.ts": 2605, - "2370-group-by.ts": 3569, - "2371-iterator-helpers.ts": 3561, - "2380-buffer-module-named-import.ts": 2746, - "2381-builtin-default-imports.js": 2945, - "2382-cycle-two-decl/main.ts": 2560, - "2383-cycle-assertdoc/main.js": 3011, - "2384-cycle-mixed-bindings/main.ts": 2477, - "2385-builtin-reexport-facade/main.ts": 2948, - "2386-string-to-chars.ts": 2475, - "2387-tonumber-argv.ts": 3071, - "2388-tonumber-grammar-zoo.ts": 3157, - "2389-tonumber-unary-plus.ts": 2176, - "2390-dot-requires/main.cjs": 2329, - "2391-default-builtin-imports/main.ts": 2387, - "2392-block-guard-alias-scope.ts": 2363, - "2393-loop-exit-guard-narrow.ts": 2936, - "2394-loop-narrow-containment.ts": 2244, - "2395-while-cond-guard.ts": 2443, - "2396-born-narrowed-decl.ts": 2276, - "2397-branch-kill-merge.ts": 2681, - "2398-switch-arm-kill.ts": 3027, - "2399-reassign-kill-polarity.ts": 2662, - "240-stdout-write.ts": 1918, - "2400-kill-return-edge.ts": 2414, - "2401-kill-break-staging.ts": 2162, - "2402-labeled-break-kill.ts": 2493, - "2403-kill-continue-backedge.ts": 2457, - "2404-kill-throw-catch.ts": 1792, - "2405-sibling-arm-narrow.ts": 1781, - "2406-switch-clause-sibling-narrow.ts": 2641, - "2407-infinite-loop-seal.ts": 2308, - "2408-loop-terminality-reopen.ts": 2756, - "2409-loop-body-return-not-terminal.ts": 2759, - "2410-stacked-cases-terminality.ts": 2830, - "2411-exhaustive-switch-terminality.ts": 2112, - "2412-dowhile-guard-trailing-test.ts": 2230, - "2413-dowhile-kill-renarrow.ts": 2630, - "2414-dowhile-continue-kill.ts": 2624, - "2415-dowhile-break-trailing-test.ts": 2524, - "2416-spread-ternary-positions.ts": 2956, - "2417-ternary-local-inference.ts": 2300, - "2418-wrapped-ternary-arms.ts": 2768, - "2419-selector-ternary-union.ts": 2727, - "2420-nullish-null-identity.ts": 2533, - "2421-float-lane-inference.ts": 2620, - "2422-ieee-div-rem-corners.ts": 2629, - "2423-param-null-reassign.ts": 2622, - "2424-ternary-miss-first-narrowing.ts": 2228, - "2425-elseif-head-exit-narrow.ts": 2186, - "2426-default-snapshot-mutable/main.ts": 2520, - "2427-perf-hooks-now.ts": 2346, - "2428-field-redeclare-inherited.ts": 2882, - "2429-destructure-class-instance.ts": 2852, - "2430-empty-literal-unknown-field.js": 2190, - "2431-primitive-ctor-values.ts": 2149, - "2432-generic-member-fields-async.ts": 3225, - "2433-as-const-command-tables.ts": 3139, - "2434-deferred-init-fields.ts": 2789, - "2435-loose-same-kind-equality.ts": 2652, - "2440-console-inspect-args.ts": 3314, - "2441-console-process-argv.ts": 2095, - "2442-union-literal-arm-widening.ts": 2062, - "2443-union-literal-shadow-narrowing.ts": 2856, - "2444-union-literal-reducer-spread.ts": 2705, - "2445-math-minmax-nary.ts": 2093, - "2446-performance-global.ts": 2484, - "2447-island-boundary-slots/main.ts": 3456, - "2448-entries-null-arms-regex-arrays.ts": 2911, - "2450-private-instance-methods.ts": 2310, - "2451-private-fields.ts": 2058, - "2452-private-statics.ts": 2844, - "2453-private-accessors.ts": 2851, - "2454-private-generator-methods.ts": 2328, - "2455-private-brand-checks.ts": 2840, - "2456-private-async-methods.ts": 2932, - "2457-private-members.js": 2832, - "2460-qs-parse-grammar.ts": 2844, - "2461-qs-parse-options.ts": 2944, - "2462-qs-stringify.ts": 3219, - "2463-qs-escape-unescape.ts": 2133, - "2464-qs-require-forms.cjs": 2362, - "2470-mockable-module-shape.js": 3020, - "2471-record-keyed-write-hasown.js": 2921, - "2472-string-regexp-union.ts": 1528, - "2473-option-table-widths.js": 2792, - "2474-island-literal-forms.ts": 2730, - "2475-variadic-wrapper-island.js": 2962, - "2476-map-regex-values.ts": 1895, - "2480-recursive-record-tree.ts": 2781, - "2481-mutual-recursive-records.ts": 2829, - "2482-recursive-union-tree.ts": 2626, - "2483-recursive-record-cycles.ts": 2385, - "2484-json-stringify-circular.ts": 1936, - "2485-inspect-circular-refs.ts": 3139, - "2486-recursive-record-boundaries.ts": 3118, - "2487-recursive-deep-equal.ts": 2998, - "2488-ast-walker.ts": 3274, - "2490-find-miss-null-compare.ts": 2608, - "2491-strict-unit-compare-no-arm.ts": 2376, - "2492-loose-null-compare-unions.ts": 2805, - "2493-switch-unit-cases.ts": 2280, - "2494-no-arm-compare-effects.ts": 2159, - "2500-net-autosel-timeout.ts": 2195, - "2510-dyn-evolving-array-map.ts": 1961, - "2511-dyn-evolving-array-filter-foreach.ts": 2859, - "2512-dyn-evolving-array-mixed-push.ts": 1607, - "2520-private-statics-class-name-calls.ts": 2420, - "2521-private-statics-class-expression.ts": 1848, - "2522-private-statics-decorated.ts": 3008, - "2523-private-statics-aliased-class.ts": 2743, - "2530-object-destructuring-decl.ts": 2036, - "2531-array-tuple-destructuring-decl.ts": 2908, - "2532-param-destructuring-options.ts": 2917, - "2533-forof-destructuring.ts": 2821, - "2534-object-rest-decl.ts": 2914, - "2535-destructuring-assign-basics.ts": 2888, - "2536-destructuring-assign-nested.ts": 2697, - "2537-destructuring-assign-member-targets.ts": 1747, - "2538-destructuring-assign-class-source.ts": 2594, - "2539-class-instance-rest.ts": 2144, - "2540-accessor-destructuring-defaults.ts": 2790, - "2541-destructuring-eval-order.ts": 2901, - "2550-generics-keyof-pick.ts": 2724, - "2551-generics-value-aliases.ts": 2899, - "2552-generics-iface-methods.ts": 2924, - "2553-generics-signature-bindings.ts": 1690, - "2554-generics-frontier-mix.ts": 2607, - "2555-generics-keyof-writes.ts": 2074, - "2556-crypto-introspection.ts": 2165, - "2556-width-hybrid-shapes.ts": 1904, - "2557-tls-ca-store.ts": 3159, - "2557-width-field-lifts.ts": 3231, - "2558-index-signature-func-values.ts": 2869, - "2558-rejection-events.cjs": 1923, - "2559-index-signature-container-values.ts": 2319, - "2560-arraybuffer-dataview-set.ts": 3376, - "2561-object-is.ts": 3499, - "2562-intl-numberformat-en-us.ts": 2371, - "2563-stream-promises-pipeline.ts": 3059, - "2564-stream-promises-finished.ts": 1663, - "2565-stream-promises-js.cjs": 2464, - "2566-promise-reject-dyn-reason.js": 2041, - "2567-rest-spread-forward.js": 3238, - "2568-rest-spread-forward-dynamic.js": 2074, - "2569-upcast-identity.ts": 2471, - "2570-buffer-arg-validation.cjs": 4288, - "2571-searchparams-arg-validation.cjs": 2294, - "2572-readable-emitted-readable-flag.cjs": 2792, - "2573-fs-url-arg-ladders.cjs": 3144, - "2574-emitter-max-listeners-ladders.cjs": 2768, - "2575-string-destructuring-decl.ts": 3093, - "2576-string-destructuring-assign.ts": 1948, - "2577-builtin-global-destructuring.js": 1471, - "2578-jsval-into-unknown-rows.ts": 2895, - "2579-jsval-object-param-crossing.js": 2920, - "2580-jsval-routed-keyed-ops.js": 2793, - "2581-jsval-routed-calls.js": 2527, - "2582-jsval-object-statics.js": 3114, - "2582-jsval-routed-keyed-ops.js": 3012, - "2583-dyn-nullish-coalesce.js": 2872, - "2583-jsval-routed-calls.js": 3060, - "2584-jsval-object-statics.js": 3017, - "2584-union-dyn-collapse.ts": 3110, - "2585-dyn-nullish-coalesce.js": 3233, - "2585-unknown-array.ts": 3147, - "2586-object-assign-spread.js": 3063, - "2587-array-entries-forof.ts": 2868, - "2588-array-entries-chains.ts": 2948, - "2589-object-create-null.cjs": 2175, - "2590-object-create-dynamic.js": 2548, - "2591-ambient-generic-traps.ts": 2668, - "2592-ambient-trap-uncaught.ts": 2071, - "2593-generic-inert-bindings.ts": 2582, - "2594-nullish-generic-bindings.ts": 2649, - "2595-fs-arg-ladders.cjs": 3450, - "2596-net-arg-ladders.cjs": 3163, - "2597-dgram-send-ladders.cjs": 3471, - "2598-tls-arg-ladders.cjs": 2644, - "2599-stream-arg-ladders.cjs": 2952, - "2600-dyn-keyed-write-harness.js": 3162, - "2601-dyn-keyed-write-ops.js": 2780, - "2602-dyn-array-destructure.js": 2123, - "2603-island-keyed-write-dyn.js": 2776, - "2604-cycle-classes-mutual/main.ts": 2653, - "2605-cycle-three-module/main.ts": 2386, - "2606-dynamic-import-cycle/main.ts": 2580, - "2608-regex-named-groups.ts": 3189, - "2609-regex-named-replace.ts": 2460, - "2610-regex-named-matchall.ts": 1815, - "2611-regex-named-groups-js.cjs": 3151, - "2613-for-init-uninitialized-let.ts": 2759, - "2614-trap-binding-later-writes.ts": 1833, - "2615-nullish-field-record-binding.ts": 2522, - "2616-js-collect-probe-defers.js": 2932, - "2617-enum-static-field-import/main.ts": 2674, - "2618-ee-emit-override.ts": 2416, - "2619-ee-override-chain.ts": 2759, - "2620-ee-override-once-order.ts": 2863, - "2621-ee-override-error-throw.ts": 2669, - "2622-ee-override-filter.ts": 2972, - "2623-ee-job-queue.ts": 2457, - "2624-ee-override-js.cjs": 2851, - "2625-bytes-views.ts": 1866, - "2626-stream-event-names.ts": 3082, - "2627-stream-ticks-are-nextticks.ts": 2115, - "2628-stream-push-encodings.cjs": 2780, - "2629-stream-consumers.ts": 3333, - "2630-stream-consumers-errors.ts": 2597, - "2631-create-require/main.ts": 3215, - "2632-dyn-jsval-iterate.js": 3094, - "2633-island-promise-crossing.js": 2715, - "2634-stream-pipeline-arg-ladders.cjs": 2970, - "2635-trap-binding-unmappable-written.ts": 2644, - "2636-trap-binding-ambient-rooted-rewrite.ts": 2711, - "2637-create-require-bare/main.ts": 2926, - "2638-http-dyn-res-compat.cjs": 3551, - "2639-http-dyn-req-pause.cjs": 2114, - "2640-net-dyn-socket-compat.cjs": 3221, - "2641-http-agent-surface.cjs": 3393, - "2642-http-agent-maxsockets.cjs": 2445, - "2643-or-default-retag.ts": 2951, - "2644-http-client-url-argument.ts": 3003, - "2645-https-client-url-argument.ts": 1965, - "2646-top-level-await.ts": 1994, - "2647-top-level-await-modules/main.ts": 2883, - "2648-top-level-await-rejection.ts": 2548, - "2649-top-level-await-pending.ts": 2420, - "2650-top-level-await-self-import.ts": 2738, - "2651-top-level-await-pending-unhandled.ts": 1959, - "2652-top-level-await-dynamic/main.ts": 1976, - "2653-top-level-await-rejection-stops-loop.ts": 2530, - "2654-top-level-await-unrelated-rejection.ts": 2557, - "2655-top-level-await-cycle/main.ts": 2575, - "2656-top-level-await-cycle-order/main.ts": 2788, - "2657-top-level-await-cycle-dynamic/main.ts": 1945, - "2658-top-level-await-sync-completion/main.ts": 2486, - "2659-top-level-await-dynamic-cycle/main.ts": 2311, - "2660-top-level-await-cycle-rejection/main.ts": 1648, - "2661-top-level-await-dynamic-runtime-root/main.ts": 2615, - "2662-top-level-await-cycle-external-wait/main.ts": 2307, - "2663-top-level-await-dependency-errors/main.ts": 2145, - "2664-top-level-await-same-checkpoint-rejection.ts": 2652, - "2665-top-level-await-unhandled-listener-liveness.ts": 3003, - "2666-array-to-sorted.ts": 5347, - "2668-stored-number-array-iterator.ts": 2840, - "2669-array-copying-methods.ts": 2792, - "2670-uint8array-copy-iterate.ts": 2664, - "2671-array-copying-js.cjs": 2591, - "2672-http-request-response-callback.ts": 2953, - "2673-top-level-await-implicit-module.ts": 1743, - "2674-top-level-for-await-implicit-module.ts": 2697, - "2675-create-require-nested-esm.js": 2199, - "2675-process-self-reexec.ts": 2588, - "2676-indexed-read-strict-equality.ts": 2188, - "2676-record-clone-overrides.ts": 2426, - "2676-top-level-await-ambiguous/main.ts": 2482, - "2677-runtime-optional-closure.ts": 3477, - "2677-top-level-await-module-scope/main.ts": 2623, - "2678-date-instances.ts": 3208, - "2678-large-string-sparse-index.ts": 2981, - "2678-util-parseargs.ts": 5281, - "2679-util-parseargs-cjs.cjs": 3377, - "2680-util-parseargs-default.ts": 2722, - "2681-util-parseargs-dynamic.js": 1944, - "2682-fs-rename.ts": 3375, - "2683-filter-truthy-predicate.ts": 2838, - "2683-fs-rename-js.cjs": 1913, - "2684-filter-no-predicate-dyn.cjs": 2576, - "2684-fs-rename-abort.ts": 2742, - "2685-array-unshift-reverse.ts": 2654, - "2685-fs-write-sync.ts": 2517, - "2686-fs-file-handle.ts": 3648, - "2687-fsp-write-file-options.ts": 2384, - "2687-process-write-args.ts": 2846, - "2688-fs-stats-disk-fields.ts": 2938, - "2689-http-server-timeout-properties.ts": 3060, - "2690-https-server-timeout-option.ts": 2700, - "2691-retained-lowering-record-order.ts": 4234, - "2692-inline-record-assert-index.ts": 2826, - "2692-string-accumulation.ts": 2691, - "2693-math-constants.ts": 2761, - "2700-array-sort-complexity.ts": 2705, - "2700-http-static-trailers.ts": 2446, - "2700-wasi-core.ts": 2208, - "2701-array-sort-snapshot.ts": 2717, - "2701-http-static-trailer-wire.ts": 2689, - "2701-import-meta/main.mjs": 2846, - "2702-http-static-trailer-end.ts": 2522, - "2702-type-import-link-static/main.ts": 1984, - "2702-uint8array-to-sorted.ts": 2225, - "2703-array-sparse-sort.ts": 5044, - "2703-type-import-link-static-reexport/main.ts": 2359, - "2704-array-sparse-to-sorted.ts": 4461, - "2704-type-import-link-static-success/main.ts": 2324, - "2705-array-sparse-sort-append.ts": 5020, - "2705-type-import-link-dynamic/main.ts": 2074, - "2706-array-search-missing-needle.ts": 1941, - "2706-type-import-link-dynamic-success/main.ts": 2411, - "2707-array-search-huge-sparse.ts": 45551, - "2707-type-import-link-static-default-reexport/main.ts": 2522, - "2708-type-import-link-dynamic/main.ts": 2609, - "2720-array-read-parity.ts": 1979, - "2721-array-nested-missing-receiver.ts": 2483, - "2750-array-sparse-foundation.ts": 2217, - "2751-buffer-concat-sparse-list.ts": 2792, - "2752-array-optional-stores.ts": 2339, - "2753-array-optional-method-values.ts": 2060, - "2754-array-property-undefined.ts": 2275, - "2755-array-optional-literal-forwarding.ts": 2382, - "2780-array-parity-composition.ts": 6446, - "2781-array-missing-value-escape.ts": 1639, - "2782-array-sparse-callbacks.ts": 3365, - "2783-array-defaults-rest.ts": 2775, - "2784-array-reduce-missing-result.ts": 2916, - "2785-array-missing-destructuring.ts": 2952, - "2786-array-sparse-serialization.ts": 3296, - "2787-array-missing-string-arithmetic.ts": 2457, - "2788-array-missing-builtin-conversions.ts": 2610, - "2789-array-missing-optional-tostring.ts": 2734, - "2790-dynamic-import-self-name/main.ts": 2631, - "2791-record-optional-keys.ts": 1771, - "2792-record-optional-spread-entries.ts": 2836, - "2793-union-conversion-identity-capture.ts": 1991, - "2794-array-generic-callback-values.ts": 2454, - "2795-array-optional-typedarray-source.ts": 2778, - "2796-array-sparse-class-value-instanceof.ts": 1902, - "2800-array-expression-consumers.ts": 2537, - "2801-array-switch-consumers.ts": 2609, - "2820-array-missing-method-receivers.ts": 1866, - "2821-array-optional-numeric-comparisons.ts": 2322, - "2830-cjs-require-self-name/main.cjs": 1845, - "2840-finally-completions.ts": 2496, - "2841-using-sync.ts": 2927, - "2842-await-using.ts": 2618, - "2843-using-suppressed-error.ts": 2318, - "2844-node-disposable-resources.ts": 2824, - "2845-for-using-of.ts": 2486, - "2846-generator-using.ts": 2761, - "2850-async-generators-protocol.ts": 3258, - "2851-async-generators-values.ts": 2768, - "2852-timers-promises-interval.ts": 2398, - "2854-leading-bom-literals.ts": 1935, - "2855-searchparams-sort-complexity.ts": 2792, - "2856-dynamic-any-local-operators.ts": 2781, - "2857-branded-primitives.ts": 2351, - "2858-import-meta-resolve/main.mjs": 1967, - "2859-import-meta-resolve-dynamic/main.mjs": 1446, - "2860-require-resolve/main.cjs": 2029, - "2861-readable-iterator-close.ts": 3028, - "2862-web-readable-async-iteration.ts": 3505, - "2863-class-async-iterator.ts": 2866, - "2864-array-class-method-receivers.ts": 2760, - "2865-cjs-process-alias.cjs": 2491, - "2866-dyn-switch.ts": 1865, - "2867-array-shift-length.js": 1558, - "2868-empty-record-promise-presence.js": 2022, - "2869-nullish-mixed-lazy.ts": 2676, - "2870-and-dropped-truthy-arm.ts": 2329, - "2871-optional-promise-to-unknown.ts": 2191, - "2872-unobserved-dynamic-event.ts": 2513, - "2873-optional-receiver-loop-lifetime.js": 1923, - "2874-nullable-callback-field-cycle.js": 2614, - "2875-evolving-let-read-before-write.js": 2456, - "2876-class-unknown-roundtrip.ts": 2982, - "2877-child-unknown-roundtrip.ts": 2124, - "2878-class-private-unknown.cjs": 2900, - "2880-cjs-module-graph/main.cjs": 2229, - "2890-crypto-static-utility.ts": 3535, - "2891-json-record-key-escapes.ts": 3128, - "2892-windows-console-unicode.ts": 2483, - "2893-child-stdin-duplex.ts": 3150, - "2894-child-stdin-backpressure.ts": 2319, - "2895-child-stdin-write-after-end.ts": 3184, - "2896-child-stdin-write-after-finish.ts": 2909, - "2897-child-stdin-destroy.ts": 3007, - "2898-child-stdin-spawn-failure.ts": 2417, - "2899-nested-mutual-recursion.ts": 2782, - "2900-float64array-static.ts": 2797, - "2900-void-conditional-arrow.ts": 2455, - "2901-bigint-core.ts": 2012, - "2902-bigint-bytes.ts": 2175, - "2903-bigint-storage.ts": 2677, - "2904-bigint-errors.ts": 2992, - "2905-bigint-edges.ts": 2250, - "2906-bigint-wasi-width.ts": 2455, - "2910-overloaded-callable-alias.ts": 2480, - "2911-execfile-callback.ts": 2820, - "2912-execfile-callback-options.ts": 2673, - "2912-promisify-fs-readfile.ts": 1599, - "2913-builtin-callable-alias.ts": 2823, - "2914-fixed-tuple-call-spread.ts": 2909, - "2915-path-function-values.ts": 2957, - "2916-path-function-values-cjs.ts": 2512, - "2917-builtin-callable-widths.ts": 3024, - "2918-builtin-callable-widths-cjs.ts": 2656, - "2919-fs-function-values.ts": 3021, - "2920-fs-promises-function-values.ts": 2741, - "2921-zlib-callbacks.ts": 3153, - "2922-dyn-bitwise-not.cjs": 2708, - "2923-cjs-factory-export/main.cjs": 2093, - "2930-union-receiver-calls.ts": 2543, - "2931-union-dynamic-field-call.js": 2484, - "2932-create-require-program/main.ts": 2505, - "2933-static-dynamic-import/main.ts": 2593, - "2934-static-import-stored.ts": 2045, - "2935-module-namespace-values/main.ts": 2788, + "1550-param-defaults-func-set.ts": 3236, + "1551-dyn-receiver-methods.ts": 4427, + "1552-exec-options-record.ts": 3644, + "1553-truthy-hof-predicates.ts": 3271, + "1554-caught-into-unknown.ts": 3523, + "1555-index-spread-into-declared.ts": 4108, + "1556-union-retag-width-arms.ts": 2796, + "1557-url-host.ts": 3260, + "1558-any-joins-and-dyn-validation.ts": 2875, + "1559-conditional-spread-index-merge.ts": 2528, + "1560-forof-homogeneous-tuples.ts": 2537, + "1561-forof-strings.ts": 2246, + "1561-promise-then.ts": 3068, + "1562-optional-chain-tails.ts": 2705, + "1562-spawn-conditional-spread.ts": 3287, + "1563-forof-iterator-projections.ts": 2707, + "1563-string-raw-fold.ts": 2255, + "1564-fs-watch.ts": 3802, + "1564-string-raw.ts": 2918, + "1565-spawn-pipe-streams.ts": 3630, + "1565-union-element-join.ts": 3683, + "1566-child-duck-interface.ts": 3169, + "1567-server-close-override.ts": 2292, + "1568-x509-fingerprint.ts": 3260, + "1569-fsp-mkdir-unlink-chmod.ts": 2151, + "1570-child-unref-kill-reffed.ts": 8153, + "1571-optional-call-tostring-tail.ts": 2977, + "1571-stdin-set-raw-mode-non-tty.ts": 2223, + "1572-promise-reject-all-tuple.ts": 3566, + "1572-x509-validity-date-gettime.ts": 2517, + "1573-promisify-execfile-env-spread.ts": 3520, + "1573-tdz-scalar-forward-capture.ts": 2526, + "1574-dyn-optional-method-number-keys.ts": 3924, + "1574-promise-all-tuple-literal.ts": 2676, + "1575-unknown-assert-into-record.ts": 3519, + "1576-width-coercions.ts": 2683, + "1577-url-hostname.ts": 2337, + "1578-exec-input-optional.ts": 3059, + "1579-matchall-index.ts": 2856, + "1580-exec-env-conditional-spread.ts": 2426, + "1581-declare-const-read.ts": 3033, + "1582-timer-sleep-resolve.ts": 3454, + "1583-loops-and-stream-captures.ts": 2185, + "1584-union-field-unassigned.ts": 2354, + "1585-union-field-conditional-ctor.ts": 2702, + "1586-derived-field-before-super-init.ts": 2376, + "1590-js-unannotated.js": 2299, + "1591-js-closures.js": 3459, + "1592-js-classes.js": 3000, + "1593-js-jsdoc-records.js": 2837, + "1594-js-async.js": 3183, + "1595-js-island-gap/main.js": 3402, + "1596-cjs-modules/main.js": 2196, + "1597-mjs-graph/main.mjs": 3071, + "1598-cjs-builtin-require/main.js": 2199, + "1599-js-uncaught-throw.js": 2702, + "1600-assert-passing.ts": 3435, + "1601-assert-fail-exit.ts": 2059, + "1602-assert-caught-error.ts": 3377, + "1603-assert-scalar-messages.ts": 3468, + "1604-assert-deep-structures.ts": 3981, + "1605-assert-import-forms.ts": 3304, + "1606-assert-strict-module.ts": 3605, + "1607-assert-throws-match.ts": 2614, + "1608-cjs-assert/main.js": 3331, + "1609-assert-async.ts": 3158, + "1610-path-win32-full.ts": 3354, + "1611-url-file-bridge-neutral.ts": 2896, + "1612-cjs-module-globals.cjs": 1926, + "1613-cjs-esm-proxy-named/main.mjs": 2400, + "1614-js-fence-dodges.cjs": 2746, + "1615-cjs-export-shapes/main.cjs": 3057, + "1616-cjs-esm-lexer-invisible/main.mjs": 2969, + "1617-cjs-esm-lexer-visible/main.mjs": 3072, + "1618-cjs-esm-poisoned-tail/main.mjs": 2562, + "1619-cjs-esm-reexport-invisible/main.mjs": 2897, + "1620-cjs-require-effects-order/main.js": 3000, + "1621-cjs-require-cache-hit/main.js": 2851, + "1622-cjs-require-conditional/main.js": 3013, + "1623-cjs-require-diamond/main.js": 2407, + "1624-cjs-require-dir-mid-file/main.js": 2600, + "1625-cjs-require-lazy-fn/main.js": 2150, + "1626-cjs-require-mjs/main.js": 2871, + "1627-mjs-import-cjs-requires/main.mjs": 1644, + "1628-checked-dynamic-builtin-args.cjs": 3084, + "1629-require-main-filename.cjs": 2697, + "1630-inspect-scalars.ts": 2908, + "1630-rmsync-retry-options.cjs": 2250, + "1631-inspect-arrays.ts": 3807, + "1632-inspect-records.ts": 3072, + "1633-inspect-map-set.ts": 3749, + "1634-inspect-classes.ts": 3647, + "1635-inspect-buffer.ts": 2966, + "1636-util-format.ts": 2790, + "1637-inspect-dyn.ts": 3304, + "1638-inspect-cjs.cjs": 2542, + "1639-versions-openssl-probe.ts": 2867, + "1640-fd-read-decode.ts": 2932, + "1641-string-search.ts": 2902, + "1642-object-fromentries-rows.ts": 3493, + "1643-metadata-dyn-return.cjs": 3745, + "1644-ee-basics.ts": 2848, + "1645-ee-extends.ts": 2459, + "1646-ee-once-remove.ts": 3027, + "1647-ee-meta-events.ts": 2585, + "1648-ee-error-event.ts": 2283, + "1649-ee-names-counts.ts": 2675, + "1650-ee-prepend.ts": 2768, + "1651-ee-max-listeners.ts": 2226, + "1652-ee-snapshot.ts": 2979, + "1653-ee-cjs.cjs": 2570, + "1654-ee-namespace.ts": 2090, + "1655-spawnsync-neutral.ts": 4974, + "1656-execsync-neutral.ts": 2907, + "1657-spawn-async-neutral.ts": 3429, + "1660-buffer-read-write-num.ts": 3576, + "1661-buffer-encodings-full.ts": 3754, + "1662-string-decoder-encodings.ts": 3115, + "1663-buffer-compare-search-fill.ts": 3954, + "1664-dyn-fn-boundary.cjs": 3077, + "1665-dyn-fn-mustcall/main.cjs": 2296, + "1666-dyn-fn-identity.ts": 1815, + "1667-dyn-fn-not-callable.cjs": 3076, + "1668-dyn-fn-throws.cjs": 2849, + "1669-symbol-identity.ts": 2663, + "1670-symbol-registry.ts": 2947, + "1671-symbol-typeof.ts": 3427, + "1672-symbol-containers.ts": 2913, + "1673-symbol-cjs.cjs": 2504, + "1674-symbol-inspect.ts": 2841, + "1676-func-array-surface.ts": 3070, + "1677-emitter-listeners.ts": 3184, + "1678-emitter-dyn-listeners.cjs": 4068, + "1679-console-dyn.js": 3572, + "1680-assert-bytes.ts": 2927, + "1681-assert-funcs.ts": 3461, + "1685-stream-readable-basics.ts": 3135, + "1686-stream-readable-paused.ts": 2443, + "1687-stream-readable-flow-control.ts": 3237, + "1688-stream-writable-basics.ts": 2329, + "1689-stream-writable-async-drain.ts": 2789, + "1690-stream-duplex.ts": 2966, + "1691-stream-transform.ts": 2618, + "1692-stream-pipe.ts": 1917, + "1693-stream-pipe-backpressure.ts": 2276, + "1694-stream-destroy.ts": 3398, + "1695-stream-props.ts": 3260, + "1696-stream-read-inside-read.ts": 2732, + "1697-stream-tick-vs-timer.ts": 2767, + "1698-stream-uncaught-error.ts": 2710, + "1699-stream-callback-shapes.ts": 5108, + "1700-mustcall-common/main.cjs": 2603, + "1701-mustcall-exit-report/main.cjs": 3638, + "1702-dyn-proto-dispatch.cjs": 3719, + "1703-arguments-rest-props.cjs": 3420, + "1710-cjs-export-class/main.js": 3197, + "1711-cjs-export-single-values/main.js": 1720, + "1712-field-incdec.ts": 2250, + "1713-js-dyn-fields.js": 2301, + "1720-assert-throws-shape.ts": 3820, + "1721-assert-throws-regex-class.ts": 3123, + "1722-assert-rejects.ts": 3400, + "1723-assert-does-not-reject.ts": 2181, + "1724-assert-iferror.ts": 2290, + "1725-assert-symbols.ts": 2728, + "1726-promise-with-resolvers.ts": 3835, + "1727-assert-throws-shape-exit.ts": 2906, + "1730-countdown-symbol-keys/main.js": 3476, + "1731-symbol-field-shapes.cjs": 2330, + "1732-symbol-field-cross-module/main.js": 2189, + "1740-stream-extends-readable.ts": 2897, + "1741-stream-extends-writable.ts": 2368, + "1742-stream-extends-duplex-transform.ts": 2283, + "1743-stream-extends-vt-dispatch.ts": 3339, + "1744-stream-set-encoding.ts": 3916, + "1745-stream-encoding-js.cjs": 2742, + "1746-stream-for-await.ts": 3433, + "1747-stream-for-await-js.cjs": 2649, + "1750-http-agent-options.ts": 3028, + "1751-options-record-stance.ts": 3136, + "1760-surplus-args-drop.cjs": 2857, + "1761-emitter-special-event-names.cjs": 2907, + "1770-assert-dyn-strict.ts": 2622, + "1771-assert-dyn-deep.ts": 3046, + "1772-assert-dyn-js.cjs": 2864, + "1773-assert-dyn-exit.ts": 3097, + "1780-http-res-surface.ts": 3598, + "1781-http-server-shapes.cjs": 3736, + "1790-computed-key-folds.ts": 2845, + "1791-searchparams-core.ts": 3126, + "1792-searchparams-encoding.ts": 2170, + "1793-searchparams-iteration.ts": 2956, + "1794-searchparams-url-live.ts": 2603, + "1795-dyn-handle-request.cjs": 2396, + "1796-dyn-handle-body.cjs": 3535, + "1797-dyn-handle-socket.cjs": 3460, + "1798-dyn-handle-typed-box.ts": 2566, + "1800-immediate-basics.ts": 2566, + "1801-immediate-handle.ts": 2028, + "1802-immediate-unref-exit.ts": 3806, + "1803-timeout-refresh.ts": 2342, + "1804-timers-module.ts": 2401, + "1805-timer-callback-args.ts": 2781, + "1806-timer-delay-trunc.ts": 2824, + "1810-stream-options-const-record.ts": 2399, + "1811-stream-option-value-callbacks.cjs": 2961, + "1812-stream-super-options-forwarding.cjs": 3737, + "1813-stream-finished.ts": 3060, + "1814-stream-pipeline.cjs": 3701, + "1815-stream-state-reads.cjs": 2427, + "1820-static-block-basics.ts": 2518, + "1821-static-block-order.ts": 1976, + "1822-static-block-js.js": 3002, + "1823-static-instance-method-names.ts": 2691, + "1824-for-of-destructuring-defaults.ts": 2461, + "1825-exhaustive-typeof-switch.ts": 2514, + "1826-settimeout-arguments-callback.js": 2251, + "1830-enum-numeric-basics.ts": 2064, + "1831-enum-string-const-reverse.ts": 2264, + "1832-enum-modules/main.ts": 1833, + "1835-var-basics.ts": 2710, + "1836-var-loop-capture.ts": 3374, + "1837-var-undefined-hoisting.ts": 2917, + "1838-var-modules/main.ts": 2984, + "1839-var-js/main.cjs": 2891, + "1840-jsdoc-import-type-only/main.js": 1993, + "1850-overload-basics.ts": 2300, + "1851-overload-return-narrowing.ts": 2471, + "1852-overload-class-members.ts": 3006, + "1853-overload-modules/main.ts": 2503, + "1854-ambient-declare-fn.ts": 2630, + "1855-ambient-declare-fn-uncaught.ts": 3114, + "1870-unit-type-values.ts": 3109, + "1871-empty-array-never.ts": 2887, + "1872-template-tostring-composite.ts": 3584, + "1880-json-declared-field-order.ts": 3331, + "1881-default-anon/main.ts": 2353, + "1882-default-cjs-interop/main.ts": 2739, + "1883-default-exports/main.ts": 2650, + "1890-ns-imports/main.ts": 2779, + "1891-ns-reexport/main.ts": 2711, + "1940-class-values-basics.ts": 2460, + "1941-class-values-registry.ts": 3025, + "1942-class-expressions.ts": 2872, + "1943-class-statics-expanded.ts": 2580, + "1944-class-values-modules/main.ts": 2749, + "1950-generic-fn-values.ts": 2970, + "1951-generic-classes-basics.ts": 2980, + "1952-generic-class-statics-values.ts": 3062, + "1953-generic-class-hierarchy.ts": 2835, + "1954-generic-modules/main.ts": 1880, + "1960-namespace-basics.ts": 2265, + "1961-namespace-nested.ts": 2468, + "1962-namespace-classes.ts": 2516, + "1963-namespace-aliases.ts": 2375, + "1964-namespace-type-only.ts": 2816, + "1965-namespace-ambient.ts": 2803, + "1966-namespace-modules/main.ts": 3021, + "1967-namespace-alias-typeonly.ts": 2847, + "1968-namespace-import-eq-snapshot.ts": 2494, + "1970-decorators-basics.ts": 2822, + "1971-decorators-rebinding.ts": 2744, + "1972-decorators-throwing.ts": 2170, + "1973-decorators-ambient.ts": 2056, + "1980-primitive-proto-statics.ts": 2953, + "1981-date-utc.ts": 3276, + "1982-freeze-resolve-passthrough.ts": 2464, + "1983-array-tuple-surfaces.ts": 2644, + "1990-labels-basics.ts": 2635, + "1991-for-in-loops.ts": 3295, + "1992-small-syntax.ts": 3144, + "200-strings.ts": 2045, + "2000-generic-methods-basic.ts": 2851, + "2001-generic-methods-generic-class.ts": 2303, + "2002-generic-methods-inheritance.ts": 2257, + "2003-generic-methods-object-literal.ts": 3223, + "2004-generic-methods-statics.ts": 2748, + "201-templates.ts": 2400, + "2010-generators-basics.ts": 2273, + "2011-generators-forof.ts": 2704, + "2012-generators-return-throw.ts": 3247, + "2013-generators-sent-values.ts": 2662, + "2014-generators-values.ts": 3279, + "2015-generators-yieldstar.ts": 2320, + "2016-generators-rc-stress.ts": 2649, + "2017-generators-async.ts": 1806, + "2018-generators-uncaught.ts": 2418, + "2019-generators-loops.ts": 2694, + "2020-generic-value-bindings.ts": 3269, + "2021-generic-value-binding-modules/main.ts": 2143, + "2022-width-index-capture.ts": 3286, + "2023-width-readonly.ts": 2938, + "2024-width-array-elems.ts": 3159, + "2025-width-union-compose.ts": 3090, + "2026-width-spread.ts": 2628, + "2030-width-nested.ts": 3229, + "2031-width-tuples.ts": 2339, + "2032-cjs-export-assigned-class-expression/main.cjs": 2543, + "2033-property-assigned-class-extends.cjs": 1959, + "2035-ternary-array-retag.cjs": 2840, + "2036-evolving-array-decl.cjs": 2905, + "2037-fn-decl-hoisting.cjs": 2710, + "2038-evolving-array-js.cjs": 2879, + "2040-any-bindings.ts": 1964, + "2040-mixin-heritage.ts": 3294, + "2041-any-params-returns.ts": 2494, + "2041-mixin-values.ts": 3171, + "2042-any-flow-loops.ts": 2765, + "2042-mixin-modules/main.ts": 2821, + "2043-any-dom-values.ts": 1989, + "2043-mixin-rc-stress.ts": 2763, + "2044-vtable-sibling-slots.ts": 3156, + "2045-objlit-accessors-basic.ts": 2839, + "2045-parameter-properties.ts": 2262, + "2046-abstract-classes.ts": 2943, + "2046-objlit-accessors-effects.ts": 3238, + "2047-objlit-accessors-shapes.ts": 2962, + "2047-optional-class-fields.ts": 2352, + "2050-dynamic-import-own-module/main.ts": 2258, + "2051-dynamic-import-then/main.ts": 2628, + "2052-dynamic-import-self.ts": 2111, + "2053-typeof-static-fold.ts": 2331, + "2054-destructuring-island-source.ts": 2721, + "2060-empty-tuple.ts": 2638, + "2070-computed-key-folds.ts": 2482, + "2071-integer-key-enumeration-order.ts": 1999, + "2072-expando-function-members.ts": 2249, + "2073-destructuring-assignment.ts": 3060, + "2074-island-destructuring.ts": 3490, + "2075-index-signature-runtime-keys.ts": 3003, + "2080-destructuring-defaults.ts": 2782, + "2081-destructuring-rest.ts": 2626, + "2082-destructuring-assignment.ts": 2395, + "2085-destructuring-heads-rest-params.ts": 3137, + "2087-destructuring-for-heads.ts": 1934, + "2090-index-signature-number-keys.ts": 3257, + "2091-index-signature-string-intersection.ts": 2929, + "2092-package-imports/main.ts": 2114, + "2093-timers-promises.ts": 2678, + "2094-diagnostics-channel.ts": 3068, + "2095-js-catch-unknown.js": 2369, + "2096-os-type.ts": 2451, + "2097-js-evolving-globals.js": 2097, + "210-string-methods.ts": 2359, + "2100-stream-default-hwm.ts": 3022, + "2101-dyn-param-defaults.ts": 3172, + "2102-empty-pattern-decls.ts": 2881, + "2105-computed-key-static-folds.ts": 2838, + "2106-comma-expressions.ts": 1834, + "211-string-unicode.ts": 2972, + "2110-top-object-types.ts": 2238, + "2111-json-stringify-unknown.ts": 3135, + "2112-array-at-findlast.ts": 3283, + "2113-string-index-methods.js": 2879, + "212-string-aliasing-append.ts": 2677, + "2120-package-self-import/main.ts": 2837, + "2121-esm-cycle-inert-backedge/main.ts": 2507, + "2123-ambient-import-crash/main.ts": 2934, + "2124-imports-field-wildcard/main.ts": 2541, + "2140-uri-component-codecs.ts": 2133, + "2160-dc-tracing-channel.cjs": 2230, + "2161-js-object-literal-identity.cjs": 2537, + "2162-js-dyn-destructure.cjs": 2853, + "2163-js-selfref-const.cjs": 2693, + "2164-js-then-dyn-handler.cjs": 3004, + "2165-js-throw-dyn.cjs": 2225, + "2166-cjs-getter-this/main.cjs": 2804, + "2170-island-array-exits.ts": 2101, + "2171-island-json-stringify.ts": 2821, + "2172-island-regexp-boundary.ts": 2351, + "2190-new-object-and-string-wrappers.ts": 1908, + "2191-uri-encoders.ts": 3002, + "2192-object-default-tostring.ts": 2457, + "2193-discarded-stdlib-reads.ts": 2611, + "2194-ambient-undef-chains.ts": 1952, + "2195-require-missing-package/main.mjs": 3141, + "2196-island-computed-key-chain.ts": 2827, + "2210-dyn-promise-crossing.cjs": 3139, + "2211-dc-trace-promise.cjs": 2409, + "2212-unhandled-rejection-listener.cjs": 3057, + "2213-async-local-storage.cjs": 3299, + "2214-dc-bind-store.cjs": 3410, + "2215-process-emit-warning-exit.cjs": 3115, + "2240-width-class-into-record.ts": 2461, + "2241-width-record-into-class.ts": 2711, + "2242-width-statics-into-record.ts": 2854, + "2243-width-assert-satisfies-shapes.ts": 2928, + "2250-tagged-templates.ts": 2744, + "2252-class-iterators.ts": 3258, + "2253-union-coercions.ts": 3096, + "2260-http2-constants.cjs": 2383, + "2280-builtin-namespace-destructure.cjs": 2801, + "2281-domexception-atob-btoa.cjs": 2886, + "2282-queue-microtask.cjs": 2614, + "2283-structured-clone.cjs": 3700, + "2284-regexp-constructor.cjs": 2429, + "2285-iferror-dyn.cjs": 2807, + "2286-dyn-object-walks.cjs": 2926, + "2300-dyn-record-spread-and-keyed-access.cjs": 2890, + "2301-cjs-export-table-dom-attach.cjs": 2512, + "2310-process-next-tick.ts": 3216, + "2311-next-tick-js-callbacks.js": 2966, + "2312-stream-underscore-assign.ts": 3290, + "2313-stream-underscore-assign-js.cjs": 2122, + "2314-process-introspection.ts": 2917, + "2320-await-unit.ts": 2292, + "2321-emitter-static-setmax.cjs": 2256, + "2322-dyn-array-sort.cjs": 2432, + "2323-timer-callback-returns.ts": 2842, + "2330-tls-server-runtime-options.cjs": 2815, + "2331-tls-server-options-typed.ts": 3087, + "2350-nan-global.ts": 3034, + "2351-async-methods.ts": 2783, + "2352-void-coercions.ts": 3060, + "2353-decorators-member-ambient.ts": 2052, + "2354-decorators-expression-ambient.ts": 1987, + "2360-tuple-to-array.ts": 3001, + "2361-assign-index-record.ts": 2918, + "2362-execsync-inherit.ts": 2884, + "2363-nullish-retag.ts": 3048, + "2364-in-runtime-key.ts": 2311, + "2365-dyn-into-island.ts": 2070, + "2366-string-well-formed.ts": 2331, + "2367-regexp-escape.ts": 3110, + "2368-set-methods.ts": 2456, + "2369-promise-try.ts": 2986, + "2370-group-by.ts": 3578, + "2371-iterator-helpers.ts": 4030, + "2380-buffer-module-named-import.ts": 2871, + "2381-builtin-default-imports.js": 2605, + "2382-cycle-two-decl/main.ts": 2659, + "2383-cycle-assertdoc/main.js": 2644, + "2384-cycle-mixed-bindings/main.ts": 2274, + "2385-builtin-reexport-facade/main.ts": 2047, + "2386-string-to-chars.ts": 2950, + "2387-tonumber-argv.ts": 2189, + "2388-tonumber-grammar-zoo.ts": 2227, + "2389-tonumber-unary-plus.ts": 2546, + "2390-dot-requires/main.cjs": 2258, + "2391-default-builtin-imports/main.ts": 3224, + "2392-block-guard-alias-scope.ts": 2115, + "2393-loop-exit-guard-narrow.ts": 2686, + "2394-loop-narrow-containment.ts": 2464, + "2395-while-cond-guard.ts": 2793, + "2396-born-narrowed-decl.ts": 2989, + "2397-branch-kill-merge.ts": 2557, + "2398-switch-arm-kill.ts": 2776, + "2399-reassign-kill-polarity.ts": 2005, + "240-stdout-write.ts": 2170, + "2400-kill-return-edge.ts": 2417, + "2401-kill-break-staging.ts": 2710, + "2402-labeled-break-kill.ts": 2048, + "2403-kill-continue-backedge.ts": 2629, + "2404-kill-throw-catch.ts": 1738, + "2405-sibling-arm-narrow.ts": 2542, + "2406-switch-clause-sibling-narrow.ts": 1729, + "2407-infinite-loop-seal.ts": 2732, + "2408-loop-terminality-reopen.ts": 2758, + "2409-loop-body-return-not-terminal.ts": 2649, + "2410-stacked-cases-terminality.ts": 2587, + "2411-exhaustive-switch-terminality.ts": 2117, + "2412-dowhile-guard-trailing-test.ts": 2829, + "2413-dowhile-kill-renarrow.ts": 2634, + "2414-dowhile-continue-kill.ts": 2056, + "2415-dowhile-break-trailing-test.ts": 2838, + "2416-spread-ternary-positions.ts": 2794, + "2417-ternary-local-inference.ts": 1836, + "2418-wrapped-ternary-arms.ts": 2376, + "2419-selector-ternary-union.ts": 1886, + "2420-nullish-null-identity.ts": 2382, + "2421-float-lane-inference.ts": 2567, + "2422-ieee-div-rem-corners.ts": 2214, + "2423-param-null-reassign.ts": 2589, + "2424-ternary-miss-first-narrowing.ts": 2704, + "2425-elseif-head-exit-narrow.ts": 2085, + "2426-default-snapshot-mutable/main.ts": 2501, + "2427-perf-hooks-now.ts": 2322, + "2428-field-redeclare-inherited.ts": 2811, + "2429-destructure-class-instance.ts": 2113, + "2430-empty-literal-unknown-field.js": 2775, + "2431-primitive-ctor-values.ts": 2709, + "2432-generic-member-fields-async.ts": 3359, + "2433-as-const-command-tables.ts": 3152, + "2434-deferred-init-fields.ts": 2675, + "2435-loose-same-kind-equality.ts": 2929, + "2440-console-inspect-args.ts": 3616, + "2441-console-process-argv.ts": 2729, + "2442-union-literal-arm-widening.ts": 2394, + "2443-union-literal-shadow-narrowing.ts": 2878, + "2444-union-literal-reducer-spread.ts": 2611, + "2445-math-minmax-nary.ts": 2928, + "2446-performance-global.ts": 1959, + "2447-island-boundary-slots/main.ts": 3526, + "2448-entries-null-arms-regex-arrays.ts": 3606, + "2450-private-instance-methods.ts": 3040, + "2451-private-fields.ts": 2458, + "2452-private-statics.ts": 2875, + "2453-private-accessors.ts": 2477, + "2454-private-generator-methods.ts": 3086, + "2455-private-brand-checks.ts": 2830, + "2456-private-async-methods.ts": 3027, + "2457-private-members.js": 2823, + "2460-qs-parse-grammar.ts": 2369, + "2461-qs-parse-options.ts": 2633, + "2462-qs-stringify.ts": 2904, + "2463-qs-escape-unescape.ts": 2627, + "2464-qs-require-forms.cjs": 2308, + "2470-mockable-module-shape.js": 3113, + "2471-record-keyed-write-hasown.js": 3326, + "2472-string-regexp-union.ts": 2731, + "2473-option-table-widths.js": 3152, + "2474-island-literal-forms.ts": 2479, + "2475-variadic-wrapper-island.js": 3198, + "2476-map-regex-values.ts": 2520, + "2480-recursive-record-tree.ts": 2079, + "2481-mutual-recursive-records.ts": 2753, + "2482-recursive-union-tree.ts": 2627, + "2483-recursive-record-cycles.ts": 3056, + "2484-json-stringify-circular.ts": 3122, + "2485-inspect-circular-refs.ts": 2852, + "2486-recursive-record-boundaries.ts": 3348, + "2487-recursive-deep-equal.ts": 2661, + "2488-ast-walker.ts": 3060, + "2490-find-miss-null-compare.ts": 1733, + "2491-strict-unit-compare-no-arm.ts": 2221, + "2492-loose-null-compare-unions.ts": 2888, + "2493-switch-unit-cases.ts": 2663, + "2494-no-arm-compare-effects.ts": 2604, + "2500-net-autosel-timeout.ts": 2518, + "2510-dyn-evolving-array-map.ts": 2547, + "2511-dyn-evolving-array-filter-foreach.ts": 2095, + "2512-dyn-evolving-array-mixed-push.ts": 1858, + "2520-private-statics-class-name-calls.ts": 2236, + "2521-private-statics-class-expression.ts": 2886, + "2522-private-statics-decorated.ts": 2242, + "2523-private-statics-aliased-class.ts": 2547, + "2530-object-destructuring-decl.ts": 2810, + "2531-array-tuple-destructuring-decl.ts": 2637, + "2532-param-destructuring-options.ts": 1880, + "2533-forof-destructuring.ts": 2933, + "2534-object-rest-decl.ts": 2924, + "2535-destructuring-assign-basics.ts": 2850, + "2536-destructuring-assign-nested.ts": 3192, + "2537-destructuring-assign-member-targets.ts": 2938, + "2538-destructuring-assign-class-source.ts": 2800, + "2539-class-instance-rest.ts": 3105, + "2540-accessor-destructuring-defaults.ts": 2832, + "2541-destructuring-eval-order.ts": 2813, + "2550-generics-keyof-pick.ts": 2927, + "2551-generics-value-aliases.ts": 2674, + "2552-generics-iface-methods.ts": 2402, + "2553-generics-signature-bindings.ts": 3014, + "2554-generics-frontier-mix.ts": 2966, + "2555-generics-keyof-writes.ts": 2779, + "2556-crypto-introspection.ts": 3064, + "2556-width-hybrid-shapes.ts": 1985, + "2557-tls-ca-store.ts": 3012, + "2557-width-field-lifts.ts": 3351, + "2558-index-signature-func-values.ts": 3392, + "2558-rejection-events.cjs": 2929, + "2559-index-signature-container-values.ts": 3437, + "2560-arraybuffer-dataview-set.ts": 3189, + "2561-object-is.ts": 2016, + "2562-intl-numberformat-en-us.ts": 2324, + "2563-stream-promises-pipeline.ts": 2778, + "2564-stream-promises-finished.ts": 2282, + "2565-stream-promises-js.cjs": 2174, + "2566-promise-reject-dyn-reason.js": 2837, + "2567-rest-spread-forward.js": 3053, + "2568-rest-spread-forward-dynamic.js": 3336, + "2569-upcast-identity.ts": 2549, + "2570-buffer-arg-validation.cjs": 3495, + "2571-searchparams-arg-validation.cjs": 3289, + "2572-readable-emitted-readable-flag.cjs": 2702, + "2573-fs-url-arg-ladders.cjs": 2908, + "2574-emitter-max-listeners-ladders.cjs": 2125, + "2575-string-destructuring-decl.ts": 3056, + "2576-string-destructuring-assign.ts": 2769, + "2577-builtin-global-destructuring.js": 2592, + "2578-jsval-into-unknown-rows.ts": 3507, + "2579-jsval-object-param-crossing.js": 2689, + "2580-jsval-routed-keyed-ops.js": 3049, + "2581-jsval-routed-calls.js": 2613, + "2582-jsval-object-statics.js": 3028, + "2582-jsval-routed-keyed-ops.js": 2927, + "2583-dyn-nullish-coalesce.js": 2319, + "2583-jsval-routed-calls.js": 3227, + "2584-jsval-object-statics.js": 2921, + "2584-union-dyn-collapse.ts": 2532, + "2585-dyn-nullish-coalesce.js": 3154, + "2585-unknown-array.ts": 3043, + "2586-object-assign-spread.js": 3635, + "2587-array-entries-forof.ts": 2696, + "2588-array-entries-chains.ts": 2632, + "2589-object-create-null.cjs": 3471, + "2590-object-create-dynamic.js": 2856, + "2591-ambient-generic-traps.ts": 2325, + "2592-ambient-trap-uncaught.ts": 2711, + "2593-generic-inert-bindings.ts": 2516, + "2594-nullish-generic-bindings.ts": 2446, + "2595-fs-arg-ladders.cjs": 3442, + "2596-net-arg-ladders.cjs": 3131, + "2597-dgram-send-ladders.cjs": 3331, + "2598-tls-arg-ladders.cjs": 3733, + "2599-stream-arg-ladders.cjs": 2976, + "2600-dyn-keyed-write-harness.js": 3406, + "2601-dyn-keyed-write-ops.js": 2727, + "2602-dyn-array-destructure.js": 2959, + "2603-island-keyed-write-dyn.js": 2708, + "2604-cycle-classes-mutual/main.ts": 2723, + "2605-cycle-three-module/main.ts": 1625, + "2606-dynamic-import-cycle/main.ts": 2126, + "2608-regex-named-groups.ts": 2860, + "2609-regex-named-replace.ts": 2148, + "2610-regex-named-matchall.ts": 2297, + "2611-regex-named-groups-js.cjs": 2862, + "2613-for-init-uninitialized-let.ts": 2631, + "2614-trap-binding-later-writes.ts": 2032, + "2615-nullish-field-record-binding.ts": 2520, + "2616-js-collect-probe-defers.js": 2218, + "2617-enum-static-field-import/main.ts": 2916, + "2618-ee-emit-override.ts": 2896, + "2619-ee-override-chain.ts": 2889, + "2620-ee-override-once-order.ts": 2166, + "2621-ee-override-error-throw.ts": 2609, + "2622-ee-override-filter.ts": 3169, + "2623-ee-job-queue.ts": 3061, + "2624-ee-override-js.cjs": 2641, + "2625-bytes-views.ts": 2414, + "2626-stream-event-names.ts": 3336, + "2627-stream-ticks-are-nextticks.ts": 2921, + "2628-stream-push-encodings.cjs": 2936, + "2629-stream-consumers.ts": 2548, + "2630-stream-consumers-errors.ts": 2549, + "2631-create-require/main.ts": 3179, + "2632-dyn-jsval-iterate.js": 2810, + "2633-island-promise-crossing.js": 3789, + "2634-stream-pipeline-arg-ladders.cjs": 3204, + "2635-trap-binding-unmappable-written.ts": 2573, + "2636-trap-binding-ambient-rooted-rewrite.ts": 2836, + "2637-create-require-bare/main.ts": 3077, + "2638-http-dyn-res-compat.cjs": 3513, + "2639-http-dyn-req-pause.cjs": 3242, + "2640-net-dyn-socket-compat.cjs": 3276, + "2641-http-agent-surface.cjs": 2546, + "2642-http-agent-maxsockets.cjs": 2399, + "2643-or-default-retag.ts": 2038, + "2644-http-client-url-argument.ts": 3141, + "2645-https-client-url-argument.ts": 3327, + "2646-top-level-await.ts": 1674, + "2647-top-level-await-modules/main.ts": 2735, + "2648-top-level-await-rejection.ts": 2839, + "2649-top-level-await-pending.ts": 2632, + "2650-top-level-await-self-import.ts": 2130, + "2651-top-level-await-pending-unhandled.ts": 2661, + "2652-top-level-await-dynamic/main.ts": 2738, + "2653-top-level-await-rejection-stops-loop.ts": 2112, + "2654-top-level-await-unrelated-rejection.ts": 2041, + "2655-top-level-await-cycle/main.ts": 1850, + "2656-top-level-await-cycle-order/main.ts": 2731, + "2657-top-level-await-cycle-dynamic/main.ts": 2538, + "2658-top-level-await-sync-completion/main.ts": 2977, + "2659-top-level-await-dynamic-cycle/main.ts": 2760, + "2660-top-level-await-cycle-rejection/main.ts": 2805, + "2661-top-level-await-dynamic-runtime-root/main.ts": 2535, + "2662-top-level-await-cycle-external-wait/main.ts": 2399, + "2663-top-level-await-dependency-errors/main.ts": 2147, + "2664-top-level-await-same-checkpoint-rejection.ts": 2912, + "2665-top-level-await-unhandled-listener-liveness.ts": 2595, + "2666-array-to-sorted.ts": 5539, + "2668-stored-number-array-iterator.ts": 3042, + "2669-array-copying-methods.ts": 2580, + "2670-uint8array-copy-iterate.ts": 3366, + "2671-array-copying-js.cjs": 2250, + "2672-http-request-response-callback.ts": 2816, + "2673-top-level-await-implicit-module.ts": 2785, + "2674-top-level-for-await-implicit-module.ts": 1961, + "2675-create-require-nested-esm.js": 2652, + "2675-process-self-reexec.ts": 2948, + "2676-indexed-read-strict-equality.ts": 2688, + "2676-record-clone-overrides.ts": 2029, + "2676-top-level-await-ambiguous/main.ts": 2537, + "2677-runtime-optional-closure.ts": 3484, + "2677-top-level-await-module-scope/main.ts": 2041, + "2678-date-instances.ts": 2275, + "2678-large-string-sparse-index.ts": 2301, + "2678-util-parseargs.ts": 5332, + "2679-util-parseargs-cjs.cjs": 2235, + "2680-util-parseargs-default.ts": 2688, + "2681-util-parseargs-dynamic.js": 3031, + "2682-fs-rename.ts": 3590, + "2683-filter-truthy-predicate.ts": 3261, + "2683-fs-rename-js.cjs": 2894, + "2684-filter-no-predicate-dyn.cjs": 2218, + "2684-fs-rename-abort.ts": 2755, + "2685-array-unshift-reverse.ts": 2996, + "2685-fs-write-sync.ts": 3069, + "2686-fs-file-handle.ts": 4210, + "2687-fsp-write-file-options.ts": 2069, + "2687-process-write-args.ts": 2527, + "2688-fs-stats-disk-fields.ts": 2259, + "2689-http-server-timeout-properties.ts": 2541, + "2690-https-server-timeout-option.ts": 1835, + "2691-retained-lowering-record-order.ts": 3261, + "2692-inline-record-assert-index.ts": 2994, + "2692-string-accumulation.ts": 2802, + "2693-math-constants.ts": 2159, + "2700-array-sort-complexity.ts": 3020, + "2700-http-static-trailers.ts": 2315, + "2700-wasi-core.ts": 2595, + "2701-array-sort-snapshot.ts": 2502, + "2701-http-static-trailer-wire.ts": 2176, + "2701-import-meta/main.mjs": 3392, + "2702-http-static-trailer-end.ts": 2071, + "2702-type-import-link-static/main.ts": 2443, + "2702-uint8array-to-sorted.ts": 2965, + "2703-array-sparse-sort.ts": 3909, + "2703-type-import-link-static-reexport/main.ts": 2704, + "2704-array-sparse-to-sorted.ts": 3697, + "2704-type-import-link-static-success/main.ts": 2487, + "2705-array-sparse-sort-append.ts": 4843, + "2705-type-import-link-dynamic/main.ts": 2701, + "2706-array-search-missing-needle.ts": 2539, + "2706-type-import-link-dynamic-success/main.ts": 2462, + "2707-array-search-huge-sparse.ts": 45317, + "2707-type-import-link-static-default-reexport/main.ts": 2670, + "2708-type-import-link-dynamic/main.ts": 2350, + "2720-array-read-parity.ts": 1959, + "2721-array-nested-missing-receiver.ts": 2561, + "2750-array-sparse-foundation.ts": 2117, + "2751-buffer-concat-sparse-list.ts": 1676, + "2752-array-optional-stores.ts": 2649, + "2753-array-optional-method-values.ts": 2199, + "2754-array-property-undefined.ts": 2439, + "2755-array-optional-literal-forwarding.ts": 2745, + "2780-array-parity-composition.ts": 7200, + "2781-array-missing-value-escape.ts": 2902, + "2782-array-sparse-callbacks.ts": 3115, + "2783-array-defaults-rest.ts": 2837, + "2784-array-reduce-missing-result.ts": 2800, + "2785-array-missing-destructuring.ts": 3065, + "2786-array-sparse-serialization.ts": 2409, + "2787-array-missing-string-arithmetic.ts": 2854, + "2788-array-missing-builtin-conversions.ts": 2132, + "2789-array-missing-optional-tostring.ts": 1804, + "2790-dynamic-import-self-name/main.ts": 2534, + "2791-record-optional-keys.ts": 2401, + "2792-record-optional-spread-entries.ts": 2956, + "2793-union-conversion-identity-capture.ts": 3189, + "2794-array-generic-callback-values.ts": 2738, + "2795-array-optional-typedarray-source.ts": 3311, + "2796-array-sparse-class-value-instanceof.ts": 2925, + "2800-array-expression-consumers.ts": 2649, + "2801-array-switch-consumers.ts": 2865, + "2820-array-missing-method-receivers.ts": 1887, + "2821-array-optional-numeric-comparisons.ts": 2197, + "2830-cjs-require-self-name/main.cjs": 2632, + "2840-finally-completions.ts": 3271, + "2841-using-sync.ts": 2134, + "2842-await-using.ts": 1855, + "2843-using-suppressed-error.ts": 1631, + "2844-node-disposable-resources.ts": 2377, + "2845-for-using-of.ts": 2775, + "2846-generator-using.ts": 2854, + "2850-async-generators-protocol.ts": 2671, + "2851-async-generators-values.ts": 2378, + "2852-timers-promises-interval.ts": 2688, + "2854-leading-bom-literals.ts": 2637, + "2855-searchparams-sort-complexity.ts": 1784, + "2856-dynamic-any-local-operators.ts": 2953, + "2857-branded-primitives.ts": 2640, + "2858-import-meta-resolve/main.mjs": 2725, + "2859-import-meta-resolve-dynamic/main.mjs": 1820, + "2860-require-resolve/main.cjs": 2780, + "2861-readable-iterator-close.ts": 3397, + "2862-web-readable-async-iteration.ts": 3414, + "2863-class-async-iterator.ts": 2684, + "2864-array-class-method-receivers.ts": 2886, + "2865-cjs-process-alias.cjs": 2940, + "2866-dyn-switch.ts": 2042, + "2867-array-shift-length.js": 1841, + "2868-empty-record-promise-presence.js": 1948, + "2869-nullish-mixed-lazy.ts": 2998, + "2870-and-dropped-truthy-arm.ts": 1701, + "2871-optional-promise-to-unknown.ts": 2708, + "2872-unobserved-dynamic-event.ts": 1982, + "2873-optional-receiver-loop-lifetime.js": 2129, + "2874-nullable-callback-field-cycle.js": 2941, + "2875-evolving-let-read-before-write.js": 2038, + "2876-class-unknown-roundtrip.ts": 3117, + "2877-child-unknown-roundtrip.ts": 2838, + "2878-class-private-unknown.cjs": 2816, + "2880-cjs-module-graph/main.cjs": 2623, + "2890-crypto-static-utility.ts": 3216, + "2891-json-record-key-escapes.ts": 3136, + "2892-windows-console-unicode.ts": 2711, + "2893-child-stdin-duplex.ts": 2652, + "2894-child-stdin-backpressure.ts": 3049, + "2895-child-stdin-write-after-end.ts": 2813, + "2896-child-stdin-write-after-finish.ts": 1947, + "2897-child-stdin-destroy.ts": 3101, + "2898-child-stdin-spawn-failure.ts": 3024, + "2899-nested-mutual-recursion.ts": 2834, + "2900-float64array-static.ts": 2695, + "2900-void-conditional-arrow.ts": 2641, + "2901-bigint-core.ts": 2912, + "2902-bigint-bytes.ts": 2182, + "2903-bigint-storage.ts": 2897, + "2904-bigint-errors.ts": 2971, + "2905-bigint-edges.ts": 2917, + "2906-bigint-wasi-width.ts": 2941, + "2910-overloaded-callable-alias.ts": 2710, + "2911-execfile-callback.ts": 3076, + "2912-execfile-callback-options.ts": 1918, + "2912-promisify-fs-readfile.ts": 2767, + "2913-builtin-callable-alias.ts": 2872, + "2914-fixed-tuple-call-spread.ts": 2555, + "2915-path-function-values.ts": 2085, + "2916-path-function-values-cjs.ts": 2881, + "2917-builtin-callable-widths.ts": 2912, + "2918-builtin-callable-widths-cjs.ts": 1902, + "2919-fs-function-values.ts": 2935, + "2920-fs-promises-function-values.ts": 2882, + "2921-zlib-callbacks.ts": 2124, + "2922-dyn-bitwise-not.cjs": 2707, + "2923-cjs-factory-export/main.cjs": 2830, + "2930-union-receiver-calls.ts": 2484, + "2931-union-dynamic-field-call.js": 2846, + "2932-create-require-program/main.ts": 3067, + "2933-static-dynamic-import/main.ts": 2168, + "2934-static-import-stored.ts": 3004, + "2935-module-namespace-values/main.ts": 2141, "2936-static-loose-equality.ts": 3392, - "2937-bitwise-hot-loop.ts": 2487, - "2938-fs-sync-overloads.cjs": 1878, - "2939-child-shell-text.ts": 3433, - "2940-date-parse.ts": 2705, - "2940-fsp-realpath.ts": 2908, - "2941-fsp-lstat-identity.ts": 3091, - "2941-process-exit-code.ts": 2544, - "2942-fsp-readdir-dirent.ts": 3069, - "2942-process-exit-code-override.ts": 2534, - "2943-process-exit-code-invalid.ts": 2277, - "2944-process-exit-code-wrap.ts": 1815, - "2945-url-origin-username.ts": 2639, - "2946-child-fork-ipc/main.ts": 3716, - "2946-url-port-hash.ts": 1906, - "2947-set-readonly-seeds.ts": 2763, - "2948-child-fork-eof-callback/main.ts": 2163, - "2948-stdio-callback-record.ts": 2566, - "2949-child-fork-default/main.mjs": 3027, - "2949-url-password.ts": 1993, - "2950-fs-descriptor-publication.ts": 2687, - "2951-math-static-analytic.ts": 3185, - "2952-math-static-remaining.ts": 2865, - "2953-http-header-validation.ts": 2969, - "2954-http-outgoing-headers.ts": 3565, - "2955-http-static-state.ts": 2954, - "2956-http-static-informational.ts": 2194, - "2957-http-static-response-controls.ts": 3186, - "2961-emitter-computed-names.cjs": 1565, - "2962-emitter-computed-optional.ts": 2714, - "2963-child-fork-dispatch/main.ts": 3146, - "2964-indexed-compound.ts": 3331, - "2966-numeric-array-read-fusion.ts": 3033, - "2967-numeric-array-read-lifetime.ts": 2835, - "2968-numeric-array-borrow.ts": 2871, - "2969-scalar-record-results.ts": 2889, - "2970-constant-numeric-tables.ts": 3083, - "2971-constant-table-modules/main.ts": 2199, - "2972-http-static-distinct-snapshots.ts": 3234, - "2972-math-receiver-borrow.ts": 3625, - "2973-http-static-agent.ts": 2730, - "2973-integer-bitwise-arithmetic.ts": 2687, - "2974-array-search-from-index.ts": 104135, - "2974-http-static-module-values.ts": 2450, - "2974-numeric-remainder.ts": 3031, - "2975-bigint-default-radix.ts": 2379, - "2975-http-static-client-controls.ts": 2663, - "2976-http-static-incoming-state.ts": 2293, - "2976-json-stringify-no-arguments.js": 2688, - "2977-http-static-incoming-timeout.ts": 2143, - "2977-nested-array-binding-defaults.js": 2455, - "2978-http-static-client-timeout.ts": 2987, - "2978-regexp-optional-subject.js": 2083, - "2979-array-search-mixed-needles.js": 2924, - "2979-http-static-server-timeout.ts": 2502, - "2980-http-static-server-timeout-default.ts": 2655, - "2980-string-position-arguments.js": 2015, - "2981-http-static-events.ts": 2563, - "2981-string-optional-positions.ts": 2841, - "2982-http-static-close-all.ts": 1931, - "2982-string-position-coercion-order.js": 2986, - "2983-http-static-close-idle.ts": 2485, - "2984-http-static-close-upgrade.ts": 2815, - "2985-http-static-message-destroy.ts": 2511, - "2986-http-static-client-socket-finish.ts": 2889, - "2987-http-static-timeout-errors.ts": 2695, - "2988-http-static-client-abort.ts": 2770, - "2989-http-static-response-timeout-handled.ts": 2973, - "2990-http-static-request-timeout-handled.ts": 3045, - "2991-array-indexed-equality.ts": 3039, - "2992-stream-rows.ts": 1990, - "2993-fiber-stack-lifetimes.ts": 3353, - "2994-fromcharcode-scalar.ts": 2251, - "2995-math-hyperbolic.ts": 3028, - "2996-math-near-one.ts": 2750, - "2997-math-integer-float.ts": 2792, - "300-if-else.ts": 2615, - "3001-caught-typeof-object.js": 2565, - "3002-promise-then-two.ts": 3076, - "301-while.ts": 2690, - "302-for.ts": 2617, - "3020-string-last-index-position.ts": 2669, - "3021-buffer-union-narrow-callback.ts": 3133, - "3022-string-affix-positions.ts": 2471, - "3023-string-affix-position-coercion.js": 2793, - "3024-string-number-narrow-for-in.ts": 2773, - "3025-string-search-position-coercion.js": 2152, - "3026-array-last-index-of.js": 2967, - "3027-array-last-index-of-records.ts": 1994, - "3028-string-search-dynamic-needle.js": 2238, - "3029-string-search-union-needle.js": 2519, - "303-break-continue.ts": 2536, - "3030-array-search-no-arg.js": 2653, - "3031-array-relative-index-coercion.js": 3093, - "3031-string-last-index-search-value.js": 1619, - "3032-string-search-value.js": 2450, - "3033-string-search-needle-coercion.js": 2494, - "3034-arguments-with-parameters.js": 3025, - "3035-string-positioned-search-value.js": 3075, - "3036-string-object-search-value.js": 2233, - "3037-number-nullish-conversion.js": 2181, - "3038-number-scalar-unions.ts": 2410, - "3039-string-repeat-count.js": 2478, - "304-compound-incdec.ts": 2719, - "3040-string-prototype-call.js": 3243, - "3041-string-prototype-object-call.js": 2455, - "3042-string-padding-coercion.js": 3099, - "3043-string-split-arguments.js": 2355, - "3044-array-slice-splice-positions.js": 2214, - "3045-array-indexed-mutation.js": 3434, - "3046-array-indexed-ref-identity.ts": 2361, - "3047-object-prototype-tag.js": 3196, - "3048-object-own-prototype.ts": 3472, - "3049-array-flat-depth.ts": 1949, - "305-truthiness.ts": 2568, - "3050-array-splice-insert.ts": 3099, - "3051-array-join-default.ts": 1846, - "3052-array-construction.ts": 3399, - "3053-array-construction-js.js": 1676, - "3054-dynamic-abort-record.ts": 1731, - "3055-default-builtin-nodenext/main.ts": 2687, - "3056-default-builtin-bundler/main.ts": 2789, - "3057-default-builtin-nodenext-dynamic/main.ts": 2579, - "3058-optional-array-chain-join.ts": 2967, - "3059-arguments-property-names.ts": 2947, - "3061-concurrent-fiber-stacks.ts": 2717, - "3062-runtime-optional-record-guards.ts": 3531, - "3063-runtime-optional-class-guards.ts": 3234, - "3064-installed-entry-imports/main.ts": 2104, - "3065-installed-entry-js/main.js": 2454, - "3066-source-debugging/main.ts": 2680, - "3067-cjs-function-export-require/main.cjs": 2781, - "3068-debug-variables/main.ts": 2201, - "3068-url-checked-identity.ts": 3005, - "3069-set-checked-seed.js": 3167, - "3069-tuple-spread.ts": 3057, - "3070-checked-object-accessors.js": 3314, - "3070-collection-views.ts": 2586, - "3071-checked-specialization-narrowing.js": 2429, - "3071-map-contextual-record-seeds.ts": 2886, - "3072-optional-union-receivers.ts": 3001, - "3072-weak-process-streams.js": 2971, - "3073-optional-callable-module.js": 2030, - "3073-union-keyed-reads.ts": 3228, - "3074-discriminated-intersections.ts": 3008, - "3075-recursive-contextual-literals.ts": 3333, - "3076-nullish-record-defaults.ts": 3030, - "3077-optional-union-array-reads.ts": 2968, - "3078-forward-mutable-captures.ts": 1926, - "3079-forward-mutable-tdz.ts": 2889, - "3080-exhaustive-never-bindings.ts": 2787, - "3081-recursive-array-destinations.ts": 2576, - "3082-forward-write-unwind.ts": 2875, + "2937-bitwise-hot-loop.ts": 2114, + "2938-fs-sync-overloads.cjs": 1863, + "2939-child-shell-text.ts": 3119, + "2940-date-parse.ts": 2606, + "2940-fsp-realpath.ts": 2319, + "2941-fsp-lstat-identity.ts": 3102, + "2941-process-exit-code.ts": 2025, + "2942-fsp-readdir-dirent.ts": 2835, + "2942-process-exit-code-override.ts": 2255, + "2943-process-exit-code-invalid.ts": 2733, + "2944-process-exit-code-wrap.ts": 1969, + "2945-url-origin-username.ts": 1974, + "2946-child-fork-ipc/main.ts": 3772, + "2946-url-port-hash.ts": 2074, + "2947-set-readonly-seeds.ts": 3071, + "2948-child-fork-eof-callback/main.ts": 3013, + "2948-stdio-callback-record.ts": 2065, + "2949-child-fork-default/main.mjs": 2829, + "2949-url-password.ts": 2408, + "2950-fs-descriptor-publication.ts": 2677, + "2951-math-static-analytic.ts": 2349, + "2952-math-static-remaining.ts": 2335, + "2953-http-header-validation.ts": 2772, + "2954-http-outgoing-headers.ts": 3428, + "2955-http-static-state.ts": 2945, + "2956-http-static-informational.ts": 2218, + "2957-http-static-response-controls.ts": 2590, + "2961-emitter-computed-names.cjs": 2830, + "2962-emitter-computed-optional.ts": 2777, + "2963-child-fork-dispatch/main.ts": 3250, + "2964-indexed-compound.ts": 3270, + "2966-numeric-array-read-fusion.ts": 2442, + "2967-numeric-array-read-lifetime.ts": 2772, + "2968-numeric-array-borrow.ts": 3227, + "2969-scalar-record-results.ts": 3038, + "2970-constant-numeric-tables.ts": 2771, + "2971-constant-table-modules/main.ts": 1871, + "2972-http-static-distinct-snapshots.ts": 3053, + "2972-math-receiver-borrow.ts": 2947, + "2973-http-static-agent.ts": 3397, + "2973-integer-bitwise-arithmetic.ts": 2920, + "2974-array-search-from-index.ts": 124091, + "2974-http-static-module-values.ts": 2984, + "2974-numeric-remainder.ts": 3296, + "2975-bigint-default-radix.ts": 2470, + "2975-http-static-client-controls.ts": 2919, + "2976-http-static-incoming-state.ts": 2589, + "2976-json-stringify-no-arguments.js": 2303, + "2977-http-static-incoming-timeout.ts": 2944, + "2977-nested-array-binding-defaults.js": 2175, + "2978-http-static-client-timeout.ts": 2391, + "2978-regexp-optional-subject.js": 2308, + "2979-array-search-mixed-needles.js": 2358, + "2979-http-static-server-timeout.ts": 1739, + "2980-http-static-server-timeout-default.ts": 2883, + "2980-string-position-arguments.js": 2832, + "2981-http-static-events.ts": 2774, + "2981-string-optional-positions.ts": 2352, + "2982-http-static-close-all.ts": 2171, + "2982-string-position-coercion-order.js": 2155, + "2983-http-static-close-idle.ts": 3021, + "2984-http-static-close-upgrade.ts": 2125, + "2985-http-static-message-destroy.ts": 2402, + "2986-http-static-client-socket-finish.ts": 2843, + "2987-http-static-timeout-errors.ts": 3151, + "2988-http-static-client-abort.ts": 2768, + "2989-http-static-response-timeout-handled.ts": 2766, + "2990-http-static-request-timeout-handled.ts": 3159, + "2991-array-indexed-equality.ts": 2285, + "2992-stream-rows.ts": 2873, + "2993-fiber-stack-lifetimes.ts": 3425, + "2994-fromcharcode-scalar.ts": 3028, + "2995-math-hyperbolic.ts": 2938, + "2996-math-near-one.ts": 3222, + "2997-math-integer-float.ts": 2299, + "300-if-else.ts": 2867, + "3001-caught-typeof-object.js": 2563, + "3002-promise-then-two.ts": 3204, + "301-while.ts": 2926, + "302-for.ts": 2606, + "3020-string-last-index-position.ts": 2319, + "3021-buffer-union-narrow-callback.ts": 2195, + "3022-string-affix-positions.ts": 2341, + "3023-string-affix-position-coercion.js": 2752, + "3024-string-number-narrow-for-in.ts": 1609, + "3025-string-search-position-coercion.js": 2728, + "3026-array-last-index-of.js": 2413, + "3027-array-last-index-of-records.ts": 2116, + "3028-string-search-dynamic-needle.js": 1998, + "3029-string-search-union-needle.js": 2405, + "303-break-continue.ts": 2031, + "3030-array-search-no-arg.js": 3128, + "3031-array-relative-index-coercion.js": 2454, + "3031-string-last-index-search-value.js": 2375, + "3032-string-search-value.js": 2888, + "3033-string-search-needle-coercion.js": 2002, + "3034-arguments-with-parameters.js": 3443, + "3035-string-positioned-search-value.js": 2991, + "3036-string-object-search-value.js": 2678, + "3037-number-nullish-conversion.js": 2958, + "3038-number-scalar-unions.ts": 2263, + "3039-string-repeat-count.js": 2105, + "304-compound-incdec.ts": 2747, + "3040-string-prototype-call.js": 3083, + "3041-string-prototype-object-call.js": 2578, + "3042-string-padding-coercion.js": 2198, + "3043-string-split-arguments.js": 2450, + "3044-array-slice-splice-positions.js": 3038, + "3045-array-indexed-mutation.js": 3285, + "3046-array-indexed-ref-identity.ts": 1964, + "3047-object-prototype-tag.js": 2750, + "3048-object-own-prototype.ts": 3516, + "3049-array-flat-depth.ts": 2507, + "305-truthiness.ts": 3022, + "3050-array-splice-insert.ts": 3679, + "3051-array-join-default.ts": 2848, + "3052-array-construction.ts": 2982, + "3053-array-construction-js.js": 3024, + "3054-dynamic-abort-record.ts": 2146, + "3055-default-builtin-nodenext/main.ts": 2904, + "3056-default-builtin-bundler/main.ts": 2933, + "3057-default-builtin-nodenext-dynamic/main.ts": 2973, + "3058-optional-array-chain-join.ts": 2285, + "3059-arguments-property-names.ts": 2296, + "3061-concurrent-fiber-stacks.ts": 1843, + "3062-runtime-optional-record-guards.ts": 3177, + "3063-runtime-optional-class-guards.ts": 2891, + "3064-installed-entry-imports/main.ts": 2942, + "3065-installed-entry-js/main.js": 2574, + "3066-source-debugging/main.ts": 2037, + "3067-cjs-function-export-require/main.cjs": 2917, + "3068-debug-variables/main.ts": 2538, + "3068-url-checked-identity.ts": 2749, + "3069-set-checked-seed.js": 2271, + "3069-tuple-spread.ts": 2404, + "3070-checked-object-accessors.js": 3199, + "3070-collection-views.ts": 3106, + "3071-checked-specialization-narrowing.js": 2927, + "3071-map-contextual-record-seeds.ts": 3315, + "3072-optional-union-receivers.ts": 3294, + "3072-weak-process-streams.js": 2924, + "3073-optional-callable-module.js": 2944, + "3073-union-keyed-reads.ts": 2310, + "3074-discriminated-intersections.ts": 2137, + "3075-recursive-contextual-literals.ts": 3075, + "3076-nullish-record-defaults.ts": 2013, + "3077-optional-union-array-reads.ts": 3340, + "3078-forward-mutable-captures.ts": 3407, + "3079-forward-mutable-tdz.ts": 3267, + "3080-exhaustive-never-bindings.ts": 2952, + "3081-recursive-array-destinations.ts": 2842, + "3082-forward-write-unwind.ts": 2956, "3083-set-string-seed.ts": 2684, - "3084-record-own-membership.ts": 3102, - "3085-conditional-record-construction.ts": 1925, - "3086-error-constructor-options.ts": 3227, - "3087-error-options-lifetime.ts": 2113, - "3088-array-wide-callbacks.ts": 2993, - "3089-array-find-narrowing.ts": 3128, - "3090-json-discriminated-records.ts": 3480, - "3091-json-recursive-discriminants.ts": 2300, - "3092-number-union-predicates.ts": 2639, - "3093-error-option-data.ts": 2191, - "3094-json-replacer-traversal.ts": 2898, - "3095-json-reviver-traversal.ts": 2824, - "3096-json-callback-nonfinite.ts": 1927, - "3097-json-callback-reentrancy.ts": 3321, - "3098-json-callback-space.ts": 2551, - "3099-json-callback-functions.ts": 3507, - "3100-json-callback-holder.js": 3048, - "3101-json-callback-bytes.ts": 2658, - "3102-json-unknown-fields.ts": 2725, - "3103-scalar-record-nested-control-flow.ts": 3195, - "3104-native-analysis-tables-loops.ts": 1557, - "3105-nullable-collections.ts": 1888, - "3106-mixed-insertion-spreads.ts": 3368, - "3107-nullable-collection-lifetimes.ts": 3149, - "3108-for-await-sync-arrays.js": 4447, - "3108-identity-map-keys.ts": 3401, - "3109-destructuring-unknown-defaults.js": 2735, - "3109-identity-union-collections.ts": 3270, - "3110-builtin-error-families.ts": 2441, - "3110-identity-collection-mutation.ts": 2906, - "3111-identity-collection-cycles.ts": 3069, - "3112-union-switch-control-flow.ts": 2641, - "3113-union-array-removal.ts": 3416, - "3114-union-record-field-write.ts": 3033, - "3115-zlib-static-compression-levels.ts": 2443, - "3116-sequence-expression-lifetimes.ts": 3044, - "3117-unknown-switch-control-flow.ts": 2684, - "3118-recursive-union-spread.ts": 2422, - "3119-runtime-optional-spread.ts": 2447, - "3120-dynamic-property-descriptors.js": 3293, - "3120-generator-method-loop-bindings.ts": 3248, - "3120-ir-nonfinite-numbers.ts": 3000, - "3121-compound-assignment-values.js": 2549, - "3121-dynamic-accessor-descriptors.js": 3250, - "3122-dynamic-delete-descriptors.cjs": 2600, - "3122-dynamic-delete-descriptors.js": 2091, - "3122-js-async-class-methods.js": 2297, - "3123-destructured-global-tdz.js": 2836, - "3124-array-prototype-borrow.js": 3537, - "3125-regex-global-match.ts": 2402, - "3126-js-number-radix/main.ts": 3052, - "3127-spawn-runtime-options.ts": 3285, - "3128-regex-last-index.ts": 3076, - "3129-js-token-union/main.ts": 2700, - "3130-child-generic-streams.ts": 3044, - "3131-child-rest-listeners.js": 2943, - "3132-child-generic-stream-completion.ts": 6235, - "3133-text-decoder-streaming.ts": 2265, - "3134-fs-vectors.ts": 2815, - "3135-fs-file-handle-controls.ts": 2278, - "3136-fs-file-handle-options.ts": 3814, - "3137-fs-vector-callbacks.cjs": 3509, - "3138-array-large-storage.ts": 4245, - "3139-regex-native-deep-alternatives.ts": 27587, - "3140-array-dense-access.ts": 3800, - "3141-map-string-key-hash.ts": 2566, - "3150-integer-remainder.ts": 3289, - "3151-array-push-writes.ts": 3227, - "3170-number-conversion-fast-paths.ts": 2553, - "3171-method-census-data-writes.ts": 3442, - "400-fib.ts": 2589, - "401-mutual-recursion.ts": 2527, - "402-string-functions.ts": 2176, - "403-void-and-params.ts": 2350, - "4030-runtime-object-truthiness.ts": 2749, - "4031-event-emitter-long-tuples.ts": 2083, - "4032-inline-rc-fast-paths.ts": 4192, - "404-rc-stress.ts": 2456, - "4040-adapted-function-identity.ts": 2867, - "4041-adapted-function-properties.ts": 2991, - "4042-object-is-union-subclass.ts": 2310, - "4043-nonnull-missing-element.ts": 2433, - "4044-adapted-callback-modules/main.ts": 2886, - "4045-optional-element-projections.ts": 3138, - "4046-captured-parameter-values.ts": 3423, - "4047-captured-parameter-rebinding.ts": 2500, - "405-params-optional.ts": 2755, - "406-params-defaults.ts": 2105, - "4060-cycle-shared-instance/main.ts": 2837, - "4060-stack-union-reads.ts": 3299, - "4061-cycle-evaluation-order/main.ts": 2712, - "4061-nullable-ref-fields.ts": 4653, - "4062-cycle-tdz-read/main.ts": 1857, - "4063-cycle-hoisted-calls/main.ts": 2616, - "4064-cycle-classes-after-init/main.ts": 2926, - "4065-cycle-init-throws/main.ts": 2592, - "4066-cycle-top-level-tdz/main.ts": 1456, - "4067-dynamic-import-cycle-tdz/main.ts": 2785, - "407-params-rest.ts": 2693, - "408-params-ctors-inheritance.ts": 2837, - "4080-optional-read-presence-tests.ts": 2357, - "4080-string-index-bounds.ts": 2174, - "4081-hoisted-function-tdz.ts": 3131, - "4081-string-index-unproven.ts": 2850, - "4082-hoisted-function-tdz-uncaught.ts": 2634, - "4083-dynamic-import-failure/main.ts": 2355, - "4084-record-optional-field-copies.ts": 2952, - "4085-generator-loop-close.ts": 3078, - "4086-optional-capture-defaults.ts": 2684, - "4088-class-static-tdz.ts": 2183, - "4089-class-wrapper-tdz.js": 2911, - "409-params-async-generics.ts": 1894, - "4090-computed-key-tdz.js": 2483, - "4091-class-evaluation-deferred.ts": 3134, - "410-params-rc-stress.ts": 1591, - "4140-array-callback-split-visit.ts": 4467, - "4141-array-callback-ambient-receiver/main.ts": 2178, - "4142-array-callback-factories.ts": 3521, - "4143-union-refinement-intersection-arms.ts": 3254, - "420-dead-strip-modules/main.ts": 2523, - "4290-acyclic-immutable-trees.ts": 3062, - "4291-acyclic-constructor-escapes.ts": 2390, - "4292-acyclic-readonly-bypass.ts": 1956, - "4293-acyclic-dynamic-writes.ts": 3149, - "4294-console-line-sizes.ts": 5491, - "4295-console-template-parts.ts": 3025, - "4296-console-glued-long-parts.ts": 4102, - "4410-inline-object-allocation.ts": 3371, - "4411-nullable-ref-values.ts": 3446, - "4412-nullable-record-values.ts": 3505, - "4413-cycle-old-late-death.ts": 3210, - "4413-nullable-null-and-undefined.ts": 3960, - "4414-cycle-old-weak-keys.ts": 2210, - "4414-nullable-string-values.ts": 3960, - "4415-identity-borrowed-operands.ts": 2923, - "4415-nullable-container-values.ts": 4078, - "4431-exception-pending-contexts.ts": 3547, - "4432-checked-downcast-failures.ts": 3362, - "4451-int32-field-storage.ts": 3587, - "4452-int32-field-dynamic-writes.ts": 2629, - "4453-int32-closed-locals.ts": 2708, - "4454-int32-field-reflection-reads.ts": 3626, - "4455-live-view-reads-without-stores.ts": 3673, - "4471-unassigned-field-reads.ts": 3063, - "4476-string-ascii-header-fact.ts": 3053, - "4477-buffer-write-ascii-runs.ts": 1845, - "4478-string-large-index-reads.ts": 2385, - "4481-array-optional-push.ts": 2921, - "4482-instanceof-static-class-optional.ts": 2110, - "4483-array-splice-statement.ts": 3260, - "4484-array-length-reset.ts": 2963, - "4485-array-splice-optional-item.ts": 3033, - "4486-array-field-element-borrows.ts": 2099, - "4487-array-literal-optional-values.ts": 2387, - "4520-optional-guard-narrowing.ts": 3290, - "4521-array-callback-element-presence.ts": 4205, - "4522-captured-parameter-lifetimes.ts": 3072, - "4523-array-pop-removal.ts": 2939, - "4524-array-callback-supertype-params.ts": 4250, - "4541-nullable-wrap-borrows.ts": 2850, - "4542-preserving-call-borrows.ts": 3298, - "4543-walk-borrowed-locals.ts": 3324, - "4544-checked-cast-aliases.ts": 2878, - "4545-borrowed-returns.ts": 3935, - "4546-rebound-borrowed-params.ts": 2128, - "4560-field-store-borrowed-receivers.ts": 3268, - "4561-virtual-borrowed-parameters.ts": 2119, - "4562-string-self-concat-move.ts": 2875, - "4563-array-read-projection-receivers.ts": 2961, - "4564-literal-choice-strings.ts": 3091, - "4568-for-of-hole-elements.ts": 3194, - "4569-shorthand-missing-elements.ts": 2799, - "4570-map-lookup-default-record.ts": 2885, - "4591-weak-keys-union-records.ts": 3283, - "4592-cycle-const-from-import/main.ts": 2283, - "4593-weak-keys-empty-objects.ts": 1759, - "4594-union-class-field-mixed-types.ts": 3165, - "4595-union-class-field-optional-receiver.ts": 2742, - "4596-error-subclass-int-fields.ts": 2574, - "4596-tdz-nullable-forward-capture.ts": 3762, - "4597-callback-field-method-name.ts": 3397, - "4598-live-array-ref-element-access.ts": 4852, - "4598-map-set-clear-reuse.ts": 4729, - "4598-os-available-parallelism.ts": 2510, - "4598-publish-constructor-stores.ts": 1852, - "4599-construction-only-field-borrows.ts": 3236, - "4600-construction-only-fields-dynamic-writes.ts": 3072, - "4601-cycle-holders.ts": 2734, - "4602-constructor-escape-order.ts": 2610, - "4610-array-ext-dyn-refresh.ts": 2862, - "4620-optional-chain-borrowed-receivers.ts": 3224, - "4621-edge-preserving-callees/main.ts": 3365, - "4630-contract-int32.ts": 2754, - "4630-reference-write-call-arguments.ts": 3053, - "4631-contract-nothrow.ts": 2070, - "4631-reference-write-aliases.ts": 2695, - "4632-contract-immutable.ts": 2863, - "4632-reference-write-loops-and-walks.ts": 3098, - "4633-contract-program-lifetime.ts": 3689, - "4633-reference-write-callbacks-returns.ts": 3144, - "4634-contract-program-lifetime-publish.ts": 4904, - "4634-optional-element-borrowed-returns.ts": 2709, - "4640-bitwise-identity-ranges.ts": 2778, - "4641-nothrow-try-catch.ts": 2708, - "4642-acyclic-contract.ts": 3288, - "4650-stale-property-narrowing.ts": 3851, - "4651-map-string-get-entry.ts": 3371, - "4652-stale-closure-binding-narrowing.ts": 3495, - "4660-typed-rest-spread-forwarding.ts": 2766, - "4671-scoped-array-read-borrows.ts": 3085, - "4690-cycle-bypass-long-lived.ts": 2735, - "4691-publish-constructor-self-alias.ts": 3219, - "4692-borrowed-result-mutating-callees.ts": 2601, - "4720-cold-throw-paths.ts": 3390, - "4721-integer-induction-numbers.ts": 2467, - "4730-touint32-large-magnitudes.ts": 3097, - "4731-string-mixed-ascii-slices.ts": 2704, - "4732-buffer-write-utf16le-runs.ts": 1998, - "4733-typed-array-read-compares.ts": 3234, - "4750-map-string-absent-filter.ts": 3594, - "4751-string-search-multibyte-needles.ts": 2725, - "4795-published-untyped-member-reads.ts": 3268, - "4806-uint32-loop-accumulators.ts": 3231, - "4810-union-identity-retags.ts": 4620, - "4811-union-retag-checked-cast.ts": 3091, - "4812-int32-wrapping-sums.ts": 3463, - "4813-typed-array-read-equality-bindings.ts": 4674, - "4820-sort-comparator-lent-arguments.ts": 4000, - "4821-callback-lent-arguments.ts": 2333, - "4822-stable-capture-reads.ts": 2409, - "4823-array-store-receivers.ts": 2969, - "4830-typed-teardown-chains.ts": 2905, - "4831-cycle-bypass-probe-windows.ts": 2840, - "4840-array-hole-free-prefix.ts": 2459, - "4860-int32-local-storage.ts": 4170, - "4870-array-pipeline-fusion.ts": 7346, - "4871-array-pipeline-analytics.ts": 4533, - "4872-array-pipeline-temporaries.ts": 7994, - "4875-stream-consumers-array-buffer.ts": 3281, - "4876-array-buffer-inspect.ts": 2814, - "4880-await-call-turn-order.ts": 1921, - "4881-await-call-exceptions.ts": 3225, - "4882-await-call-request-chain.ts": 3022, - "4883-await-values-and-hops.ts": 2825, - "4884-await-call-unhandled-sibling.ts": 2163, - "4885-await-call-checkpoints.ts": 2954, - "4890-regex-literal-sites.ts": 3163, - "4891-regex-plain-text-patterns.ts": 2001, - "4892-regex-exec-read-captures.ts": 3652, - "4900-bigint-division-cross-check.ts": 3357, - "4900-console-instances.ts": 3637, - "4901-bigint-radix-text.ts": 2779, - "4901-console-instance-errors.ts": 3196, - "4902-bigint-compound-assign.ts": 1706, - "4903-bigint-fixed-width.ts": 3128, - "4904-bigint-large-products.ts": 3340, - "4905-bigint-fixed-width-fusion.ts": 3031, - "4906-bigint-small-value-trees.ts": 3759, - "4907-bigint-random-trees.ts": 5188, - "4910-hole-free-prefix-upkeep.ts": 3084, - "4920-string-literal-switch.ts": 3310, - "4930-typed-record-reflection.ts": 4737, - "4931-typed-data-generic-walks.ts": 4118, - "4932-typed-json-unknown.ts": 3475, - "4940-async-return-adoption.ts": 3491, - "4941-async-return-adoption-try.ts": 3096, - "4942-async-return-adoption-values.ts": 2964, - "4943-async-return-adoption-interleaved.ts": 2876, - "4950-regex-compiled-captures.ts": 4852, - "4951-regex-compiled-last-index.ts": 2706, - "4952-regex-compiled-anchors-classes.ts": 2724, - "4953-regex-compiled-backtracking.ts": 4297, - "4954-regex-log-report.ts": 3687, - "4955-regex-compiled-differential.ts": 13757, - "4970-int32-call-abi.ts": 3580, - "4980-generator-early-exit-finally.ts": 3050, - "4981-generator-delegation-iterables.ts": 4127, - "4982-generator-sent-values.ts": 2957, - "4983-generator-reuse-iterables.ts": 3475, - "4984-generator-exceptions.ts": 3390, - "4985-generator-lazy-pipeline.ts": 3419, - "4986-generator-default-channels.ts": 3152, - "4987-generator-closures-methods.ts": 3151, - "4988-generator-async-interplay.ts": 2316, - "4989-generator-step-drives.ts": 3427, - "4990-lone-surrogates.ts": 3491, - "4991-lone-surrogate-halves.ts": 3293, - "4992-lone-surrogate-search.ts": 2456, - "4993-lone-surrogate-json.ts": 3728, - "4994-lone-surrogate-uri.ts": 1777, - "4995-lone-surrogate-regex.ts": 2799, - "4996-lone-surrogate-stdio.ts": 3100, - "4997-lone-surrogate-stdout-patch.js": 1716, - "4998-lone-surrogate-buffers.ts": 3414, - "4999-lone-surrogate-io.ts": 2886, - "500-array-basics.ts": 2955, - "501-array-push-pop.ts": 1902, - "5010-lifetime-region-generations.ts": 3477, - "5011-lifetime-region-outside-references.ts": 2843, - "5012-lifetime-region-shapes.ts": 4150, - "5013-lifetime-region-async.ts": 3814, - "5014-lifetime-region-nesting.ts": 2997, - "5015-lifetime-region-publish.ts": 2741, - "5016-lifetime-region-weak-keys.ts": 3235, - "5017-lifetime-region-cycles.ts": 3057, - "5018-lifetime-region-hierarchies.ts": 4043, - "5019-lifetime-region-values.ts": 2895, - "502-array-for-of.ts": 2808, - "5020-lifetime-region-large.ts": 3808, - "5021-lifetime-region-opaque-holders.ts": 3422, - "5022-lifetime-region-workers.ts": 2531, - "503-array-functions.ts": 2837, - "504-array-rc-stress.ts": 2722, - "5040-promise-all-race-turns.ts": 3860, - "5041-promise-all-turns.js": 3644, - "5042-async-generator-return-promise.ts": 3304, - "5043-async-generator-return-forms.ts": 3190, - "5045-generator-delegation-typed-next.ts": 3751, - "5046-generator-delegation-return-throw.ts": 2749, - "5047-generator-delegation-iterables-typed.ts": 4798, - "5048-generator-delegation-async.ts": 3315, - "5049-generator-delegation-edges.ts": 3539, - "5050-inherited-in-membership.ts": 3427, - "5051-typed-record-prototypes.ts": 2418, - "5052-class-for-in-unknown.ts": 3692, - "5053-json-replacer-arrays.ts": 3781, - "5054-required-field-delete.ts": 2108, - "5055-object-create-record-literal.ts": 2773, - "5056-generator-in-unknown.ts": 2634, - "5060-child-fork-exit-after-messages/main.ts": 2129, - "5061-child-fork-local-disconnect/main.ts": 3136, - "5062-child-fork-message-before-eof/main.ts": 3024, - "5065-global-increment-initializers.ts": 2900, - "5066-global-compound-updates.ts": 3224, - "5067-global-updates-in-functions.ts": 2208, - "5068-global-var-let-const-updates.ts": 2542, - "5069-global-update-modules/main.ts": 1962, - "5070-optional-read-bindings.ts": 2623, - "5071-optional-chain-scalars.ts": 2743, - "5072-optional-nullish-ternary.ts": 2840, - "5073-optional-results.ts": 3242, - "5074-optional-pop-shift.ts": 2144, - "5075-optional-reads-unchecked/main.ts": 3167, - "5076-optional-escapes.ts": 2155, - "5080-boolean-array-storage.ts": 4783, - "5081-boolean-array-dynamic-views.ts": 2550, - "5085-promise-allsettled-turns.ts": 4142, - "5086-promise-any-turns.ts": 3722, - "5087-promise-allsettled-any-dyn.js": 5509, - "5088-promise-combinator-thenables.js": 4706, - "5089-promise-settled-records.ts": 3855, - "5090-generator-finished-result-value.ts": 2787, - "5091-generator-delegation-arrays-strings.ts": 4059, - "5092-generator-delegation-sets-maps.ts": 3822, - "5095-console-count-group.ts": 3219, - "5096-console-assert-dir.ts": 3665, - "5097-console-table.ts": 2407, - "5098-console-time-warnings.ts": 5609, - "5099-console-methods-dynamic.cjs": 3155, - "510-array-map-filter-foreach.ts": 2313, - "511-array-indexof-includes.ts": 2884, - "5110-var-hoisting-early-reads.ts": 2759, - "5111-var-hoisting-closures-classes.ts": 2869, - "5112-var-hoisting-function-scope.ts": 2697, - "5113-tdz-let-const-class.ts": 2402, - "5114-var-hoisting-js.js": 2192, - "5115-regex-replace-compiled.ts": 2826, - "5116-regex-capture-reads.ts": 3329, - "5117-regex-log-report-spans.ts": 3686, - "5118-regex-replace-char-chains.ts": 2917, - "512-array-join-chains.ts": 1729, - "5120-frame-records.ts": 2763, - "5121-frame-objects.ts": 2346, - "5122-frame-result-slots.ts": 3086, - "5123-frame-reassigned.ts": 2807, - "5124-frame-objects-control.ts": 2789, - "5125-frame-mutating-methods.ts": 2122, - "5126-frame-returned-params.ts": 2597, - "5127-frame-loop-bindings.ts": 2498, - "513-array-methods-rc-stress.ts": 3202, - "5130-event-target-dispatch.js": 4435, - "5131-event-target-listener-errors.js": 1856, - "5132-event-target-typed.ts": 2296, - "5133-abort-signal-event-target.ts": 3474, - "5134-events-error-monitor.ts": 2972, - "5135-event-target-warnings.js": 2909, - "5136-events-error-monitor-string-name.ts": 2529, - "5137-events-error-monitor-computed-name.js": 3132, - "5138-events-error-monitor-shared-listener.ts": 2744, - "5139-event-target-listener-throw.ts": 2800, - "514-array-find-some-every.ts": 3281, - "5140-os-host-facts.ts": 3044, - "5141-os-constants.ts": 3300, - "5142-path-parse-format.ts": 2224, - "5145-path-matches-glob-basics.ts": 2906, - "5146-path-matches-glob-braces.ts": 5151, - "5147-path-matches-glob-extglob.ts": 2798, - "5148-path-matches-glob-classes.ts": 2450, - "5149-path-matches-glob-win32.ts": 3351, - "515-array-flatmap.ts": 3014, - "5150-small-array-inline-slots.ts": 3873, - "5155-cycle-header-types.ts": 3715, - "516-array-reduce.ts": 3532, - "5160-field-callback-receiver.ts": 3321, - "5161-field-callback-receiver-escape.ts": 2766, - "5162-field-method-reference-receiver.ts": 2634, - "5163-field-callback-receiver.cjs": 3329, - "5164-worker-field-callback-receiver.ts": 3447, - "5165-interface-method-dispatch.ts": 3406, - "5166-interface-method-values.ts": 4300, - "5167-interface-method-order.ts": 3903, - "5168-interface-method-hierarchy.ts": 5186, - "5169-interface-method-chains.ts": 2434, - "517-array-hof-index-args.ts": 3100, - "5170-string-scan-eviction.ts": 1929, - "5171-lone-surrogate-replace-seams.ts": 2824, - "5175-forin-typed-as-unknown.ts": 2364, - "5176-object-keys-typed-as-unknown.ts": 1967, - "5177-forin-dynamic-objects.ts": 2917, - "5178-forin-keys-js.js": 3039, - "5179-forin-typed-shapes.ts": 3389, - "518-array-sort.ts": 3117, - "518-promise-void-union-callbacks.ts": 2562, - "5180-interface-arrays.ts": 3202, - "5181-interface-array-methods.ts": 6982, - "5182-interface-array-boundaries.ts": 3287, - "5183-interface-property-reads.ts": 3238, - "5184-interface-property-objects.ts": 3177, - "5185-util-inherits.cjs": 3654, - "5186-util-inherits.ts": 3139, - "5187-util-deprecate.cjs": 2383, - "5188-util-deprecate-flags.cjs": 2907, - "5189-util-deprecate.ts": 2180, - "519-array-from-length.ts": 2896, - "519-promise-union-await-values.ts": 2702, - "5190-util-callbackify.cjs": 3059, - "5191-util-callbackify.ts": 3126, - "5192-util-debuglog.cjs": 3809, - "5193-util-debuglog.ts": 2614, - "5194-process-emit-warning-tick.cjs": 2394, - "5195-object-entries-typed-as-unknown.ts": 3883, - "5196-object-values-typed-as-unknown.ts": 3399, - "5197-object-entries-dynamic-objects.ts": 3397, - "5198-object-entries-values-js.js": 2635, - "5199-object-entries-identity.ts": 3121, - "520-map-basics.ts": 2823, - "5200-array-sort-keyed-numbers.ts": 4287, - "5201-array-sort-keyed-records.ts": 4564, - "5202-array-sort-keyed-lookalikes.ts": 3516, - "5203-typed-array-sort-default.ts": 6009, - "5204-typed-array-sort-comparators.ts": 4333, - "521-map-number-keys.ts": 2785, - "5210-process-memory-usage.ts": 2299, - "5211-process-identity.ts": 3103, - "5212-perf-marks-measures.ts": 3829, - "5213-perf-timing-errors.ts": 3477, - "5214-perf-entry-inspect.ts": 4088, - "5215-perf-timing-validation.js": 3386, - "5216-perf-spread-arguments.js": 4128, - "5217-perf-spread-typed.ts": 3454, - "522-map-foreach.ts": 2702, - "5220-url-parse-warnings.ts": 2881, - "5221-url-parse-shapes.ts": 1930, - "5222-url-parse-hosts.ts": 3064, - "5223-url-parse-query.ts": 3104, - "5224-url-format-objects.ts": 3496, - "5225-url-format-whatwg.ts": 2608, - "5226-url-resolve.ts": 2695, - "5227-url-legacy-dependency/main.ts": 2825, - "5228-url-domain-conversion.ts": 2843, - "5229-url-legacy-errors.cjs": 3833, - "523-map-ref-values.ts": 3192, - "5230-inline-union-fields.ts": 2629, - "5231-inline-union-field-kinds.ts": 2513, - "5232-inline-union-fields-dynamic.ts": 3917, - "5233-inline-union-fields-shapes.ts": 3689, - "5234-inline-union-class-fields.ts": 3417, - "5235-inline-union-fields-publish.ts": 2910, - "5236-inline-union-unchecked-reads.ts": 2919, - "5237-inline-union-frame-objects.ts": 2775, - "524-map-cycles.ts": 2820, - "5240-event-target-subclass.ts": 4712, - "5241-event-subclass.ts": 3442, - "5242-event-target-subclass-hierarchy.ts": 3429, - "5243-event-target-subclass-dynamic.ts": 3827, - "5244-event-target-subclass.js": 3772, - "5245-event-target-subclass-signals.ts": 3197, - "5246-event-target-subclass-listener-throw.ts": 1982, - "5247-event-target-subclass-lifetimes.ts": 4315, - "5248-event-target-subclass-warnings.ts": 2798, - "5249-event-target-subclass-unconstructed.ts": 2600, - "525-map-rc-stress.ts": 2751, - "5250-cipher-aes-gcm.ts": 6095, - "5251-cipher-aes-cbc.ts": 3544, - "5252-cipher-aes-ctr.ts": 2536, - "5253-cipher-chacha20-poly1305.ts": 3577, - "5254-cipher-errors.js": 3835, - "5255-cipher-encodings.cjs": 3839, - "5256-cipher-deprecation.cjs": 3149, - "5257-cipher-vectors.ts": 3374, - "5258-cipher-handles.js": 2798, - "5259-cipher-chunked.ts": 3781, - "526-set-basics.ts": 2514, - "5260-record-unknown-identity.ts": 3342, - "5261-optional-field-identity.ts": 2813, - "5262-record-unknown-many.ts": 2768, - "527-set-foreach.ts": 2947, - "5270-url-parse-no-deprecation.cjs": 3204, - "5271-url-parse-throw-deprecation.cjs": 3229, - "5275-http-end-callback-order.ts": 3224, - "5276-style-text-hex-colors.cjs": 2193, - "5277-fs-read-file-buffer-option.cjs": 1864, - "5278-host-null-bytes.cjs": 2972, - "5279-search-params-null-init.cjs": 1662, - "528-set-seeded.ts": 1937, - "5285-blob-construct.ts": 3802, - "5286-blob-readers.ts": 2609, - "5287-blob-inspect.ts": 2930, - "5288-blob-validation.js": 4282, - "5289-blob-read-order.ts": 3276, - "529-map-seeded.ts": 2575, - "5290-blob-dynamic.js": 3409, - "5295-readline-promises-question.ts": 2860, - "5296-readline-lines.ts": 3085, - "5297-readline-callback-events.cjs": 2092, - "5298-readline-abort.cjs": 3384, - "5299-readline-stdin.ts": 2909, - "530-record-arrays.ts": 3090, - "5300-stream-add-abort-signal.ts": 2505, - "5301-stream-add-abort-signal-errors.cjs": 3168, - "5302-stream-promises-options.ts": 2812, - "5303-stream-finished-callback-opts.cjs": 2840, - "5305-json-stringify-typed-arrays.ts": 4425, - "531-record-array-hofs.ts": 3107, - "5315-map-iterate-after-front-deletes.ts": 3372, - "5316-map-lru-eviction.ts": 2980, - "5317-map-iterate-while-mutating.ts": 3025, - "5318-set-iterate-after-deletes.ts": 2325, - "5319-map-iteration-values.ts": 2767, - "532-record-arrays-rc-stress.ts": 2605, - "5320-map-iterate-across-compaction.ts": 3341, - "5321-integer-closed-arithmetic-loops.ts": 2935, - "5321-json-parse-cycles.ts": 2739, - "5322-integer-variable-step-loops.ts": 2732, - "5322-json-stringify-parsed-trees.ts": 3539, - "5323-dyn-numeric-index-reads.ts": 1771, - "5323-int32-nonnegative-slot-facts.ts": 2925, - "5324-int32-initializer-locals.ts": 2126, - "5324-structured-clone-documents.ts": 3093, - "5325-record-boundary-returns.ts": 2952, - "5326-record-boundary-params.ts": 3045, - "5327-record-boundary-identity.ts": 2913, - "5328-record-boundary-open.ts": 2787, - "5329-record-boundary-recursion.ts": 2543, - "533-array-element-cycles.ts": 2595, - "5330-record-boundary-fields.ts": 2690, - "5331-record-boundary-methods.ts": 2941, - "5332-int32-narrowed-slot-facts.ts": 3036, - "5333-integer-guarded-while-counters.ts": 2907, - "5333-record-boundary-nullable-argument.ts": 3066, - "5334-fetch-mentions-without-calls.ts": 2537, - "5335-stream-operators-values.ts": 3463, - "5335-top-level-await-pending-exit-code.ts": 2626, - "5336-stream-operators-promise-timing.ts": 3056, - "5336-top-level-await-pending-exit-listener.ts": 2547, - "5337-dc-subscriber-throw-next-tick.cjs": 2655, - "5337-stream-operators-concurrency.ts": 2539, - "5338-js-tdz-function-element.js": 2247, - "5338-stream-operators-checks.cjs": 3619, - "5339-array-buffer-constructor.js": 3106, - "5339-stream-for-await-hops.ts": 2525, - "534-record-width-subtyping.ts": 2764, - "5340-readable-from-options.ts": 3427, - "5341-compound-any-operand.ts": 3571, - "5341-generator-callback-params.ts": 3696, - "5341-integer-recursion-boundaries.ts": 2410, - "5341-readable-from-dynamic.cjs": 3652, - "5342-compound-any-operand.cjs": 2807, - "5342-generator-scalar-channels.ts": 2386, - "5342-integer-recursion-stack-and-mutual.ts": 2999, - "5342-stream-compose.ts": 3332, - "5343-any-flow-compound.ts": 1598, - "5343-integer-recursion-array-index.ts": 3219, - "5343-iterator-result-records.ts": 2018, - "5343-stream-compose-edges.ts": 3167, - "5344-json-parse-undeclared-keys.ts": 4016, - "5344-stream-pipeline-timing.ts": 3216, - "5345-object-values-for-of-unknown.ts": 2662, - "5346-object-values-length-dynamic.ts": 3253, - "5347-object-values-loop-control.ts": 3534, - "5348-object-values-for-of-js.js": 3133, - "5349-object-entries-values-optional.ts": 3434, - "535-object-statics.ts": 3684, - "5350-object-values-wide-record.ts": 3383, - "5351-object-values-methods-index.ts": 4044, - "5352-final-field-loop-reads.ts": 2982, - "5353-captured-const-values.ts": 3255, - "5354-captured-const-tdz.ts": 1913, - "5355-captured-function-declarations.ts": 2960, - "5356-captured-tdz-ordering.ts": 2164, - "5357-init-only-module-bindings.ts": 3203, - "536-map-seed-array.ts": 2803, - "5360-array-sort-comparator-calls.ts": 2961, - "5361-array-sort-inconsistent-comparators.ts": 2659, - "5362-array-sort-comparator-throws.ts": 2991, - "5363-array-sort-comparator-writes.ts": 5900, - "5364-array-sort-union-and-boolean-elements.ts": 10497, - "5365-array-sort-dynamic-values.js": 3189, - "537-map-iter-drains.ts": 2987, - "5370-zlib-stream-roundtrip.ts": 3454, - "5371-zlib-stream-chunking.cjs": 3925, - "5372-zlib-stream-errors.cjs": 2700, - "5373-zlib-stream-options.cjs": 3872, - "5374-zlib-stream-flush-params.ts": 3102, - "5375-zlib-stream-promises.ts": 2399, - "5376-zlib-constants.cjs": 2483, - "5377-zlib-stream-backpressure.cjs": 3427, - "5378-zlib-sync-options.cjs": 2176, - "5379-zlib-callback-options.ts": 3566, - "538-map-set-for-of.ts": 2976, - "5390-interface-loop-element-lifetimes.ts": 3153, - "5391-interface-dispatch-hierarchies.ts": 3899, - "5392-interface-receiver-bindings.ts": 3131, - "5393-interface-array-holes.ts": 3093, - "5394-interface-implementers.ts": 3579, - "5395-locale-compare-ascii.ts": 2963, - "5396-locale-compare-latin.ts": 1885, - "5397-locale-compare-sorting.ts": 3156, - "540-tuples-basics.ts": 2555, - "5400-json-parse-typed-keys.ts": 3448, - "5405-buffer-arraybuffer-window.ts": 3039, - "5406-util-types-keys.ts": 2823, - "5407-http-header-field-limit.ts": 3316, - "5408-http-unread-request-end.ts": 3667, - "5409-http-held-request-body.ts": 2506, - "541-ref-array-json.ts": 2521, - "5410-inspect-class-values.ts": 2528, - "5411-inspect-class-hierarchies.ts": 3094, - "5412-inspect-dynamic-collections.ts": 3071, - "5413-inspect-class-values.cjs": 3263, - "5415-zlib-dynamic-inputs.cjs": 2520, - "542-union-element-arrays.ts": 2223, - "5420-readable-from-generators.ts": 3661, - "5421-readable-from-generators.cjs": 3036, - "5422-stream-async-push-wakeup.ts": 3138, - "5423-stream-end-and-eos-timing.ts": 3247, - "5424-stream-write-buffer-encoding.ts": 2663, - "5425-pipeline-generator-stage.ts": 2060, - "5426-pipeline-generator-errors.ts": 3490, - "5427-pipeline-generator-backpressure.ts": 2729, - "5428-pipeline-generator-stages.cjs": 3499, - "5429-pipeline-generator-buffers.ts": 3223, - "5430-dyn-number-string-boxes.ts": 3048, - "5435-crypto-hash-algorithms.ts": 2461, - "5436-crypto-hash-names.js": 3064, - "5437-crypto-hmac-algorithms.ts": 3107, - "5438-crypto-kdf-digests.ts": 3109, - "5439-crypto-kdf-callbacks.js": 2368, - "5440-crypto-hash-encodings.js": 4093, - "5441-crypto-hash-output-length.ts": 3652, - "5442-crypto-random-values.ts": 4190, - "5443-crypto-random-arguments.js": 3529, - "5444-crypto-timing-safe-equal.js": 3508, - "5445-crypto-secret-key-objects.ts": 3186, - "5445-stream-buffer-chunks.ts": 3012, - "5446-crypto-secret-key-errors.js": 3785, - "5446-stream-buffer-chunks-dynamic.js": 3127, - "5447-fs-readdir-order.ts": 2143, - "5448-fs-glob-patterns.ts": 3113, - "5449-fs-glob-options.ts": 3649, - "5450-fs-glob-validation.js": 2855, - "5451-fs-promises-glob.ts": 3569, - "5452-fs-glob-callback.ts": 2885, - "5455-power-of-two-remainder.ts": 3093, - "5456-remainder-large-integer-dividends.ts": 2991, - "5457-lcg-modulus.ts": 2871, - "5458-fractional-remainder.ts": 2988, - "5460-locale-compare-contractions.ts": 2881, - "5461-locale-compare-equivalents.ts": 2942, - "5462-locale-compare-probe-sweep.ts": 2752, - "5463-locale-compare-combining-letters.ts": 3006, - "5464-locale-compare-fractions.ts": 2946, - "5465-dyn-index-read-arrays.ts": 3424, - "5466-dyn-index-read-special.ts": 2632, - "5470-strip-vt-osc.cjs": 2376, - "5471-strip-vt-csi.cjs": 2167, - "5472-strip-vt-random.cjs": 3001, - "5473-strip-vt-unterminated.cjs": 3560, - "5474-strip-vt-surrogates.ts": 3301, - "5510-assert-error-properties.js": 3653, - "5511-assert-error-class.ts": 3637, - "5512-assert-error-options.js": 3115, - "5513-assert-deep-equal-loose.js": 3866, - "5514-assert-deep-equal-typed.ts": 3778, - "5515-assert-deep-strict-typed-messages.ts": 1850, - "5516-assert-deep-equal-edges.js": 3662, - "5517-assert-partial-deep-equal.js": 2640, - "5518-assert-partial-deep-typed.ts": 3542, - "5519-assert-partial-deep-typed-edges.ts": 3280, - "5520-assert-record-literal-failures.ts": 3499, - "5520-dyn-property-read-receivers.ts": 3367, - "5521-assert-empty-message.js": 3321, - "5521-dyn-property-read-keys.ts": 2391, - "5522-assert-throws-failure-properties.ts": 3436, - "5523-assert-class-options.js": 3102, - "5524-assert-class-skip-prototype.ts": 3823, - "5530-buffer-pool.ts": 3971, - "5531-buffer-pool-first-slab.ts": 5569, - "5532-buffer-pool-first-slab-untyped.mjs": 40038, - "5540-fs-callback-forms.cjs": 3631, - "5541-fs-stats-fields.cjs": 3800, - "5542-fs-promises-parity.cjs": 3962, - "5543-fs-promises-typed.ts": 2212, - "5544-fs-opendir.cjs": 3332, - "5545-fs-options-encoding.cjs": 4482, - "5546-fs-read-stream.cjs": 4502, - "5547-fs-write-stream.cjs": 5101, - "5548-fs-callback-arguments.cjs": 4306, - "5549-fs-callback-option-checks.cjs": 4187, - "5550-locale-compare-ascii-words.ts": 2669, - "5551-array-search-references.ts": 3663, - "5552-string-appends.ts": 3195, - "5553-string-append-char-code.ts": 2446, - "5554-fs-streams-typed.ts": 3785, - "5555-fs-callback-turns.cjs": 3093, - "5555-http-server-close-keep-alive.ts": 7242, - "5556-http-client-agent-connection.ts": 2788, - "5557-http-outgoing-header-values.ts": 3401, - "5558-http-incoming-duplicate-headers.ts": 2354, - "5559-http-expect-header.ts": 3766, - "5560-http-response-framing.ts": 4849, - "5561-http-max-header-size.ts": 3443, - "5562-https-verify-errors.ts": 3494, - "5563-http-keep-alive-timeout.ts": 11607, - "5564-http-request-signal.ts": 3916, - "5565-fs-dirent-untyped.mjs": 3810, - "5566-fs-dirent-dyn-boundaries/main.mjs": 3533, - "5567-fs-cpsync.ts": 3626, - "5568-fs-cp-errors.js": 3163, - "5569-fs-cp-symlinks.ts": 3704, - "5570-fs-cp-async.ts": 3480, - "5571-fs-cp-deep.ts": 4934, - "5585-record-results-inlined.ts": 3154, - "5595-net-ref-unref.ts": 2641, - "5600-dyn-cycle-self.ts": 2124, - "5601-dyn-cycle-mutual.ts": 3279, - "5602-dyn-cycle-arrays.ts": 2568, - "5603-dyn-cycle-identity.ts": 2702, - "5604-dyn-cycle-checks.ts": 3057, - "5605-dyn-cycle-containers.ts": 3526, - "5606-dyn-cycle-capsules.ts": 1609, - "5610-readable-from-sets-and-views.ts": 3539, - "5611-readable-from-class-iterables.ts": 2637, - "5612-readable-from-iterables.cjs": 4089, - "5613-readable-from-iterable-timing.cjs": 4101, - "5614-readable-from-iterable-errors.cjs": 4082, - "5615-next-tick-callback-phases.ts": 3272, - "5616-next-tick-callback-phases.cjs": 2953, - "5617-pipeline-function-ends.ts": 2551, - "5618-pipeline-function-ends-errors.ts": 3775, - "5619-pipeline-function-ends.cjs": 2549, - "5620-timers-promises-values.ts": 3225, - "5621-util-format-float.ts": 2907, - "5622-events-once.mjs": 3347, - "5623-events-once.ts": 2334, - "5624-timers-promises-unawaited.ts": 3127, - "5625-promisify-exec.ts": 7142, - "5626-promisify-forms.ts": 2175, - "5627-exec-callback.ts": 1900, - "5628-promisify-timers.ts": 3185, - "5629-promisify-stream.ts": 3048, - "5630-promisify-zlib.ts": 1934, - "5631-promisify-crypto.ts": 2200, - "5632-promisify-dns.ts": 1700, - "5644-net-socket-addresses.ts": 3275, - "5645-net-socket-callbacks.ts": 3377, - "5646-net-server-connections.ts": 2448, - "5647-net-is-ip.ts": 2731, - "5648-dns-lookup-forms.ts": 3763, - "5649-dns-service-servers.ts": 2892, - "5650-dns-lookup-errors-untyped.cjs": 2811, - "5651-tls-socket-protocol.ts": 3198, - "5652-http-client-trailer-overflow.ts": 2916, - "5653-net-socket-read-ahead.ts": 4816, - "5654-https-empty-servername.ts": 3117, - "5655-dgram-socket-options.ts": 3309, - "5656-dgram-option-states.ts": 3364, - "5657-net-reset-and-address.ts": 2680, - "5658-net-reset-dynamic.cjs": 2474, - "5659-net-blocklist-socketaddress.ts": 4089, - "5664-tls-client-identity.ts": 2704, - "5674-union-instanceof-array-arms.ts": 3663, - "5680-array-growth-after-copy.ts": 3726, - "5681-array-pop-and-length.ts": 4270, - "5682-publish-wide-objects.ts": 3077, - "5700-cycle-release-retained.ts": 2148, - "5701-cycle-release-old-edges.ts": 2696, - "5702-publish-candidate-buffers.ts": 2775, - "5703-lifetime-region-debug.ts": 2224, - "5704-publish-refused-restores-counts.ts": 3329, - "5710-map-number-keys-hashed.ts": 3647, - "5711-map-number-write-after-read.ts": 2210, - "5712-map-number-overwrite-at-growth.ts": 3023, - "5714-cycle-large-candidate-buffers.ts": 2468, - "5715-json-parse-fitted-tables.ts": 3870, - "5717-set-prototype-of-primitives.ts": 2889, - "5719-int32-fields-dynamic-operators.ts": 3112, - "5720-intern-table-basics.ts": 3730, - "5721-intern-table-values.ts": 3508, - "5722-intern-table-workers.ts": 2907, - "5723-intern-table-shared-types.ts": 4686, - "5724-intern-table-array-keys.ts": 3089, - "5725-intern-table-callbacks.ts": 3280, - "5726-intern-table-key-limits.ts": 2828, - "5740-atomics-operation-semantics.ts": 4575, - "5741-atomics-contended-counters.ts": 2574, - "5742-atomics-lock-ordering.ts": 3308, - "5743-atomics-wait-notify.ts": 3213, - "5744-atomics-ring-buffer.ts": 2799, - "5745-atomics-semaphore-stress.ts": 3529, - "5746-shared-bulk-operations.ts": 3548, - "5747-fs-stat-throw-if-no-entry.ts": 2061, - "5748-fs-stat-throw-if-no-entry-js.cjs": 3369, - "5752-string-number-concat.ts": 1990, - "5760-crypto-hash-stream.ts": 3142, - "5761-crypto-hash-stream-states.ts": 3329, - "5762-crypto-hash-stream.cjs": 3414, - "5763-crypto-sha-blocks.ts": 3741, - "5764-class-structural-view-writes.ts": 3376, - "5764-crypto-hmac-edges.cjs": 2142, - "5765-class-structural-view-identity.ts": 3439, - "5766-class-structural-view-callbacks.ts": 2597, - "5767-class-opaque-accessor-view.ts": 3393, - "5776-power-of-two-remainder-integer-path.ts": 2953, - "5780-readline-history-options.ts": 2935, - "5781-readline-history-options.cjs": 2270, - "5782-readline-terminal-editing.ts": 3076, - "5783-readline-terminal-completion.cjs": 5270, - "5784-readline-terminal-promises.ts": 2520, - "5785-readline-terminal-keys.ts": 3009, - "5786-readline-terminal-history.cjs": 2912, - "5787-readline-cursor-helpers.cjs": 1948, - "5788-readline-promises-readline.ts": 3069, - "5789-readline-cursor-pos.cjs": 2494, - "5790-readline-keypress-events.ts": 3064, - "5791-dyn-constant-key-read-sites.ts": 3916, - "5791-readline-keypress-interfaces.cjs": 3122, - "5792-json-parse-repeated-layouts.ts": 3794, - "5792-readline-keypress-listeners.ts": 2820, - "5793-worker-message-channel.ts": 2538, - "5794-worker-message-port-close-order.ts": 2834, - "5795-worker-message-port-batches.ts": 2254, - "5796-worker-message-channel.cjs": 3566, - "5797-worker-message-port-transfer.ts": 3180, - "5800-broadcast-channel.ts": 3206, - "5801-broadcast-channel.cjs": 3035, - "5802-broadcast-channel-workers.ts": 3120, - "5803-worker-environment-data.ts": 3113, - "5804-worker-environment-data.cjs": 3000, - "5805-worker-receive-message-parent-port.ts": 3259, - "5806-worker-resource-limits.ts": 3191, - "5807-worker-error-values.ts": 3239, - "5808-worker-unhandled-rejections.ts": 3439, - "5809-process-exit-and-rejections.cjs": 3393, - "5810-mock-method-records.ts": 3670, - "5811-mock-tracker-restore.ts": 3216, - "5812-dyn-box-async-fields.ts": 2941, - "5813-mock-timers-module.ts": 3052, - "5814-mock-timers-date.ts": 3365, - "5830-timers-promises-signal.ts": 3771, - "5831-util-types-brands.ts": 3300, - "5832-util-types-brands-dynamic.js": 3811, - "5833-url-search-params-iterators.ts": 3578, - "5834-url-search-params-iterators-dynamic.mjs": 3566, - "5835-util-format-integer-specifiers.ts": 2544, - "5836-url-search-params-tuple-pairs.ts": 2830, - "5837-util-format-json-circular.ts": 2387, - "5838-qs-stringify-bigint.ts": 3072, - "5839-timers-promises-scheduler.ts": 2609, - "5840-promise-with-resolvers-js.js": 2922, - "5841-json-typed-dyn-members.ts": 3536, - "5842-qs-parse-null-prototype.ts": 3138, - "5843-qs-parse-null-prototype-js.mjs": 2658, - "5844-date-unknown-values.ts": 3255, - "5845-groupby-null-prototype.ts": 3675, - "5846-events-esm-default-max.ts": 2633, - "5847-events-cjs-default-max.cjs": 2823, - "5849-class-view-observations.ts": 2583, - "5850-using-disposable-values.ts": 3206, - "5851-using-suppressed-error-values.ts": 3035, - "5852-using-disposable-values-js.js": 1792, - "5853-set-methods-map-arguments.ts": 2849, - "5854-array-from-async.ts": 3165, - "5855-array-from-async-js.js": 3186, - "5856-error-is-error.ts": 3631, - "5857-regexp-unicode-sets.ts": 2021, - "5858-disposable-stack.ts": 4753, - "5859-disposable-stack-js.js": 3636, - "5860-url-ipv4-hosts.ts": 3030, - "5870-worker-thread-names.ts": 3457, - "5871-worker-untransferable.cjs": 2368, - "5872-readline-positional-create-interface.mjs": 2993, - "5873-readline-promises-namespace.cjs": 2951, - "5874-worker-stdio-streams.ts": 2974, - "5875-worker-stdout-pipe.cjs": 3115, - "5879-worker-stdin.ts": 3644, - "5880-emitter-leak-warning-delivery.ts": 2660, - "5881-inspect-weak-collections.ts": 2621, - "5882-string-decoder-runtime-encoding.ts": 2742, - "5883-os-set-priority.ts": 2927, - "5884-inspect-layout-options.ts": 3552, - "5885-events-max-listener-helpers.ts": 3645, - "5886-inspect-dates.ts": 2931, - "5887-inspect-typed-arrays.ts": 2476, - "5888-inspect-sorted.ts": 3227, - "5889-timers-scheduler-signal.ts": 2549, - "5890-while-string-length-counters.ts": 3080, - "5892-buffer-write-utf16le-runs.ts": 3098, - "5900-float16-array.ts": 3586, - "5901-float16-array-js.js": 3449, - "5904-async-generator-completion.ts": 5816, - "5905-array-from-async-generator.ts": 2793, - "5906-array-from-async-generator-js.js": 3377, - "5907-regex-groups-match-rows.ts": 3150, - "5910-set-prototype-of-primitive-object-kinds.ts": 2148, - "5911-dyn-class-to-primitive.ts": 6231, - "5912-dyn-class-conversion-methods.ts": 4317, - "5913-prototype-type-error-messages.ts": 2831, - "5914-dyn-in-class-prototype-members.ts": 2811, - "5915-dyn-error-string-conversions.ts": 3158, - "5920-promise-try-args.ts": 3150, - "5921-promise-try-args-js.js": 2112, - "5922-matchall-groups-callbacks.ts": 4259, - "5923-matchall-groups-js.js": 4523, - "5924-js-literal-identity.js": 3064, - "5925-class-view-identity-observers.ts": 2653, - "5926-class-view-switch-js.js": 1690, - "5927-switch-object-identity.ts": 2783, - "5928-groupby-iterables.ts": 3526, - "5929-groupby-js.js": 1756, - "5930-contract-int32-arrays.ts": 3803, - "5930-method-census-asserted-number-keys.ts": 2348, - "5931-asserted-reads-keep-number-parameters.ts": 2715, - "5932-generic-class-observed-methods.ts": 4825, - "5933-class-fields-unknown-object.ts": 3920, - "5934-js-class-fields-property-order.js": 4713, - "5935-js-subclass-fields-and-element-calls.js": 3523, - "5936-checked-js-class-types.js": 2384, - "5937-override-narrowed-union-returns.ts": 3039, - "5938-object-literal-computed-keys-keep-methods.ts": 3195, - "5939-js-let-object-reassigned-wider.js": 2362, - "5940-callback-helper-specialization.ts": 3130, - "5941-callback-specialization-recursion.ts": 3996, - "5942-callback-specialization-throws.ts": 2908, - "5943-fields-read-before-assignment.ts": 6856, - "5944-js-fields-read-before-assignment.js": 4247, - "5945-local-class-observed-methods.ts": 5063, - "5946-nested-record-field-optional-writes.ts": 6045, - "5950-tuple-predicate-methods.ts": 3865, - "5951-result-never-widening.ts": 3022, - "5952-record-missing-keys.ts": 6090, - "5953-nan-coded-method-returns.ts": 4100, - "5955-any-promise-methods.js": 3111, - "5956-erased-generic-members.ts": 5669, - "5958-asserted-union-receiver.ts": 1929, - "5959-date-to-json.ts": 2922, - "5960-generic-mapped-types.ts": 3167, - "5970-net-connect-host-name.ts": 1992, - "5971-buffer-chunks-to-string.ts": 3183, - "5972-net-set-encoding-listeners.ts": 2129, - "5974-typeof-module-exports.cjs": 2008, - "5975-zlib-class-values.ts": 2800, - "5990-worker-uncloneable.mjs": 3202, - "5991-worker-async-dispose.mjs": 5853, - "5992-worker-thread-name-lifetime.mjs": 2058, + "3084-record-own-membership.ts": 3434, + "3085-conditional-record-construction.ts": 2128, + "3086-error-constructor-options.ts": 2138, + "3087-error-options-lifetime.ts": 2004, + "3088-array-wide-callbacks.ts": 2257, + "3089-array-find-narrowing.ts": 2620, + "3090-json-discriminated-records.ts": 2285, + "3091-json-recursive-discriminants.ts": 2190, + "3092-number-union-predicates.ts": 2281, + "3093-error-option-data.ts": 2642, + "3094-json-replacer-traversal.ts": 3187, + "3095-json-reviver-traversal.ts": 2938, + "3096-json-callback-nonfinite.ts": 2858, + "3097-json-callback-reentrancy.ts": 2787, + "3098-json-callback-space.ts": 3229, + "3099-json-callback-functions.ts": 3214, + "3100-json-callback-holder.js": 2206, + "3101-json-callback-bytes.ts": 2646, + "3102-json-unknown-fields.ts": 3086, + "3103-scalar-record-nested-control-flow.ts": 2112, + "3104-native-analysis-tables-loops.ts": 2780, + "3105-nullable-collections.ts": 3028, + "3106-mixed-insertion-spreads.ts": 2007, + "3107-nullable-collection-lifetimes.ts": 3338, + "3108-for-await-sync-arrays.js": 2682, + "3108-identity-map-keys.ts": 2227, + "3109-destructuring-unknown-defaults.js": 2915, + "3109-identity-union-collections.ts": 3423, + "3110-builtin-error-families.ts": 2570, + "3110-identity-collection-mutation.ts": 2678, + "3111-identity-collection-cycles.ts": 2997, + "3112-union-switch-control-flow.ts": 2901, + "3113-union-array-removal.ts": 3399, + "3114-union-record-field-write.ts": 2336, + "3115-zlib-static-compression-levels.ts": 2528, + "3116-sequence-expression-lifetimes.ts": 3297, + "3117-unknown-switch-control-flow.ts": 2618, + "3118-recursive-union-spread.ts": 3545, + "3119-runtime-optional-spread.ts": 2406, + "3120-dynamic-property-descriptors.js": 3089, + "3120-generator-method-loop-bindings.ts": 3317, + "3120-ir-nonfinite-numbers.ts": 1849, + "3121-compound-assignment-values.js": 2286, + "3121-dynamic-accessor-descriptors.js": 4553, + "3122-dynamic-delete-descriptors.cjs": 1796, + "3122-dynamic-delete-descriptors.js": 2168, + "3122-js-async-class-methods.js": 2287, + "3123-destructured-global-tdz.js": 2851, + "3124-array-prototype-borrow.js": 3706, + "3125-regex-global-match.ts": 3004, + "3126-js-number-radix/main.ts": 3034, + "3127-spawn-runtime-options.ts": 2691, + "3128-regex-last-index.ts": 2151, + "3129-js-token-union/main.ts": 2990, + "3130-child-generic-streams.ts": 3199, + "3131-child-rest-listeners.js": 1690, + "3132-child-generic-stream-completion.ts": 5607, + "3133-text-decoder-streaming.ts": 3055, + "3134-fs-vectors.ts": 3055, + "3135-fs-file-handle-controls.ts": 3371, + "3136-fs-file-handle-options.ts": 2897, + "3137-fs-vector-callbacks.cjs": 3277, + "3138-array-large-storage.ts": 3756, + "3139-regex-native-deep-alternatives.ts": 28435, + "3140-array-dense-access.ts": 3894, + "3141-map-string-key-hash.ts": 3167, + "3150-integer-remainder.ts": 3353, + "3151-array-push-writes.ts": 3497, + "3170-number-conversion-fast-paths.ts": 3302, + "3171-method-census-data-writes.ts": 2848, + "400-fib.ts": 2397, + "401-mutual-recursion.ts": 2469, + "402-string-functions.ts": 2915, + "403-void-and-params.ts": 1930, + "4030-runtime-object-truthiness.ts": 2360, + "4031-event-emitter-long-tuples.ts": 1978, + "4032-inline-rc-fast-paths.ts": 4391, + "404-rc-stress.ts": 2580, + "4040-adapted-function-identity.ts": 3640, + "4041-adapted-function-properties.ts": 3228, + "4042-object-is-union-subclass.ts": 1738, + "4043-nonnull-missing-element.ts": 3185, + "4044-adapted-callback-modules/main.ts": 2445, + "4045-optional-element-projections.ts": 2663, + "4046-captured-parameter-values.ts": 3523, + "4047-captured-parameter-rebinding.ts": 2990, + "405-params-optional.ts": 2128, + "406-params-defaults.ts": 2785, + "4060-cycle-shared-instance/main.ts": 2724, + "4060-stack-union-reads.ts": 3544, + "4061-cycle-evaluation-order/main.ts": 2941, + "4061-nullable-ref-fields.ts": 4633, + "4062-cycle-tdz-read/main.ts": 2132, + "4063-cycle-hoisted-calls/main.ts": 2837, + "4064-cycle-classes-after-init/main.ts": 2919, + "4065-cycle-init-throws/main.ts": 2003, + "4066-cycle-top-level-tdz/main.ts": 2633, + "4067-dynamic-import-cycle-tdz/main.ts": 2814, + "407-params-rest.ts": 3063, + "408-params-ctors-inheritance.ts": 2314, + "4080-optional-read-presence-tests.ts": 2434, + "4080-string-index-bounds.ts": 2754, + "4081-hoisted-function-tdz.ts": 3289, + "4081-string-index-unproven.ts": 2424, + "4082-hoisted-function-tdz-uncaught.ts": 2711, + "4083-dynamic-import-failure/main.ts": 3307, + "4084-record-optional-field-copies.ts": 3992, + "4085-generator-loop-close.ts": 2360, + "4086-optional-capture-defaults.ts": 2000, + "4088-class-static-tdz.ts": 2016, + "4089-class-wrapper-tdz.js": 2230, + "409-params-async-generics.ts": 2900, + "4090-computed-key-tdz.js": 2345, + "4091-class-evaluation-deferred.ts": 2676, + "410-params-rc-stress.ts": 2904, + "4140-array-callback-split-visit.ts": 4145, + "4141-array-callback-ambient-receiver/main.ts": 3151, + "4142-array-callback-factories.ts": 3774, + "4143-union-refinement-intersection-arms.ts": 1858, + "420-dead-strip-modules/main.ts": 2735, + "4290-acyclic-immutable-trees.ts": 3335, + "4291-acyclic-constructor-escapes.ts": 2796, + "4292-acyclic-readonly-bypass.ts": 2522, + "4293-acyclic-dynamic-writes.ts": 2365, + "4294-console-line-sizes.ts": 6187, + "4295-console-template-parts.ts": 2942, + "4296-console-glued-long-parts.ts": 4142, + "4410-inline-object-allocation.ts": 2124, + "4411-nullable-ref-values.ts": 4400, + "4412-nullable-record-values.ts": 4209, + "4413-cycle-old-late-death.ts": 2986, + "4413-nullable-null-and-undefined.ts": 2888, + "4414-cycle-old-weak-keys.ts": 3194, + "4414-nullable-string-values.ts": 4815, + "4415-identity-borrowed-operands.ts": 2337, + "4415-nullable-container-values.ts": 4436, + "4431-exception-pending-contexts.ts": 2184, + "4432-checked-downcast-failures.ts": 3797, + "4451-int32-field-storage.ts": 3817, + "4452-int32-field-dynamic-writes.ts": 3773, + "4453-int32-closed-locals.ts": 2395, + "4454-int32-field-reflection-reads.ts": 3951, + "4455-live-view-reads-without-stores.ts": 3598, + "4471-unassigned-field-reads.ts": 2666, + "4476-string-ascii-header-fact.ts": 2214, + "4477-buffer-write-ascii-runs.ts": 3271, + "4478-string-large-index-reads.ts": 2510, + "4481-array-optional-push.ts": 3023, + "4482-instanceof-static-class-optional.ts": 2810, + "4483-array-splice-statement.ts": 3482, + "4484-array-length-reset.ts": 2127, + "4485-array-splice-optional-item.ts": 2800, + "4486-array-field-element-borrows.ts": 3650, + "4487-array-literal-optional-values.ts": 3286, + "4520-optional-guard-narrowing.ts": 2046, + "4521-array-callback-element-presence.ts": 4687, + "4522-captured-parameter-lifetimes.ts": 2497, + "4523-array-pop-removal.ts": 3081, + "4524-array-callback-supertype-params.ts": 3932, + "4541-nullable-wrap-borrows.ts": 2389, + "4542-preserving-call-borrows.ts": 3360, + "4543-walk-borrowed-locals.ts": 3391, + "4544-checked-cast-aliases.ts": 3252, + "4545-borrowed-returns.ts": 3896, + "4546-rebound-borrowed-params.ts": 1833, + "4560-field-store-borrowed-receivers.ts": 2735, + "4561-virtual-borrowed-parameters.ts": 3750, + "4562-string-self-concat-move.ts": 2152, + "4563-array-read-projection-receivers.ts": 2323, + "4564-literal-choice-strings.ts": 2445, + "4568-for-of-hole-elements.ts": 3409, + "4569-shorthand-missing-elements.ts": 2920, + "4570-map-lookup-default-record.ts": 3442, + "4591-weak-keys-union-records.ts": 3061, + "4592-cycle-const-from-import/main.ts": 2838, + "4593-weak-keys-empty-objects.ts": 3425, + "4594-union-class-field-mixed-types.ts": 3724, + "4595-union-class-field-optional-receiver.ts": 3074, + "4596-error-subclass-int-fields.ts": 2744, + "4596-tdz-nullable-forward-capture.ts": 3971, + "4597-callback-field-method-name.ts": 2791, + "4598-live-array-ref-element-access.ts": 5033, + "4598-map-set-clear-reuse.ts": 4347, + "4598-os-available-parallelism.ts": 2628, + "4598-publish-constructor-stores.ts": 3091, + "4599-construction-only-field-borrows.ts": 3355, + "4600-construction-only-fields-dynamic-writes.ts": 2213, + "4601-cycle-holders.ts": 2024, + "4602-constructor-escape-order.ts": 2992, + "4610-array-ext-dyn-refresh.ts": 3195, + "4620-optional-chain-borrowed-receivers.ts": 3095, + "4621-edge-preserving-callees/main.ts": 3779, + "4630-contract-int32.ts": 2865, + "4630-reference-write-call-arguments.ts": 2202, + "4631-contract-nothrow.ts": 2128, + "4631-reference-write-aliases.ts": 3078, + "4632-contract-immutable.ts": 2740, + "4632-reference-write-loops-and-walks.ts": 3256, + "4633-contract-program-lifetime.ts": 2525, + "4633-reference-write-callbacks-returns.ts": 3120, + "4634-contract-program-lifetime-publish.ts": 5678, + "4634-optional-element-borrowed-returns.ts": 2332, + "4640-bitwise-identity-ranges.ts": 3148, + "4641-nothrow-try-catch.ts": 3252, + "4642-acyclic-contract.ts": 2463, + "4650-stale-property-narrowing.ts": 3973, + "4651-map-string-get-entry.ts": 2471, + "4652-stale-closure-binding-narrowing.ts": 3516, + "4660-typed-rest-spread-forwarding.ts": 3181, + "4671-scoped-array-read-borrows.ts": 2667, + "4690-cycle-bypass-long-lived.ts": 4305, + "4691-publish-constructor-self-alias.ts": 2372, + "4692-borrowed-result-mutating-callees.ts": 1719, + "4720-cold-throw-paths.ts": 3494, + "4721-integer-induction-numbers.ts": 2519, + "4730-touint32-large-magnitudes.ts": 3115, + "4731-string-mixed-ascii-slices.ts": 3544, + "4732-buffer-write-utf16le-runs.ts": 3493, + "4733-typed-array-read-compares.ts": 3222, + "4750-map-string-absent-filter.ts": 2733, + "4751-string-search-multibyte-needles.ts": 2428, + "4795-published-untyped-member-reads.ts": 3850, + "4806-uint32-loop-accumulators.ts": 3676, + "4810-union-identity-retags.ts": 4908, + "4811-union-retag-checked-cast.ts": 2426, + "4812-int32-wrapping-sums.ts": 3340, + "4813-typed-array-read-equality-bindings.ts": 4912, + "4820-sort-comparator-lent-arguments.ts": 4229, + "4821-callback-lent-arguments.ts": 4442, + "4822-stable-capture-reads.ts": 3053, + "4823-array-store-receivers.ts": 3132, + "4830-typed-teardown-chains.ts": 2523, + "4831-cycle-bypass-probe-windows.ts": 2952, + "4840-array-hole-free-prefix.ts": 3114, + "4860-int32-local-storage.ts": 4294, + "4870-array-pipeline-fusion.ts": 4815, + "4871-array-pipeline-analytics.ts": 3642, + "4872-array-pipeline-temporaries.ts": 8318, + "4875-stream-consumers-array-buffer.ts": 2209, + "4876-array-buffer-inspect.ts": 3069, + "4880-await-call-turn-order.ts": 2111, + "4881-await-call-exceptions.ts": 3319, + "4882-await-call-request-chain.ts": 2496, + "4883-await-values-and-hops.ts": 2868, + "4884-await-call-unhandled-sibling.ts": 2184, + "4885-await-call-checkpoints.ts": 3054, + "4890-regex-literal-sites.ts": 2434, + "4891-regex-plain-text-patterns.ts": 2078, + "4892-regex-exec-read-captures.ts": 2821, + "4900-bigint-division-cross-check.ts": 3490, + "4900-console-instances.ts": 3829, + "4901-bigint-radix-text.ts": 2425, + "4901-console-instance-errors.ts": 2457, + "4902-bigint-compound-assign.ts": 2147, + "4903-bigint-fixed-width.ts": 2614, + "4904-bigint-large-products.ts": 3572, + "4905-bigint-fixed-width-fusion.ts": 3509, + "4906-bigint-small-value-trees.ts": 3794, + "4907-bigint-random-trees.ts": 4702, + "4910-hole-free-prefix-upkeep.ts": 2383, + "4920-string-literal-switch.ts": 2483, + "4930-typed-record-reflection.ts": 5024, + "4931-typed-data-generic-walks.ts": 4893, + "4932-typed-json-unknown.ts": 3278, + "4940-async-return-adoption.ts": 3536, + "4941-async-return-adoption-try.ts": 2995, + "4942-async-return-adoption-values.ts": 4513, + "4943-async-return-adoption-interleaved.ts": 2479, + "4950-regex-compiled-captures.ts": 4860, + "4951-regex-compiled-last-index.ts": 3606, + "4952-regex-compiled-anchors-classes.ts": 3738, + "4953-regex-compiled-backtracking.ts": 2856, + "4954-regex-log-report.ts": 4801, + "4955-regex-compiled-differential.ts": 24475, + "4970-int32-call-abi.ts": 3417, + "4980-generator-early-exit-finally.ts": 3144, + "4981-generator-delegation-iterables.ts": 4656, + "4982-generator-sent-values.ts": 2721, + "4983-generator-reuse-iterables.ts": 3420, + "4984-generator-exceptions.ts": 3409, + "4985-generator-lazy-pipeline.ts": 3627, + "4986-generator-default-channels.ts": 3616, + "4987-generator-closures-methods.ts": 2884, + "4988-generator-async-interplay.ts": 2217, + "4989-generator-step-drives.ts": 3530, + "4990-lone-surrogates.ts": 2833, + "4991-lone-surrogate-halves.ts": 2382, + "4992-lone-surrogate-search.ts": 2602, + "4993-lone-surrogate-json.ts": 2479, + "4994-lone-surrogate-uri.ts": 3069, + "4995-lone-surrogate-regex.ts": 3486, + "4996-lone-surrogate-stdio.ts": 3232, + "4997-lone-surrogate-stdout-patch.js": 2640, + "4998-lone-surrogate-buffers.ts": 2452, + "4999-lone-surrogate-io.ts": 2454, + "500-array-basics.ts": 2089, + "501-array-push-pop.ts": 2391, + "5010-lifetime-region-generations.ts": 2818, + "5011-lifetime-region-outside-references.ts": 3377, + "5012-lifetime-region-shapes.ts": 3312, + "5013-lifetime-region-async.ts": 3967, + "5014-lifetime-region-nesting.ts": 3224, + "5015-lifetime-region-publish.ts": 3866, + "5016-lifetime-region-weak-keys.ts": 2328, + "5017-lifetime-region-cycles.ts": 2417, + "5018-lifetime-region-hierarchies.ts": 4028, + "5019-lifetime-region-values.ts": 3115, + "502-array-for-of.ts": 2081, + "5020-lifetime-region-large.ts": 4189, + "5021-lifetime-region-opaque-holders.ts": 2035, + "5022-lifetime-region-workers.ts": 3716, + "5023-lifetime-region-await.ts": 3656, + "5024-lifetime-region-await-forms.ts": 3342, + "503-array-functions.ts": 2924, + "504-array-rc-stress.ts": 3242, + "5040-promise-all-race-turns.ts": 4173, + "5041-promise-all-turns.js": 2741, + "5042-async-generator-return-promise.ts": 3826, + "5043-async-generator-return-forms.ts": 2473, + "5045-generator-delegation-typed-next.ts": 4238, + "5046-generator-delegation-return-throw.ts": 3793, + "5047-generator-delegation-iterables-typed.ts": 4942, + "5048-generator-delegation-async.ts": 3582, + "5049-generator-delegation-edges.ts": 2876, + "5050-inherited-in-membership.ts": 3767, + "5051-typed-record-prototypes.ts": 3580, + "5052-class-for-in-unknown.ts": 3587, + "5053-json-replacer-arrays.ts": 2213, + "5054-required-field-delete.ts": 2545, + "5055-object-create-record-literal.ts": 2467, + "5056-generator-in-unknown.ts": 2333, + "5060-child-fork-exit-after-messages/main.ts": 2415, + "5061-child-fork-local-disconnect/main.ts": 3036, + "5062-child-fork-message-before-eof/main.ts": 2882, + "5065-global-increment-initializers.ts": 2801, + "5066-global-compound-updates.ts": 3218, + "5067-global-updates-in-functions.ts": 3110, + "5068-global-var-let-const-updates.ts": 2271, + "5069-global-update-modules/main.ts": 2850, + "5070-optional-read-bindings.ts": 2832, + "5071-optional-chain-scalars.ts": 2863, + "5072-optional-nullish-ternary.ts": 2578, + "5073-optional-results.ts": 3429, + "5074-optional-pop-shift.ts": 2389, + "5075-optional-reads-unchecked/main.ts": 2697, + "5076-optional-escapes.ts": 2437, + "5080-boolean-array-storage.ts": 6485, + "5081-boolean-array-dynamic-views.ts": 2359, + "5085-promise-allsettled-turns.ts": 3904, + "5086-promise-any-turns.ts": 3934, + "5087-promise-allsettled-any-dyn.js": 5476, + "5088-promise-combinator-thenables.js": 3403, + "5089-promise-settled-records.ts": 3102, + "5090-generator-finished-result-value.ts": 3342, + "5091-generator-delegation-arrays-strings.ts": 4412, + "5092-generator-delegation-sets-maps.ts": 3102, + "5095-console-count-group.ts": 3177, + "5096-console-assert-dir.ts": 3849, + "5097-console-table.ts": 3057, + "5098-console-time-warnings.ts": 6642, + "5099-console-methods-dynamic.cjs": 3356, + "510-array-map-filter-foreach.ts": 3363, + "511-array-indexof-includes.ts": 3037, + "5110-var-hoisting-early-reads.ts": 2475, + "5111-var-hoisting-closures-classes.ts": 3177, + "5112-var-hoisting-function-scope.ts": 2961, + "5113-tdz-let-const-class.ts": 3714, + "5114-var-hoisting-js.js": 2962, + "5115-regex-replace-compiled.ts": 3348, + "5116-regex-capture-reads.ts": 3537, + "5117-regex-log-report-spans.ts": 2918, + "5118-regex-replace-char-chains.ts": 2863, + "512-array-join-chains.ts": 2158, + "5120-frame-records.ts": 2742, + "5121-frame-objects.ts": 2716, + "5122-frame-result-slots.ts": 2032, + "5123-frame-reassigned.ts": 2738, + "5124-frame-objects-control.ts": 2735, + "5125-frame-mutating-methods.ts": 2979, + "5126-frame-returned-params.ts": 2879, + "5127-frame-loop-bindings.ts": 3193, + "513-array-methods-rc-stress.ts": 2584, + "5130-event-target-dispatch.js": 3996, + "5131-event-target-listener-errors.js": 2992, + "5132-event-target-typed.ts": 2663, + "5133-abort-signal-event-target.ts": 3726, + "5134-events-error-monitor.ts": 3026, + "5135-event-target-warnings.js": 3015, + "5136-events-error-monitor-string-name.ts": 1974, + "5137-events-error-monitor-computed-name.js": 2881, + "5138-events-error-monitor-shared-listener.ts": 1863, + "5139-event-target-listener-throw.ts": 2263, + "514-array-find-some-every.ts": 3260, + "5140-os-host-facts.ts": 3684, + "5141-os-constants.ts": 3492, + "5142-path-parse-format.ts": 2821, + "5145-path-matches-glob-basics.ts": 2871, + "5146-path-matches-glob-braces.ts": 4793, + "5147-path-matches-glob-extglob.ts": 3097, + "5148-path-matches-glob-classes.ts": 3036, + "5149-path-matches-glob-win32.ts": 3100, + "515-array-flatmap.ts": 3003, + "5150-small-array-inline-slots.ts": 3147, + "5155-cycle-header-types.ts": 3920, + "516-array-reduce.ts": 3545, + "5160-field-callback-receiver.ts": 2905, + "5161-field-callback-receiver-escape.ts": 2883, + "5162-field-method-reference-receiver.ts": 2527, + "5163-field-callback-receiver.cjs": 3464, + "5164-worker-field-callback-receiver.ts": 3434, + "5165-interface-method-dispatch.ts": 3679, + "5166-interface-method-values.ts": 3253, + "5167-interface-method-order.ts": 3399, + "5168-interface-method-hierarchy.ts": 3873, + "5169-interface-method-chains.ts": 4165, + "517-array-hof-index-args.ts": 2228, + "5170-string-scan-eviction.ts": 2996, + "5171-lone-surrogate-replace-seams.ts": 3136, + "5175-forin-typed-as-unknown.ts": 2043, + "5176-object-keys-typed-as-unknown.ts": 3098, + "5177-forin-dynamic-objects.ts": 3236, + "5178-forin-keys-js.js": 3163, + "5179-forin-typed-shapes.ts": 3384, + "518-array-sort.ts": 2963, + "518-promise-void-union-callbacks.ts": 3093, + "5180-interface-arrays.ts": 3147, + "5181-interface-array-methods.ts": 8906, + "5182-interface-array-boundaries.ts": 2573, + "5183-interface-property-reads.ts": 3303, + "5184-interface-property-objects.ts": 2438, + "5185-util-inherits.cjs": 3986, + "5186-util-inherits.ts": 3513, + "5187-util-deprecate.cjs": 3994, + "5188-util-deprecate-flags.cjs": 2993, + "5189-util-deprecate.ts": 3292, + "519-array-from-length.ts": 2634, + "519-promise-union-await-values.ts": 2998, + "5190-util-callbackify.cjs": 2477, + "5191-util-callbackify.ts": 3362, + "5192-util-debuglog.cjs": 3445, + "5193-util-debuglog.ts": 3383, + "5194-process-emit-warning-tick.cjs": 2282, + "5195-object-entries-typed-as-unknown.ts": 3460, + "5196-object-values-typed-as-unknown.ts": 3267, + "5197-object-entries-dynamic-objects.ts": 3904, + "5198-object-entries-values-js.js": 2966, + "5199-object-entries-identity.ts": 3380, + "520-map-basics.ts": 2986, + "5200-array-sort-keyed-numbers.ts": 3421, + "5201-array-sort-keyed-records.ts": 5202, + "5202-array-sort-keyed-lookalikes.ts": 3629, + "5203-typed-array-sort-default.ts": 5027, + "5204-typed-array-sort-comparators.ts": 3154, + "521-map-number-keys.ts": 2975, + "5210-process-memory-usage.ts": 2993, + "5211-process-identity.ts": 2460, + "5212-perf-marks-measures.ts": 3807, + "5213-perf-timing-errors.ts": 2266, + "5214-perf-entry-inspect.ts": 4135, + "5215-perf-timing-validation.js": 3297, + "5216-perf-spread-arguments.js": 2533, + "5217-perf-spread-typed.ts": 2686, + "522-map-foreach.ts": 3042, + "5220-url-parse-warnings.ts": 2728, + "5221-url-parse-shapes.ts": 3405, + "5222-url-parse-hosts.ts": 3159, + "5223-url-parse-query.ts": 3506, + "5224-url-format-objects.ts": 3987, + "5225-url-format-whatwg.ts": 3370, + "5226-url-resolve.ts": 3030, + "5227-url-legacy-dependency/main.ts": 2891, + "5228-url-domain-conversion.ts": 2727, + "5229-url-legacy-errors.cjs": 3507, + "523-map-ref-values.ts": 2648, + "5230-inline-union-fields.ts": 3279, + "5231-inline-union-field-kinds.ts": 2225, + "5232-inline-union-fields-dynamic.ts": 4075, + "5233-inline-union-fields-shapes.ts": 3388, + "5234-inline-union-class-fields.ts": 3532, + "5235-inline-union-fields-publish.ts": 2491, + "5236-inline-union-unchecked-reads.ts": 3193, + "5237-inline-union-frame-objects.ts": 3058, + "524-map-cycles.ts": 2269, + "5240-event-target-subclass.ts": 4204, + "5241-event-subclass.ts": 2870, + "5242-event-target-subclass-hierarchy.ts": 2589, + "5243-event-target-subclass-dynamic.ts": 3729, + "5244-event-target-subclass.js": 3769, + "5245-event-target-subclass-signals.ts": 3471, + "5246-event-target-subclass-listener-throw.ts": 3466, + "5247-event-target-subclass-lifetimes.ts": 4294, + "5248-event-target-subclass-warnings.ts": 3036, + "5249-event-target-subclass-unconstructed.ts": 2612, + "525-map-rc-stress.ts": 2418, + "5250-cipher-aes-gcm.ts": 5771, + "5251-cipher-aes-cbc.ts": 3823, + "5252-cipher-aes-ctr.ts": 2580, + "5253-cipher-chacha20-poly1305.ts": 3418, + "5254-cipher-errors.js": 4743, + "5255-cipher-encodings.cjs": 2250, + "5256-cipher-deprecation.cjs": 3088, + "5257-cipher-vectors.ts": 3572, + "5258-cipher-handles.js": 2980, + "5259-cipher-chunked.ts": 2586, + "526-set-basics.ts": 2254, + "5260-record-unknown-identity.ts": 2475, + "5261-optional-field-identity.ts": 3183, + "5262-record-unknown-many.ts": 2600, + "527-set-foreach.ts": 2444, + "5270-url-parse-no-deprecation.cjs": 3324, + "5271-url-parse-throw-deprecation.cjs": 3222, + "5275-http-end-callback-order.ts": 3388, + "5276-style-text-hex-colors.cjs": 2986, + "5277-fs-read-file-buffer-option.cjs": 2730, + "5278-host-null-bytes.cjs": 2802, + "5279-search-params-null-init.cjs": 2749, + "528-set-seeded.ts": 3056, + "5285-blob-construct.ts": 2884, + "5286-blob-readers.ts": 2550, + "5287-blob-inspect.ts": 3329, + "5288-blob-validation.js": 3838, + "5289-blob-read-order.ts": 3430, + "529-map-seeded.ts": 2821, + "5290-blob-dynamic.js": 3167, + "5295-readline-promises-question.ts": 3310, + "5296-readline-lines.ts": 2423, + "5297-readline-callback-events.cjs": 2594, + "5298-readline-abort.cjs": 3296, + "5299-readline-stdin.ts": 3344, + "530-record-arrays.ts": 2381, + "5300-stream-add-abort-signal.ts": 3578, + "5301-stream-add-abort-signal-errors.cjs": 3164, + "5302-stream-promises-options.ts": 2875, + "5303-stream-finished-callback-opts.cjs": 3111, + "5305-json-stringify-typed-arrays.ts": 3510, + "531-record-array-hofs.ts": 3334, + "5315-map-iterate-after-front-deletes.ts": 2670, + "5316-map-lru-eviction.ts": 3171, + "5317-map-iterate-while-mutating.ts": 3109, + "5318-set-iterate-after-deletes.ts": 3338, + "5319-map-iteration-values.ts": 2901, + "532-record-arrays-rc-stress.ts": 2965, + "5320-map-iterate-across-compaction.ts": 2712, + "5321-integer-closed-arithmetic-loops.ts": 3349, + "5321-json-parse-cycles.ts": 3308, + "5322-integer-variable-step-loops.ts": 2801, + "5322-json-stringify-parsed-trees.ts": 3139, + "5323-dyn-numeric-index-reads.ts": 2266, + "5323-int32-nonnegative-slot-facts.ts": 2381, + "5324-int32-initializer-locals.ts": 3123, + "5324-structured-clone-documents.ts": 3223, + "5325-record-boundary-returns.ts": 1813, + "5326-record-boundary-params.ts": 2295, + "5327-record-boundary-identity.ts": 3016, + "5328-record-boundary-open.ts": 2956, + "5329-record-boundary-recursion.ts": 3001, + "533-array-element-cycles.ts": 2575, + "5330-record-boundary-fields.ts": 2897, + "5331-record-boundary-methods.ts": 2874, + "5332-int32-narrowed-slot-facts.ts": 2932, + "5333-integer-guarded-while-counters.ts": 2773, + "5333-record-boundary-nullable-argument.ts": 2389, + "5334-fetch-mentions-without-calls.ts": 2822, + "5335-stream-operators-values.ts": 3448, + "5335-top-level-await-pending-exit-code.ts": 2359, + "5336-stream-operators-promise-timing.ts": 3509, + "5336-top-level-await-pending-exit-listener.ts": 2649, + "5337-dc-subscriber-throw-next-tick.cjs": 2705, + "5337-stream-operators-concurrency.ts": 2478, + "5338-js-tdz-function-element.js": 2787, + "5338-stream-operators-checks.cjs": 3991, + "5339-array-buffer-constructor.js": 3134, + "5339-stream-for-await-hops.ts": 2919, + "534-record-width-subtyping.ts": 3068, + "5340-readable-from-options.ts": 1980, + "5341-compound-any-operand.ts": 3314, + "5341-generator-callback-params.ts": 3955, + "5341-integer-recursion-boundaries.ts": 2534, + "5341-readable-from-dynamic.cjs": 3057, + "5342-compound-any-operand.cjs": 3386, + "5342-generator-scalar-channels.ts": 3184, + "5342-integer-recursion-stack-and-mutual.ts": 3097, + "5342-stream-compose.ts": 2940, + "5343-any-flow-compound.ts": 2063, + "5343-integer-recursion-array-index.ts": 2905, + "5343-iterator-result-records.ts": 3426, + "5343-stream-compose-edges.ts": 3078, + "5344-json-parse-undeclared-keys.ts": 4193, + "5344-stream-pipeline-timing.ts": 3177, + "5345-object-values-for-of-unknown.ts": 3435, + "5346-object-values-length-dynamic.ts": 3274, + "5347-object-values-loop-control.ts": 3443, + "5348-object-values-for-of-js.js": 2832, + "5349-object-entries-values-optional.ts": 3325, + "535-object-statics.ts": 3232, + "5350-object-values-wide-record.ts": 2628, + "5351-object-values-methods-index.ts": 4093, + "5352-final-field-loop-reads.ts": 2894, + "5353-captured-const-values.ts": 3727, + "5354-captured-const-tdz.ts": 2243, + "5355-captured-function-declarations.ts": 2917, + "5356-captured-tdz-ordering.ts": 2726, + "5357-init-only-module-bindings.ts": 1956, + "536-map-seed-array.ts": 1912, + "5360-array-sort-comparator-calls.ts": 3363, + "5361-array-sort-inconsistent-comparators.ts": 3560, + "5362-array-sort-comparator-throws.ts": 3410, + "5363-array-sort-comparator-writes.ts": 7945, + "5364-array-sort-union-and-boolean-elements.ts": 10573, + "5365-array-sort-dynamic-values.js": 2528, + "537-map-iter-drains.ts": 3127, + "5370-zlib-stream-roundtrip.ts": 3486, + "5371-zlib-stream-chunking.cjs": 4025, + "5372-zlib-stream-errors.cjs": 2794, + "5373-zlib-stream-options.cjs": 3210, + "5374-zlib-stream-flush-params.ts": 3572, + "5375-zlib-stream-promises.ts": 3156, + "5376-zlib-constants.cjs": 2490, + "5377-zlib-stream-backpressure.cjs": 2917, + "5378-zlib-sync-options.cjs": 2777, + "5379-zlib-callback-options.ts": 2861, + "538-map-set-for-of.ts": 2968, + "5390-interface-loop-element-lifetimes.ts": 3450, + "5391-interface-dispatch-hierarchies.ts": 2856, + "5392-interface-receiver-bindings.ts": 2639, + "5393-interface-array-holes.ts": 3216, + "5394-interface-implementers.ts": 3420, + "5395-locale-compare-ascii.ts": 2643, + "5396-locale-compare-latin.ts": 3373, + "5397-locale-compare-sorting.ts": 2181, + "540-tuples-basics.ts": 3148, + "5400-json-parse-typed-keys.ts": 3311, + "5405-buffer-arraybuffer-window.ts": 2743, + "5406-util-types-keys.ts": 3041, + "5407-http-header-field-limit.ts": 3155, + "5408-http-unread-request-end.ts": 3012, + "5409-http-held-request-body.ts": 3019, + "541-ref-array-json.ts": 2632, + "5410-inspect-class-values.ts": 3232, + "5411-inspect-class-hierarchies.ts": 3027, + "5412-inspect-dynamic-collections.ts": 2914, + "5413-inspect-class-values.cjs": 3313, + "5415-zlib-dynamic-inputs.cjs": 3606, + "542-union-element-arrays.ts": 3131, + "5420-readable-from-generators.ts": 3459, + "5421-readable-from-generators.cjs": 3156, + "5422-stream-async-push-wakeup.ts": 3051, + "5423-stream-end-and-eos-timing.ts": 3065, + "5424-stream-write-buffer-encoding.ts": 2687, + "5425-pipeline-generator-stage.ts": 2503, + "5426-pipeline-generator-errors.ts": 3640, + "5427-pipeline-generator-backpressure.ts": 3096, + "5428-pipeline-generator-stages.cjs": 2057, + "5429-pipeline-generator-buffers.ts": 2918, + "5430-dyn-number-string-boxes.ts": 3282, + "5435-crypto-hash-algorithms.ts": 2301, + "5436-crypto-hash-names.js": 2084, + "5437-crypto-hmac-algorithms.ts": 3303, + "5438-crypto-kdf-digests.ts": 2137, + "5439-crypto-kdf-callbacks.js": 3353, + "5440-crypto-hash-encodings.js": 4466, + "5441-crypto-hash-output-length.ts": 3422, + "5442-crypto-random-values.ts": 3350, + "5443-crypto-random-arguments.js": 3269, + "5444-crypto-timing-safe-equal.js": 2816, + "5445-crypto-secret-key-objects.ts": 3209, + "5445-stream-buffer-chunks.ts": 3329, + "5446-crypto-secret-key-errors.js": 2813, + "5446-stream-buffer-chunks-dynamic.js": 2503, + "5447-fs-readdir-order.ts": 2263, + "5448-fs-glob-patterns.ts": 2912, + "5449-fs-glob-options.ts": 3879, + "5450-fs-glob-validation.js": 4118, + "5451-fs-promises-glob.ts": 3698, + "5452-fs-glob-callback.ts": 2619, + "5455-power-of-two-remainder.ts": 2806, + "5456-remainder-large-integer-dividends.ts": 3156, + "5457-lcg-modulus.ts": 2975, + "5458-fractional-remainder.ts": 2938, + "5460-locale-compare-contractions.ts": 2684, + "5461-locale-compare-equivalents.ts": 3166, + "5462-locale-compare-probe-sweep.ts": 4453, + "5463-locale-compare-combining-letters.ts": 2871, + "5464-locale-compare-fractions.ts": 3156, + "5465-dyn-index-read-arrays.ts": 3603, + "5466-dyn-index-read-special.ts": 2823, + "5470-strip-vt-osc.cjs": 2872, + "5471-strip-vt-csi.cjs": 2359, + "5472-strip-vt-random.cjs": 3265, + "5473-strip-vt-unterminated.cjs": 3751, + "5474-strip-vt-surrogates.ts": 2805, + "5510-assert-error-properties.js": 2744, + "5511-assert-error-class.ts": 3998, + "5512-assert-error-options.js": 3572, + "5513-assert-deep-equal-loose.js": 3537, + "5514-assert-deep-equal-typed.ts": 2922, + "5515-assert-deep-strict-typed-messages.ts": 2776, + "5516-assert-deep-equal-edges.js": 3465, + "5517-assert-partial-deep-equal.js": 4023, + "5518-assert-partial-deep-typed.ts": 3538, + "5519-assert-partial-deep-typed-edges.ts": 3741, + "5520-assert-record-literal-failures.ts": 3435, + "5520-dyn-property-read-receivers.ts": 3114, + "5521-assert-empty-message.js": 3945, + "5521-dyn-property-read-keys.ts": 2472, + "5522-assert-throws-failure-properties.ts": 3505, + "5523-assert-class-options.js": 3797, + "5524-assert-class-skip-prototype.ts": 2105, + "5530-buffer-pool.ts": 3788, + "5531-buffer-pool-first-slab.ts": 5451, + "5532-buffer-pool-first-slab-untyped.mjs": 37592, + "5540-fs-callback-forms.cjs": 3863, + "5541-fs-stats-fields.cjs": 4344, + "5542-fs-promises-parity.cjs": 2640, + "5543-fs-promises-typed.ts": 3538, + "5544-fs-opendir.cjs": 3175, + "5545-fs-options-encoding.cjs": 3831, + "5546-fs-read-stream.cjs": 3808, + "5547-fs-write-stream.cjs": 5798, + "5548-fs-callback-arguments.cjs": 4728, + "5549-fs-callback-option-checks.cjs": 4270, + "5550-locale-compare-ascii-words.ts": 2457, + "5551-array-search-references.ts": 2240, + "5552-string-appends.ts": 3367, + "5553-string-append-char-code.ts": 2628, + "5554-fs-streams-typed.ts": 4016, + "5555-fs-callback-turns.cjs": 3136, + "5555-http-server-close-keep-alive.ts": 6777, + "5556-http-client-agent-connection.ts": 3427, + "5557-http-outgoing-header-values.ts": 2893, + "5558-http-incoming-duplicate-headers.ts": 3230, + "5559-http-expect-header.ts": 3517, + "5560-http-response-framing.ts": 5004, + "5561-http-max-header-size.ts": 3610, + "5562-https-verify-errors.ts": 3646, + "5563-http-keep-alive-timeout.ts": 11895, + "5564-http-request-signal.ts": 4124, + "5565-fs-dirent-untyped.mjs": 2565, + "5566-fs-dirent-dyn-boundaries/main.mjs": 3508, + "5567-fs-cpsync.ts": 3736, + "5568-fs-cp-errors.js": 4246, + "5569-fs-cp-symlinks.ts": 2136, + "5570-fs-cp-async.ts": 3348, + "5571-fs-cp-deep.ts": 4817, + "5585-record-results-inlined.ts": 3419, + "5595-net-ref-unref.ts": 3245, + "5600-dyn-cycle-self.ts": 2318, + "5601-dyn-cycle-mutual.ts": 2455, + "5602-dyn-cycle-arrays.ts": 3115, + "5603-dyn-cycle-identity.ts": 3197, + "5604-dyn-cycle-checks.ts": 3210, + "5605-dyn-cycle-containers.ts": 2935, + "5606-dyn-cycle-capsules.ts": 2308, + "5610-readable-from-sets-and-views.ts": 3154, + "5611-readable-from-class-iterables.ts": 3984, + "5612-readable-from-iterables.cjs": 3740, + "5613-readable-from-iterable-timing.cjs": 4549, + "5614-readable-from-iterable-errors.cjs": 4240, + "5615-next-tick-callback-phases.ts": 3053, + "5616-next-tick-callback-phases.cjs": 3322, + "5617-pipeline-function-ends.ts": 2710, + "5618-pipeline-function-ends-errors.ts": 3693, + "5619-pipeline-function-ends.cjs": 3677, + "5620-timers-promises-values.ts": 2181, + "5621-util-format-float.ts": 2886, + "5622-events-once.mjs": 3520, + "5623-events-once.ts": 2509, + "5624-timers-promises-unawaited.ts": 2304, + "5625-promisify-exec.ts": 7463, + "5626-promisify-forms.ts": 2936, + "5627-exec-callback.ts": 2909, + "5628-promisify-timers.ts": 3194, + "5629-promisify-stream.ts": 2517, + "5630-promisify-zlib.ts": 2503, + "5631-promisify-crypto.ts": 4296, + "5632-promisify-dns.ts": 2784, + "5644-net-socket-addresses.ts": 2435, + "5645-net-socket-callbacks.ts": 2678, + "5646-net-server-connections.ts": 3279, + "5647-net-is-ip.ts": 2496, + "5648-dns-lookup-forms.ts": 2735, + "5649-dns-service-servers.ts": 3175, + "5650-dns-lookup-errors-untyped.cjs": 1968, + "5651-tls-socket-protocol.ts": 2771, + "5652-http-client-trailer-overflow.ts": 3884, + "5653-net-socket-read-ahead.ts": 4524, + "5654-https-empty-servername.ts": 3451, + "5655-dgram-socket-options.ts": 3481, + "5656-dgram-option-states.ts": 3002, + "5657-net-reset-and-address.ts": 3415, + "5658-net-reset-dynamic.cjs": 2564, + "5659-net-blocklist-socketaddress.ts": 4443, + "5664-tls-client-identity.ts": 3727, + "5674-union-instanceof-array-arms.ts": 2159, + "5680-array-growth-after-copy.ts": 3791, + "5681-array-pop-and-length.ts": 2915, + "5682-publish-wide-objects.ts": 3326, + "5700-cycle-release-retained.ts": 2156, + "5701-cycle-release-old-edges.ts": 2601, + "5702-publish-candidate-buffers.ts": 3469, + "5703-lifetime-region-debug.ts": 3115, + "5704-publish-refused-restores-counts.ts": 2979, + "5710-map-number-keys-hashed.ts": 3019, + "5711-map-number-write-after-read.ts": 2613, + "5712-map-number-overwrite-at-growth.ts": 2614, + "5714-cycle-large-candidate-buffers.ts": 3979, + "5715-json-parse-fitted-tables.ts": 3940, + "5717-set-prototype-of-primitives.ts": 3887, + "5719-int32-fields-dynamic-operators.ts": 3207, + "5720-intern-table-basics.ts": 3625, + "5721-intern-table-values.ts": 4014, + "5722-intern-table-workers.ts": 3210, + "5723-intern-table-shared-types.ts": 4601, + "5724-intern-table-array-keys.ts": 4072, + "5725-intern-table-callbacks.ts": 1996, + "5726-intern-table-key-limits.ts": 2644, + "5740-atomics-operation-semantics.ts": 4810, + "5741-atomics-contended-counters.ts": 2504, + "5742-atomics-lock-ordering.ts": 3000, + "5743-atomics-wait-notify.ts": 3638, + "5744-atomics-ring-buffer.ts": 3352, + "5745-atomics-semaphore-stress.ts": 3671, + "5746-shared-bulk-operations.ts": 2732, + "5747-fs-stat-throw-if-no-entry.ts": 2662, + "5748-fs-stat-throw-if-no-entry-js.cjs": 3085, + "5752-string-number-concat.ts": 3186, + "5760-crypto-hash-stream.ts": 3011, + "5761-crypto-hash-stream-states.ts": 3241, + "5762-crypto-hash-stream.cjs": 3286, + "5763-crypto-sha-blocks.ts": 3264, + "5764-class-structural-view-writes.ts": 4118, + "5764-crypto-hmac-edges.cjs": 2105, + "5765-class-structural-view-identity.ts": 3529, + "5766-class-structural-view-callbacks.ts": 3162, + "5767-class-opaque-accessor-view.ts": 2108, + "5770-guarded-union-narrows.ts": 2881, + "5771-guarded-downcasts.ts": 3555, + "5772-guarded-catch-narrows.ts": 2601, + "5773-stale-narrowing-inherited.ts": 2486, + "5776-power-of-two-remainder-integer-path.ts": 3263, + "5780-readline-history-options.ts": 2909, + "5781-readline-history-options.cjs": 3288, + "5782-readline-terminal-editing.ts": 2661, + "5783-readline-terminal-completion.cjs": 4948, + "5784-readline-terminal-promises.ts": 3042, + "5785-readline-terminal-keys.ts": 3376, + "5786-readline-terminal-history.cjs": 2745, + "5787-readline-cursor-helpers.cjs": 3241, + "5788-readline-promises-readline.ts": 3322, + "5789-readline-cursor-pos.cjs": 3206, + "5790-readline-keypress-events.ts": 3280, + "5791-dyn-constant-key-read-sites.ts": 2813, + "5791-readline-keypress-interfaces.cjs": 3397, + "5792-json-parse-repeated-layouts.ts": 3939, + "5792-readline-keypress-listeners.ts": 2151, + "5793-worker-message-channel.ts": 3274, + "5794-worker-message-port-close-order.ts": 3161, + "5795-worker-message-port-batches.ts": 1925, + "5796-worker-message-channel.cjs": 2678, + "5797-worker-message-port-transfer.ts": 3445, + "5800-broadcast-channel.ts": 3609, + "5801-broadcast-channel.cjs": 3080, + "5802-broadcast-channel-workers.ts": 2610, + "5803-worker-environment-data.ts": 3416, + "5804-worker-environment-data.cjs": 2230, + "5805-worker-receive-message-parent-port.ts": 3538, + "5806-worker-resource-limits.ts": 2813, + "5807-worker-error-values.ts": 4237, + "5808-worker-unhandled-rejections.ts": 4239, + "5809-process-exit-and-rejections.cjs": 3639, + "5810-mock-method-records.ts": 3521, + "5811-mock-tracker-restore.ts": 2838, + "5812-dyn-box-async-fields.ts": 3501, + "5813-mock-timers-module.ts": 3107, + "5814-mock-timers-date.ts": 2412, + "5830-timers-promises-signal.ts": 3875, + "5831-util-types-brands.ts": 4018, + "5832-util-types-brands-dynamic.js": 3859, + "5833-url-search-params-iterators.ts": 2320, + "5834-url-search-params-iterators-dynamic.mjs": 3863, + "5835-util-format-integer-specifiers.ts": 2838, + "5836-url-search-params-tuple-pairs.ts": 3097, + "5837-util-format-json-circular.ts": 2711, + "5838-qs-stringify-bigint.ts": 3073, + "5839-timers-promises-scheduler.ts": 3195, + "5840-promise-with-resolvers-js.js": 2842, + "5841-json-typed-dyn-members.ts": 3759, + "5842-qs-parse-null-prototype.ts": 3419, + "5843-qs-parse-null-prototype-js.mjs": 2453, + "5844-date-unknown-values.ts": 3400, + "5845-groupby-null-prototype.ts": 2868, + "5846-events-esm-default-max.ts": 2670, + "5847-events-cjs-default-max.cjs": 2274, + "5849-class-view-observations.ts": 3073, + "5850-using-disposable-values.ts": 3391, + "5851-using-suppressed-error-values.ts": 2932, + "5852-using-disposable-values-js.js": 3132, + "5853-set-methods-map-arguments.ts": 3034, + "5854-array-from-async.ts": 4140, + "5855-array-from-async-js.js": 3324, + "5856-error-is-error.ts": 2937, + "5857-regexp-unicode-sets.ts": 2520, + "5858-disposable-stack.ts": 4398, + "5859-disposable-stack-js.js": 3669, + "5860-url-ipv4-hosts.ts": 3101, + "5870-worker-thread-names.ts": 3899, + "5871-worker-untransferable.cjs": 3409, + "5872-readline-positional-create-interface.mjs": 3151, + "5873-readline-promises-namespace.cjs": 2023, + "5874-worker-stdio-streams.ts": 3395, + "5875-worker-stdout-pipe.cjs": 3257, + "5879-worker-stdin.ts": 3922, + "5880-emitter-leak-warning-delivery.ts": 3418, + "5881-inspect-weak-collections.ts": 2457, + "5882-string-decoder-runtime-encoding.ts": 2823, + "5883-os-set-priority.ts": 2720, + "5884-inspect-layout-options.ts": 3781, + "5885-events-max-listener-helpers.ts": 2992, + "5886-inspect-dates.ts": 3072, + "5887-inspect-typed-arrays.ts": 2960, + "5888-inspect-sorted.ts": 3397, + "5889-timers-scheduler-signal.ts": 2284, + "5890-while-string-length-counters.ts": 2516, + "5892-buffer-write-utf16le-runs.ts": 3107, + "5900-float16-array.ts": 3631, + "5901-float16-array-js.js": 3789, + "5904-async-generator-completion.ts": 5745, + "5905-array-from-async-generator.ts": 3532, + "5906-array-from-async-generator-js.js": 3910, + "5907-regex-groups-match-rows.ts": 4071, + "5910-set-prototype-of-primitive-object-kinds.ts": 3248, + "5911-dyn-class-to-primitive.ts": 6701, + "5912-dyn-class-conversion-methods.ts": 4374, + "5913-prototype-type-error-messages.ts": 3102, + "5914-dyn-in-class-prototype-members.ts": 2530, + "5915-dyn-error-string-conversions.ts": 3023, + "5920-promise-try-args.ts": 3028, + "5921-promise-try-args-js.js": 3179, + "5922-matchall-groups-callbacks.ts": 4418, + "5923-matchall-groups-js.js": 3161, + "5924-js-literal-identity.js": 2577, + "5925-class-view-identity-observers.ts": 2297, + "5926-class-view-switch-js.js": 2243, + "5927-switch-object-identity.ts": 2986, + "5928-groupby-iterables.ts": 3444, + "5929-groupby-js.js": 2997, + "5930-contract-int32-arrays.ts": 3715, + "5930-method-census-asserted-number-keys.ts": 3330, + "5931-asserted-reads-keep-number-parameters.ts": 2990, + "5932-generic-class-observed-methods.ts": 4272, + "5933-class-fields-unknown-object.ts": 4189, + "5934-js-class-fields-property-order.js": 4613, + "5935-js-subclass-fields-and-element-calls.js": 2484, + "5936-checked-js-class-types.js": 3412, + "5937-override-narrowed-union-returns.ts": 3036, + "5938-object-literal-computed-keys-keep-methods.ts": 3273, + "5939-js-let-object-reassigned-wider.js": 1819, + "5940-callback-helper-specialization.ts": 3109, + "5941-callback-specialization-recursion.ts": 3112, + "5942-callback-specialization-throws.ts": 3221, + "5943-fields-read-before-assignment.ts": 3902, + "5944-js-fields-read-before-assignment.js": 2868, + "5945-local-class-observed-methods.ts": 2284, + "5946-nested-record-field-optional-writes.ts": 2987, + "5950-tuple-predicate-methods.ts": 4611, + "5951-result-never-widening.ts": 2943, + "5952-record-missing-keys.ts": 2332, + "5953-nan-coded-method-returns.ts": 2799, + "5955-any-promise-methods.js": 3148, + "5956-erased-generic-members.ts": 4927, + "5958-asserted-union-receiver.ts": 2198, + "5959-date-to-json.ts": 3051, + "5960-frame-records-own-references.ts": 3563, + "5960-generic-mapped-types.ts": 2996, + "5961-frame-spread-updates.ts": 3260, + "5962-frame-tuples.ts": 3208, + "5970-net-connect-host-name.ts": 1747, + "5971-buffer-chunks-to-string.ts": 3079, + "5972-net-set-encoding-listeners.ts": 3253, + "5973-large-closure-environment.ts": 4499, + "5974-typeof-module-exports.cjs": 2558, + "5975-zlib-class-values.ts": 2531, + "5990-worker-uncloneable.mjs": 3772, + "5991-worker-async-dispose.mjs": 4075, + "5992-worker-thread-name-lifetime.mjs": 3241, "5993-array-length-loop-resizing.ts": 3187, "5994-array-length-sparse-loops.ts": 3292, "5995-array-dense-loop-boundaries.ts": 2596, - "600-closures-basic.ts": 2637, - "601-closures-loops.ts": 2250, - "602-closures-identity-recursion.ts": 2821, - "6020-class-extends-function-constructor.js": 3026, - "6021-asserted-literal-union-arm.ts": 3400, - "603-closures-rc-stress.ts": 2800, - "604-closures-for-of.ts": 1980, - "605-closures-forward-capture-tdz.ts": 2765, - "700-classes-basic.ts": 1650, - "701-classes-composition.ts": 2262, - "702-classes-this-capture.ts": 1945, - "703-classes-rc-stress.ts": 2498, - "710-inheritance-basics.ts": 1936, - "711-inheritance-dispatch.ts": 2643, - "712-inheritance-instanceof.ts": 2608, - "713-inheritance-rc-stress.ts": 2855, - "720-accessors-basics.ts": 2703, - "721-accessors-eval-order.ts": 2000, - "722-accessors-inheritance.ts": 2558, - "723-accessors-rc-stress.ts": 2721, - "750-cycle-closure-box.ts": 2521, - "751-cycle-records-mutual.ts": 2024, - "752-cycle-classes.ts": 2646, - "753-cycle-owned-arrays.ts": 2810, - "754-cycle-external-ref.ts": 2655, - "755-cycle-async-promise.ts": 2228, - "756-cycle-inheritance.ts": 2657, - "757-cycle-cross-generation.ts": 2901, - "762-any-boundary.ts": 2854, - "764-any-async.ts": 2890, - "765-any-optional-chain.ts": 2394, - "766-any-union-boundary.ts": 2672, - "767-string-literal-keys.ts": 2479, - "768-any-uninitialized.ts": 2844, - "800-switch-basics.ts": 2758, - "801-switch-lazy-tests.ts": 2588, - "802-switch-loops.ts": 1780, - "803-switch-rc-stress.ts": 2015, - "804-switch-braced-blocks.ts": 2537, - "810-do-while.ts": 1969, - "820-multi-decl.ts": 1629, - "830-let-uninitialized.ts": 2899, - "900-records-basics.ts": 2778, - "901-records-eval-order.ts": 2686, - "902-records-functions-closures.ts": 2628, - "903-records-rc-stress.ts": 2550, - "904-records-optional-fields.ts": 3083, - "905-records-optional-rc-stress.ts": 2791, - "906-records-utility-types.ts": 1783, - "907-records-utility-generics.ts": 2604, - "908-records-index-signatures.ts": 2041, - "909-records-index-json.ts": 3081, - "910-records-index-rc-stress.ts": 2746, - "911-records-index-dot-access.ts": 3174, - "912-unknown-slots.ts": 2915, - "913-records-index-iteration.ts": 3669, - "914-records-from-entries.ts": 3427, - "915-unknown-tostring-eq.ts": 3373, - "916-unknown-bytes.ts": 2791, - "917-record-array-index-dot.ts": 2745, - "950-modules-basic/main.ts": 2721, - "951-modules-diamond/main.ts": 1492, - "952-modules-cross/main.ts": 1431, - "953-modules-default/main.ts": 2552, - "954-modules-reexport/main.ts": 2362, - "957-builtins-namespace.ts": 2216, - "960-generics-basics.ts": 2982, - "961-generics-recursion.ts": 2893, - "962-generics-closures.ts": 2684, - "963-generics-modules/main.ts": 2595, - "964-generics-rc-stress.ts": 3029, - "965-generics-async.ts": 3085, - "965-unions-retag.ts": 2457, - "966-unions-retag-rc-stress.ts": 2098, - "967-record-field-widening.ts": 2939, - "969-unions-arm-matrix.ts": 2998, - "970-unions-basics.ts": 2779, - "971-unions-switch.ts": 2261, - "972-unions-nested.ts": 2825, - "973-unions-rc-stress.ts": 2576, - "974-unions-modules/main.ts": 2186, - "975-unions-undefined.ts": 2396, - "976-unions-null.ts": 2274, - "977-unions-unit-rc-stress.ts": 2486, - "978-unions-nullish.ts": 2487, - "979-unions-optional-chaining.ts": 2987, - "980-exceptions-basics.ts": 2385, - "981-exceptions-values.ts": 2867, - "982-exceptions-rc-stress.ts": 1550, - "983-exceptions-control-flow.ts": 2778, - "984-exceptions-finally.ts": 2144, - "985-exceptions-call-chains.ts": 3115, - "986-exceptions-uncaught.ts": 2615, - "987-exceptions-result-unions.ts": 1576, - "990-process-basics.ts": 2148, - "991-process-exit.ts": 2021, - "992-fs-roundtrip.ts": 2662, - "993-fs-readdir.ts": 2790, - "994-fs-errors.ts": 2954, - "995-fs-uncaught.ts": 2485, - "996-fs-rc-stress.ts": 2801, - "997-fs-modules/main.ts": 1791, - "998-process-env.ts": 2322, - "abstract-property-dispatch.ts": 3676, - "arguments-arrow-capture.mjs": 2969, - "arguments-reexport/main.ts": 2670, - "array-argument-lifetimes-exits.ts": 3229, - "array-argument-lifetimes-mutation.ts": 2355, - "array-argument-lifetimes-strings.ts": 2875, - "array-argument-lifetimes-values.ts": 3135, - "array-buffer-conversions.js": 2768, - "array-buffer-storage.ts": 2184, - "array-checked-callback-results.mjs": 3207, - "array-checked-constructor.js": 2168, - "array-concat-widening.ts": 3084, - "array-deque-unshift.ts": 3209, - "array-element-compound-updates.ts": 4339, - "array-fill-unit-values.ts": 2510, - "array-from-checked.js": 4274, - "array-from-value.mjs": 3224, - "array-isarray-value/main.js": 2742, - "array-numeric-own-keys.ts": 1884, - "array-optional-number-write-index.ts": 2617, - "array-primitive-ordering.ts": 2544, - "array-queue-head-room.ts": 3344, - "array-read-helper-effects.ts": 2217, - "array-refined-storage.ts": 2827, - "array-sort-dense-effects.ts": 3621, - "array-sort-dense-values.ts": 3004, - "array-sort-holes-published.ts": 7729, - "array-sort-runs.ts": 4117, - "array-sort-runtime-comparator.ts": 4714, - "array-sort-unknown-comparator.ts": 2824, - "array-storage-transitions.ts": 3984, - "array-truncate-reuse.ts": 2234, - "async-backend-factory.mjs": 1807, - "async-local-typed-results.ts": 2185, - "atomics-integer-operations.ts": 2603, - "bigint-checked-casts.ts": 2636, - "bigint-checked-storage.js": 3528, - "bigint-union-conversion.ts": 2763, - "boxed-error-rethrows.mjs": 2627, - "buffer-codec-boundaries.ts": 2453, - "buffer-primitive-predicate.ts": 2183, - "builtin-prototype-method-values.mjs": 3361, - "byte-loop-bounds.ts": 3029, - "byte-number-pipeline.ts": 3197, - "byte-record-windows.ts": 2142, - "call-lifetimes-argument-order.ts": 2451, - "call-lifetimes-control-flow.ts": 2879, - "call-lifetimes-owned-boundaries.ts": 3007, - "call-lifetimes-projections.ts": 1722, - "call-lifetimes-union-values.ts": 2751, - "call-lifetimes-virtual-optionals.ts": 3153, - "callable-module-members.mjs": 2485, - "callable-properties.mjs": 3432, - "callable-property-cycles.js": 3096, - "callable-reexport/main.ts": 3039, - "captured-class-refinement.ts": 3032, - "catch-capture.ts": 2928, - "caught-class-identity.ts": 2572, - "caught-standalone-class.ts": 3034, - "caught-system-error-fields.ts": 2540, - "checked-addition.js": 2460, - "checked-any-addition.ts": 2597, - "checked-array-assignment.ts": 1938, - "checked-array-flat/main.ts": 2376, - "checked-bitwise/main.js": 2931, - "checked-builder-cycles.js": 2124, - "checked-byte-storage/main.ts": 2136, - "checked-callback-options.ts": 2655, - "checked-class-descriptors.mjs": 3730, - "checked-class-factory.mjs": 2259, - "checked-collection-iterators.ts": 3189, - "checked-collection-symbol-methods.ts": 2758, - "checked-dispatch-input-lifetimes.js": 3290, - "checked-increment/main.js": 2209, - "checked-inherited-fields.ts": 1885, - "checked-iterator-consumption.js": 3562, - "checked-numeric-arithmetic.js": 2775, - "checked-object-module-alias.js": 2993, - "checked-optional-calls.mjs": 2857, - "checked-promise-recovery.ts": 2965, - "checked-proxy-callback/main.ts": 2460, - "checked-record-constructor.ts": 2536, - "checked-renderer-defaults.js": 2974, - "checked-rest-function-adapters.js": 2402, - "checked-storage-transitions.js": 3227, - "checked-symbol-array.ts": 2138, - "checked-value-input-lifetimes.ts": 2968, - "class-accessor-returned-function.js": 2548, - "class-array-optional-return.ts": 2505, - "class-bracket-method-calls.js": 3232, - "class-brand-overload.js": 2772, - "class-callback-replacement.js": 4256, - "class-callback-storage.ts": 3103, - "class-checked-composites.ts": 2644, - "class-checked-upcast.ts": 2728, - "class-collection-insertion.ts": 4030, - "class-computed-presence.ts": 3380, - "class-computed-symbols.js": 2436, - "class-covariant-returns.ts": 3091, - "class-curried-factory.mjs": 3427, - "class-data-descriptors.js": 3815, - "class-factory-inherited-statics.mjs": 3016, - "class-factory-parameter-base.mjs": 3162, - "class-factory-record-base.mjs": 5127, - "class-factory-recursive-statics.mjs": 2561, - "class-factory-static-members.mjs": 3200, - "class-function-base/main.js": 3392, - "class-instance-constructor.js": 3735, - "class-interface-protocols.ts": 5264, - "class-interface-refinements.ts": 2054, - "class-json-checked.ts": 2470, - "class-local-function-base.mjs": 3094, - "class-method-spreads.ts": 4098, - "class-narrowed-views.ts": 1811, - "class-property-call-values.mjs": 3042, - "class-prototype-data.js": 2959, - "class-prototype-descriptor-copy.mjs": 3884, - "class-specialized-computed-base.mjs": 3695, - "class-static-data.js": 2083, - "class-subclass-assertions.ts": 2716, - "class-super-surplus-spread.mjs": 3129, - "class-symbol-accessors.ts": 2288, - "class-symbol-cache.mjs": 3599, - "class-value-constructor-exceptions.ts": 2725, - "closed-virtual-dispatch-modules/main.ts": 2752, - "closed-virtual-dispatch.ts": 3200, - "closure-nullable-union-return.ts": 2492, - "closure-union-locals.ts": 2959, - "collection-array-cycles.ts": 3095, - "collection-array-maps.ts": 3559, - "collection-array-missing.ts": 3686, - "collection-array-sets.ts": 3501, - "collection-copy-identities.ts": 2360, - "collection-data-unions.ts": 3003, - "collection-ingestion-mappers.ts": 2535, - "collection-ingestion-protocol/main.ts": 3823, - "collection-ingestion-references.ts": 2342, - "collection-ingestion.ts": 3093, - "collection-storage-copies.ts": 2080, - "collection-value-keys.ts": 2956, - "compound-field-receivers.ts": 1671, - "compound-presence-guards.ts": 3200, - "conditional-tuple-destructuring.ts": 2750, - "console-imports.cjs": 1673, - "console-native-value.js": 2807, - "const-enum-module-cycle/main.ts": 2704, - "constant-callback-dispatch.ts": 1960, - "constant-module-globals/main.ts": 1705, - "constant-number-remainders.ts": 2349, - "constructed-class-dispatch.ts": 3130, - "contextual-array-union-write.ts": 6681, - "contextual-return-layouts.ts": 3422, - "counted-loop-numbers.ts": 2709, - "counted-loop-storage.ts": 2965, - "crypto-hash-optional-input.ts": 2865, - "cycle-generations-long-lived.ts": 2572, - "cycle-growth-yield.ts": 3019, - "date-checked-native.js": 2742, - "declared-index-spread.ts": 3806, - "deep-reference-teardown.ts": 3156, - "default-undefined-parameters.ts": 2963, - "deferred-field-updates.ts": 1865, - "deferred-registry-many.ts": 3051, - "derived-numeric-updates.ts": 1958, - "destructure-call-assignment.js": 2640, - "destructure-inferred-row-defaults.js": 2122, - "destructure-union-arrays.ts": 2784, - "dynamic-function-descriptors.js": 2749, - "error-cause-writes.js": 2022, - "error-inherited-message.mjs": 2684, - "error-inherited-name.mjs": 2378, - "error-property-writes.mjs": 2676, - "error-prototype-tostring.js": 3103, - "error-stack-frames.ts": 2531, - "error-stack-limit.ts": 2338, - "error-tostring-overrides.ts": 2421, - "error-values-inspect.ts": 2394, - "exact-index-round-trip.ts": 2708, - "expression-runtime-values.ts": 2672, - "fiber-switch-stress.ts": 2404, - "fiberless-async-ordering.ts": 2698, - "fiberless-async-unhandled.ts": 2605, - "field-assignment-values.ts": 2753, - "file-handle-values.ts": 2888, - "file-read-storage.ts": 3335, - "file-url-percent-decoding.ts": 1678, - "final-field-borrows.ts": 2810, - "for-multiple-bindings.ts": 2621, - "for-multiple-lexical-bindings.ts": 2696, - "for-of-checked-iterator.js": 2735, - "for-of-subclass-elements.ts": 2538, - "forward-generic-signatures.ts": 1734, - "fresh-array-union-layout.js": 2661, - "frozen-checked-dictionaries.mjs": 2513, - "fs-native-realpath.ts": 2900, - "fs-null-byte-paths-js.cjs": 2166, - "fs-null-byte-paths.ts": 3560, - "fs-read-encodings.ts": 2192, - "fs-read-utf8-edges.ts": 3494, - "fs-read-utf8-handle-forms.ts": 1894, - "fs-remove-readonly.ts": 2005, - "fs-write-string-bytes-union.ts": 2781, - "function-apply-value.mjs": 2795, - "function-constructor-global.mjs": 2338, - "function-constructor-kinds/main.js": 3030, - "function-custom-prototype.js": 2801, - "function-custom-to-string.mjs": 1937, - "function-object-assign.js": 1754, - "function-own-prototype/main.js": 2470, - "generator-checked-protocol.ts": 2909, - "generator-checked-return.js": 3084, - "generator-custom-delegation/main.ts": 5038, - "generator-default-return-pattern.ts": 2685, - "generator-delegation-values.ts": 1962, - "generator-inferred-date.js": 3181, - "generator-mixed-checked-channels.ts": 2887, - "generator-untyped-consumer/main.ts": 2216, - "generic-base-specializations.ts": 2930, - "generic-binding-ownership.ts": 2565, - "generic-class-js-functions/main.ts": 2055, - "generic-class-recovery.ts": 2723, - "generic-namespace-factories/main.ts": 2103, - "generic-nullable-collections.ts": 2282, - "generic-pattern-bindings.ts": 2536, - "generic-record-index.ts": 2488, - "generic-visitor-void.ts": 2848, - "global-accumulator-loops.ts": 2271, - "global-error-subclasses.ts": 1850, - "global-runtime-probes.js": 3085, - "global-stored-probes.js": 3029, - "global-string-cache/main.js": 2487, - "global-symbol-cache/main.js": 2631, - "guarded-native-iterables.ts": 2969, - "heap-input-aliases.ts": 2864, - "heap-input-collections.ts": 2900, - "in-array-runtime-index.ts": 3065, - "indexed-assignment-values.js": 2826, - "indexed-assignment-values.ts": 1639, - "indexed-element-field-reads.ts": 1506, - "inferred-array-assignment-values.mjs": 2520, - "inferred-class-default.mjs": 2339, - "inferred-compound-values.mjs": 2708, - "inferred-conditional-class.mjs": 2429, - "inferred-error-fields.js": 2383, - "inferred-map-patterns.mjs": 2476, - "inferred-method-override.js": 2284, - "inferred-partial-destructuring.mjs": 1972, - "inferred-primitive-properties.mjs": 2268, - "inferred-record-return.mjs": 2543, - "inferred-recursive-record.mjs": 2822, - "inferred-undefined-field.mjs": 2615, - "input-lifetime-intervals.ts": 2188, - "input-lifetimes-modules/main.ts": 2672, - "instanceof-class-record-union.ts": 2441, - "integer-flow-arithmetic.ts": 1990, - "integer-loop-forms.ts": 2426, - "integer-view-control.ts": 2085, - "integer-view-numbers.ts": 2088, - "integer-view-storage.ts": 2560, - "intl-grapheme-conformance/main.ts": 4354, - "intl-grapheme.ts": 1787, - "iterator-typed-returns.ts": 2556, - "js-abort-portable.js": 3289, - "js-array-constructor.js": 3326, - "js-array-default-buffer.js": 2785, - "js-array-iterators.js": 2367, - "js-arrow-bind.cjs": 3832, - "js-buffer-callback-brand.cjs": 2996, - "js-callable-proxy.js": 3619, - "js-chained-native-results.mjs": 2794, - "js-checked-array-iterator.js": 2235, - "js-checked-array-reference.js": 3562, - "js-checked-number-negation.mjs": 2819, - "js-checked-sort-result.js": 2743, - "js-child-error-listener.cjs": 2228, - "js-cjs-callable-snapshots/main.cjs": 2256, - "js-class-added-parameters.js": 2567, - "js-class-checked-overrides.js": 2547, - "js-class-computed-fields.js": 2943, - "js-class-enumeration.js": 3714, - "js-class-field-accessor-override.js": 3000, - "js-class-fluent-overrides.js": 2749, - "js-class-late-method-values.js": 2358, - "js-class-member-dispatch.js": 3594, - "js-class-return-shapes.js": 3435, - "js-class-shadowed-methods.js": 3639, - "js-class-stored-method-receiver.js": 2943, - "js-class-subclass-properties.js": 3662, - "js-class-symbol-spread.cjs": 2503, - "js-computed-prototype-additions.js": 2456, - "js-constructor-returned-callable.js": 2517, - "js-constructor-spread.js": 3593, - "js-dataview-dispatch.js": 2188, - "js-declared-fields.cjs": 4540, - "js-default-listener-arguments.cjs": 2448, - "js-default-options/main.ts": 3104, - "js-deferred-field-initializers.js": 2710, - "js-deferred-registry-effects.js": 2361, - "js-derived-constructor-hoisting.js": 2306, - "js-dormant-array-write.js": 2104, - "js-dormant-overrides.js": 1741, - "js-expando-records.js": 2473, - "js-implicit-call-results.js": 2893, - "js-inferred-callback-exports/main.js": 4125, - "js-inferred-class-array-return.js": 2816, - "js-inferred-object-values.js": 2369, - "js-inherited-field-storage.js": 3308, - "js-inherited-parameter-abi.js": 2238, - "js-iterable-spread.js": 2086, - "js-loose-dynamic-primitives.js": 2810, - "js-map-object-seeds.js": 2592, - "js-member-increment.js": 3352, - "js-module-function-values.js": 2994, - "js-mutable-null-members.js": 2723, - "js-nested-native-descriptors.js": 2548, - "js-normalize-dispatch.js": 2929, - "js-nullish-inherited-fields.mjs": 2189, - "js-object-receiver-storage.js": 2175, - "js-object-returning-constructors.mjs": 2945, - "js-object-shared-arrays.js": 2935, - "js-omitted-typed-arguments.js": 2736, - "js-open-binding-writes.js": 2167, - "js-optional-class-fields.js": 3219, - "js-optional-member-call.js": 3110, - "js-primitive-union-addition.js": 2549, - "js-promise-all-values.js": 3527, - "js-promise-catch-handler.js": 2649, - "js-promise-finally-order.js": 2445, - "js-promise-pending-reactions.js": 2595, - "js-prototype-host-boundary.js": 2723, - "js-reflect-receivers.js": 3391, - "js-regex-record-captures.js": 3115, - "js-scalar-iterables.js": 2746, - "js-shared-method-dispatch.js": 2796, - "js-specialized-field-method.js": 2049, - "js-static-accessors.js": 3053, - "js-static-method-values.js": 2375, - "js-static-registries.cjs": 2790, - "js-super-accessor-initialization.js": 2104, - "js-uninitialized-native-fields.js": 1764, - "json-guarded-map-values.ts": 3144, - "json-output-bulk.ts": 2572, - "json-runtime-options.mjs": 2583, - "json-stringify-value.js": 2182, - "json-typed-parse-direct.ts": 3644, - "json-typed-parse-index-signatures.ts": 4122, - "json-typed-parse-optional-members.ts": 3273, - "json-typed-parse-union-members.ts": 3078, - "literal-switch-dispatch.ts": 2252, - "live-reference-shared-converters.ts": 3470, - "llvm-read-receiver-lifetime.ts": 3118, - "local-class-call-spreads.js": 2490, - "local-class-declaration.ts": 2302, - "local-class-evaluation.ts": 2915, - "local-class-inheritance.ts": 2396, - "local-class-lifetimes.ts": 2780, - "local-class-namespace/main.js": 3248, - "local-class-prototype-data.js": 3273, - "local-class-specialization.js": 2054, - "local-class-unknown.ts": 1964, - "local-class-values.ts": 2059, - "local-union-storage.ts": 2500, - "locale-compare-root-order.ts": 2609, - "logical-assignment-dynamic.js": 2892, - "logical-assignment-values.ts": 2287, - "logical-runtime-optional-record.ts": 2390, - "loop-reference-lifetimes.ts": 2959, - "map-checked-boundary/main.ts": 2651, - "map-checked-seed.js": 1821, - "map-get-set-fusion.ts": 3131, - "map-number-keys-dense.ts": 2480, - "map-read-lifetimes-exits.ts": 2004, - "map-read-lifetimes.ts": 2956, - "map-seeds-and-spreads.ts": 2807, - "map-typed-array-values.ts": 2864, - "math-function-values.js": 2704, - "missing-read-lambda-results.ts": 2964, - "missing-read-narrowed-storage.ts": 2975, - "missing-read-number-conversions.ts": 2247, - "module-byte-loops.ts": 2710, - "module-fallback-functions/main.js": 2953, - "narrowed-nullish-values.ts": 2689, - "native-any-timer-callback.ts": 2256, - "native-array-borrowed-find-last.js": 2331, - "native-array-borrowed-slice.js": 2738, - "native-array-copying-methods.js": 2547, - "native-array-fill-copywithin.js": 2422, - "native-array-frozen-noops.js": 1940, - "native-array-index-boundaries.js": 1855, - "native-array-integrity.js": 3078, - "native-array-length.js": 2779, - "native-array-named-properties.js": 2991, - "native-array-prototype/main.js": 1536, - "native-array-read-lifetimes.ts": 3338, - "native-array-reduce-find-last.js": 2328, - "native-array-search-from-index.js": 2430, - "native-array-splice-coercion.js": 2633, - "native-array-splice-flat.js": 2555, - "native-buffer-coercion.js": 2993, - "native-callback-dispatch.ts": 3551, - "native-class-array-boundaries.ts": 2938, - "native-class-cache.js": 4207, - "native-class-properties.cjs": 3301, - "native-class-property-cycles.cjs": 2085, - "native-class-property-order.cjs": 2417, - "native-class-type-predicates.ts": 2597, - "native-factory-records.js": 2167, - "native-method-values.js": 3675, - "native-method-values.ts": 2504, - "native-npm-imports/main.ts": 3572, - "native-object-descriptors.js": 2795, - "native-object-for-in-minimal.js": 2689, - "native-object-property-attributes.js": 2700, - "native-object-prototype.js": 2600, - "native-property-names.ts": 2409, - "native-proxy-env.js": 3746, - "native-worker-arena-reuse.ts": 4764, - "native-worker-bounded-errors.ts": 3072, - "native-worker-buffer-consumers.ts": 2989, - "native-worker-cancel-hot.ts": 2633, - "native-worker-class-fields.ts": 3458, - "native-worker-clone-errors.ts": 2734, - "native-worker-commonjs.cjs": 2159, - "native-worker-delayed-messages.ts": 2169, - "native-worker-discarded-heaps.ts": 5523, - "native-worker-environment.ts": 3190, - "native-worker-error.ts": 2740, - "native-worker-exception-state.ts": 4140, - "native-worker-exit-listeners.ts": 2056, - "native-worker-io.ts": 2596, - "native-worker-loop-cancellation.ts": 2554, - "native-worker-message-graphs.ts": 3182, - "native-worker-messages.ts": 2651, - "native-worker-poll-exceptions.ts": 3212, - "native-worker-port-lifetime.ts": 3033, - "native-worker-process-exit.ts": 2692, - "native-worker-publish-classes.ts": 4065, - "native-worker-publish-refusals.ts": 3039, - "native-worker-published-graphs.ts": 3663, - "native-worker-references.ts": 2640, - "native-worker-roots/main.ts": 3080, - "native-worker-shared-views.ts": 3041, - "native-worker-stack-overflow.ts": 2862, - "native-worker-terminate-exception-state.ts": 3985, - "native-worker-terminate-loop.ts": 2725, - "native-worker-terminate-recursion.ts": 3128, - "native-worker-terminate-suspended.ts": 2867, - "native-worker-terminate-tested-loops.ts": 3161, - "native-worker-terminate-wait.ts": 1905, - "native-worker-typed-arrays.ts": 2971, - "nested-map-cycles.ts": 2802, - "nested-map-values.ts": 3022, - "never-returning-calls.ts": 2411, - "next-tick-commonjs-entry.cjs": 2251, - "node24-buffer-encoding-errors.ts": 2393, - "node24-buffer-encoding.ts": 2789, - "node24-crypto-kdf-errors.ts": 2833, - "node24-crypto-kdf-options.ts": 2131, - "node24-crypto-kdf.ts": 4066, - "node24-crypto-sha2.ts": 1593, - "node24-deep-equality-properties.js": 2924, - "node24-deep-equality.cjs": 2596, - "node24-deep-equality.ts": 3235, - "node24-env-files-errors.ts": 2781, - "node24-env-files.ts": 2586, - "node24-env-imports.cjs": 1729, - "node24-env-parse-errors.ts": 2642, - "node24-env-parse.ts": 2636, - "node24-esm-metadata/main.mjs": 2627, - "node24-file-url-buffer.ts": 2669, - "node24-file-url-errors.js": 2467, - "node24-file-url-options.ts": 3030, - "node24-fs-links-callbacks.cjs": 3015, - "node24-fs-links-errors.cjs": 2843, - "node24-fs-links-options.cjs": 3229, - "node24-fs-links-promise-errors.cjs": 2844, - "node24-fs-links-promises.ts": 2107, - "node24-fs-links.ts": 1958, - "node24-fs-statfs-callbacks.cjs": 2203, - "node24-fs-statfs-errors.cjs": 2705, - "node24-fs-statfs-options.cjs": 2846, - "node24-fs-statfs.ts": 2174, - "node24-fs-timestamps-callbacks.cjs": 2972, - "node24-fs-timestamps-errors.cjs": 1969, - "node24-fs-timestamps-promises.ts": 2959, - "node24-fs-timestamps-symlinks.ts": 2931, - "node24-fs-timestamps.ts": 1989, - "node24-no-error-assertions-coercion.js": 3207, - "node24-no-error-assertions.cjs": 1972, - "node24-no-error-assertions.ts": 2214, - "node24-parseargs.js": 4158, - "node24-string-decoder.ts": 2635, - "node24-style-text-environment.js": 2062, - "node24-style-text-validation.js": 3237, - "node24-style-text.cjs": 2491, - "node24-style-text.ts": 2829, - "node24-system-error-validation.js": 2660, - "node24-system-errors.cjs": 2361, - "node24-system-errors.ts": 2897, - "node24-text-codec-properties.ts": 2383, - "node24-text-encode-into.ts": 2992, - "node24-text-utilities-coercion.js": 2902, - "node24-text-utilities-validation.js": 2997, - "node24-text-utilities.cjs": 2432, - "node24-text-utilities.ts": 1910, - "node24-url-authority-coercion.js": 2861, - "node24-url-authority.ts": 2689, - "node24-url-factories.ts": 1863, - "node24-url-factory-errors.ts": 1955, - "node24-url-mutation-coercion.js": 2400, - "node24-url-mutation.ts": 2663, - "node24-util-types.cjs": 3712, - "node24-util-types.js": 2869, - "node24-util-types.ts": 3395, - "non-null-class-iteration.ts": 2220, - "nonnull-element-arguments.ts": 2568, - "nonnull-forwarded-class-values.ts": 2603, - "nullable-object-extension.mjs": 2408, - "nullish-asserted-class-arms.ts": 2116, - "nullish-assignment-values.ts": 2517, - "nullish-long-chain.ts": 2430, - "number-parse-statics.ts": 1887, - "number-predicates-unknown.ts": 1974, - "numeric-call-specialization.ts": 2627, - "object-enumeration-array-reads.ts": 2586, - "object-from-checked-entries.js": 2775, - "object-inherited-to-string.js": 2674, - "object-key-indexes.js": 2909, - "object-prototype-identity.mjs": 2317, - "object-reexport/main.js": 2625, - "object-spread-computed.ts": 2429, - "opentui-byte-queue.js": 3139, - "optional-callback-arity.ts": 2294, - "optional-class-flows.ts": 2613, - "optional-element-defaults.ts": 2793, - "optional-flag-comparisons.ts": 2714, - "optional-native-callables.js": 2344, - "optional-node-list-iteration.ts": 2344, - "optional-string-index/main.ts": 2788, - "path-to-file-url-options.ts": 2568, - "performance-presence.ts": 2450, - "primitive-and-function-descriptors.js": 2677, - "primitive-union-string.ts": 1777, - "process-builtin-values.js": 3974, - "process-constrained-memory.ts": 1850, - "process-env-computed-keys.js": 2019, - "process-hrtime.js": 2975, - "process-named-signals.cjs": 2191, - "process-uncaught-handler-throws.cjs": 2460, - "process-uncaught-loop.cjs": 2411, - "process-uncaught-module.mjs": 1942, - "process-uncaught-monitor.cjs": 1718, - "process-uncaught-rejection.cjs": 2645, - "process-uncaught-sync.cjs": 2436, - "process-version-pin.ts": 1717, - "process-versions-storage.ts": 2502, - "projected-collection-lifetimes.ts": 2791, - "promise-checked-rejections.ts": 2434, - "promise-resolve-void.ts": 2330, - "prototype-method-overrides.mjs": 4995, - "prototype-named-data-records.ts": 2858, - "rc-last-use-moves.ts": 2819, - "rc-private-array-writes.ts": 2121, - "record-field-presence.ts": 3356, - "record-key-order.ts": 2943, - "record-optional-json-presence.ts": 2861, - "record-presence-copies.ts": 2372, - "record-presence-delete-json.ts": 3243, - "record-unchecked-read-presence.ts": 2717, - "record-unknown-values.ts": 3976, - "reflect-own-keys.mjs": 2238, - "reflect-record-union-keys.mjs": 2626, - "reflect-typed-record-keys.ts": 2852, - "regex-callback-replacements.ts": 2111, - "regex-callback-values.js": 2464, - "regex-checked-casts.ts": 2160, - "regex-checked-storage.js": 2310, - "regex-exec-long-subject.ts": 4567, - "regex-exec-result-arrays.ts": 3123, - "regex-fs-text-surfaces.ts": 2847, - "regex-input-lifetimes.ts": 2221, - "regex-native-matcher.ts": 4414, - "regex-optional-captures.ts": 3043, - "regex-optional-templates.ts": 2695, - "regex-split-captures.ts": 2413, - "regex-text-paths.ts": 3078, - "regexp-constructor-repeat.ts": 2829, - "regexp-optional-constructor.ts": 2162, - "regexp-string-coercion.js": 2219, - "renderer-export-dictionaries.js": 2331, - "renderer-null-state.js": 1751, - "renderer-specializations.js": 2860, - "repeat-and-typed-read-errors.ts": 2689, - "rest-optional-array-arguments.ts": 2219, - "rest-optional-elements.ts": 2503, - "return-void-through-finally.ts": 2582, - "runtime-optional-string-flows.ts": 2381, - "scalar-string-slices.ts": 2256, - "set-checked-methods.js": 2598, - "set-checked-storage.ts": 2088, - "set-iterator-seed-references.ts": 2454, - "set-iterator-seeds.ts": 3016, - "set-optional-seeds.ts": 2563, - "small-collection-transitions.ts": 2967, - "speculative-integer-globals.ts": 2480, - "speculative-integer-loops.ts": 3219, - "speculative-integer-reads.ts": 2852, - "stack-depth-async-bodies.ts": 2421, - "stack-overflow-async.ts": 1922, - "stack-overflow-caught.ts": 2542, - "stack-overflow-finally.ts": 2607, - "stack-overflow-shapes.ts": 3083, - "stack-overflow-uncaught.ts": 2465, - "stackless-async-concurrency.ts": 2441, - "stackless-async-context.ts": 2934, - "stackless-async-exceptions.ts": 2936, - "stackless-async-ordering.ts": 2618, - "stackless-async-unhandled.ts": 2477, - "static-field-updates/main.ts": 2461, - "static-method-receivers.ts": 1849, - "stdio-values.mjs": 2236, - "stdio-write-errors.mjs": 2342, - "stdio-write-overrides.mjs": 2002, - "stored-native-builtins.js": 2708, - "stored-object-helpers.js": 2808, - "stream-dynamic-entry-kinds.cjs": 3015, - "stream-dynamic-entry-kinds.ts": 1582, - "stream-encoded-from-entries.cjs": 3058, - "stream-encoded-from-entries.ts": 2590, - "string-char-code-integer-loops.ts": 2802, - "string-code-points.ts": 2658, - "string-concat-number-parts.ts": 2339, - "string-construction-order.ts": 2902, - "string-field-append.ts": 3251, - "string-lifetimes-boundaries.ts": 2858, - "string-lifetimes-evaluation.ts": 1805, - "string-lifetimes-iteration.ts": 2235, - "string-lifetimes-operations.ts": 2468, - "string-normalize.ts": 2348, - "string-pattern-replacement.ts": 1662, - "string-scan-fast-paths.ts": 2133, - "string-split-checked-separator.mjs": 2285, - "string-split-traversal.ts": 1939, - "structural-class-properties.ts": 3139, - "structured-text-boundaries.js": 3111, - "structured-text-storage.ts": 2912, - "switch-integer-dispatch.ts": 2264, - "symbol-checked-boundary/main.ts": 2800, - "symbol-class-fields.ts": 2364, - "symbol-class-fields/main.cjs": 2507, - "symbol-class-methods/main.ts": 2255, - "symbol-fields-deferred-factory.ts": 2386, - "symbol-fields-inferred.js": 2386, - "symbol-object-properties/main.js": 3085, - "synchronous-callback-lifetimes.ts": 2296, - "terminal-stream-properties.ts": 2094, - "text-codec-values/main.ts": 2338, - "text-codec-var.ts": 2708, - "text-encode-into-boundaries.ts": 2679, - "timers-clear-many.ts": 2665, - "tuple-and-string-search.ts": 2567, - "tuple-array-union.ts": 2150, - "tuple-callback-visitation.ts": 3321, - "tuple-forof-visitation.ts": 2818, - "typed-array-bulk-conversion.mjs": 4061, - "typed-array-byte-io.js": 3073, - "typed-array-checked-index.js": 2572, - "typed-array-constructor-alias.ts": 2243, - "typed-array-constructor-identity.js": 2693, - "typed-array-constructor-union.ts": 2646, - "typed-array-constructor-values.mjs": 2380, - "typed-array-dynamic-methods.js": 2112, - "typed-array-integer-widths.ts": 2661, - "typed-array-nan-coded-reads.ts": 3761, - "typed-array-numeric-import.ts": 2783, - "typed-array-present-reads.ts": 3074, - "typed-array-reversed-storage.ts": 2650, - "typed-array-unknown.ts": 2830, - "typed-collection-iterator-references.ts": 3315, - "typed-collection-iterators.ts": 3098, - "typed-collection-views/main.ts": 1720, - "typed-index-arguments.ts": 2531, - "typed-prototype-methods.ts": 3386, - "typed-rest-callables.ts": 2393, - "typed-rest-filtered-return.ts": 2745, - "typedarray-native-inputs.js": 3102, - "typeof-checked-comparison.js": 2558, - "uint8array-sort-domains.ts": 2057, - "unicode-case-paths.ts": 2222, - "unicode-process-argv.ts": 2491, - "union-discriminant-width.ts": 2970, - "union-literal-scalar-discriminants.ts": 3053, - "union-literal-slot-conversion.ts": 2820, - "union-nested-layout-discriminant.ts": 1976, - "union-optional-semantic-identity.ts": 3464, - "union-record-clone.ts": 2368, - "union-record-structural-copy.ts": 3130, - "union-reference-comparison.ts": 2882, - "unknown-array-holes.ts": 1889, - "unknown-collections.ts": 3133, - "unknown-object-enumeration.ts": 4341, - "unknown-record-views.ts": 3288, - "url-runtime-base.ts": 2471, - "utf8-span-decoding.ts": 2821, - "util-parseargs-wrapped/main.ts": 2971, - "virtual-runtime-optional-returns.ts": 3001, - "weak-map-array-buffer.ts": 1951, - "weak-map-fresh-array.js": 2498, - "weak-map-native.js": 3238, - "weak-native-class-identity.ts": 2197, - "weak-set-native.js": 2814, - "worker-class-instance-clone.ts": 3421 + "600-closures-basic.ts": 2093, + "601-closures-loops.ts": 2964, + "602-closures-identity-recursion.ts": 2859, + "6020-class-extends-function-constructor.js": 3170, + "6021-asserted-literal-union-arm.ts": 3166, + "603-closures-rc-stress.ts": 2756, + "604-closures-for-of.ts": 2963, + "6041-error-cause-redeclared.ts": 2988, + "6042-regex-match-object-destructuring.ts": 3393, + "6043-string-index-narrowed-union.ts": 2983, + "605-closures-forward-capture-tdz.ts": 2902, + "6140-cjs-require-tdz-throws/main.js": 2731, + "6141-cjs-require-tdz-checked/main.js": 2856, + "6142-cjs-require-published-early/main.js": 3400, + "6143-cjs-require-json/main.js": 3245, + "6144-cjs-require-builtin-nested/main.js": 2181, + "6145-cjs-require-cycle/main.js": 3507, + "700-classes-basic.ts": 2476, + "701-classes-composition.ts": 2819, + "702-classes-this-capture.ts": 2834, + "703-classes-rc-stress.ts": 2484, + "710-inheritance-basics.ts": 2629, + "711-inheritance-dispatch.ts": 2199, + "712-inheritance-instanceof.ts": 2914, + "713-inheritance-rc-stress.ts": 2307, + "720-accessors-basics.ts": 2496, + "721-accessors-eval-order.ts": 3007, + "722-accessors-inheritance.ts": 2266, + "723-accessors-rc-stress.ts": 2951, + "750-cycle-closure-box.ts": 2797, + "751-cycle-records-mutual.ts": 2867, + "752-cycle-classes.ts": 2668, + "753-cycle-owned-arrays.ts": 2613, + "754-cycle-external-ref.ts": 2566, + "755-cycle-async-promise.ts": 2707, + "756-cycle-inheritance.ts": 2258, + "757-cycle-cross-generation.ts": 3080, + "762-any-boundary.ts": 3283, + "764-any-async.ts": 2876, + "765-any-optional-chain.ts": 3213, + "766-any-union-boundary.ts": 3515, + "767-string-literal-keys.ts": 2750, + "768-any-uninitialized.ts": 2902, + "800-switch-basics.ts": 2776, + "801-switch-lazy-tests.ts": 2159, + "802-switch-loops.ts": 2543, + "803-switch-rc-stress.ts": 3003, + "804-switch-braced-blocks.ts": 2593, + "810-do-while.ts": 2089, + "820-multi-decl.ts": 2503, + "830-let-uninitialized.ts": 2817, + "900-records-basics.ts": 2340, + "901-records-eval-order.ts": 2257, + "902-records-functions-closures.ts": 2757, + "903-records-rc-stress.ts": 2938, + "904-records-optional-fields.ts": 2935, + "905-records-optional-rc-stress.ts": 2626, + "906-records-utility-types.ts": 2717, + "907-records-utility-generics.ts": 2997, + "908-records-index-signatures.ts": 3162, + "909-records-index-json.ts": 3408, + "910-records-index-rc-stress.ts": 2486, + "911-records-index-dot-access.ts": 3533, + "912-unknown-slots.ts": 2761, + "913-records-index-iteration.ts": 3662, + "914-records-from-entries.ts": 3551, + "915-unknown-tostring-eq.ts": 3814, + "916-unknown-bytes.ts": 2926, + "917-record-array-index-dot.ts": 2493, + "950-modules-basic/main.ts": 2549, + "951-modules-diamond/main.ts": 2015, + "952-modules-cross/main.ts": 2203, + "953-modules-default/main.ts": 2058, + "954-modules-reexport/main.ts": 2223, + "957-builtins-namespace.ts": 2583, + "960-generics-basics.ts": 2371, + "961-generics-recursion.ts": 2698, + "962-generics-closures.ts": 2945, + "963-generics-modules/main.ts": 1815, + "964-generics-rc-stress.ts": 3183, + "965-generics-async.ts": 3138, + "965-unions-retag.ts": 2552, + "966-unions-retag-rc-stress.ts": 2838, + "967-record-field-widening.ts": 3366, + "969-unions-arm-matrix.ts": 2362, + "970-unions-basics.ts": 2298, + "971-unions-switch.ts": 2850, + "972-unions-nested.ts": 2374, + "973-unions-rc-stress.ts": 1915, + "974-unions-modules/main.ts": 2639, + "975-unions-undefined.ts": 2297, + "976-unions-null.ts": 1941, + "977-unions-unit-rc-stress.ts": 2513, + "978-unions-nullish.ts": 3070, + "979-unions-optional-chaining.ts": 3263, + "980-exceptions-basics.ts": 2631, + "981-exceptions-values.ts": 2273, + "982-exceptions-rc-stress.ts": 2398, + "983-exceptions-control-flow.ts": 2350, + "984-exceptions-finally.ts": 2928, + "985-exceptions-call-chains.ts": 2642, + "986-exceptions-uncaught.ts": 2072, + "987-exceptions-result-unions.ts": 2255, + "990-process-basics.ts": 2565, + "991-process-exit.ts": 1649, + "992-fs-roundtrip.ts": 2134, + "993-fs-readdir.ts": 2805, + "994-fs-errors.ts": 1790, + "995-fs-uncaught.ts": 2295, + "996-fs-rc-stress.ts": 3230, + "997-fs-modules/main.ts": 2893, + "998-process-env.ts": 1803, + "abstract-property-dispatch.ts": 3619, + "arguments-arrow-capture.mjs": 2943, + "arguments-reexport/main.ts": 2123, + "array-argument-lifetimes-exits.ts": 3367, + "array-argument-lifetimes-mutation.ts": 2372, + "array-argument-lifetimes-strings.ts": 2429, + "array-argument-lifetimes-values.ts": 3148, + "array-buffer-conversions.js": 2274, + "array-buffer-storage.ts": 2433, + "array-checked-callback-results.mjs": 2526, + "array-checked-constructor.js": 3336, + "array-concat-widening.ts": 1977, + "array-deque-unshift.ts": 3233, + "array-element-compound-updates.ts": 3547, + "array-fill-unit-values.ts": 2929, + "array-from-checked.js": 3397, + "array-from-value.mjs": 3059, + "array-isarray-value/main.js": 2918, + "array-numeric-own-keys.ts": 2790, + "array-optional-number-write-index.ts": 2704, + "array-primitive-ordering.ts": 4576, + "array-queue-head-room.ts": 2847, + "array-read-helper-effects.ts": 3311, + "array-refined-storage.ts": 2961, + "array-sort-dense-effects.ts": 4064, + "array-sort-dense-values.ts": 4011, + "array-sort-holes-published.ts": 7513, + "array-sort-runs.ts": 5700, + "array-sort-runtime-comparator.ts": 4830, + "array-sort-unknown-comparator.ts": 3102, + "array-storage-transitions.ts": 3965, + "array-truncate-reuse.ts": 3475, + "async-backend-factory.mjs": 2766, + "async-local-typed-results.ts": 3471, + "atomics-integer-operations.ts": 3518, + "bigint-checked-casts.ts": 3182, + "bigint-checked-storage.js": 3679, + "bigint-union-conversion.ts": 2403, + "boxed-error-rethrows.mjs": 2704, + "buffer-codec-boundaries.ts": 3023, + "buffer-primitive-predicate.ts": 2153, + "builtin-prototype-method-values.mjs": 2713, + "byte-loop-bounds.ts": 3126, + "byte-number-pipeline.ts": 3555, + "byte-record-windows.ts": 3164, + "call-lifetimes-argument-order.ts": 3386, + "call-lifetimes-control-flow.ts": 2774, + "call-lifetimes-owned-boundaries.ts": 2902, + "call-lifetimes-projections.ts": 2603, + "call-lifetimes-union-values.ts": 3045, + "call-lifetimes-virtual-optionals.ts": 2344, + "callable-module-members.mjs": 2928, + "callable-properties.mjs": 2765, + "callable-property-cycles.js": 1847, + "callable-reexport/main.ts": 2222, + "captured-class-refinement.ts": 3000, + "catch-capture.ts": 3112, + "caught-class-identity.ts": 3640, + "caught-standalone-class.ts": 3171, + "caught-system-error-fields.ts": 3152, + "checked-addition.js": 2684, + "checked-any-addition.ts": 2642, + "checked-array-assignment.ts": 2697, + "checked-array-flat/main.ts": 2840, + "checked-bitwise/main.js": 2581, + "checked-builder-cycles.js": 2948, + "checked-byte-storage/main.ts": 2611, + "checked-callback-options.ts": 1643, + "checked-class-descriptors.mjs": 3640, + "checked-class-factory.mjs": 2778, + "checked-collection-iterators.ts": 3241, + "checked-collection-symbol-methods.ts": 2293, + "checked-dispatch-input-lifetimes.js": 2742, + "checked-increment/main.js": 2072, + "checked-inherited-fields.ts": 3028, + "checked-iterator-consumption.js": 3107, + "checked-numeric-arithmetic.js": 2378, + "checked-object-module-alias.js": 2947, + "checked-optional-calls.mjs": 3142, + "checked-promise-recovery.ts": 2855, + "checked-proxy-callback/main.ts": 1847, + "checked-record-constructor.ts": 2481, + "checked-renderer-defaults.js": 2013, + "checked-rest-function-adapters.js": 3046, + "checked-storage-transitions.js": 2689, + "checked-symbol-array.ts": 2459, + "checked-value-input-lifetimes.ts": 3335, + "class-accessor-returned-function.js": 2629, + "class-array-optional-return.ts": 2795, + "class-bracket-method-calls.js": 3486, + "class-brand-overload.js": 2784, + "class-callback-replacement.js": 2660, + "class-callback-storage.ts": 3042, + "class-checked-composites.ts": 3335, + "class-checked-upcast.ts": 3076, + "class-collection-insertion.ts": 2281, + "class-computed-presence.ts": 3266, + "class-computed-symbols.js": 2803, + "class-covariant-returns.ts": 3398, + "class-curried-factory.mjs": 3626, + "class-data-descriptors.js": 3529, + "class-factory-inherited-statics.mjs": 3667, + "class-factory-parameter-base.mjs": 2767, + "class-factory-record-base.mjs": 3407, + "class-factory-recursive-statics.mjs": 3184, + "class-factory-static-members.mjs": 3515, + "class-function-base/main.js": 3746, + "class-instance-constructor.js": 3651, + "class-interface-protocols.ts": 5020, + "class-interface-refinements.ts": 2194, + "class-json-checked.ts": 1821, + "class-local-function-base.mjs": 3398, + "class-method-spreads.ts": 3880, + "class-narrowed-views.ts": 3116, + "class-property-call-values.mjs": 3490, + "class-prototype-data.js": 3512, + "class-prototype-descriptor-copy.mjs": 4571, + "class-specialized-computed-base.mjs": 3883, + "class-static-data.js": 2886, + "class-subclass-assertions.ts": 3020, + "class-super-surplus-spread.mjs": 2209, + "class-symbol-accessors.ts": 2490, + "class-symbol-cache.mjs": 2911, + "class-value-constructor-exceptions.ts": 2697, + "closed-virtual-dispatch-modules/main.ts": 2682, + "closed-virtual-dispatch.ts": 3944, + "closure-nullable-union-return.ts": 3308, + "closure-union-locals.ts": 3570, + "collection-array-cycles.ts": 2714, + "collection-array-maps.ts": 3451, + "collection-array-missing.ts": 3109, + "collection-array-sets.ts": 2862, + "collection-copy-identities.ts": 3119, + "collection-data-unions.ts": 3087, + "collection-ingestion-mappers.ts": 3823, + "collection-ingestion-protocol/main.ts": 2461, + "collection-ingestion-references.ts": 3913, + "collection-ingestion.ts": 3524, + "collection-storage-copies.ts": 3595, + "collection-value-keys.ts": 2425, + "compound-field-receivers.ts": 2962, + "compound-presence-guards.ts": 3337, + "conditional-tuple-destructuring.ts": 2631, + "console-imports.cjs": 2257, + "console-native-value.js": 2531, + "const-enum-module-cycle/main.ts": 2437, + "constant-callback-dispatch.ts": 2800, + "constant-module-globals/main.ts": 3036, + "constant-number-remainders.ts": 2724, + "constructed-class-dispatch.ts": 3005, + "contextual-array-union-write.ts": 6554, + "contextual-return-layouts.ts": 2859, + "counted-loop-numbers.ts": 2703, + "counted-loop-storage.ts": 2473, + "crypto-hash-optional-input.ts": 3036, + "cycle-generations-long-lived.ts": 2902, + "cycle-growth-yield.ts": 3252, + "date-checked-native.js": 2177, + "declared-index-spread.ts": 3543, + "deep-reference-teardown.ts": 2409, + "default-undefined-parameters.ts": 3171, + "deferred-field-updates.ts": 2290, + "deferred-registry-many.ts": 3267, + "derived-numeric-updates.ts": 2762, + "destructure-call-assignment.js": 2259, + "destructure-inferred-row-defaults.js": 2953, + "destructure-union-arrays.ts": 3202, + "dynamic-function-descriptors.js": 2214, + "error-cause-writes.js": 3441, + "error-inherited-message.mjs": 3449, + "error-inherited-name.mjs": 2955, + "error-property-writes.mjs": 2326, + "error-prototype-tostring.js": 2596, + "error-stack-frames.ts": 2880, + "error-stack-limit.ts": 2871, + "error-tostring-overrides.ts": 2481, + "error-values-inspect.ts": 2856, + "exact-index-round-trip.ts": 3660, + "expression-runtime-values.ts": 2159, + "fiber-switch-stress.ts": 2800, + "fiberless-async-ordering.ts": 3075, + "fiberless-async-unhandled.ts": 2437, + "field-assignment-values.ts": 2878, + "file-handle-values.ts": 2035, + "file-read-storage.ts": 2737, + "file-url-percent-decoding.ts": 2029, + "final-field-borrows.ts": 3105, + "for-multiple-bindings.ts": 2994, + "for-multiple-lexical-bindings.ts": 2863, + "for-of-checked-iterator.js": 3515, + "for-of-subclass-elements.ts": 2469, + "forward-generic-signatures.ts": 3287, + "fresh-array-union-layout.js": 2961, + "frozen-checked-dictionaries.mjs": 3021, + "fs-native-realpath.ts": 3263, + "fs-null-byte-paths-js.cjs": 2762, + "fs-null-byte-paths.ts": 3411, + "fs-read-encodings.ts": 3220, + "fs-read-utf8-edges.ts": 3246, + "fs-read-utf8-handle-forms.ts": 3163, + "fs-remove-readonly.ts": 2468, + "fs-write-string-bytes-union.ts": 2571, + "function-apply-value.mjs": 2118, + "function-constructor-global.mjs": 2459, + "function-constructor-kinds/main.js": 2510, + "function-custom-prototype.js": 3445, + "function-custom-to-string.mjs": 3088, + "function-object-assign.js": 2894, + "function-own-prototype/main.js": 2937, + "generator-checked-protocol.ts": 3202, + "generator-checked-return.js": 2917, + "generator-custom-delegation/main.ts": 5180, + "generator-default-return-pattern.ts": 2163, + "generator-delegation-values.ts": 2121, + "generator-inferred-date.js": 1700, + "generator-mixed-checked-channels.ts": 3203, + "generator-untyped-consumer/main.ts": 3571, + "generic-base-specializations.ts": 2610, + "generic-binding-ownership.ts": 3653, + "generic-class-js-functions/main.ts": 2631, + "generic-class-recovery.ts": 3190, + "generic-namespace-factories/main.ts": 2712, + "generic-nullable-collections.ts": 2692, + "generic-pattern-bindings.ts": 2004, + "generic-record-index.ts": 2705, + "generic-visitor-void.ts": 2865, + "global-accumulator-loops.ts": 3053, + "global-error-subclasses.ts": 2690, + "global-runtime-probes.js": 1976, + "global-stored-probes.js": 2924, + "global-string-cache/main.js": 2572, + "global-symbol-cache/main.js": 2380, + "guarded-native-iterables.ts": 2466, + "heap-input-aliases.ts": 2784, + "heap-input-collections.ts": 3100, + "in-array-runtime-index.ts": 3210, + "indexed-assignment-values.js": 3521, + "indexed-assignment-values.ts": 2224, + "indexed-element-field-reads.ts": 2611, + "inferred-array-assignment-values.mjs": 2976, + "inferred-class-default.mjs": 2564, + "inferred-compound-values.mjs": 2110, + "inferred-conditional-class.mjs": 2584, + "inferred-error-fields.js": 2163, + "inferred-map-patterns.mjs": 2233, + "inferred-method-override.js": 2516, + "inferred-partial-destructuring.mjs": 2158, + "inferred-primitive-properties.mjs": 2508, + "inferred-record-return.mjs": 2099, + "inferred-recursive-record.mjs": 2183, + "inferred-undefined-field.mjs": 3012, + "input-lifetime-intervals.ts": 3244, + "input-lifetimes-modules/main.ts": 2793, + "instanceof-class-record-union.ts": 2242, + "integer-flow-arithmetic.ts": 3060, + "integer-loop-forms.ts": 2872, + "integer-view-control.ts": 2400, + "integer-view-numbers.ts": 2753, + "integer-view-storage.ts": 2545, + "intl-grapheme-conformance/main.ts": 4747, + "intl-grapheme.ts": 2345, + "iterator-typed-returns.ts": 3833, + "js-abort-portable.js": 2996, + "js-array-constructor.js": 3177, + "js-array-default-buffer.js": 2796, + "js-array-iterators.js": 3414, + "js-arrow-bind.cjs": 4772, + "js-buffer-callback-brand.cjs": 2001, + "js-callable-proxy.js": 3739, + "js-chained-native-results.mjs": 2683, + "js-checked-array-iterator.js": 2865, + "js-checked-array-reference.js": 3607, + "js-checked-number-negation.mjs": 2731, + "js-checked-sort-result.js": 2328, + "js-child-error-listener.cjs": 2751, + "js-cjs-callable-snapshots/main.cjs": 2946, + "js-class-added-parameters.js": 2228, + "js-class-checked-overrides.js": 2130, + "js-class-computed-fields.js": 2657, + "js-class-enumeration.js": 2642, + "js-class-field-accessor-override.js": 2687, + "js-class-fluent-overrides.js": 2370, + "js-class-late-method-values.js": 3690, + "js-class-member-dispatch.js": 3108, + "js-class-return-shapes.js": 3149, + "js-class-shadowed-methods.js": 3491, + "js-class-stored-method-receiver.js": 2218, + "js-class-subclass-properties.js": 4610, + "js-class-symbol-spread.cjs": 2295, + "js-computed-prototype-additions.js": 3232, + "js-constructor-returned-callable.js": 2404, + "js-constructor-spread.js": 3538, + "js-dataview-dispatch.js": 3187, + "js-declared-fields.cjs": 4825, + "js-default-listener-arguments.cjs": 1767, + "js-default-options/main.ts": 3097, + "js-deferred-field-initializers.js": 1977, + "js-deferred-registry-effects.js": 2772, + "js-derived-constructor-hoisting.js": 2288, + "js-dormant-array-write.js": 2420, + "js-dormant-overrides.js": 2890, + "js-expando-records.js": 2867, + "js-implicit-call-results.js": 2946, + "js-inferred-callback-exports/main.js": 4147, + "js-inferred-class-array-return.js": 3209, + "js-inferred-object-values.js": 2234, + "js-inherited-field-storage.js": 2161, + "js-inherited-parameter-abi.js": 2457, + "js-iterable-spread.js": 3088, + "js-loose-dynamic-primitives.js": 2797, + "js-map-object-seeds.js": 3253, + "js-member-increment.js": 3027, + "js-module-function-values.js": 3358, + "js-mutable-null-members.js": 2588, + "js-nested-native-descriptors.js": 2862, + "js-normalize-dispatch.js": 3006, + "js-nullish-inherited-fields.mjs": 2812, + "js-object-receiver-storage.js": 2500, + "js-object-returning-constructors.mjs": 2542, + "js-object-shared-arrays.js": 2369, + "js-omitted-typed-arguments.js": 2596, + "js-open-binding-writes.js": 2909, + "js-optional-class-fields.js": 3469, + "js-optional-member-call.js": 3126, + "js-primitive-union-addition.js": 2730, + "js-promise-all-values.js": 3561, + "js-promise-catch-handler.js": 2902, + "js-promise-finally-order.js": 2511, + "js-promise-pending-reactions.js": 2712, + "js-prototype-host-boundary.js": 2617, + "js-reflect-receivers.js": 3341, + "js-regex-record-captures.js": 3157, + "js-scalar-iterables.js": 3299, + "js-shared-method-dispatch.js": 3057, + "js-specialized-field-method.js": 2254, + "js-static-accessors.js": 3374, + "js-static-method-values.js": 3629, + "js-static-registries.cjs": 3164, + "js-super-accessor-initialization.js": 2332, + "js-uninitialized-native-fields.js": 2069, + "json-guarded-map-values.ts": 3048, + "json-output-bulk.ts": 1978, + "json-runtime-options.mjs": 3034, + "json-stringify-value.js": 2308, + "json-typed-parse-direct.ts": 2696, + "json-typed-parse-index-signatures.ts": 3686, + "json-typed-parse-optional-members.ts": 3044, + "json-typed-parse-union-members.ts": 3090, + "literal-switch-dispatch.ts": 2612, + "live-reference-shared-converters.ts": 3144, + "llvm-read-receiver-lifetime.ts": 1978, + "local-class-call-spreads.js": 1989, + "local-class-declaration.ts": 1927, + "local-class-evaluation.ts": 2816, + "local-class-inheritance.ts": 2647, + "local-class-lifetimes.ts": 3188, + "local-class-namespace/main.js": 3542, + "local-class-prototype-data.js": 2714, + "local-class-specialization.js": 2650, + "local-class-unknown.ts": 2915, + "local-class-values.ts": 2331, + "local-union-storage.ts": 2638, + "locale-compare-root-order.ts": 3001, + "logical-assignment-dynamic.js": 3172, + "logical-assignment-values.ts": 2043, + "logical-runtime-optional-record.ts": 2200, + "loop-reference-lifetimes.ts": 2559, + "map-checked-boundary/main.ts": 2442, + "map-checked-seed.js": 2756, + "map-get-set-fusion.ts": 3284, + "map-number-keys-dense.ts": 2972, + "map-read-lifetimes-exits.ts": 2860, + "map-read-lifetimes.ts": 2905, + "map-seeds-and-spreads.ts": 2984, + "map-typed-array-values.ts": 2649, + "math-function-values.js": 2638, + "missing-read-lambda-results.ts": 2850, + "missing-read-narrowed-storage.ts": 3077, + "missing-read-number-conversions.ts": 3015, + "module-byte-loops.ts": 2315, + "module-fallback-functions/main.js": 2716, + "narrowed-nullish-values.ts": 2405, + "native-any-timer-callback.ts": 2380, + "native-array-borrowed-find-last.js": 2591, + "native-array-borrowed-slice.js": 2966, + "native-array-copying-methods.js": 2605, + "native-array-fill-copywithin.js": 2662, + "native-array-frozen-noops.js": 2568, + "native-array-index-boundaries.js": 2581, + "native-array-integrity.js": 3066, + "native-array-length.js": 3005, + "native-array-named-properties.js": 2812, + "native-array-prototype/main.js": 3103, + "native-array-read-lifetimes.ts": 2912, + "native-array-reduce-find-last.js": 2732, + "native-array-search-from-index.js": 2720, + "native-array-splice-coercion.js": 1769, + "native-array-splice-flat.js": 2701, + "native-buffer-coercion.js": 2837, + "native-callback-dispatch.ts": 3750, + "native-class-array-boundaries.ts": 3033, + "native-class-cache.js": 3922, + "native-class-properties.cjs": 5335, + "native-class-property-cycles.cjs": 2421, + "native-class-property-order.cjs": 2798, + "native-class-type-predicates.ts": 2523, + "native-factory-records.js": 2515, + "native-method-values.js": 4031, + "native-method-values.ts": 2347, + "native-npm-imports/main.ts": 3454, + "native-object-descriptors.js": 1755, + "native-object-for-in-minimal.js": 2603, + "native-object-property-attributes.js": 3035, + "native-object-prototype.js": 2445, + "native-property-names.ts": 2425, + "native-proxy-env.js": 3704, + "native-worker-arena-reuse.ts": 6858, + "native-worker-bounded-errors.ts": 2058, + "native-worker-buffer-consumers.ts": 3068, + "native-worker-cancel-hot.ts": 2722, + "native-worker-class-fields.ts": 2782, + "native-worker-clone-errors.ts": 2690, + "native-worker-commonjs.cjs": 3412, + "native-worker-delayed-messages.ts": 2375, + "native-worker-discarded-heaps.ts": 5717, + "native-worker-environment.ts": 2804, + "native-worker-error.ts": 2211, + "native-worker-exception-state.ts": 4167, + "native-worker-exit-listeners.ts": 2523, + "native-worker-io.ts": 3345, + "native-worker-loop-cancellation.ts": 2510, + "native-worker-message-graphs.ts": 2419, + "native-worker-messages.ts": 2757, + "native-worker-poll-exceptions.ts": 3061, + "native-worker-port-lifetime.ts": 2699, + "native-worker-process-exit.ts": 2130, + "native-worker-publish-classes.ts": 3636, + "native-worker-publish-refusals.ts": 2020, + "native-worker-published-graphs.ts": 2461, + "native-worker-references.ts": 2598, + "native-worker-roots/main.ts": 3212, + "native-worker-shared-views.ts": 2802, + "native-worker-stack-overflow.ts": 2946, + "native-worker-terminate-exception-state.ts": 3847, + "native-worker-terminate-loop.ts": 2735, + "native-worker-terminate-recursion.ts": 4636, + "native-worker-terminate-suspended.ts": 2692, + "native-worker-terminate-tested-loops.ts": 3271, + "native-worker-terminate-wait.ts": 2775, + "native-worker-typed-arrays.ts": 3254, + "nested-map-cycles.ts": 2753, + "nested-map-values.ts": 4785, + "never-returning-calls.ts": 2228, + "next-tick-commonjs-entry.cjs": 1929, + "node24-buffer-encoding-errors.ts": 2283, + "node24-buffer-encoding.ts": 2691, + "node24-crypto-kdf-errors.ts": 3129, + "node24-crypto-kdf-options.ts": 3852, + "node24-crypto-kdf.ts": 3936, + "node24-crypto-sha2.ts": 1860, + "node24-deep-equality-properties.js": 2441, + "node24-deep-equality.cjs": 2912, + "node24-deep-equality.ts": 3378, + "node24-env-files-errors.ts": 2760, + "node24-env-files.ts": 2643, + "node24-env-imports.cjs": 1749, + "node24-env-parse-errors.ts": 2987, + "node24-env-parse.ts": 1797, + "node24-esm-metadata/main.mjs": 2385, + "node24-file-url-buffer.ts": 2665, + "node24-file-url-errors.js": 3394, + "node24-file-url-options.ts": 3117, + "node24-fs-links-callbacks.cjs": 2182, + "node24-fs-links-errors.cjs": 2221, + "node24-fs-links-options.cjs": 3438, + "node24-fs-links-promise-errors.cjs": 1752, + "node24-fs-links-promises.ts": 2960, + "node24-fs-links.ts": 3132, + "node24-fs-statfs-callbacks.cjs": 2404, + "node24-fs-statfs-errors.cjs": 3053, + "node24-fs-statfs-options.cjs": 3275, + "node24-fs-statfs.ts": 2771, + "node24-fs-timestamps-callbacks.cjs": 3442, + "node24-fs-timestamps-errors.cjs": 2214, + "node24-fs-timestamps-promises.ts": 2905, + "node24-fs-timestamps-symlinks.ts": 2911, + "node24-fs-timestamps.ts": 2652, + "node24-no-error-assertions-coercion.js": 3450, + "node24-no-error-assertions.cjs": 2131, + "node24-no-error-assertions.ts": 3704, + "node24-parseargs.js": 3975, + "node24-string-decoder.ts": 1840, + "node24-style-text-environment.js": 1777, + "node24-style-text-validation.js": 2850, + "node24-style-text.cjs": 2428, + "node24-style-text.ts": 2934, + "node24-system-error-validation.js": 2301, + "node24-system-errors.cjs": 2559, + "node24-system-errors.ts": 2989, + "node24-text-codec-properties.ts": 3210, + "node24-text-encode-into.ts": 2657, + "node24-text-utilities-coercion.js": 2506, + "node24-text-utilities-validation.js": 3129, + "node24-text-utilities.cjs": 2550, + "node24-text-utilities.ts": 2610, + "node24-url-authority-coercion.js": 3075, + "node24-url-authority.ts": 2397, + "node24-url-factories.ts": 3132, + "node24-url-factory-errors.ts": 2346, + "node24-url-mutation-coercion.js": 2926, + "node24-url-mutation.ts": 2845, + "node24-util-types.cjs": 2459, + "node24-util-types.js": 2601, + "node24-util-types.ts": 3126, + "non-null-class-iteration.ts": 1674, + "nonnull-element-arguments.ts": 2593, + "nonnull-forwarded-class-values.ts": 1775, + "nullable-object-extension.mjs": 1502, + "nullish-asserted-class-arms.ts": 2652, + "nullish-assignment-values.ts": 2755, + "nullish-long-chain.ts": 3588, + "number-parse-statics.ts": 2229, + "number-predicates-unknown.ts": 2605, + "numeric-call-specialization.ts": 1690, + "object-enumeration-array-reads.ts": 3043, + "object-from-checked-entries.js": 3900, + "object-inherited-to-string.js": 1733, + "object-key-indexes.js": 3227, + "object-prototype-identity.mjs": 2689, + "object-reexport/main.js": 2801, + "object-spread-computed.ts": 2239, + "opentui-byte-queue.js": 3379, + "optional-callback-arity.ts": 1977, + "optional-class-flows.ts": 2120, + "optional-element-defaults.ts": 2378, + "optional-flag-comparisons.ts": 2194, + "optional-native-callables.js": 2420, + "optional-node-list-iteration.ts": 2425, + "optional-string-index/main.ts": 2629, + "path-to-file-url-options.ts": 1964, + "performance-presence.ts": 2369, + "primitive-and-function-descriptors.js": 2715, + "primitive-union-string.ts": 2231, + "process-builtin-values.js": 3831, + "process-constrained-memory.ts": 2154, + "process-env-computed-keys.js": 2619, + "process-hrtime.js": 2376, + "process-named-signals.cjs": 2024, + "process-uncaught-handler-throws.cjs": 2023, + "process-uncaught-loop.cjs": 1789, + "process-uncaught-module.mjs": 1660, + "process-uncaught-monitor.cjs": 2359, + "process-uncaught-rejection.cjs": 2287, + "process-uncaught-sync.cjs": 2104, + "process-version-pin.ts": 2000, + "process-versions-storage.ts": 2763, + "projected-collection-lifetimes.ts": 2478, + "promise-checked-rejections.ts": 2584, + "promise-resolve-void.ts": 1939, + "prototype-method-overrides.mjs": 5633, + "prototype-named-data-records.ts": 2571, + "rc-last-use-moves.ts": 2854, + "rc-private-array-writes.ts": 3076, + "record-field-presence.ts": 3566, + "record-key-order.ts": 2682, + "record-optional-json-presence.ts": 2822, + "record-presence-copies.ts": 3201, + "record-presence-delete-json.ts": 3074, + "record-unchecked-read-presence.ts": 2374, + "record-unknown-values.ts": 3234, + "reflect-own-keys.mjs": 1796, + "reflect-record-union-keys.mjs": 2278, + "reflect-typed-record-keys.ts": 2418, + "regex-callback-replacements.ts": 2839, + "regex-callback-values.js": 2887, + "regex-checked-casts.ts": 1808, + "regex-checked-storage.js": 2999, + "regex-exec-long-subject.ts": 2794, + "regex-exec-result-arrays.ts": 3204, + "regex-fs-text-surfaces.ts": 3720, + "regex-input-lifetimes.ts": 2060, + "regex-native-matcher.ts": 4292, + "regex-optional-captures.ts": 2856, + "regex-optional-templates.ts": 2387, + "regex-split-captures.ts": 2496, + "regex-text-paths.ts": 3201, + "regexp-constructor-repeat.ts": 2842, + "regexp-optional-constructor.ts": 2495, + "regexp-string-coercion.js": 1920, + "renderer-export-dictionaries.js": 2828, + "renderer-null-state.js": 2692, + "renderer-specializations.js": 2881, + "repeat-and-typed-read-errors.ts": 2395, + "rest-optional-array-arguments.ts": 2478, + "rest-optional-elements.ts": 2534, + "return-void-through-finally.ts": 2913, + "runtime-optional-string-flows.ts": 2188, + "scalar-string-slices.ts": 2172, + "set-checked-methods.js": 3226, + "set-checked-storage.ts": 1974, + "set-iterator-seed-references.ts": 2018, + "set-iterator-seeds.ts": 3264, + "set-optional-seeds.ts": 2769, + "small-collection-transitions.ts": 3115, + "speculative-integer-globals.ts": 2544, + "speculative-integer-loops.ts": 2308, + "speculative-integer-reads.ts": 3059, + "stack-depth-async-bodies.ts": 2625, + "stack-overflow-async.ts": 1714, + "stack-overflow-caught.ts": 2878, + "stack-overflow-finally.ts": 2668, + "stack-overflow-shapes.ts": 3524, + "stack-overflow-uncaught.ts": 2587, + "stackless-async-concurrency.ts": 3322, + "stackless-async-context.ts": 1853, + "stackless-async-exceptions.ts": 3251, + "stackless-async-ordering.ts": 3551, + "stackless-async-unhandled.ts": 1779, + "static-field-updates/main.ts": 2473, + "static-method-receivers.ts": 2567, + "stdio-values.mjs": 2963, + "stdio-write-errors.mjs": 2760, + "stdio-write-overrides.mjs": 2090, + "stored-native-builtins.js": 2900, + "stored-object-helpers.js": 2328, + "stream-dynamic-entry-kinds.cjs": 2778, + "stream-dynamic-entry-kinds.ts": 2624, + "stream-encoded-from-entries.cjs": 2924, + "stream-encoded-from-entries.ts": 3274, + "string-char-code-integer-loops.ts": 1819, + "string-code-points.ts": 1858, + "string-concat-number-parts.ts": 1705, + "string-construction-order.ts": 2928, + "string-field-append.ts": 2926, + "string-lifetimes-boundaries.ts": 1843, + "string-lifetimes-evaluation.ts": 2718, + "string-lifetimes-iteration.ts": 2668, + "string-lifetimes-operations.ts": 2866, + "string-normalize.ts": 2507, + "string-pattern-replacement.ts": 3053, + "string-scan-fast-paths.ts": 2942, + "string-split-checked-separator.mjs": 2465, + "string-split-traversal.ts": 3686, + "structural-class-properties.ts": 2071, + "structured-text-boundaries.js": 2038, + "structured-text-storage.ts": 2083, + "switch-integer-dispatch.ts": 2561, + "symbol-checked-boundary/main.ts": 3073, + "symbol-class-fields.ts": 1839, + "symbol-class-fields/main.cjs": 2716, + "symbol-class-methods/main.ts": 1920, + "symbol-fields-deferred-factory.ts": 2270, + "symbol-fields-inferred.js": 1610, + "symbol-object-properties/main.js": 2842, + "synchronous-callback-lifetimes.ts": 3460, + "terminal-stream-properties.ts": 2151, + "text-codec-values/main.ts": 2261, + "text-codec-var.ts": 2601, + "text-encode-into-boundaries.ts": 2554, + "timers-clear-many.ts": 2390, + "tuple-and-string-search.ts": 2238, + "tuple-array-union.ts": 2290, + "tuple-callback-visitation.ts": 3777, + "tuple-forof-visitation.ts": 2917, + "typed-array-bulk-conversion.mjs": 4510, + "typed-array-byte-io.js": 2794, + "typed-array-checked-index.js": 1963, + "typed-array-constructor-alias.ts": 2203, + "typed-array-constructor-identity.js": 2030, + "typed-array-constructor-union.ts": 2632, + "typed-array-constructor-values.mjs": 3162, + "typed-array-dynamic-methods.js": 2468, + "typed-array-integer-widths.ts": 2823, + "typed-array-nan-coded-reads.ts": 3658, + "typed-array-numeric-import.ts": 2758, + "typed-array-present-reads.ts": 2812, + "typed-array-reversed-storage.ts": 2702, + "typed-array-unknown.ts": 2767, + "typed-collection-iterator-references.ts": 3694, + "typed-collection-iterators.ts": 3044, + "typed-collection-views/main.ts": 3027, + "typed-index-arguments.ts": 2801, + "typed-prototype-methods.ts": 2702, + "typed-rest-callables.ts": 2066, + "typed-rest-filtered-return.ts": 1741, + "typedarray-native-inputs.js": 3278, + "typeof-checked-comparison.js": 2471, + "uint8array-sort-domains.ts": 2675, + "unicode-case-paths.ts": 2617, + "unicode-process-argv.ts": 2688, + "union-discriminant-width.ts": 3120, + "union-literal-scalar-discriminants.ts": 3160, + "union-literal-slot-conversion.ts": 2002, + "union-nested-layout-discriminant.ts": 2160, + "union-optional-semantic-identity.ts": 3319, + "union-record-clone.ts": 3245, + "union-record-structural-copy.ts": 3278, + "union-reference-comparison.ts": 2689, + "unknown-array-holes.ts": 1863, + "unknown-collections.ts": 2098, + "unknown-object-enumeration.ts": 4264, + "unknown-record-views.ts": 2126, + "url-runtime-base.ts": 2747, + "utf8-span-decoding.ts": 2143, + "util-parseargs-wrapped/main.ts": 3020, + "virtual-runtime-optional-returns.ts": 3408, + "weak-map-array-buffer.ts": 2113, + "weak-map-fresh-array.js": 2822, + "weak-map-native.js": 2623, + "weak-native-class-identity.ts": 1967, + "weak-set-native.js": 2320, + "worker-class-instance-clone.ts": 3408 }, "san": { - "001-hello.ts": 47467, - "002-log-args.ts": 4723, - "100-number-format.ts": 49913, - "1000-json-stringify-basics.ts": 49071, - "1001-json-escapes-unicode.ts": 5167, - "1002-json-parse-cast.ts": 48226, - "1003-json-parse-unions.ts": 5247, - "1004-json-parse-errors.ts": 4196, - "1005-json-nested.ts": 8262, - "1006-json-fs-config.ts": 36095, - "1007-json-rc-stress.ts": 30487, - "1008-json-null-arms.ts": 48758, - "1009-json-optional-fields.ts": 3469, - "101-arithmetic.ts": 49638, - "1010-json-stringify-space.ts": 48585, - "1011-json-unknown-typeof.ts": 52058, - "102-comparisons.ts": 47851, - "1020-async-basics.ts": 4722, - "1021-async-ordering.ts": 4973, - "1022-async-exceptions.ts": 49732, - "1023-async-rc-stress.ts": 6131, - "1024-async-pending-exit.ts": 48202, - "1025-async-promise-capture.ts": 3959, - "1026-throw-promise.ts": 4948, - "1027-async-return-promise.ts": 4908, - "1028-async-return-record-literals.ts": 4271, - "1029-async-eager-chains.ts": 3619, - "103-ternary.ts": 5182, - "104-ternary-empty-arrays.ts": 7669, - "1050-comptime-tables.ts": 4897, - "1051-comptime-strings.ts": 47107, - "1052-comptime-records.ts": 39735, - "1053-comptime-json.ts": 5104, - "1054-comptime-modules/main.ts": 48253, - "110-number-radix.ts": 3792, - "111-record-entries.ts": 7069, - "1110-math-members.ts": 5365, - "1111-math-random.ts": 4260, - "1113-string-methods.ts": 54370, - "1114-string-unicode-island.ts": 52372, - "1115-parse-globals.ts": 3948, - "1116-island-static-mix.ts": 42223, - "1117-typeof-static-union.ts": 4732, - "1118-object-spread-conditional.ts": 39126, - "1119-switch-union.ts": 28754, - "112-class-descriptor-key.js": 39424, - "1121-infinity-number-tostring.ts": 4725, - "1122-any-captures.ts": 7404, - "1124-union-narrowed-retag.ts": 6000, - "113-promise-checked-exits.ts": 3453, - "114-live-record-delete.ts": 4924, - "115-array-compound.js": 5191, - "116-text-decoder-runtime.js": 46050, - "117-weak-cache-cycle.js": 5083, - "118-fs-stored-callbacks.cjs": 56960, - "119-native-patterns.js": 8396, - "1200-regex-test-basics.ts": 52932, - "1201-regex-replace.ts": 57037, - "1202-regex-substitutions.ts": 57467, - "1203-regex-split.ts": 3335, - "1204-regex-empty-unicode.ts": 42721, - "1205-regex-rc-stress.ts": 4531, - "1300-errors-basics.ts": 4518, - "1301-errors-subclass.ts": 4955, - "1302-errors-typed-catch.ts": 4560, - "1303-errors-rc-stress.ts": 3938, - "1304-errors-uncaught.ts": 4101, - "1305-errors-async-rejections.ts": 3614, - "1306-errors-runtime-instances.ts": 4054, - "1350-path-normalize-join.ts": 3568, - "1351-path-parts.ts": 4963, - "1352-path-resolve-relative.ts": 4503, - "1353-os-basics.ts": 4704, - "1354-builtin-bare-specifiers.ts": 4189, - "1355-url-parse.ts": 3863, - "1356-url-file-bridge.ts": 4207, - "1357-fsp-roundtrip.ts": 4886, - "1358-crypto-random.ts": 4050, - "1359-json-module/main.ts": 3853, - "1360-spawn-sync.ts": 4896, - "1361-spawn-events.ts": 3844, - "1362-spawn-timers.ts": 9749, - "1363-spawn-unhandled-error.ts": 5302, - "1364-union-truthiness.ts": 4307, - "1365-union-logical.ts": 4482, - "1366-union-equality.ts": 4253, - "1367-destructuring.ts": 5033, - "1368-constructor-functions.ts": 4831, - "1369-promise-union.ts": 3513, - "1370-spread.ts": 3969, - "1371-union-template-tostring.ts": 4126, - "1372-loose-null-tests.ts": 4513, - "1373-union-array-arms.ts": 3764, - "140-bitwise-operators.ts": 5173, - "1400-typedarray-basics.ts": 5411, - "1401-typedarray-slice-set.ts": 6335, - "1402-buffer-encodings.ts": 3500, - "1403-buffer-fs.ts": 7777, - "1404-zlib-crypto-bytes.ts": 6742, - "1405-bytes-unions-arrays.ts": 3762, - "1406-dataview-mp4.ts": 4549, - "1407-dataview-bounds.ts": 3820, - "1408-string-indexing.ts": 4530, - "1409-typedarray-integer-loops.ts": 4694, - "1420-number-statics.ts": 2928, - "1421-number-parse-strings.ts": 4454, - "1422-date-iso.ts": 3607, - "1423-text-codec.ts": 45738, - "1424-fs-options.ts": 3565, - "1425-stdin-tty.ts": 3853, - "1426-stdin-read.ts": 4250, - "1427-fromcharcode-lastindexof.ts": 3449, - "1428-settled-await-order.ts": 3904, - "1429-promise-catch-finally.ts": 6712, - "1430-promise-race.ts": 5576, - "1431-caught-tostring.ts": 4594, - "1432-destructured-params.ts": 5133, - "1433-filter-narrow.ts": 5015, - "1434-async-never.ts": 4402, - "1435-math-spread.ts": 4605, - "1436-default-undef-param.ts": 3807, - "1437-pad-default.ts": 3436, - "1438-promise-all.ts": 7568, - "1440-interval-basics.ts": 4290, - "1441-interval-clear-cross.ts": 7227, - "1442-interval-throw.ts": 4291, - "1443-signal-handlers.ts": 9442, - "1444-exit-listeners.ts": 5858, - "1445-exit-process-exit.ts": 5492, - "1446-exit-uncaught.ts": 4521, - "1447-stdin-closed-events.ts": 5005, - "1448-stream-columns.ts": 4280, - "1450-incdec-expression.ts": 3444, - "1451-instanceof-uint8array-unknown.ts": 4098, - "1452-return-through-finally.ts": 4660, - "1453-pmap-settled.ts": 7068, - "1454-nonnull-narrow-and-fcc-bytes.ts": 4716, - "1455-lambda-union-return-adoption.ts": 4826, - "1460-console-error-warn.ts": 4457, - "1461-process-pid-getuid-kill.ts": 4447, - "1462-exec-sync.ts": 4723, - "1463-timeout-unref.ts": 3720, - "1464-env-writes.ts": 4414, - "1465-env-value.ts": 4722, - "1466-child-containers.ts": 3465, - "1467-string-match.ts": 3798, - "1468-exec-path.ts": 4492, - "1469-remove-listener.ts": 6954, - "1470-child-lifecycle.ts": 4162, - "1471-child-unref.ts": 8772, - "1472-errno-code.ts": 5205, - "1473-promisify-execfile.ts": 5324, - "1474-string-decoder.ts": 4470, - "1475-readline-closed-stdin.ts": 55374, - "1476-assign-expression.ts": 4697, - "1477-in-expressions.ts": 3393, - "1478-promise-reject.ts": 4340, - "1479-destructuring-assign.ts": 4907, - "1480-os-network-interfaces.ts": 5202, - "1481-string-case-static.ts": 5232, - "1482-spawnsync-error.ts": 4518, - "1483-array-slice.ts": 47847, - "1520-fs-wider-surface.ts": 4261, - "1520-string-split-static.ts": 3932, - "1521-fs-lstat-lock.ts": 4472, - "1521-string-trim-pad-static.ts": 3262, - "1522-parseint-static.ts": 4734, - "1522-spawnsync-options.ts": 5888, - "1523-isnan-floor-static.ts": 4375, - "1523-spawn-options.ts": 4320, - "1524-atomics-sleep-static.ts": 4175, - "1524-catch-narrowing.ts": 4322, - "1525-child-exit-signal.ts": 4107, - "1525-unknown-typeof-validation.ts": 4804, - "1526-set-spread.ts": 5272, - "1527-logical-mixed-operands.ts": 3380, - "1528-delete-records-env.ts": 26816, - "1529-class-with-statics.ts": 3554, - "1530-array-push-variadic.ts": 4410, - "1530-spread-override-completion.ts": 4642, - "1531-delete-optional-fields.ts": 4468, - "1531-process-arch-versions.ts": 4294, - "1532-array-splice-shift.ts": 4135, - "1532-union-shared-field-read.ts": 3539, - "1533-bool-equality.ts": 3797, - "1533-path-platform-namespaces.ts": 4105, - "1534-crypto-hash-chain.ts": 4243, - "1534-union-as-arm-cast.ts": 3852, - "1535-spawn-fd-stdio.ts": 3827, - "1535-union-param-defaults.ts": 3756, - "1536-destructuring-defaults.ts": 4441, - "1536-string-array-sweep.ts": 4773, - "1537-chalk-hybrid/main.ts": 4555, - "1537-os-release-spawnsync-stdio.ts": 3030, - "1538-await-promiselike-return.ts": 4081, - "1538-math-static-scalar.ts": 2688, - "1539-readonly-set-map.ts": 4386, - "1539-unknown-truthiness.ts": 4573, - "1540-os-userinfo.ts": 4277, - "1540-void-statement.ts": 3770, - "1541-fs-readdir-dirent.ts": 5970, - "1541-union-keyed-reads.ts": 5137, - "1542-map-promise-values.ts": 3680, - "1542-record-literal-into-union.ts": 4161, - "1543-rest-destructuring.ts": 5386, - "1543-set-server-handles.ts": 8749, - "1544-dyn-json-reads.ts": 5370, - "1544-string-matchall.ts": 4375, - "1545-spread-order-and-optional.ts": 4546, - "1546-union-element-reads.ts": 50679, - "1547-computed-key-fold.ts": 5436, - "1548-boolean-condition-forms.ts": 3960, - "1549-array-isarray-unions.ts": 3329, - "1550-param-defaults-func-set.ts": 3161, - "1551-dyn-receiver-methods.ts": 6009, - "1552-exec-options-record.ts": 3255, - "1553-truthy-hof-predicates.ts": 4287, - "1554-caught-into-unknown.ts": 3533, - "1555-index-spread-into-declared.ts": 4772, - "1556-union-retag-width-arms.ts": 4319, - "1557-url-host.ts": 4070, - "1558-any-joins-and-dyn-validation.ts": 54305, - "1559-conditional-spread-index-merge.ts": 2926, - "1560-forof-homogeneous-tuples.ts": 32566, - "1561-forof-strings.ts": 3862, - "1561-promise-then.ts": 4850, - "1562-optional-chain-tails.ts": 4960, - "1562-spawn-conditional-spread.ts": 3616, - "1563-forof-iterator-projections.ts": 4225, - "1563-string-raw-fold.ts": 4244, - "1564-fs-watch.ts": 5142, - "1564-string-raw.ts": 4078, - "1565-spawn-pipe-streams.ts": 4189, - "1565-union-element-join.ts": 3622, - "1566-child-duck-interface.ts": 4142, - "1567-server-close-override.ts": 8728, - "1568-x509-fingerprint.ts": 3542, - "1569-fsp-mkdir-unlink-chmod.ts": 4083, - "1570-child-unref-kill-reffed.ts": 9583, - "1571-optional-call-tostring-tail.ts": 28217, - "1571-stdin-set-raw-mode-non-tty.ts": 3839, - "1572-promise-reject-all-tuple.ts": 4539, - "1572-x509-validity-date-gettime.ts": 4354, - "1573-promisify-execfile-env-spread.ts": 5359, - "1573-tdz-scalar-forward-capture.ts": 4394, - "1574-dyn-optional-method-number-keys.ts": 4461, - "1574-promise-all-tuple-literal.ts": 5082, - "1575-unknown-assert-into-record.ts": 4680, - "1576-width-coercions.ts": 4595, - "1577-url-hostname.ts": 3199, - "1578-exec-input-optional.ts": 3688, - "1579-matchall-index.ts": 4163, - "1580-exec-env-conditional-spread.ts": 3992, - "1581-declare-const-read.ts": 3904, - "1582-timer-sleep-resolve.ts": 5122, - "1583-loops-and-stream-captures.ts": 2955, - "1584-union-field-unassigned.ts": 4202, - "1585-union-field-conditional-ctor.ts": 4837, - "1586-derived-field-before-super-init.ts": 3740, - "1590-js-unannotated.js": 5105, - "1591-js-closures.js": 4745, - "1592-js-classes.js": 5879, - "1593-js-jsdoc-records.js": 4650, - "1594-js-async.js": 4426, - "1595-js-island-gap/main.js": 26477, - "1596-cjs-modules/main.js": 3160, - "1597-mjs-graph/main.mjs": 4960, - "1598-cjs-builtin-require/main.js": 3030, - "1599-js-uncaught-throw.js": 4259, - "1600-assert-passing.ts": 4325, - "1601-assert-fail-exit.ts": 4804, - "1602-assert-caught-error.ts": 5361, - "1603-assert-scalar-messages.ts": 4806, - "1604-assert-deep-structures.ts": 6023, - "1605-assert-import-forms.ts": 5339, - "1606-assert-strict-module.ts": 4600, - "1607-assert-throws-match.ts": 4414, - "1608-cjs-assert/main.js": 5188, - "1609-assert-async.ts": 4729, - "1610-path-win32-full.ts": 2755, - "1611-url-file-bridge-neutral.ts": 3733, - "1612-cjs-module-globals.cjs": 4516, - "1613-cjs-esm-proxy-named/main.mjs": 4105, - "1614-js-fence-dodges.cjs": 5207, - "1615-cjs-export-shapes/main.cjs": 5553, - "1616-cjs-esm-lexer-invisible/main.mjs": 3099, - "1617-cjs-esm-lexer-visible/main.mjs": 4087, - "1618-cjs-esm-poisoned-tail/main.mjs": 2476, - "1619-cjs-esm-reexport-invisible/main.mjs": 3415, - "1620-cjs-require-effects-order/main.js": 2713, - "1621-cjs-require-cache-hit/main.js": 3783, - "1622-cjs-require-conditional/main.js": 3828, - "1623-cjs-require-diamond/main.js": 3626, - "1624-cjs-require-dir-mid-file/main.js": 2336, - "1625-cjs-require-lazy-fn/main.js": 3015, - "1626-cjs-require-mjs/main.js": 2250, - "1627-mjs-import-cjs-requires/main.mjs": 2873, - "1628-checked-dynamic-builtin-args.cjs": 3077, - "1629-require-main-filename.cjs": 3479, - "1630-inspect-scalars.ts": 3977, - "1630-rmsync-retry-options.cjs": 3932, - "1631-inspect-arrays.ts": 5457, - "1632-inspect-records.ts": 4882, - "1633-inspect-map-set.ts": 4086, - "1634-inspect-classes.ts": 5725, - "1635-inspect-buffer.ts": 5155, - "1636-util-format.ts": 5015, - "1637-inspect-dyn.ts": 4071, - "1638-inspect-cjs.cjs": 3892, - "1639-versions-openssl-probe.ts": 4020, - "1640-fd-read-decode.ts": 4014, - "1641-string-search.ts": 21121, - "1642-object-fromentries-rows.ts": 4097, - "1643-metadata-dyn-return.cjs": 56433, - "1644-ee-basics.ts": 3623, - "1645-ee-extends.ts": 5009, - "1646-ee-once-remove.ts": 3768, - "1647-ee-meta-events.ts": 3840, - "1648-ee-error-event.ts": 2892, - "1649-ee-names-counts.ts": 4454, - "1650-ee-prepend.ts": 2707, - "1651-ee-max-listeners.ts": 4174, - "1652-ee-snapshot.ts": 5505, - "1653-ee-cjs.cjs": 4390, - "1654-ee-namespace.ts": 4636, - "1655-spawnsync-neutral.ts": 6342, - "1656-execsync-neutral.ts": 4702, - "1657-spawn-async-neutral.ts": 4011, - "1660-buffer-read-write-num.ts": 4936, - "1661-buffer-encodings-full.ts": 4916, - "1662-string-decoder-encodings.ts": 4639, - "1663-buffer-compare-search-fill.ts": 4818, - "1664-dyn-fn-boundary.cjs": 3636, - "1665-dyn-fn-mustcall/main.cjs": 4145, - "1666-dyn-fn-identity.ts": 3840, - "1667-dyn-fn-not-callable.cjs": 2882, - "1668-dyn-fn-throws.cjs": 3462, - "1669-symbol-identity.ts": 4719, - "1670-symbol-registry.ts": 4117, - "1671-symbol-typeof.ts": 5887, - "1672-symbol-containers.ts": 4625, - "1673-symbol-cjs.cjs": 6028, - "1674-symbol-inspect.ts": 4649, - "1676-func-array-surface.ts": 3616, - "1677-emitter-listeners.ts": 5664, - "1678-emitter-dyn-listeners.cjs": 6093, - "1679-console-dyn.js": 4398, - "1680-assert-bytes.ts": 3589, - "1681-assert-funcs.ts": 4450, - "1685-stream-readable-basics.ts": 8176, - "1686-stream-readable-paused.ts": 8142, - "1687-stream-readable-flow-control.ts": 6069, - "1688-stream-writable-basics.ts": 9377, - "1689-stream-writable-async-drain.ts": 7873, - "1690-stream-duplex.ts": 8422, - "1691-stream-transform.ts": 6383, - "1692-stream-pipe.ts": 5114, - "1693-stream-pipe-backpressure.ts": 3801, - "1694-stream-destroy.ts": 3612, - "1695-stream-props.ts": 8560, - "1696-stream-read-inside-read.ts": 4132, - "1697-stream-tick-vs-timer.ts": 7129, - "1698-stream-uncaught-error.ts": 4025, - "1699-stream-callback-shapes.ts": 4137, - "1700-mustcall-common/main.cjs": 4739, - "1701-mustcall-exit-report/main.cjs": 4788, - "1702-dyn-proto-dispatch.cjs": 4406, - "1703-arguments-rest-props.cjs": 3234, - "1710-cjs-export-class/main.js": 4152, - "1711-cjs-export-single-values/main.js": 3547, - "1712-field-incdec.ts": 3906, - "1713-js-dyn-fields.js": 5278, - "1720-assert-throws-shape.ts": 4205, - "1721-assert-throws-regex-class.ts": 3161, - "1722-assert-rejects.ts": 4021, - "1723-assert-does-not-reject.ts": 4049, - "1724-assert-iferror.ts": 3854, - "1725-assert-symbols.ts": 3165, - "1726-promise-with-resolvers.ts": 2792, - "1727-assert-throws-shape-exit.ts": 4670, - "1730-countdown-symbol-keys/main.js": 3893, - "1731-symbol-field-shapes.cjs": 4357, - "1732-symbol-field-cross-module/main.js": 4117, - "1740-stream-extends-readable.ts": 5412, - "1741-stream-extends-writable.ts": 7703, - "1742-stream-extends-duplex-transform.ts": 8664, - "1743-stream-extends-vt-dispatch.ts": 7746, - "1744-stream-set-encoding.ts": 3694, - "1745-stream-encoding-js.cjs": 3919, - "1746-stream-for-await.ts": 6732, - "1747-stream-for-await-js.cjs": 11913, - "1750-http-agent-options.ts": 7010, - "1751-options-record-stance.ts": 4331, - "1760-surplus-args-drop.cjs": 3419, - "1761-emitter-special-event-names.cjs": 3326, - "1770-assert-dyn-strict.ts": 4129, - "1771-assert-dyn-deep.ts": 4621, - "1772-assert-dyn-js.cjs": 3690, - "1773-assert-dyn-exit.ts": 3870, - "1780-http-res-surface.ts": 7391, - "1781-http-server-shapes.cjs": 11204, - "1790-computed-key-folds.ts": 3769, - "1791-searchparams-core.ts": 2566, - "1792-searchparams-encoding.ts": 3926, - "1793-searchparams-iteration.ts": 3839, - "1794-searchparams-url-live.ts": 3667, - "1795-dyn-handle-request.cjs": 7469, - "1796-dyn-handle-body.cjs": 4708, - "1797-dyn-handle-socket.cjs": 6317, - "1798-dyn-handle-typed-box.ts": 12433, - "1800-immediate-basics.ts": 3461, - "1801-immediate-handle.ts": 2828, - "1802-immediate-unref-exit.ts": 3773, - "1803-timeout-refresh.ts": 2890, - "1804-timers-module.ts": 4324, - "1805-timer-callback-args.ts": 4084, - "1806-timer-delay-trunc.ts": 3166, - "1810-stream-options-const-record.ts": 3962, - "1811-stream-option-value-callbacks.cjs": 3964, - "1812-stream-super-options-forwarding.cjs": 8384, - "1813-stream-finished.ts": 5772, - "1814-stream-pipeline.cjs": 8091, - "1815-stream-state-reads.cjs": 7977, - "1820-static-block-basics.ts": 3028, - "1821-static-block-order.ts": 2726, - "1822-static-block-js.js": 4178, - "1823-static-instance-method-names.ts": 2438, - "1824-for-of-destructuring-defaults.ts": 3053, - "1825-exhaustive-typeof-switch.ts": 3216, - "1826-settimeout-arguments-callback.js": 2649, - "1830-enum-numeric-basics.ts": 3631, - "1831-enum-string-const-reverse.ts": 3353, - "1832-enum-modules/main.ts": 3697, - "1835-var-basics.ts": 3553, - "1836-var-loop-capture.ts": 3991, - "1837-var-undefined-hoisting.ts": 3692, - "1838-var-modules/main.ts": 2987, - "1839-var-js/main.cjs": 3074, - "1840-jsdoc-import-type-only/main.js": 3723, - "1850-overload-basics.ts": 3730, - "1851-overload-return-narrowing.ts": 3097, - "1852-overload-class-members.ts": 4001, - "1853-overload-modules/main.ts": 4277, - "1854-ambient-declare-fn.ts": 2860, - "1855-ambient-declare-fn-uncaught.ts": 4252, - "1870-unit-type-values.ts": 3913, - "1871-empty-array-never.ts": 2656, - "1872-template-tostring-composite.ts": 3669, - "1880-json-declared-field-order.ts": 5166, - "1881-default-anon/main.ts": 3155, - "1882-default-cjs-interop/main.ts": 4152, - "1883-default-exports/main.ts": 4005, - "1890-ns-imports/main.ts": 4423, - "1891-ns-reexport/main.ts": 2975, - "1940-class-values-basics.ts": 2991, - "1941-class-values-registry.ts": 4395, - "1942-class-expressions.ts": 4086, - "1943-class-statics-expanded.ts": 3500, - "1944-class-values-modules/main.ts": 3932, - "1950-generic-fn-values.ts": 4360, - "1951-generic-classes-basics.ts": 4948, - "1952-generic-class-statics-values.ts": 4310, - "1953-generic-class-hierarchy.ts": 3171, - "1954-generic-modules/main.ts": 3610, - "1960-namespace-basics.ts": 3656, - "1961-namespace-nested.ts": 4076, - "1962-namespace-classes.ts": 3740, - "1963-namespace-aliases.ts": 3282, - "1964-namespace-type-only.ts": 3064, - "1965-namespace-ambient.ts": 3659, - "1966-namespace-modules/main.ts": 4077, - "1967-namespace-alias-typeonly.ts": 2697, - "1968-namespace-import-eq-snapshot.ts": 2527, - "1970-decorators-basics.ts": 4151, - "1971-decorators-rebinding.ts": 2897, - "1972-decorators-throwing.ts": 2556, - "1973-decorators-ambient.ts": 3932, - "1980-primitive-proto-statics.ts": 4096, - "1981-date-utc.ts": 3463, - "1982-freeze-resolve-passthrough.ts": 4042, - "1983-array-tuple-surfaces.ts": 4356, - "1990-labels-basics.ts": 3887, - "1991-for-in-loops.ts": 5008, - "1992-small-syntax.ts": 3829, - "200-strings.ts": 3521, - "2000-generic-methods-basic.ts": 4027, - "2001-generic-methods-generic-class.ts": 3431, - "2002-generic-methods-inheritance.ts": 3737, - "2003-generic-methods-object-literal.ts": 4544, - "2004-generic-methods-statics.ts": 3642, - "201-templates.ts": 2558, - "2010-generators-basics.ts": 3652, - "2011-generators-forof.ts": 3852, - "2012-generators-return-throw.ts": 3950, - "2013-generators-sent-values.ts": 4017, - "2014-generators-values.ts": 4246, - "2015-generators-yieldstar.ts": 3908, - "2016-generators-rc-stress.ts": 4275, - "2017-generators-async.ts": 2845, - "2018-generators-uncaught.ts": 3328, - "2019-generators-loops.ts": 3191, - "2020-generic-value-bindings.ts": 5274, - "2021-generic-value-binding-modules/main.ts": 3546, - "2022-width-index-capture.ts": 4336, - "2023-width-readonly.ts": 3104, - "2024-width-array-elems.ts": 3482, - "2025-width-union-compose.ts": 4076, - "2026-width-spread.ts": 3943, - "2030-width-nested.ts": 4567, - "2031-width-tuples.ts": 2753, - "2032-cjs-export-assigned-class-expression/main.cjs": 4056, - "2033-property-assigned-class-extends.cjs": 3174, - "2035-ternary-array-retag.cjs": 4091, - "2036-evolving-array-decl.cjs": 3778, - "2037-fn-decl-hoisting.cjs": 2776, - "2038-evolving-array-js.cjs": 4351, - "2040-any-bindings.ts": 3377, - "2040-mixin-heritage.ts": 3511, - "2041-any-params-returns.ts": 3626, - "2041-mixin-values.ts": 4380, - "2042-any-flow-loops.ts": 3135, - "2042-mixin-modules/main.ts": 4398, - "2043-any-dom-values.ts": 3973, - "2043-mixin-rc-stress.ts": 3648, - "2044-vtable-sibling-slots.ts": 3788, - "2045-objlit-accessors-basic.ts": 3867, - "2045-parameter-properties.ts": 4798, - "2046-abstract-classes.ts": 5738, - "2046-objlit-accessors-effects.ts": 3922, - "2047-objlit-accessors-shapes.ts": 3974, - "2047-optional-class-fields.ts": 5957, - "2050-dynamic-import-own-module/main.ts": 4276, - "2051-dynamic-import-then/main.ts": 3569, - "2052-dynamic-import-self.ts": 2505, - "2053-typeof-static-fold.ts": 3591, - "2054-destructuring-island-source.ts": 4039, - "2060-empty-tuple.ts": 3547, - "2070-computed-key-folds.ts": 5392, - "2071-integer-key-enumeration-order.ts": 4114, - "2072-expando-function-members.ts": 3911, - "2073-destructuring-assignment.ts": 3331, - "2074-island-destructuring.ts": 2722, - "2075-index-signature-runtime-keys.ts": 2808, - "2080-destructuring-defaults.ts": 4723, - "2081-destructuring-rest.ts": 3815, - "2082-destructuring-assignment.ts": 4463, - "2085-destructuring-heads-rest-params.ts": 3370, - "2087-destructuring-for-heads.ts": 3817, - "2090-index-signature-number-keys.ts": 3307, - "2091-index-signature-string-intersection.ts": 4503, - "2092-package-imports/main.ts": 3209, - "2093-timers-promises.ts": 4576, - "2094-diagnostics-channel.ts": 5184, - "2095-js-catch-unknown.js": 3505, - "2096-os-type.ts": 3468, - "2097-js-evolving-globals.js": 3426, - "210-string-methods.ts": 3239, - "2100-stream-default-hwm.ts": 4068, - "2101-dyn-param-defaults.ts": 4169, - "2102-empty-pattern-decls.ts": 3916, - "2105-computed-key-static-folds.ts": 3626, - "2106-comma-expressions.ts": 4728, + "001-hello.ts": 48584, + "002-log-args.ts": 53231, + "100-number-format.ts": 36832, + "1000-json-stringify-basics.ts": 52367, + "1001-json-escapes-unicode.ts": 4807, + "1002-json-parse-cast.ts": 5113, + "1003-json-parse-unions.ts": 7293, + "1004-json-parse-errors.ts": 49116, + "1005-json-nested.ts": 41496, + "1006-json-fs-config.ts": 48813, + "1007-json-rc-stress.ts": 4968, + "1008-json-null-arms.ts": 49375, + "1009-json-optional-fields.ts": 52902, + "101-arithmetic.ts": 4596, + "1010-json-stringify-space.ts": 7197, + "1011-json-unknown-typeof.ts": 38530, + "102-comparisons.ts": 45324, + "1020-async-basics.ts": 5928, + "1021-async-ordering.ts": 3518, + "1022-async-exceptions.ts": 4562, + "1023-async-rc-stress.ts": 49059, + "1024-async-pending-exit.ts": 4366, + "1025-async-promise-capture.ts": 4983, + "1026-throw-promise.ts": 47886, + "1027-async-return-promise.ts": 3187, + "1028-async-return-record-literals.ts": 53064, + "1029-async-eager-chains.ts": 5109, + "103-ternary.ts": 4538, + "104-ternary-empty-arrays.ts": 50460, + "1050-comptime-tables.ts": 7149, + "1051-comptime-strings.ts": 4737, + "1052-comptime-records.ts": 37872, + "1053-comptime-json.ts": 4779, + "1054-comptime-modules/main.ts": 7660, + "110-number-radix.ts": 4935, + "111-record-entries.ts": 7207, + "1110-math-members.ts": 4805, + "1111-math-random.ts": 5313, + "1113-string-methods.ts": 39688, + "1114-string-unicode-island.ts": 61280, + "1115-parse-globals.ts": 4273, + "1116-island-static-mix.ts": 58945, + "1117-typeof-static-union.ts": 4726, + "1118-object-spread-conditional.ts": 5790, + "1119-switch-union.ts": 3967, + "112-class-descriptor-key.js": 6359, + "1121-infinity-number-tostring.ts": 6448, + "1122-any-captures.ts": 5744, + "1124-union-narrowed-retag.ts": 48623, + "113-promise-checked-exits.ts": 5906, + "114-live-record-delete.ts": 5041, + "115-array-compound.js": 45694, + "116-text-decoder-runtime.js": 42554, + "117-weak-cache-cycle.js": 4096, + "118-fs-stored-callbacks.cjs": 67405, + "119-native-patterns.js": 6976, + "1200-regex-test-basics.ts": 59964, + "1201-regex-replace.ts": 59629, + "1202-regex-substitutions.ts": 64765, + "1203-regex-split.ts": 40181, + "1204-regex-empty-unicode.ts": 4019, + "1205-regex-rc-stress.ts": 6786, + "1300-errors-basics.ts": 4602, + "1301-errors-subclass.ts": 4547, + "1302-errors-typed-catch.ts": 5456, + "1303-errors-rc-stress.ts": 3915, + "1304-errors-uncaught.ts": 4301, + "1305-errors-async-rejections.ts": 25668, + "1306-errors-runtime-instances.ts": 56774, + "1350-path-normalize-join.ts": 4099, + "1351-path-parts.ts": 3517, + "1352-path-resolve-relative.ts": 4602, + "1353-os-basics.ts": 4075, + "1354-builtin-bare-specifiers.ts": 4565, + "1355-url-parse.ts": 3650, + "1356-url-file-bridge.ts": 5481, + "1357-fsp-roundtrip.ts": 4525, + "1358-crypto-random.ts": 3809, + "1359-json-module/main.ts": 4642, + "1360-spawn-sync.ts": 14534, + "1361-spawn-events.ts": 3384, + "1362-spawn-timers.ts": 9556, + "1363-spawn-unhandled-error.ts": 3577, + "1364-union-truthiness.ts": 4455, + "1365-union-logical.ts": 5263, + "1366-union-equality.ts": 5404, + "1367-destructuring.ts": 6097, + "1368-constructor-functions.ts": 4502, + "1369-promise-union.ts": 5171, + "1370-spread.ts": 5455, + "1371-union-template-tostring.ts": 5704, + "1372-loose-null-tests.ts": 4863, + "1373-union-array-arms.ts": 6061, + "140-bitwise-operators.ts": 5704, + "1400-typedarray-basics.ts": 4417, + "1401-typedarray-slice-set.ts": 6150, + "1402-buffer-encodings.ts": 6652, + "1403-buffer-fs.ts": 4712, + "1404-zlib-crypto-bytes.ts": 8302, + "1405-bytes-unions-arrays.ts": 4908, + "1406-dataview-mp4.ts": 4190, + "1407-dataview-bounds.ts": 5248, + "1408-string-indexing.ts": 6549, + "1409-typedarray-integer-loops.ts": 5748, + "1420-number-statics.ts": 4080, + "1421-number-parse-strings.ts": 3030, + "1422-date-iso.ts": 4656, + "1423-text-codec.ts": 42827, + "1424-fs-options.ts": 4763, + "1425-stdin-tty.ts": 3515, + "1426-stdin-read.ts": 4428, + "1427-fromcharcode-lastindexof.ts": 4393, + "1428-settled-await-order.ts": 3638, + "1429-promise-catch-finally.ts": 6438, + "1430-promise-race.ts": 5872, + "1431-caught-tostring.ts": 4401, + "1432-destructured-params.ts": 3887, + "1433-filter-narrow.ts": 5268, + "1434-async-never.ts": 3971, + "1435-math-spread.ts": 5075, + "1436-default-undef-param.ts": 4896, + "1437-pad-default.ts": 5306, + "1438-promise-all.ts": 8026, + "1440-interval-basics.ts": 3886, + "1441-interval-clear-cross.ts": 8806, + "1442-interval-throw.ts": 3908, + "1443-signal-handlers.ts": 10098, + "1444-exit-listeners.ts": 6271, + "1445-exit-process-exit.ts": 6288, + "1446-exit-uncaught.ts": 4829, + "1447-stdin-closed-events.ts": 5308, + "1448-stream-columns.ts": 3842, + "1450-incdec-expression.ts": 4062, + "1451-instanceof-uint8array-unknown.ts": 4913, + "1452-return-through-finally.ts": 3940, + "1453-pmap-settled.ts": 5769, + "1454-nonnull-narrow-and-fcc-bytes.ts": 5066, + "1455-lambda-union-return-adoption.ts": 4687, + "1460-console-error-warn.ts": 4173, + "1461-process-pid-getuid-kill.ts": 3798, + "1462-exec-sync.ts": 4955, + "1463-timeout-unref.ts": 3605, + "1464-env-writes.ts": 3898, + "1465-env-value.ts": 5166, + "1466-child-containers.ts": 4567, + "1467-string-match.ts": 31065, + "1468-exec-path.ts": 3971, + "1469-remove-listener.ts": 5771, + "1470-child-lifecycle.ts": 4259, + "1471-child-unref.ts": 8596, + "1472-errno-code.ts": 3697, + "1473-promisify-execfile.ts": 5268, + "1474-string-decoder.ts": 4402, + "1475-readline-closed-stdin.ts": 7198, + "1476-assign-expression.ts": 4160, + "1477-in-expressions.ts": 3377, + "1478-promise-reject.ts": 4766, + "1479-destructuring-assign.ts": 3620, + "1480-os-network-interfaces.ts": 5191, + "1481-string-case-static.ts": 47079, + "1482-spawnsync-error.ts": 4222, + "1483-array-slice.ts": 37812, + "1520-fs-wider-surface.ts": 4505, + "1520-string-split-static.ts": 5103, + "1521-fs-lstat-lock.ts": 4862, + "1521-string-trim-pad-static.ts": 4149, + "1522-parseint-static.ts": 3342, + "1522-spawnsync-options.ts": 6589, + "1523-isnan-floor-static.ts": 4386, + "1523-spawn-options.ts": 4864, + "1524-atomics-sleep-static.ts": 5554, + "1524-catch-narrowing.ts": 4776, + "1525-child-exit-signal.ts": 3419, + "1525-unknown-typeof-validation.ts": 4171, + "1526-set-spread.ts": 6387, + "1527-logical-mixed-operands.ts": 56825, + "1528-delete-records-env.ts": 3989, + "1529-class-with-statics.ts": 4851, + "1530-array-push-variadic.ts": 4575, + "1530-spread-override-completion.ts": 4651, + "1531-delete-optional-fields.ts": 5027, + "1531-process-arch-versions.ts": 4345, + "1532-array-splice-shift.ts": 5472, + "1532-union-shared-field-read.ts": 4768, + "1533-bool-equality.ts": 4449, + "1533-path-platform-namespaces.ts": 3877, + "1534-crypto-hash-chain.ts": 4113, + "1534-union-as-arm-cast.ts": 3510, + "1535-spawn-fd-stdio.ts": 3466, + "1535-union-param-defaults.ts": 3648, + "1536-destructuring-defaults.ts": 3985, + "1536-string-array-sweep.ts": 4779, + "1537-chalk-hybrid/main.ts": 4311, + "1537-os-release-spawnsync-stdio.ts": 3803, + "1538-await-promiselike-return.ts": 4183, + "1538-math-static-scalar.ts": 4776, + "1539-readonly-set-map.ts": 4240, + "1539-unknown-truthiness.ts": 3925, + "1540-os-userinfo.ts": 3976, + "1540-void-statement.ts": 3920, + "1541-fs-readdir-dirent.ts": 6148, + "1541-union-keyed-reads.ts": 5049, + "1542-map-promise-values.ts": 4830, + "1542-record-literal-into-union.ts": 4691, + "1543-rest-destructuring.ts": 4682, + "1543-set-server-handles.ts": 11403, + "1544-dyn-json-reads.ts": 5540, + "1544-string-matchall.ts": 4621, + "1545-spread-order-and-optional.ts": 4810, + "1546-union-element-reads.ts": 4735, + "1547-computed-key-fold.ts": 4346, + "1548-boolean-condition-forms.ts": 4311, + "1549-array-isarray-unions.ts": 4783, + "1550-param-defaults-func-set.ts": 4654, + "1551-dyn-receiver-methods.ts": 47581, + "1552-exec-options-record.ts": 4931, + "1553-truthy-hof-predicates.ts": 3759, + "1554-caught-into-unknown.ts": 4792, + "1555-index-spread-into-declared.ts": 5295, + "1556-union-retag-width-arms.ts": 4339, + "1557-url-host.ts": 4062, + "1558-any-joins-and-dyn-validation.ts": 4201, + "1559-conditional-spread-index-merge.ts": 4811, + "1560-forof-homogeneous-tuples.ts": 3801, + "1561-forof-strings.ts": 4569, + "1561-promise-then.ts": 5688, + "1562-optional-chain-tails.ts": 4544, + "1562-spawn-conditional-spread.ts": 5015, + "1563-forof-iterator-projections.ts": 3931, + "1563-string-raw-fold.ts": 2934, + "1564-fs-watch.ts": 4633, + "1564-string-raw.ts": 4462, + "1565-spawn-pipe-streams.ts": 4825, + "1565-union-element-join.ts": 4303, + "1566-child-duck-interface.ts": 3784, + "1567-server-close-override.ts": 8452, + "1568-x509-fingerprint.ts": 4642, + "1569-fsp-mkdir-unlink-chmod.ts": 4604, + "1570-child-unref-kill-reffed.ts": 10519, + "1571-optional-call-tostring-tail.ts": 4149, + "1571-stdin-set-raw-mode-non-tty.ts": 3975, + "1572-promise-reject-all-tuple.ts": 4421, + "1572-x509-validity-date-gettime.ts": 3928, + "1573-promisify-execfile-env-spread.ts": 4371, + "1573-tdz-scalar-forward-capture.ts": 3510, + "1574-dyn-optional-method-number-keys.ts": 5406, + "1574-promise-all-tuple-literal.ts": 4446, + "1575-unknown-assert-into-record.ts": 4160, + "1576-width-coercions.ts": 4905, + "1577-url-hostname.ts": 3830, + "1578-exec-input-optional.ts": 4111, + "1579-matchall-index.ts": 3935, + "1580-exec-env-conditional-spread.ts": 4157, + "1581-declare-const-read.ts": 4532, + "1582-timer-sleep-resolve.ts": 5668, + "1583-loops-and-stream-captures.ts": 4447, + "1584-union-field-unassigned.ts": 4778, + "1585-union-field-conditional-ctor.ts": 4205, + "1586-derived-field-before-super-init.ts": 4167, + "1590-js-unannotated.js": 4511, + "1591-js-closures.js": 4889, + "1592-js-classes.js": 7239, + "1593-js-jsdoc-records.js": 5280, + "1594-js-async.js": 3437, + "1595-js-island-gap/main.js": 3858, + "1596-cjs-modules/main.js": 3826, + "1597-mjs-graph/main.mjs": 4207, + "1598-cjs-builtin-require/main.js": 4782, + "1599-js-uncaught-throw.js": 3029, + "1600-assert-passing.ts": 4584, + "1601-assert-fail-exit.ts": 5710, + "1602-assert-caught-error.ts": 5606, + "1603-assert-scalar-messages.ts": 6055, + "1604-assert-deep-structures.ts": 4164, + "1605-assert-import-forms.ts": 4744, + "1606-assert-strict-module.ts": 3846, + "1607-assert-throws-match.ts": 3634, + "1608-cjs-assert/main.js": 22902, + "1609-assert-async.ts": 5276, + "1610-path-win32-full.ts": 4297, + "1611-url-file-bridge-neutral.ts": 4511, + "1612-cjs-module-globals.cjs": 4120, + "1613-cjs-esm-proxy-named/main.mjs": 4168, + "1614-js-fence-dodges.cjs": 5147, + "1615-cjs-export-shapes/main.cjs": 5790, + "1616-cjs-esm-lexer-invisible/main.mjs": 3074, + "1617-cjs-esm-lexer-visible/main.mjs": 4703, + "1618-cjs-esm-poisoned-tail/main.mjs": 4175, + "1619-cjs-esm-reexport-invisible/main.mjs": 3250, + "1620-cjs-require-effects-order/main.js": 4047, + "1621-cjs-require-cache-hit/main.js": 3190, + "1622-cjs-require-conditional/main.js": 4002, + "1623-cjs-require-diamond/main.js": 3383, + "1624-cjs-require-dir-mid-file/main.js": 4621, + "1625-cjs-require-lazy-fn/main.js": 4138, + "1626-cjs-require-mjs/main.js": 3518, + "1627-mjs-import-cjs-requires/main.mjs": 4705, + "1628-checked-dynamic-builtin-args.cjs": 4815, + "1629-require-main-filename.cjs": 3830, + "1630-inspect-scalars.ts": 3402, + "1630-rmsync-retry-options.cjs": 4168, + "1631-inspect-arrays.ts": 5636, + "1632-inspect-records.ts": 5322, + "1633-inspect-map-set.ts": 4905, + "1634-inspect-classes.ts": 50857, + "1635-inspect-buffer.ts": 3662, + "1636-util-format.ts": 3856, + "1637-inspect-dyn.ts": 4713, + "1638-inspect-cjs.cjs": 4782, + "1639-versions-openssl-probe.ts": 3624, + "1640-fd-read-decode.ts": 4777, + "1641-string-search.ts": 42621, + "1642-object-fromentries-rows.ts": 3842, + "1643-metadata-dyn-return.cjs": 6131, + "1644-ee-basics.ts": 4824, + "1645-ee-extends.ts": 4269, + "1646-ee-once-remove.ts": 5597, + "1647-ee-meta-events.ts": 4609, + "1648-ee-error-event.ts": 3894, + "1649-ee-names-counts.ts": 3445, + "1650-ee-prepend.ts": 5882, + "1651-ee-max-listeners.ts": 3513, + "1652-ee-snapshot.ts": 3828, + "1653-ee-cjs.cjs": 5160, + "1654-ee-namespace.ts": 4086, + "1655-spawnsync-neutral.ts": 5575, + "1656-execsync-neutral.ts": 5201, + "1657-spawn-async-neutral.ts": 4183, + "1660-buffer-read-write-num.ts": 4602, + "1661-buffer-encodings-full.ts": 4532, + "1662-string-decoder-encodings.ts": 4447, + "1663-buffer-compare-search-fill.ts": 6507, + "1664-dyn-fn-boundary.cjs": 3753, + "1665-dyn-fn-mustcall/main.cjs": 3637, + "1666-dyn-fn-identity.ts": 4113, + "1667-dyn-fn-not-callable.cjs": 5226, + "1668-dyn-fn-throws.cjs": 3927, + "1669-symbol-identity.ts": 5374, + "1670-symbol-registry.ts": 5422, + "1671-symbol-typeof.ts": 5011, + "1672-symbol-containers.ts": 6131, + "1673-symbol-cjs.cjs": 3807, + "1674-symbol-inspect.ts": 4101, + "1676-func-array-surface.ts": 3917, + "1677-emitter-listeners.ts": 5384, + "1678-emitter-dyn-listeners.cjs": 6837, + "1679-console-dyn.js": 5132, + "1680-assert-bytes.ts": 5780, + "1681-assert-funcs.ts": 4542, + "1685-stream-readable-basics.ts": 6799, + "1686-stream-readable-paused.ts": 7460, + "1687-stream-readable-flow-control.ts": 6103, + "1688-stream-writable-basics.ts": 8189, + "1689-stream-writable-async-drain.ts": 6061, + "1690-stream-duplex.ts": 8154, + "1691-stream-transform.ts": 8459, + "1692-stream-pipe.ts": 8943, + "1693-stream-pipe-backpressure.ts": 7445, + "1694-stream-destroy.ts": 4337, + "1695-stream-props.ts": 4409, + "1696-stream-read-inside-read.ts": 4780, + "1697-stream-tick-vs-timer.ts": 4369, + "1698-stream-uncaught-error.ts": 9453, + "1699-stream-callback-shapes.ts": 6489, + "1700-mustcall-common/main.cjs": 5513, + "1701-mustcall-exit-report/main.cjs": 5169, + "1702-dyn-proto-dispatch.cjs": 3843, + "1703-arguments-rest-props.cjs": 5139, + "1710-cjs-export-class/main.js": 4603, + "1711-cjs-export-single-values/main.js": 4271, + "1712-field-incdec.ts": 4369, + "1713-js-dyn-fields.js": 3948, + "1720-assert-throws-shape.ts": 4422, + "1721-assert-throws-regex-class.ts": 3508, + "1722-assert-rejects.ts": 4110, + "1723-assert-does-not-reject.ts": 4852, + "1724-assert-iferror.ts": 5098, + "1725-assert-symbols.ts": 4520, + "1726-promise-with-resolvers.ts": 4144, + "1727-assert-throws-shape-exit.ts": 4544, + "1730-countdown-symbol-keys/main.js": 4981, + "1731-symbol-field-shapes.cjs": 4983, + "1732-symbol-field-cross-module/main.js": 6365, + "1740-stream-extends-readable.ts": 4706, + "1741-stream-extends-writable.ts": 8537, + "1742-stream-extends-duplex-transform.ts": 8628, + "1743-stream-extends-vt-dispatch.ts": 7490, + "1744-stream-set-encoding.ts": 3923, + "1745-stream-encoding-js.cjs": 3912, + "1746-stream-for-await.ts": 5266, + "1747-stream-for-await-js.cjs": 9157, + "1750-http-agent-options.ts": 4824, + "1751-options-record-stance.ts": 4860, + "1760-surplus-args-drop.cjs": 3596, + "1761-emitter-special-event-names.cjs": 5408, + "1770-assert-dyn-strict.ts": 4549, + "1771-assert-dyn-deep.ts": 4653, + "1772-assert-dyn-js.cjs": 4842, + "1773-assert-dyn-exit.ts": 3322, + "1780-http-res-surface.ts": 7900, + "1781-http-server-shapes.cjs": 5025, + "1790-computed-key-folds.ts": 4472, + "1791-searchparams-core.ts": 3100, + "1792-searchparams-encoding.ts": 4024, + "1793-searchparams-iteration.ts": 2933, + "1794-searchparams-url-live.ts": 2969, + "1795-dyn-handle-request.cjs": 8538, + "1796-dyn-handle-body.cjs": 8773, + "1797-dyn-handle-socket.cjs": 5230, + "1798-dyn-handle-typed-box.ts": 9154, + "1800-immediate-basics.ts": 3918, + "1801-immediate-handle.ts": 3182, + "1802-immediate-unref-exit.ts": 3903, + "1803-timeout-refresh.ts": 3243, + "1804-timers-module.ts": 3435, + "1805-timer-callback-args.ts": 3958, + "1806-timer-delay-trunc.ts": 4233, + "1810-stream-options-const-record.ts": 3952, + "1811-stream-option-value-callbacks.cjs": 4066, + "1812-stream-super-options-forwarding.cjs": 8532, + "1813-stream-finished.ts": 3971, + "1814-stream-pipeline.cjs": 4413, + "1815-stream-state-reads.cjs": 4085, + "1820-static-block-basics.ts": 3479, + "1821-static-block-order.ts": 4110, + "1822-static-block-js.js": 3095, + "1823-static-instance-method-names.ts": 3531, + "1824-for-of-destructuring-defaults.ts": 3925, + "1825-exhaustive-typeof-switch.ts": 3439, + "1826-settimeout-arguments-callback.js": 3758, + "1830-enum-numeric-basics.ts": 3846, + "1831-enum-string-const-reverse.ts": 3347, + "1832-enum-modules/main.ts": 3603, + "1835-var-basics.ts": 3009, + "1836-var-loop-capture.ts": 4162, + "1837-var-undefined-hoisting.ts": 3457, + "1838-var-modules/main.ts": 4306, + "1839-var-js/main.cjs": 4870, + "1840-jsdoc-import-type-only/main.js": 3497, + "1850-overload-basics.ts": 4398, + "1851-overload-return-narrowing.ts": 3452, + "1852-overload-class-members.ts": 3733, + "1853-overload-modules/main.ts": 3524, + "1854-ambient-declare-fn.ts": 4169, + "1855-ambient-declare-fn-uncaught.ts": 2640, + "1870-unit-type-values.ts": 4848, + "1871-empty-array-never.ts": 3051, + "1872-template-tostring-composite.ts": 3835, + "1880-json-declared-field-order.ts": 5173, + "1881-default-anon/main.ts": 3809, + "1882-default-cjs-interop/main.ts": 3893, + "1883-default-exports/main.ts": 4076, + "1890-ns-imports/main.ts": 3441, + "1891-ns-reexport/main.ts": 3946, + "1940-class-values-basics.ts": 3823, + "1941-class-values-registry.ts": 3834, + "1942-class-expressions.ts": 3250, + "1943-class-statics-expanded.ts": 3491, + "1944-class-values-modules/main.ts": 3807, + "1950-generic-fn-values.ts": 4479, + "1951-generic-classes-basics.ts": 4288, + "1952-generic-class-statics-values.ts": 4461, + "1953-generic-class-hierarchy.ts": 2769, + "1954-generic-modules/main.ts": 4012, + "1960-namespace-basics.ts": 4063, + "1961-namespace-nested.ts": 4436, + "1962-namespace-classes.ts": 3835, + "1963-namespace-aliases.ts": 4480, + "1964-namespace-type-only.ts": 4245, + "1965-namespace-ambient.ts": 3646, + "1966-namespace-modules/main.ts": 3158, + "1967-namespace-alias-typeonly.ts": 2894, + "1968-namespace-import-eq-snapshot.ts": 4133, + "1970-decorators-basics.ts": 5269, + "1971-decorators-rebinding.ts": 4674, + "1972-decorators-throwing.ts": 3103, + "1973-decorators-ambient.ts": 3465, + "1980-primitive-proto-statics.ts": 4370, + "1981-date-utc.ts": 3865, + "1982-freeze-resolve-passthrough.ts": 4409, + "1983-array-tuple-surfaces.ts": 4749, + "1990-labels-basics.ts": 3921, + "1991-for-in-loops.ts": 4875, + "1992-small-syntax.ts": 4940, + "200-strings.ts": 2950, + "2000-generic-methods-basic.ts": 19968, + "2001-generic-methods-generic-class.ts": 3103, + "2002-generic-methods-inheritance.ts": 4643, + "2003-generic-methods-object-literal.ts": 4397, + "2004-generic-methods-statics.ts": 2813, + "201-templates.ts": 3364, + "2010-generators-basics.ts": 4186, + "2011-generators-forof.ts": 4950, + "2012-generators-return-throw.ts": 4210, + "2013-generators-sent-values.ts": 4475, + "2014-generators-values.ts": 4791, + "2015-generators-yieldstar.ts": 3849, + "2016-generators-rc-stress.ts": 4017, + "2017-generators-async.ts": 4735, + "2018-generators-uncaught.ts": 4005, + "2019-generators-loops.ts": 2646, + "2020-generic-value-bindings.ts": 4401, + "2021-generic-value-binding-modules/main.ts": 3358, + "2022-width-index-capture.ts": 3719, + "2023-width-readonly.ts": 3719, + "2024-width-array-elems.ts": 3231, + "2025-width-union-compose.ts": 3698, + "2026-width-spread.ts": 3241, + "2030-width-nested.ts": 4055, + "2031-width-tuples.ts": 3342, + "2032-cjs-export-assigned-class-expression/main.cjs": 3882, + "2033-property-assigned-class-extends.cjs": 3781, + "2035-ternary-array-retag.cjs": 3818, + "2036-evolving-array-decl.cjs": 4090, + "2037-fn-decl-hoisting.cjs": 3678, + "2038-evolving-array-js.cjs": 5045, + "2040-any-bindings.ts": 3791, + "2040-mixin-heritage.ts": 4699, + "2041-any-params-returns.ts": 3681, + "2041-mixin-values.ts": 4051, + "2042-any-flow-loops.ts": 3594, + "2042-mixin-modules/main.ts": 4173, + "2043-any-dom-values.ts": 2471, + "2043-mixin-rc-stress.ts": 4344, + "2044-vtable-sibling-slots.ts": 3559, + "2045-objlit-accessors-basic.ts": 3871, + "2045-parameter-properties.ts": 4491, + "2046-abstract-classes.ts": 5595, + "2046-objlit-accessors-effects.ts": 2807, + "2047-objlit-accessors-shapes.ts": 3455, + "2047-optional-class-fields.ts": 5630, + "2050-dynamic-import-own-module/main.ts": 3193, + "2051-dynamic-import-then/main.ts": 4043, + "2052-dynamic-import-self.ts": 4058, + "2053-typeof-static-fold.ts": 3537, + "2054-destructuring-island-source.ts": 3138, + "2060-empty-tuple.ts": 3805, + "2070-computed-key-folds.ts": 4750, + "2071-integer-key-enumeration-order.ts": 3546, + "2072-expando-function-members.ts": 4747, + "2073-destructuring-assignment.ts": 3553, + "2074-island-destructuring.ts": 4229, + "2075-index-signature-runtime-keys.ts": 5005, + "2080-destructuring-defaults.ts": 4463, + "2081-destructuring-rest.ts": 3264, + "2082-destructuring-assignment.ts": 4012, + "2085-destructuring-heads-rest-params.ts": 3930, + "2087-destructuring-for-heads.ts": 3872, + "2090-index-signature-number-keys.ts": 4103, + "2091-index-signature-string-intersection.ts": 3918, + "2092-package-imports/main.ts": 3799, + "2093-timers-promises.ts": 3870, + "2094-diagnostics-channel.ts": 4547, + "2095-js-catch-unknown.js": 4236, + "2096-os-type.ts": 3673, + "2097-js-evolving-globals.js": 3604, + "210-string-methods.ts": 3491, + "2100-stream-default-hwm.ts": 6786, + "2101-dyn-param-defaults.ts": 2902, + "2102-empty-pattern-decls.ts": 2680, + "2105-computed-key-static-folds.ts": 4156, + "2106-comma-expressions.ts": 4616, "211-string-unicode.ts": 3897, - "2110-top-object-types.ts": 3438, - "2111-json-stringify-unknown.ts": 3888, - "2112-array-at-findlast.ts": 3424, - "2113-string-index-methods.js": 3570, - "212-string-aliasing-append.ts": 3570, - "2120-package-self-import/main.ts": 3971, - "2121-esm-cycle-inert-backedge/main.ts": 2650, - "2123-ambient-import-crash/main.ts": 3746, - "2124-imports-field-wildcard/main.ts": 2731, - "2140-uri-component-codecs.ts": 3381, - "2160-dc-tracing-channel.cjs": 4690, - "2161-js-object-literal-identity.cjs": 4257, - "2162-js-dyn-destructure.cjs": 3551, - "2163-js-selfref-const.cjs": 4654, - "2164-js-then-dyn-handler.cjs": 5156, - "2165-js-throw-dyn.cjs": 3523, - "2166-cjs-getter-this/main.cjs": 3882, - "2170-island-array-exits.ts": 3858, - "2171-island-json-stringify.ts": 3712, - "2172-island-regexp-boundary.ts": 3327, - "2190-new-object-and-string-wrappers.ts": 2850, - "2191-uri-encoders.ts": 2942, - "2192-object-default-tostring.ts": 3177, - "2193-discarded-stdlib-reads.ts": 3355, - "2194-ambient-undef-chains.ts": 3563, - "2195-require-missing-package/main.mjs": 4117, - "2196-island-computed-key-chain.ts": 3932, - "2210-dyn-promise-crossing.cjs": 5102, - "2211-dc-trace-promise.cjs": 4621, - "2212-unhandled-rejection-listener.cjs": 4270, - "2213-async-local-storage.cjs": 4068, - "2214-dc-bind-store.cjs": 5707, - "2215-process-emit-warning-exit.cjs": 4386, - "2240-width-class-into-record.ts": 3665, - "2241-width-record-into-class.ts": 3361, - "2242-width-statics-into-record.ts": 3708, - "2243-width-assert-satisfies-shapes.ts": 3967, - "2250-tagged-templates.ts": 3434, - "2252-class-iterators.ts": 4459, - "2253-union-coercions.ts": 2359, - "2260-http2-constants.cjs": 3538, - "2280-builtin-namespace-destructure.cjs": 3057, - "2281-domexception-atob-btoa.cjs": 3389, - "2282-queue-microtask.cjs": 5820, - "2283-structured-clone.cjs": 4600, - "2284-regexp-constructor.cjs": 3741, - "2285-iferror-dyn.cjs": 2861, - "2286-dyn-object-walks.cjs": 3243, - "2300-dyn-record-spread-and-keyed-access.cjs": 2809, - "2301-cjs-export-table-dom-attach.cjs": 2887, - "2310-process-next-tick.ts": 4130, - "2311-next-tick-js-callbacks.js": 4068, - "2312-stream-underscore-assign.ts": 6594, - "2313-stream-underscore-assign-js.cjs": 4269, - "2314-process-introspection.ts": 3297, - "2320-await-unit.ts": 3657, - "2321-emitter-static-setmax.cjs": 4316, - "2322-dyn-array-sort.cjs": 3658, - "2323-timer-callback-returns.ts": 4288, - "2330-tls-server-runtime-options.cjs": 57265, - "2331-tls-server-options-typed.ts": 24831, - "2350-nan-global.ts": 3780, - "2351-async-methods.ts": 4037, - "2352-void-coercions.ts": 4230, - "2353-decorators-member-ambient.ts": 3783, - "2354-decorators-expression-ambient.ts": 3425, - "2360-tuple-to-array.ts": 4066, - "2361-assign-index-record.ts": 3954, - "2362-execsync-inherit.ts": 3811, - "2363-nullish-retag.ts": 4019, - "2364-in-runtime-key.ts": 3905, - "2365-dyn-into-island.ts": 4006, - "2366-string-well-formed.ts": 2861, - "2367-regexp-escape.ts": 3081, - "2368-set-methods.ts": 3869, - "2369-promise-try.ts": 4228, - "2370-group-by.ts": 4759, - "2371-iterator-helpers.ts": 4028, - "2380-buffer-module-named-import.ts": 3715, - "2381-builtin-default-imports.js": 3602, - "2382-cycle-two-decl/main.ts": 2942, - "2383-cycle-assertdoc/main.js": 2814, - "2384-cycle-mixed-bindings/main.ts": 2985, - "2385-builtin-reexport-facade/main.ts": 2368, - "2386-string-to-chars.ts": 3688, - "2387-tonumber-argv.ts": 4524, - "2388-tonumber-grammar-zoo.ts": 3447, - "2389-tonumber-unary-plus.ts": 3631, - "2390-dot-requires/main.cjs": 3823, - "2391-default-builtin-imports/main.ts": 4261, - "2392-block-guard-alias-scope.ts": 3432, - "2393-loop-exit-guard-narrow.ts": 4204, - "2394-loop-narrow-containment.ts": 3545, - "2395-while-cond-guard.ts": 3342, - "2396-born-narrowed-decl.ts": 3204, - "2397-branch-kill-merge.ts": 2872, - "2398-switch-arm-kill.ts": 2478, - "2399-reassign-kill-polarity.ts": 3975, - "240-stdout-write.ts": 3714, - "2400-kill-return-edge.ts": 2788, - "2401-kill-break-staging.ts": 3266, - "2402-labeled-break-kill.ts": 3546, - "2403-kill-continue-backedge.ts": 3341, - "2404-kill-throw-catch.ts": 3390, - "2405-sibling-arm-narrow.ts": 3636, - "2406-switch-clause-sibling-narrow.ts": 3321, - "2407-infinite-loop-seal.ts": 3706, - "2408-loop-terminality-reopen.ts": 3556, - "2409-loop-body-return-not-terminal.ts": 2952, - "2410-stacked-cases-terminality.ts": 2785, - "2411-exhaustive-switch-terminality.ts": 2898, - "2412-dowhile-guard-trailing-test.ts": 3018, - "2413-dowhile-kill-renarrow.ts": 3619, - "2414-dowhile-continue-kill.ts": 3030, - "2415-dowhile-break-trailing-test.ts": 3541, - "2416-spread-ternary-positions.ts": 3398, - "2417-ternary-local-inference.ts": 2779, - "2418-wrapped-ternary-arms.ts": 3414, - "2419-selector-ternary-union.ts": 2916, - "2420-nullish-null-identity.ts": 2738, - "2421-float-lane-inference.ts": 3483, - "2422-ieee-div-rem-corners.ts": 3493, - "2423-param-null-reassign.ts": 2469, - "2424-ternary-miss-first-narrowing.ts": 2704, - "2425-elseif-head-exit-narrow.ts": 3239, - "2426-default-snapshot-mutable/main.ts": 3047, - "2427-perf-hooks-now.ts": 3594, - "2428-field-redeclare-inherited.ts": 3306, - "2429-destructure-class-instance.ts": 3925, - "2430-empty-literal-unknown-field.js": 3247, - "2431-primitive-ctor-values.ts": 4135, - "2432-generic-member-fields-async.ts": 4525, - "2433-as-const-command-tables.ts": 4328, - "2434-deferred-init-fields.ts": 3024, - "2435-loose-same-kind-equality.ts": 3478, - "2440-console-inspect-args.ts": 5890, - "2441-console-process-argv.ts": 3753, - "2442-union-literal-arm-widening.ts": 3136, - "2443-union-literal-shadow-narrowing.ts": 3135, - "2444-union-literal-reducer-spread.ts": 2966, - "2445-math-minmax-nary.ts": 3844, - "2446-performance-global.ts": 3708, - "2447-island-boundary-slots/main.ts": 4610, - "2448-entries-null-arms-regex-arrays.ts": 4797, - "2450-private-instance-methods.ts": 4126, - "2451-private-fields.ts": 3682, - "2452-private-statics.ts": 3833, - "2453-private-accessors.ts": 3714, - "2454-private-generator-methods.ts": 4326, - "2455-private-brand-checks.ts": 2955, - "2456-private-async-methods.ts": 4273, - "2457-private-members.js": 3893, - "2460-qs-parse-grammar.ts": 5096, - "2461-qs-parse-options.ts": 3628, - "2462-qs-stringify.ts": 4992, - "2463-qs-escape-unescape.ts": 3734, - "2464-qs-require-forms.cjs": 4220, - "2470-mockable-module-shape.js": 2876, - "2471-record-keyed-write-hasown.js": 4081, - "2472-string-regexp-union.ts": 2606, - "2473-option-table-widths.js": 4586, - "2474-island-literal-forms.ts": 4522, - "2475-variadic-wrapper-island.js": 3845, - "2476-map-regex-values.ts": 3182, - "2480-recursive-record-tree.ts": 3879, - "2481-mutual-recursive-records.ts": 3675, - "2482-recursive-union-tree.ts": 3577, - "2483-recursive-record-cycles.ts": 3205, - "2484-json-stringify-circular.ts": 3643, - "2485-inspect-circular-refs.ts": 3845, - "2486-recursive-record-boundaries.ts": 2991, - "2487-recursive-deep-equal.ts": 4100, - "2488-ast-walker.ts": 4477, - "2490-find-miss-null-compare.ts": 3671, - "2491-strict-unit-compare-no-arm.ts": 3227, - "2492-loose-null-compare-unions.ts": 3901, - "2493-switch-unit-cases.ts": 3674, - "2494-no-arm-compare-effects.ts": 3403, - "2500-net-autosel-timeout.ts": 3482, - "2510-dyn-evolving-array-map.ts": 3667, - "2511-dyn-evolving-array-filter-foreach.ts": 4096, - "2512-dyn-evolving-array-mixed-push.ts": 4423, - "2520-private-statics-class-name-calls.ts": 3265, - "2521-private-statics-class-expression.ts": 3750, - "2522-private-statics-decorated.ts": 3195, - "2523-private-statics-aliased-class.ts": 3584, - "2530-object-destructuring-decl.ts": 3283, - "2531-array-tuple-destructuring-decl.ts": 4032, - "2532-param-destructuring-options.ts": 4645, - "2533-forof-destructuring.ts": 4187, - "2534-object-rest-decl.ts": 4358, - "2535-destructuring-assign-basics.ts": 3621, - "2536-destructuring-assign-nested.ts": 3573, - "2537-destructuring-assign-member-targets.ts": 3272, - "2538-destructuring-assign-class-source.ts": 3962, - "2539-class-instance-rest.ts": 4142, - "2540-accessor-destructuring-defaults.ts": 3446, - "2541-destructuring-eval-order.ts": 3928, - "2550-generics-keyof-pick.ts": 3409, - "2551-generics-value-aliases.ts": 3346, - "2552-generics-iface-methods.ts": 3488, - "2553-generics-signature-bindings.ts": 3749, - "2554-generics-frontier-mix.ts": 3794, - "2555-generics-keyof-writes.ts": 3364, - "2556-crypto-introspection.ts": 3435, - "2556-width-hybrid-shapes.ts": 4079, - "2557-tls-ca-store.ts": 3530, - "2557-width-field-lifts.ts": 4176, - "2558-index-signature-func-values.ts": 4225, - "2558-rejection-events.cjs": 3844, - "2559-index-signature-container-values.ts": 4449, - "2560-arraybuffer-dataview-set.ts": 3087, - "2561-object-is.ts": 4355, - "2562-intl-numberformat-en-us.ts": 3901, - "2563-stream-promises-pipeline.ts": 3564, - "2564-stream-promises-finished.ts": 6034, - "2565-stream-promises-js.cjs": 4473, - "2566-promise-reject-dyn-reason.js": 3377, - "2567-rest-spread-forward.js": 3534, - "2568-rest-spread-forward-dynamic.js": 4104, - "2569-upcast-identity.ts": 3496, - "2570-buffer-arg-validation.cjs": 5910, - "2571-searchparams-arg-validation.cjs": 4428, - "2572-readable-emitted-readable-flag.cjs": 3512, - "2573-fs-url-arg-ladders.cjs": 3763, - "2574-emitter-max-listeners-ladders.cjs": 3689, - "2575-string-destructuring-decl.ts": 4712, - "2576-string-destructuring-assign.ts": 3735, - "2577-builtin-global-destructuring.js": 4445, - "2578-jsval-into-unknown-rows.ts": 3828, - "2579-jsval-object-param-crossing.js": 3036, - "2580-jsval-routed-keyed-ops.js": 3956, - "2581-jsval-routed-calls.js": 3809, - "2582-jsval-object-statics.js": 3967, - "2582-jsval-routed-keyed-ops.js": 2714, - "2583-dyn-nullish-coalesce.js": 3955, - "2583-jsval-routed-calls.js": 4033, - "2584-jsval-object-statics.js": 3852, - "2584-union-dyn-collapse.ts": 3199, - "2585-dyn-nullish-coalesce.js": 4086, - "2585-unknown-array.ts": 3037, - "2586-object-assign-spread.js": 4129, - "2587-array-entries-forof.ts": 3963, - "2588-array-entries-chains.ts": 4778, - "2589-object-create-null.cjs": 3994, - "2590-object-create-dynamic.js": 3840, - "2591-ambient-generic-traps.ts": 3572, - "2592-ambient-trap-uncaught.ts": 3517, - "2593-generic-inert-bindings.ts": 3984, - "2594-nullish-generic-bindings.ts": 3028, - "2595-fs-arg-ladders.cjs": 6103, - "2596-net-arg-ladders.cjs": 3811, - "2597-dgram-send-ladders.cjs": 4888, - "2598-tls-arg-ladders.cjs": 26930, - "2599-stream-arg-ladders.cjs": 6141, - "2600-dyn-keyed-write-harness.js": 2931, - "2601-dyn-keyed-write-ops.js": 2148, - "2602-dyn-array-destructure.js": 2954, - "2603-island-keyed-write-dyn.js": 2848, - "2604-cycle-classes-mutual/main.ts": 3417, - "2605-cycle-three-module/main.ts": 3678, - "2606-dynamic-import-cycle/main.ts": 3530, - "2608-regex-named-groups.ts": 4497, - "2609-regex-named-replace.ts": 3665, - "2610-regex-named-matchall.ts": 3003, - "2611-regex-named-groups-js.cjs": 4787, - "2613-for-init-uninitialized-let.ts": 3768, - "2614-trap-binding-later-writes.ts": 2989, - "2615-nullish-field-record-binding.ts": 3529, - "2616-js-collect-probe-defers.js": 3466, - "2617-enum-static-field-import/main.ts": 3293, - "2618-ee-emit-override.ts": 3565, - "2619-ee-override-chain.ts": 3727, - "2620-ee-override-once-order.ts": 4249, - "2621-ee-override-error-throw.ts": 3855, - "2622-ee-override-filter.ts": 3910, - "2623-ee-job-queue.ts": 3743, - "2624-ee-override-js.cjs": 3084, - "2625-bytes-views.ts": 3970, - "2626-stream-event-names.ts": 4359, - "2627-stream-ticks-are-nextticks.ts": 7617, - "2628-stream-push-encodings.cjs": 3343, - "2629-stream-consumers.ts": 4441, - "2630-stream-consumers-errors.ts": 5041, - "2631-create-require/main.ts": 3703, - "2632-dyn-jsval-iterate.js": 3831, - "2633-island-promise-crossing.js": 5160, - "2634-stream-pipeline-arg-ladders.cjs": 3923, - "2635-trap-binding-unmappable-written.ts": 3043, - "2636-trap-binding-ambient-rooted-rewrite.ts": 3569, - "2637-create-require-bare/main.ts": 2767, - "2638-http-dyn-res-compat.cjs": 8125, - "2639-http-dyn-req-pause.cjs": 8808, - "2640-net-dyn-socket-compat.cjs": 4119, - "2641-http-agent-surface.cjs": 8974, - "2642-http-agent-maxsockets.cjs": 7586, - "2643-or-default-retag.ts": 3938, - "2644-http-client-url-argument.ts": 8788, - "2645-https-client-url-argument.ts": 5188, - "2646-top-level-await.ts": 3543, - "2647-top-level-await-modules/main.ts": 3228, - "2648-top-level-await-rejection.ts": 3718, - "2649-top-level-await-pending.ts": 3680, - "2650-top-level-await-self-import.ts": 3580, - "2651-top-level-await-pending-unhandled.ts": 3616, - "2652-top-level-await-dynamic/main.ts": 3624, - "2653-top-level-await-rejection-stops-loop.ts": 3405, - "2654-top-level-await-unrelated-rejection.ts": 3746, - "2655-top-level-await-cycle/main.ts": 3633, - "2656-top-level-await-cycle-order/main.ts": 3581, - "2657-top-level-await-cycle-dynamic/main.ts": 3334, - "2658-top-level-await-sync-completion/main.ts": 3454, - "2659-top-level-await-dynamic-cycle/main.ts": 2695, - "2660-top-level-await-cycle-rejection/main.ts": 3883, - "2661-top-level-await-dynamic-runtime-root/main.ts": 3717, - "2662-top-level-await-cycle-external-wait/main.ts": 3322, - "2663-top-level-await-dependency-errors/main.ts": 4049, - "2664-top-level-await-same-checkpoint-rejection.ts": 4075, - "2665-top-level-await-unhandled-listener-liveness.ts": 3625, - "2666-array-to-sorted.ts": 8369, - "2668-stored-number-array-iterator.ts": 3915, - "2669-array-copying-methods.ts": 4422, - "2670-uint8array-copy-iterate.ts": 4692, - "2671-array-copying-js.cjs": 3615, - "2672-http-request-response-callback.ts": 3326, - "2673-top-level-await-implicit-module.ts": 2622, - "2674-top-level-for-await-implicit-module.ts": 3487, - "2675-create-require-nested-esm.js": 3107, - "2675-process-self-reexec.ts": 3537, - "2676-indexed-read-strict-equality.ts": 3497, - "2676-record-clone-overrides.ts": 3652, - "2676-top-level-await-ambiguous/main.ts": 3641, - "2677-runtime-optional-closure.ts": 4530, - "2677-top-level-await-module-scope/main.ts": 3142, - "2678-date-instances.ts": 4477, - "2678-large-string-sparse-index.ts": 3931, - "2678-util-parseargs.ts": 7627, - "2679-util-parseargs-cjs.cjs": 4984, - "2680-util-parseargs-default.ts": 2670, - "2681-util-parseargs-dynamic.js": 3233, - "2682-fs-rename.ts": 4087, - "2683-filter-truthy-predicate.ts": 4348, - "2683-fs-rename-js.cjs": 2621, - "2684-filter-no-predicate-dyn.cjs": 3942, - "2684-fs-rename-abort.ts": 3403, - "2685-array-unshift-reverse.ts": 3942, - "2685-fs-write-sync.ts": 4263, - "2686-fs-file-handle.ts": 6233, - "2687-fsp-write-file-options.ts": 3951, - "2687-process-write-args.ts": 2844, - "2688-fs-stats-disk-fields.ts": 4789, - "2689-http-server-timeout-properties.ts": 3279, - "2690-https-server-timeout-option.ts": 56311, - "2691-retained-lowering-record-order.ts": 5946, - "2692-inline-record-assert-index.ts": 3857, - "2692-string-accumulation.ts": 3602, - "2693-math-constants.ts": 3816, - "2700-array-sort-complexity.ts": 3912, - "2700-http-static-trailers.ts": 6657, - "2700-wasi-core.ts": 3863, - "2701-array-sort-snapshot.ts": 3906, - "2701-http-static-trailer-wire.ts": 3412, - "2701-import-meta/main.mjs": 4097, - "2702-http-static-trailer-end.ts": 8433, - "2702-type-import-link-static/main.ts": 2947, - "2702-uint8array-to-sorted.ts": 3549, - "2703-array-sparse-sort.ts": 8716, - "2703-type-import-link-static-reexport/main.ts": 3510, - "2704-array-sparse-to-sorted.ts": 8447, - "2704-type-import-link-static-success/main.ts": 3172, - "2705-array-sparse-sort-append.ts": 7740, - "2705-type-import-link-dynamic/main.ts": 3687, - "2706-array-search-missing-needle.ts": 3192, - "2706-type-import-link-dynamic-success/main.ts": 4191, - "2707-array-search-huge-sparse.ts": 48438, - "2707-type-import-link-static-default-reexport/main.ts": 3502, - "2708-type-import-link-dynamic/main.ts": 3358, - "2720-array-read-parity.ts": 3686, - "2721-array-nested-missing-receiver.ts": 2904, - "2750-array-sparse-foundation.ts": 3895, - "2751-buffer-concat-sparse-list.ts": 3589, - "2752-array-optional-stores.ts": 3503, - "2753-array-optional-method-values.ts": 2814, - "2754-array-property-undefined.ts": 2681, - "2755-array-optional-literal-forwarding.ts": 3614, - "2780-array-parity-composition.ts": 12116, - "2781-array-missing-value-escape.ts": 3458, - "2782-array-sparse-callbacks.ts": 3870, - "2783-array-defaults-rest.ts": 3473, - "2784-array-reduce-missing-result.ts": 3973, - "2785-array-missing-destructuring.ts": 4123, - "2786-array-sparse-serialization.ts": 4457, - "2787-array-missing-string-arithmetic.ts": 3381, - "2788-array-missing-builtin-conversions.ts": 3415, - "2789-array-missing-optional-tostring.ts": 2621, - "2790-dynamic-import-self-name/main.ts": 3399, - "2791-record-optional-keys.ts": 3271, - "2792-record-optional-spread-entries.ts": 4055, - "2793-union-conversion-identity-capture.ts": 4295, - "2794-array-generic-callback-values.ts": 3662, - "2795-array-optional-typedarray-source.ts": 38684, - "2796-array-sparse-class-value-instanceof.ts": 3585, - "2800-array-expression-consumers.ts": 3265, - "2801-array-switch-consumers.ts": 4057, - "2820-array-missing-method-receivers.ts": 3301, - "2821-array-optional-numeric-comparisons.ts": 2316, - "2830-cjs-require-self-name/main.cjs": 3030, - "2840-finally-completions.ts": 3523, - "2841-using-sync.ts": 3234, - "2842-await-using.ts": 3418, - "2843-using-suppressed-error.ts": 3352, - "2844-node-disposable-resources.ts": 5430, - "2845-for-using-of.ts": 3355, - "2846-generator-using.ts": 3702, - "2850-async-generators-protocol.ts": 4747, - "2851-async-generators-values.ts": 4111, - "2852-timers-promises-interval.ts": 3376, - "2854-leading-bom-literals.ts": 2675, - "2855-searchparams-sort-complexity.ts": 2462, - "2856-dynamic-any-local-operators.ts": 3959, - "2857-branded-primitives.ts": 3738, - "2858-import-meta-resolve/main.mjs": 2597, - "2859-import-meta-resolve-dynamic/main.mjs": 2565, - "2860-require-resolve/main.cjs": 3076, - "2861-readable-iterator-close.ts": 3422, - "2862-web-readable-async-iteration.ts": 55094, - "2863-class-async-iterator.ts": 3586, - "2864-array-class-method-receivers.ts": 4152, - "2865-cjs-process-alias.cjs": 3499, - "2866-dyn-switch.ts": 3318, - "2867-array-shift-length.js": 3797, - "2868-empty-record-promise-presence.js": 3592, - "2869-nullish-mixed-lazy.ts": 3886, - "2870-and-dropped-truthy-arm.ts": 3748, - "2871-optional-promise-to-unknown.ts": 3966, - "2872-unobserved-dynamic-event.ts": 3095, - "2873-optional-receiver-loop-lifetime.js": 3310, - "2874-nullable-callback-field-cycle.js": 4239, - "2875-evolving-let-read-before-write.js": 2007, - "2876-class-unknown-roundtrip.ts": 3485, - "2877-child-unknown-roundtrip.ts": 3462, - "2878-class-private-unknown.cjs": 3481, - "2880-cjs-module-graph/main.cjs": 4418, - "2890-crypto-static-utility.ts": 3693, - "2891-json-record-key-escapes.ts": 3227, - "2892-windows-console-unicode.ts": 3154, - "2893-child-stdin-duplex.ts": 3517, - "2894-child-stdin-backpressure.ts": 4232, - "2895-child-stdin-write-after-end.ts": 3755, - "2896-child-stdin-write-after-finish.ts": 4128, - "2897-child-stdin-destroy.ts": 2592, - "2898-child-stdin-spawn-failure.ts": 3984, - "2899-nested-mutual-recursion.ts": 3524, - "2900-float64array-static.ts": 2647, - "2900-void-conditional-arrow.ts": 3544, - "2901-bigint-core.ts": 3085, - "2902-bigint-bytes.ts": 3574, - "2903-bigint-storage.ts": 4190, - "2904-bigint-errors.ts": 3820, - "2905-bigint-edges.ts": 3695, - "2906-bigint-wasi-width.ts": 3566, - "2910-overloaded-callable-alias.ts": 2729, - "2911-execfile-callback.ts": 3798, - "2912-execfile-callback-options.ts": 3803, - "2912-promisify-fs-readfile.ts": 3648, - "2913-builtin-callable-alias.ts": 5737, - "2914-fixed-tuple-call-spread.ts": 3851, - "2915-path-function-values.ts": 4013, - "2916-path-function-values-cjs.ts": 3957, - "2917-builtin-callable-widths.ts": 3640, - "2918-builtin-callable-widths-cjs.ts": 3701, - "2919-fs-function-values.ts": 3810, - "2920-fs-promises-function-values.ts": 3724, - "2921-zlib-callbacks.ts": 5492, - "2922-dyn-bitwise-not.cjs": 3645, - "2923-cjs-factory-export/main.cjs": 3645, - "2930-union-receiver-calls.ts": 4841, - "2931-union-dynamic-field-call.js": 3975, - "2932-create-require-program/main.ts": 4060, - "2933-static-dynamic-import/main.ts": 3736, - "2934-static-import-stored.ts": 3490, - "2935-module-namespace-values/main.ts": 3371, - "2936-static-loose-equality.ts": 4954, - "2937-bitwise-hot-loop.ts": 3448, - "2938-fs-sync-overloads.cjs": 3181, - "2939-child-shell-text.ts": 4371, - "2940-date-parse.ts": 3212, - "2940-fsp-realpath.ts": 3484, - "2941-fsp-lstat-identity.ts": 3903, - "2941-process-exit-code.ts": 3406, - "2942-fsp-readdir-dirent.ts": 4202, - "2942-process-exit-code-override.ts": 3082, - "2943-process-exit-code-invalid.ts": 3479, - "2944-process-exit-code-wrap.ts": 3266, - "2945-url-origin-username.ts": 2899, - "2946-child-fork-ipc/main.ts": 4761, - "2946-url-port-hash.ts": 2865, - "2947-set-readonly-seeds.ts": 3446, - "2948-child-fork-eof-callback/main.ts": 3476, - "2948-stdio-callback-record.ts": 3365, - "2949-child-fork-default/main.mjs": 3332, - "2949-url-password.ts": 3628, - "2950-fs-descriptor-publication.ts": 3569, - "2951-math-static-analytic.ts": 3919, - "2952-math-static-remaining.ts": 3652, - "2953-http-header-validation.ts": 7274, - "2954-http-outgoing-headers.ts": 9450, - "2955-http-static-state.ts": 6516, - "2956-http-static-informational.ts": 6092, - "2957-http-static-response-controls.ts": 6929, - "2961-emitter-computed-names.cjs": 4004, - "2962-emitter-computed-optional.ts": 2860, - "2963-child-fork-dispatch/main.ts": 3483, - "2964-indexed-compound.ts": 4204, - "2966-numeric-array-read-fusion.ts": 4381, - "2967-numeric-array-read-lifetime.ts": 3892, - "2968-numeric-array-borrow.ts": 3610, - "2969-scalar-record-results.ts": 4035, - "2970-constant-numeric-tables.ts": 2720, - "2971-constant-table-modules/main.ts": 3311, - "2972-http-static-distinct-snapshots.ts": 4474, - "2972-math-receiver-borrow.ts": 4401, - "2973-http-static-agent.ts": 3997, - "2973-integer-bitwise-arithmetic.ts": 3629, - "2974-array-search-from-index.ts": 116997, - "2974-http-static-module-values.ts": 7598, - "2974-numeric-remainder.ts": 3511, - "2975-bigint-default-radix.ts": 3179, - "2975-http-static-client-controls.ts": 3852, - "2976-http-static-incoming-state.ts": 8478, - "2976-json-stringify-no-arguments.js": 3354, - "2977-http-static-incoming-timeout.ts": 3463, - "2977-nested-array-binding-defaults.js": 2952, - "2978-http-static-client-timeout.ts": 4066, - "2978-regexp-optional-subject.js": 2771, - "2979-array-search-mixed-needles.js": 3599, - "2979-http-static-server-timeout.ts": 3821, - "2980-http-static-server-timeout-default.ts": 3238, - "2980-string-position-arguments.js": 3754, - "2981-http-static-events.ts": 3579, - "2981-string-optional-positions.ts": 3623, - "2982-http-static-close-all.ts": 2800, - "2982-string-position-coercion-order.js": 4005, - "2983-http-static-close-idle.ts": 3208, - "2984-http-static-close-upgrade.ts": 3773, - "2985-http-static-message-destroy.ts": 3787, - "2986-http-static-client-socket-finish.ts": 3574, - "2987-http-static-timeout-errors.ts": 3533, - "2988-http-static-client-abort.ts": 4341, - "2989-http-static-response-timeout-handled.ts": 3444, - "2990-http-static-request-timeout-handled.ts": 3719, - "2991-array-indexed-equality.ts": 3650, - "2992-stream-rows.ts": 3551, - "2993-fiber-stack-lifetimes.ts": 3792, - "2994-fromcharcode-scalar.ts": 4459, - "2995-math-hyperbolic.ts": 3860, - "2996-math-near-one.ts": 3086, - "2997-math-integer-float.ts": 3955, - "300-if-else.ts": 3194, - "3001-caught-typeof-object.js": 4263, - "3002-promise-then-two.ts": 4357, - "301-while.ts": 3525, - "302-for.ts": 3433, - "3020-string-last-index-position.ts": 3282, - "3021-buffer-union-narrow-callback.ts": 3951, - "3022-string-affix-positions.ts": 2990, - "3023-string-affix-position-coercion.js": 3327, - "3024-string-number-narrow-for-in.ts": 3695, - "3025-string-search-position-coercion.js": 3055, - "3026-array-last-index-of.js": 3971, - "3027-array-last-index-of-records.ts": 3174, - "3028-string-search-dynamic-needle.js": 3488, - "3029-string-search-union-needle.js": 2317, - "303-break-continue.ts": 3497, - "3030-array-search-no-arg.js": 3148, - "3031-array-relative-index-coercion.js": 4248, - "3031-string-last-index-search-value.js": 2998, - "3032-string-search-value.js": 3484, - "3033-string-search-needle-coercion.js": 3256, - "3034-arguments-with-parameters.js": 3316, - "3035-string-positioned-search-value.js": 3436, - "3036-string-object-search-value.js": 3562, - "3037-number-nullish-conversion.js": 3657, - "3038-number-scalar-unions.ts": 2371, - "3039-string-repeat-count.js": 3353, - "304-compound-incdec.ts": 3802, - "3040-string-prototype-call.js": 4850, - "3041-string-prototype-object-call.js": 3234, - "3042-string-padding-coercion.js": 3916, - "3043-string-split-arguments.js": 3976, - "3044-array-slice-splice-positions.js": 4465, - "3045-array-indexed-mutation.js": 3477, - "3046-array-indexed-ref-identity.ts": 3717, - "3047-object-prototype-tag.js": 7241, - "3048-object-own-prototype.ts": 2902, - "3049-array-flat-depth.ts": 4100, - "305-truthiness.ts": 3370, - "3050-array-splice-insert.ts": 4056, - "3051-array-join-default.ts": 3538, - "3052-array-construction.ts": 4542, - "3053-array-construction-js.js": 3392, - "3054-dynamic-abort-record.ts": 30732, - "3055-default-builtin-nodenext/main.ts": 3399, - "3056-default-builtin-bundler/main.ts": 3748, - "3057-default-builtin-nodenext-dynamic/main.ts": 3727, - "3058-optional-array-chain-join.ts": 3025, - "3059-arguments-property-names.ts": 3619, - "3061-concurrent-fiber-stacks.ts": 4083, - "3062-runtime-optional-record-guards.ts": 4619, - "3063-runtime-optional-class-guards.ts": 4458, - "3064-installed-entry-imports/main.ts": 2755, - "3065-installed-entry-js/main.js": 2496, - "3066-source-debugging/main.ts": 3345, - "3067-cjs-function-export-require/main.cjs": 3584, - "3068-debug-variables/main.ts": 2803, - "3068-url-checked-identity.ts": 3525, - "3069-set-checked-seed.js": 3730, - "3069-tuple-spread.ts": 3638, - "3070-checked-object-accessors.js": 3937, - "3070-collection-views.ts": 3112, - "3071-checked-specialization-narrowing.js": 4666, - "3071-map-contextual-record-seeds.ts": 3637, - "3072-optional-union-receivers.ts": 4348, - "3072-weak-process-streams.js": 3937, - "3073-optional-callable-module.js": 3783, - "3073-union-keyed-reads.ts": 3349, - "3074-discriminated-intersections.ts": 3833, - "3075-recursive-contextual-literals.ts": 4956, - "3076-nullish-record-defaults.ts": 3537, - "3077-optional-union-array-reads.ts": 4192, - "3078-forward-mutable-captures.ts": 4709, - "3079-forward-mutable-tdz.ts": 4069, - "3080-exhaustive-never-bindings.ts": 3678, - "3081-recursive-array-destinations.ts": 3824, - "3082-forward-write-unwind.ts": 3698, - "3083-set-string-seed.ts": 3916, - "3084-record-own-membership.ts": 4502, - "3085-conditional-record-construction.ts": 4272, - "3086-error-constructor-options.ts": 2549, - "3087-error-options-lifetime.ts": 3996, - "3088-array-wide-callbacks.ts": 4379, - "3089-array-find-narrowing.ts": 4095, - "3090-json-discriminated-records.ts": 4621, - "3091-json-recursive-discriminants.ts": 4799, - "3092-number-union-predicates.ts": 3661, - "3093-error-option-data.ts": 3834, - "3094-json-replacer-traversal.ts": 3366, - "3095-json-reviver-traversal.ts": 3492, - "3096-json-callback-nonfinite.ts": 3652, - "3097-json-callback-reentrancy.ts": 4051, - "3098-json-callback-space.ts": 4000, - "3099-json-callback-functions.ts": 4355, - "3100-json-callback-holder.js": 4131, - "3101-json-callback-bytes.ts": 4053, - "3102-json-unknown-fields.ts": 3096, - "3103-scalar-record-nested-control-flow.ts": 3773, - "3104-native-analysis-tables-loops.ts": 3270, - "3105-nullable-collections.ts": 3945, - "3106-mixed-insertion-spreads.ts": 4363, - "3107-nullable-collection-lifetimes.ts": 4026, - "3108-for-await-sync-arrays.js": 5613, - "3108-identity-map-keys.ts": 3552, - "3109-destructuring-unknown-defaults.js": 3464, - "3109-identity-union-collections.ts": 4940, - "3110-builtin-error-families.ts": 3056, - "3110-identity-collection-mutation.ts": 4022, - "3111-identity-collection-cycles.ts": 4287, - "3112-union-switch-control-flow.ts": 3956, - "3113-union-array-removal.ts": 4360, - "3114-union-record-field-write.ts": 3442, - "3115-zlib-static-compression-levels.ts": 5168, - "3116-sequence-expression-lifetimes.ts": 4189, - "3117-unknown-switch-control-flow.ts": 4180, - "3118-recursive-union-spread.ts": 3041, - "3119-runtime-optional-spread.ts": 3381, - "3120-dynamic-property-descriptors.js": 2965, - "3120-generator-method-loop-bindings.ts": 4201, - "3120-ir-nonfinite-numbers.ts": 4055, - "3121-compound-assignment-values.js": 3508, - "3121-dynamic-accessor-descriptors.js": 5206, - "3122-dynamic-delete-descriptors.cjs": 3618, - "3122-dynamic-delete-descriptors.js": 3463, - "3122-js-async-class-methods.js": 3826, - "3123-destructured-global-tdz.js": 3445, - "3124-array-prototype-borrow.js": 4427, - "3125-regex-global-match.ts": 2948, - "3126-js-number-radix/main.ts": 3569, - "3127-spawn-runtime-options.ts": 3489, - "3128-regex-last-index.ts": 4225, - "3129-js-token-union/main.ts": 4007, - "3130-child-generic-streams.ts": 4070, - "3131-child-rest-listeners.js": 3532, - "3132-child-generic-stream-completion.ts": 11386, - "3133-text-decoder-streaming.ts": 19582, - "3134-fs-vectors.ts": 4100, - "3135-fs-file-handle-controls.ts": 5084, - "3136-fs-file-handle-options.ts": 5319, - "3137-fs-vector-callbacks.cjs": 4121, - "3138-array-large-storage.ts": 5662, - "3139-regex-native-deep-alternatives.ts": 37923, - "3140-array-dense-access.ts": 5683, - "3141-map-string-key-hash.ts": 3292, - "3150-integer-remainder.ts": 4041, - "3151-array-push-writes.ts": 4409, - "3170-number-conversion-fast-paths.ts": 3918, - "3171-method-census-data-writes.ts": 4678, - "400-fib.ts": 3649, - "401-mutual-recursion.ts": 2468, - "402-string-functions.ts": 3526, - "403-void-and-params.ts": 3277, - "4030-runtime-object-truthiness.ts": 4681, - "4031-event-emitter-long-tuples.ts": 3970, - "4032-inline-rc-fast-paths.ts": 6135, - "404-rc-stress.ts": 3734, - "4040-adapted-function-identity.ts": 4226, - "4041-adapted-function-properties.ts": 3785, - "4042-object-is-union-subclass.ts": 3204, - "4043-nonnull-missing-element.ts": 4658, - "4044-adapted-callback-modules/main.ts": 3502, - "4045-optional-element-projections.ts": 4551, - "4046-captured-parameter-values.ts": 4678, - "4047-captured-parameter-rebinding.ts": 3804, - "405-params-optional.ts": 3480, - "406-params-defaults.ts": 3673, - "4060-cycle-shared-instance/main.ts": 2973, - "4060-stack-union-reads.ts": 3684, - "4061-cycle-evaluation-order/main.ts": 3762, - "4061-nullable-ref-fields.ts": 5610, - "4062-cycle-tdz-read/main.ts": 3351, - "4063-cycle-hoisted-calls/main.ts": 3608, - "4064-cycle-classes-after-init/main.ts": 3570, - "4065-cycle-init-throws/main.ts": 3220, - "4066-cycle-top-level-tdz/main.ts": 2340, - "4067-dynamic-import-cycle-tdz/main.ts": 3378, - "407-params-rest.ts": 3809, - "408-params-ctors-inheritance.ts": 4026, - "4080-optional-read-presence-tests.ts": 3072, - "4080-string-index-bounds.ts": 2694, - "4081-hoisted-function-tdz.ts": 4427, - "4081-string-index-unproven.ts": 3902, - "4082-hoisted-function-tdz-uncaught.ts": 2748, - "4083-dynamic-import-failure/main.ts": 3742, - "4084-record-optional-field-copies.ts": 4621, - "4085-generator-loop-close.ts": 4491, - "4086-optional-capture-defaults.ts": 2947, - "4088-class-static-tdz.ts": 3366, - "4089-class-wrapper-tdz.js": 2781, - "409-params-async-generics.ts": 4252, - "4090-computed-key-tdz.js": 3408, - "4091-class-evaluation-deferred.ts": 2828, - "410-params-rc-stress.ts": 2917, - "4140-array-callback-split-visit.ts": 6798, - "4141-array-callback-ambient-receiver/main.ts": 3870, - "4142-array-callback-factories.ts": 4472, - "4143-union-refinement-intersection-arms.ts": 4107, - "420-dead-strip-modules/main.ts": 2681, - "4290-acyclic-immutable-trees.ts": 3286, - "4291-acyclic-constructor-escapes.ts": 3619, - "4292-acyclic-readonly-bypass.ts": 4006, - "4293-acyclic-dynamic-writes.ts": 3787, - "4294-console-line-sizes.ts": 5430, - "4295-console-template-parts.ts": 3102, - "4296-console-glued-long-parts.ts": 4254, - "4410-inline-object-allocation.ts": 4263, - "4411-nullable-ref-values.ts": 5324, - "4412-nullable-record-values.ts": 4337, - "4413-cycle-old-late-death.ts": 3017, - "4413-nullable-null-and-undefined.ts": 4035, - "4414-cycle-old-weak-keys.ts": 3820, - "4414-nullable-string-values.ts": 5821, - "4415-identity-borrowed-operands.ts": 4327, - "4415-nullable-container-values.ts": 5953, - "4431-exception-pending-contexts.ts": 5399, - "4432-checked-downcast-failures.ts": 4507, - "4451-int32-field-storage.ts": 5079, - "4452-int32-field-dynamic-writes.ts": 4478, - "4453-int32-closed-locals.ts": 3221, - "4454-int32-field-reflection-reads.ts": 4583, - "4455-live-view-reads-without-stores.ts": 4961, - "4471-unassigned-field-reads.ts": 4391, - "4476-string-ascii-header-fact.ts": 4538, - "4477-buffer-write-ascii-runs.ts": 4115, - "4478-string-large-index-reads.ts": 4211, - "4481-array-optional-push.ts": 3640, - "4482-instanceof-static-class-optional.ts": 2991, - "4483-array-splice-statement.ts": 5079, - "4484-array-length-reset.ts": 3655, - "4485-array-splice-optional-item.ts": 4264, - "4486-array-field-element-borrows.ts": 3950, - "4487-array-literal-optional-values.ts": 5139, - "4520-optional-guard-narrowing.ts": 4441, - "4521-array-callback-element-presence.ts": 6451, - "4522-captured-parameter-lifetimes.ts": 3198, - "4523-array-pop-removal.ts": 4334, - "4524-array-callback-supertype-params.ts": 5586, - "4541-nullable-wrap-borrows.ts": 4310, - "4542-preserving-call-borrows.ts": 4231, - "4543-walk-borrowed-locals.ts": 3976, - "4544-checked-cast-aliases.ts": 4280, - "4545-borrowed-returns.ts": 4524, - "4546-rebound-borrowed-params.ts": 4010, - "4560-field-store-borrowed-receivers.ts": 3877, - "4561-virtual-borrowed-parameters.ts": 4633, - "4562-string-self-concat-move.ts": 3881, - "4563-array-read-projection-receivers.ts": 4188, - "4564-literal-choice-strings.ts": 4026, - "4568-for-of-hole-elements.ts": 4432, - "4569-shorthand-missing-elements.ts": 4672, - "4570-map-lookup-default-record.ts": 3777, - "4591-weak-keys-union-records.ts": 3889, - "4592-cycle-const-from-import/main.ts": 2581, - "4593-weak-keys-empty-objects.ts": 3813, - "4594-union-class-field-mixed-types.ts": 7147, - "4595-union-class-field-optional-receiver.ts": 3827, - "4596-error-subclass-int-fields.ts": 3477, - "4596-tdz-nullable-forward-capture.ts": 3990, - "4597-callback-field-method-name.ts": 4176, - "4598-live-array-ref-element-access.ts": 9941, - "4598-map-set-clear-reuse.ts": 5807, - "4598-os-available-parallelism.ts": 3624, - "4598-publish-constructor-stores.ts": 3208, - "4599-construction-only-field-borrows.ts": 5064, - "4600-construction-only-fields-dynamic-writes.ts": 3234, - "4601-cycle-holders.ts": 3389, - "4602-constructor-escape-order.ts": 3798, - "4610-array-ext-dyn-refresh.ts": 4533, - "4620-optional-chain-borrowed-receivers.ts": 4161, - "4621-edge-preserving-callees/main.ts": 4709, - "4630-contract-int32.ts": 4369, - "4630-reference-write-call-arguments.ts": 4010, - "4631-contract-nothrow.ts": 4027, - "4631-reference-write-aliases.ts": 4138, - "4632-contract-immutable.ts": 3925, - "4632-reference-write-loops-and-walks.ts": 4126, - "4633-contract-program-lifetime.ts": 5198, - "4633-reference-write-callbacks-returns.ts": 4361, - "4634-contract-program-lifetime-publish.ts": 51728, - "4634-optional-element-borrowed-returns.ts": 3758, - "4640-bitwise-identity-ranges.ts": 4521, - "4641-nothrow-try-catch.ts": 3856, - "4642-acyclic-contract.ts": 4836, - "4650-stale-property-narrowing.ts": 5065, - "4651-map-string-get-entry.ts": 3204, - "4652-stale-closure-binding-narrowing.ts": 4161, - "4660-typed-rest-spread-forwarding.ts": 2965, - "4671-scoped-array-read-borrows.ts": 4639, - "4690-cycle-bypass-long-lived.ts": 6384, - "4691-publish-constructor-self-alias.ts": 43679, - "4692-borrowed-result-mutating-callees.ts": 4134, - "4720-cold-throw-paths.ts": 3925, - "4721-integer-induction-numbers.ts": 3986, - "4730-touint32-large-magnitudes.ts": 3378, - "4731-string-mixed-ascii-slices.ts": 3992, - "4732-buffer-write-utf16le-runs.ts": 4419, - "4733-typed-array-read-compares.ts": 3723, - "4750-map-string-absent-filter.ts": 4339, - "4751-string-search-multibyte-needles.ts": 2934, - "4795-published-untyped-member-reads.ts": 4864, - "4806-uint32-loop-accumulators.ts": 4131, - "4810-union-identity-retags.ts": 45852, - "4811-union-retag-checked-cast.ts": 3777, - "4812-int32-wrapping-sums.ts": 4491, - "4813-typed-array-read-equality-bindings.ts": 5104, - "4820-sort-comparator-lent-arguments.ts": 4547, - "4821-callback-lent-arguments.ts": 4044, - "4822-stable-capture-reads.ts": 3520, - "4823-array-store-receivers.ts": 3708, - "4830-typed-teardown-chains.ts": 5155, - "4831-cycle-bypass-probe-windows.ts": 6539, - "4840-array-hole-free-prefix.ts": 5312, - "4860-int32-local-storage.ts": 5193, - "4870-array-pipeline-fusion.ts": 9277, - "4871-array-pipeline-analytics.ts": 4466, - "4872-array-pipeline-temporaries.ts": 8037, - "4875-stream-consumers-array-buffer.ts": 4195, - "4876-array-buffer-inspect.ts": 3460, - "4880-await-call-turn-order.ts": 3196, - "4881-await-call-exceptions.ts": 3913, - "4882-await-call-request-chain.ts": 3966, - "4883-await-values-and-hops.ts": 3305, - "4884-await-call-unhandled-sibling.ts": 3775, - "4885-await-call-checkpoints.ts": 3389, - "4890-regex-literal-sites.ts": 4481, - "4891-regex-plain-text-patterns.ts": 4954, - "4892-regex-exec-read-captures.ts": 5836, - "4900-bigint-division-cross-check.ts": 4132, - "4900-console-instances.ts": 3398, - "4901-bigint-radix-text.ts": 4240, - "4901-console-instance-errors.ts": 4118, - "4902-bigint-compound-assign.ts": 3348, - "4903-bigint-fixed-width.ts": 4053, - "4904-bigint-large-products.ts": 4084, - "4905-bigint-fixed-width-fusion.ts": 4866, - "4906-bigint-small-value-trees.ts": 4495, - "4907-bigint-random-trees.ts": 6985, - "4910-hole-free-prefix-upkeep.ts": 3869, - "4920-string-literal-switch.ts": 3948, - "4930-typed-record-reflection.ts": 6446, - "4931-typed-data-generic-walks.ts": 6005, - "4932-typed-json-unknown.ts": 4690, - "4940-async-return-adoption.ts": 4747, - "4941-async-return-adoption-try.ts": 4808, - "4942-async-return-adoption-values.ts": 4525, - "4943-async-return-adoption-interleaved.ts": 4076, - "4950-regex-compiled-captures.ts": 5853, - "4951-regex-compiled-last-index.ts": 4237, - "4952-regex-compiled-anchors-classes.ts": 2970, - "4953-regex-compiled-backtracking.ts": 4881, - "4954-regex-log-report.ts": 4017, - "4955-regex-compiled-differential.ts": 17656, - "4970-int32-call-abi.ts": 4034, - "4980-generator-early-exit-finally.ts": 4293, - "4981-generator-delegation-iterables.ts": 4701, - "4982-generator-sent-values.ts": 3850, - "4983-generator-reuse-iterables.ts": 4013, - "4984-generator-exceptions.ts": 3941, - "4985-generator-lazy-pipeline.ts": 5191, - "4986-generator-default-channels.ts": 4218, - "4987-generator-closures-methods.ts": 3564, - "4988-generator-async-interplay.ts": 4129, - "4989-generator-step-drives.ts": 3945, - "4990-lone-surrogates.ts": 4283, - "4991-lone-surrogate-halves.ts": 3965, - "4992-lone-surrogate-search.ts": 4450, - "4993-lone-surrogate-json.ts": 4533, - "4994-lone-surrogate-uri.ts": 3275, - "4995-lone-surrogate-regex.ts": 4305, - "4996-lone-surrogate-stdio.ts": 3980, - "4997-lone-surrogate-stdout-patch.js": 3708, - "4998-lone-surrogate-buffers.ts": 3397, - "4999-lone-surrogate-io.ts": 4183, - "500-array-basics.ts": 3681, - "501-array-push-pop.ts": 3744, - "5010-lifetime-region-generations.ts": 4361, - "5011-lifetime-region-outside-references.ts": 3723, - "5012-lifetime-region-shapes.ts": 5352, - "5013-lifetime-region-async.ts": 4836, - "5014-lifetime-region-nesting.ts": 4098, - "5015-lifetime-region-publish.ts": 44284, - "5016-lifetime-region-weak-keys.ts": 4090, - "5017-lifetime-region-cycles.ts": 2993, - "5018-lifetime-region-hierarchies.ts": 4448, - "5019-lifetime-region-values.ts": 4593, - "502-array-for-of.ts": 3697, - "5020-lifetime-region-large.ts": 6810, - "5021-lifetime-region-opaque-holders.ts": 3221, - "5022-lifetime-region-workers.ts": 43902, - "503-array-functions.ts": 3221, - "504-array-rc-stress.ts": 3902, - "5040-promise-all-race-turns.ts": 3963, - "5041-promise-all-turns.js": 3961, - "5042-async-generator-return-promise.ts": 4464, - "5043-async-generator-return-forms.ts": 3956, - "5045-generator-delegation-typed-next.ts": 4940, - "5046-generator-delegation-return-throw.ts": 4744, - "5047-generator-delegation-iterables-typed.ts": 5495, - "5048-generator-delegation-async.ts": 4004, - "5049-generator-delegation-edges.ts": 3818, - "5050-inherited-in-membership.ts": 2952, - "5051-typed-record-prototypes.ts": 4128, - "5052-class-for-in-unknown.ts": 4437, - "5053-json-replacer-arrays.ts": 4585, - "5054-required-field-delete.ts": 3565, - "5055-object-create-record-literal.ts": 3433, - "5056-generator-in-unknown.ts": 3552, - "5060-child-fork-exit-after-messages/main.ts": 4059, - "5061-child-fork-local-disconnect/main.ts": 3921, - "5062-child-fork-message-before-eof/main.ts": 5311, - "5065-global-increment-initializers.ts": 3409, - "5066-global-compound-updates.ts": 3878, - "5067-global-updates-in-functions.ts": 3060, - "5068-global-var-let-const-updates.ts": 3099, - "5069-global-update-modules/main.ts": 3105, - "5070-optional-read-bindings.ts": 3986, - "5071-optional-chain-scalars.ts": 4053, - "5072-optional-nullish-ternary.ts": 3786, - "5073-optional-results.ts": 3653, - "5074-optional-pop-shift.ts": 3809, - "5075-optional-reads-unchecked/main.ts": 4486, - "5076-optional-escapes.ts": 3781, - "5080-boolean-array-storage.ts": 9389, - "5081-boolean-array-dynamic-views.ts": 5005, - "5085-promise-allsettled-turns.ts": 5227, - "5086-promise-any-turns.ts": 4926, - "5087-promise-allsettled-any-dyn.js": 5648, - "5088-promise-combinator-thenables.js": 6097, - "5089-promise-settled-records.ts": 4902, - "5090-generator-finished-result-value.ts": 3980, - "5091-generator-delegation-arrays-strings.ts": 4920, - "5092-generator-delegation-sets-maps.ts": 5655, - "5095-console-count-group.ts": 4543, - "5096-console-assert-dir.ts": 3659, - "5097-console-table.ts": 4019, - "5098-console-time-warnings.ts": 7779, - "5099-console-methods-dynamic.cjs": 4211, - "510-array-map-filter-foreach.ts": 3693, - "511-array-indexof-includes.ts": 2587, - "5110-var-hoisting-early-reads.ts": 3722, - "5111-var-hoisting-closures-classes.ts": 3558, - "5112-var-hoisting-function-scope.ts": 3736, - "5113-tdz-let-const-class.ts": 3427, - "5114-var-hoisting-js.js": 2426, - "5115-regex-replace-compiled.ts": 4045, - "5116-regex-capture-reads.ts": 3563, - "5117-regex-log-report-spans.ts": 3810, - "5118-regex-replace-char-chains.ts": 3242, - "512-array-join-chains.ts": 3887, - "5120-frame-records.ts": 4007, - "5121-frame-objects.ts": 3950, - "5122-frame-result-slots.ts": 3225, - "5123-frame-reassigned.ts": 3642, - "5124-frame-objects-control.ts": 2980, - "5125-frame-mutating-methods.ts": 3316, - "5126-frame-returned-params.ts": 3759, - "5127-frame-loop-bindings.ts": 4535, - "513-array-methods-rc-stress.ts": 3991, - "5130-event-target-dispatch.js": 5194, - "5131-event-target-listener-errors.js": 5170, - "5132-event-target-typed.ts": 5485, - "5133-abort-signal-event-target.ts": 30480, - "5134-events-error-monitor.ts": 3910, - "5135-event-target-warnings.js": 38892, - "5136-events-error-monitor-string-name.ts": 3923, - "5137-events-error-monitor-computed-name.js": 4432, - "5138-events-error-monitor-shared-listener.ts": 3642, - "5139-event-target-listener-throw.ts": 4714, - "514-array-find-some-every.ts": 3747, - "5140-os-host-facts.ts": 4713, - "5141-os-constants.ts": 3991, - "5142-path-parse-format.ts": 3463, - "5145-path-matches-glob-basics.ts": 4364, - "5146-path-matches-glob-braces.ts": 5382, - "5147-path-matches-glob-extglob.ts": 3804, - "5148-path-matches-glob-classes.ts": 3686, - "5149-path-matches-glob-win32.ts": 4358, - "515-array-flatmap.ts": 4323, - "5150-small-array-inline-slots.ts": 4485, - "5155-cycle-header-types.ts": 32161, - "516-array-reduce.ts": 4410, - "5160-field-callback-receiver.ts": 4515, - "5161-field-callback-receiver-escape.ts": 3931, - "5162-field-method-reference-receiver.ts": 3961, - "5163-field-callback-receiver.cjs": 4008, - "5164-worker-field-callback-receiver.ts": 43587, - "5165-interface-method-dispatch.ts": 4146, - "5166-interface-method-values.ts": 5178, - "5167-interface-method-order.ts": 4344, - "5168-interface-method-hierarchy.ts": 5405, - "5169-interface-method-chains.ts": 5047, - "517-array-hof-index-args.ts": 3899, - "5170-string-scan-eviction.ts": 2657, - "5171-lone-surrogate-replace-seams.ts": 3047, - "5175-forin-typed-as-unknown.ts": 3918, - "5176-object-keys-typed-as-unknown.ts": 2645, - "5177-forin-dynamic-objects.ts": 3654, - "5178-forin-keys-js.js": 2761, - "5179-forin-typed-shapes.ts": 3622, - "518-array-sort.ts": 4004, - "518-promise-void-union-callbacks.ts": 3964, - "5180-interface-arrays.ts": 4400, - "5181-interface-array-methods.ts": 13672, - "5182-interface-array-boundaries.ts": 3272, - "5183-interface-property-reads.ts": 4146, - "5184-interface-property-objects.ts": 3495, - "5185-util-inherits.cjs": 6043, - "5186-util-inherits.ts": 6829, - "5187-util-deprecate.cjs": 6304, - "5188-util-deprecate-flags.cjs": 4852, - "5189-util-deprecate.ts": 5176, - "519-array-from-length.ts": 4670, - "519-promise-union-await-values.ts": 3522, - "5190-util-callbackify.cjs": 4881, - "5191-util-callbackify.ts": 5163, - "5192-util-debuglog.cjs": 5490, - "5193-util-debuglog.ts": 3737, - "5194-process-emit-warning-tick.cjs": 4043, - "5195-object-entries-typed-as-unknown.ts": 3294, - "5196-object-values-typed-as-unknown.ts": 4153, - "5197-object-entries-dynamic-objects.ts": 4163, - "5198-object-entries-values-js.js": 3223, - "5199-object-entries-identity.ts": 4287, - "520-map-basics.ts": 3177, - "5200-array-sort-keyed-numbers.ts": 5498, - "5201-array-sort-keyed-records.ts": 6386, - "5202-array-sort-keyed-lookalikes.ts": 3643, - "5203-typed-array-sort-default.ts": 7538, - "5204-typed-array-sort-comparators.ts": 5252, - "521-map-number-keys.ts": 3394, - "5210-process-memory-usage.ts": 2806, - "5211-process-identity.ts": 3698, - "5212-perf-marks-measures.ts": 4803, - "5213-perf-timing-errors.ts": 4464, - "5214-perf-entry-inspect.ts": 4525, - "5215-perf-timing-validation.js": 4263, - "5216-perf-spread-arguments.js": 4935, - "5217-perf-spread-typed.ts": 3571, - "522-map-foreach.ts": 2998, - "5220-url-parse-warnings.ts": 5276, - "5221-url-parse-shapes.ts": 5152, - "5222-url-parse-hosts.ts": 5614, - "5223-url-parse-query.ts": 5852, - "5224-url-format-objects.ts": 5092, - "5225-url-format-whatwg.ts": 5939, - "5226-url-resolve.ts": 4968, - "5227-url-legacy-dependency/main.ts": 5444, - "5228-url-domain-conversion.ts": 2782, - "5229-url-legacy-errors.cjs": 6339, - "523-map-ref-values.ts": 3549, - "5230-inline-union-fields.ts": 4686, - "5231-inline-union-field-kinds.ts": 4192, - "5232-inline-union-fields-dynamic.ts": 4074, - "5233-inline-union-fields-shapes.ts": 4531, - "5234-inline-union-class-fields.ts": 4699, - "5235-inline-union-fields-publish.ts": 3783, - "5236-inline-union-unchecked-reads.ts": 3109, - "5237-inline-union-frame-objects.ts": 2338, - "524-map-cycles.ts": 3268, - "5240-event-target-subclass.ts": 5177, - "5241-event-subclass.ts": 5478, - "5242-event-target-subclass-hierarchy.ts": 4631, - "5243-event-target-subclass-dynamic.ts": 4520, - "5244-event-target-subclass.js": 5329, - "5245-event-target-subclass-signals.ts": 33048, - "5246-event-target-subclass-listener-throw.ts": 3829, - "5247-event-target-subclass-lifetimes.ts": 6504, - "5248-event-target-subclass-warnings.ts": 4300, - "5249-event-target-subclass-unconstructed.ts": 4427, - "525-map-rc-stress.ts": 3704, - "5250-cipher-aes-gcm.ts": 7929, - "5251-cipher-aes-cbc.ts": 15678, - "5252-cipher-aes-ctr.ts": 26018, - "5253-cipher-chacha20-poly1305.ts": 7999, - "5254-cipher-errors.js": 26643, - "5255-cipher-encodings.cjs": 20470, - "5256-cipher-deprecation.cjs": 48818, - "5257-cipher-vectors.ts": 18839, - "5258-cipher-handles.js": 21996, - "5259-cipher-chunked.ts": 21780, - "526-set-basics.ts": 3497, - "5260-record-unknown-identity.ts": 3759, - "5261-optional-field-identity.ts": 3633, - "5262-record-unknown-many.ts": 4065, - "527-set-foreach.ts": 3282, - "5270-url-parse-no-deprecation.cjs": 4123, - "5271-url-parse-throw-deprecation.cjs": 5457, - "5275-http-end-callback-order.ts": 4317, - "5276-style-text-hex-colors.cjs": 4489, - "5277-fs-read-file-buffer-option.cjs": 3576, - "5278-host-null-bytes.cjs": 8285, - "5279-search-params-null-init.cjs": 3511, - "528-set-seeded.ts": 3372, - "5285-blob-construct.ts": 4331, - "5286-blob-readers.ts": 3684, - "5287-blob-inspect.ts": 4285, - "5288-blob-validation.js": 4292, - "5289-blob-read-order.ts": 3682, - "529-map-seeded.ts": 3677, - "5290-blob-dynamic.js": 4399, - "5295-readline-promises-question.ts": 3697, - "5296-readline-lines.ts": 3534, - "5297-readline-callback-events.cjs": 3926, - "5298-readline-abort.cjs": 12732, - "5299-readline-stdin.ts": 4774, - "530-record-arrays.ts": 3665, - "5300-stream-add-abort-signal.ts": 34654, - "5301-stream-add-abort-signal-errors.cjs": 12589, - "5302-stream-promises-options.ts": 13246, - "5303-stream-finished-callback-opts.cjs": 9506, - "5305-json-stringify-typed-arrays.ts": 5926, - "531-record-array-hofs.ts": 3761, - "5315-map-iterate-after-front-deletes.ts": 3399, - "5316-map-lru-eviction.ts": 4060, - "5317-map-iterate-while-mutating.ts": 3994, - "5318-set-iterate-after-deletes.ts": 3956, - "5319-map-iteration-values.ts": 4002, - "532-record-arrays-rc-stress.ts": 3024, - "5320-map-iterate-across-compaction.ts": 4445, - "5321-integer-closed-arithmetic-loops.ts": 3363, - "5321-json-parse-cycles.ts": 3162, - "5322-integer-variable-step-loops.ts": 3747, - "5322-json-stringify-parsed-trees.ts": 4167, - "5323-dyn-numeric-index-reads.ts": 3375, - "5323-int32-nonnegative-slot-facts.ts": 3657, - "5324-int32-initializer-locals.ts": 2946, - "5324-structured-clone-documents.ts": 4653, - "5325-record-boundary-returns.ts": 3627, - "5326-record-boundary-params.ts": 3878, - "5327-record-boundary-identity.ts": 2625, - "5328-record-boundary-open.ts": 3032, - "5329-record-boundary-recursion.ts": 3600, - "533-array-element-cycles.ts": 3019, - "5330-record-boundary-fields.ts": 3682, - "5331-record-boundary-methods.ts": 3949, - "5332-int32-narrowed-slot-facts.ts": 3391, - "5333-integer-guarded-while-counters.ts": 3537, - "5333-record-boundary-nullable-argument.ts": 4003, - "5334-fetch-mentions-without-calls.ts": 3134, - "5335-stream-operators-values.ts": 5552, - "5335-top-level-await-pending-exit-code.ts": 3309, - "5336-stream-operators-promise-timing.ts": 3761, - "5336-top-level-await-pending-exit-listener.ts": 4072, - "5337-dc-subscriber-throw-next-tick.cjs": 4314, - "5337-stream-operators-concurrency.ts": 9296, - "5338-js-tdz-function-element.js": 2718, - "5338-stream-operators-checks.cjs": 4825, - "5339-array-buffer-constructor.js": 3399, - "5339-stream-for-await-hops.ts": 5761, - "534-record-width-subtyping.ts": 3917, - "5340-readable-from-options.ts": 4100, - "5341-compound-any-operand.ts": 4139, - "5341-generator-callback-params.ts": 4032, - "5341-integer-recursion-boundaries.ts": 3324, - "5341-readable-from-dynamic.cjs": 5054, - "5342-compound-any-operand.cjs": 3210, - "5342-generator-scalar-channels.ts": 3572, - "5342-integer-recursion-stack-and-mutual.ts": 4091, - "5342-stream-compose.ts": 8635, - "5343-any-flow-compound.ts": 3298, - "5343-integer-recursion-array-index.ts": 4086, - "5343-iterator-result-records.ts": 3462, - "5343-stream-compose-edges.ts": 8761, - "5344-json-parse-undeclared-keys.ts": 4683, - "5344-stream-pipeline-timing.ts": 3627, - "5345-object-values-for-of-unknown.ts": 3893, - "5346-object-values-length-dynamic.ts": 4302, - "5347-object-values-loop-control.ts": 3777, - "5348-object-values-for-of-js.js": 3584, - "5349-object-entries-values-optional.ts": 3677, - "535-object-statics.ts": 4668, - "5350-object-values-wide-record.ts": 4386, - "5351-object-values-methods-index.ts": 3615, - "5352-final-field-loop-reads.ts": 3880, - "5353-captured-const-values.ts": 4470, - "5354-captured-const-tdz.ts": 3331, - "5355-captured-function-declarations.ts": 3574, - "5356-captured-tdz-ordering.ts": 3626, - "5357-init-only-module-bindings.ts": 3698, - "536-map-seed-array.ts": 3057, - "5360-array-sort-comparator-calls.ts": 4503, - "5361-array-sort-inconsistent-comparators.ts": 4396, - "5362-array-sort-comparator-throws.ts": 3173, - "5363-array-sort-comparator-writes.ts": 12179, - "5364-array-sort-union-and-boolean-elements.ts": 14770, - "5365-array-sort-dynamic-values.js": 4175, - "537-map-iter-drains.ts": 3108, - "5370-zlib-stream-roundtrip.ts": 6069, - "5371-zlib-stream-chunking.cjs": 3999, - "5372-zlib-stream-errors.cjs": 4377, - "5373-zlib-stream-options.cjs": 4901, - "5374-zlib-stream-flush-params.ts": 4306, - "5375-zlib-stream-promises.ts": 5322, - "5376-zlib-constants.cjs": 3332, - "5377-zlib-stream-backpressure.cjs": 5428, - "5378-zlib-sync-options.cjs": 5415, - "5379-zlib-callback-options.ts": 5768, - "538-map-set-for-of.ts": 3575, - "5390-interface-loop-element-lifetimes.ts": 4065, - "5391-interface-dispatch-hierarchies.ts": 4925, - "5392-interface-receiver-bindings.ts": 3293, - "5393-interface-array-holes.ts": 3549, - "5394-interface-implementers.ts": 4320, - "5395-locale-compare-ascii.ts": 4299, - "5396-locale-compare-latin.ts": 3694, - "5397-locale-compare-sorting.ts": 4218, - "540-tuples-basics.ts": 3768, - "5400-json-parse-typed-keys.ts": 4494, - "5405-buffer-arraybuffer-window.ts": 3875, - "5406-util-types-keys.ts": 4065, - "5407-http-header-field-limit.ts": 2684, - "5408-http-unread-request-end.ts": 4832, - "5409-http-held-request-body.ts": 4395, - "541-ref-array-json.ts": 4658, - "5410-inspect-class-values.ts": 4013, - "5411-inspect-class-hierarchies.ts": 3695, - "5412-inspect-dynamic-collections.ts": 2565, - "5413-inspect-class-values.cjs": 4189, - "5415-zlib-dynamic-inputs.cjs": 3913, - "542-union-element-arrays.ts": 4031, - "5420-readable-from-generators.ts": 5476, - "5421-readable-from-generators.cjs": 3700, - "5422-stream-async-push-wakeup.ts": 4528, - "5423-stream-end-and-eos-timing.ts": 3712, - "5424-stream-write-buffer-encoding.ts": 3446, - "5425-pipeline-generator-stage.ts": 3465, - "5426-pipeline-generator-errors.ts": 4156, - "5427-pipeline-generator-backpressure.ts": 3689, - "5428-pipeline-generator-stages.cjs": 5519, - "5429-pipeline-generator-buffers.ts": 4449, - "5430-dyn-number-string-boxes.ts": 3851, - "5435-crypto-hash-algorithms.ts": 4090, - "5436-crypto-hash-names.js": 3513, - "5437-crypto-hmac-algorithms.ts": 3873, - "5438-crypto-kdf-digests.ts": 4076, - "5439-crypto-kdf-callbacks.js": 3741, - "5440-crypto-hash-encodings.js": 5108, - "5441-crypto-hash-output-length.ts": 5257, - "5442-crypto-random-values.ts": 4596, - "5443-crypto-random-arguments.js": 4093, - "5444-crypto-timing-safe-equal.js": 3904, - "5445-crypto-secret-key-objects.ts": 3885, - "5445-stream-buffer-chunks.ts": 4371, - "5446-crypto-secret-key-errors.js": 3542, - "5446-stream-buffer-chunks-dynamic.js": 5530, - "5447-fs-readdir-order.ts": 3865, - "5448-fs-glob-patterns.ts": 3617, - "5449-fs-glob-options.ts": 4047, - "5450-fs-glob-validation.js": 4514, - "5451-fs-promises-glob.ts": 4041, - "5452-fs-glob-callback.ts": 3311, - "5455-power-of-two-remainder.ts": 3496, - "5456-remainder-large-integer-dividends.ts": 3106, - "5457-lcg-modulus.ts": 3217, - "5458-fractional-remainder.ts": 3231, - "5460-locale-compare-contractions.ts": 4279, - "5461-locale-compare-equivalents.ts": 4168, - "5462-locale-compare-probe-sweep.ts": 5118, - "5463-locale-compare-combining-letters.ts": 4089, - "5464-locale-compare-fractions.ts": 3465, - "5465-dyn-index-read-arrays.ts": 2910, - "5466-dyn-index-read-special.ts": 3472, - "5470-strip-vt-osc.cjs": 2950, - "5471-strip-vt-csi.cjs": 3252, - "5472-strip-vt-random.cjs": 3939, - "5473-strip-vt-unterminated.cjs": 4153, - "5474-strip-vt-surrogates.ts": 3689, - "5510-assert-error-properties.js": 3848, - "5511-assert-error-class.ts": 3354, - "5512-assert-error-options.js": 3961, - "5513-assert-deep-equal-loose.js": 4575, - "5514-assert-deep-equal-typed.ts": 4346, - "5515-assert-deep-strict-typed-messages.ts": 3857, - "5516-assert-deep-equal-edges.js": 4060, - "5517-assert-partial-deep-equal.js": 4428, - "5518-assert-partial-deep-typed.ts": 4540, - "5519-assert-partial-deep-typed-edges.ts": 4298, - "5520-assert-record-literal-failures.ts": 4043, - "5520-dyn-property-read-receivers.ts": 3946, - "5521-assert-empty-message.js": 4460, - "5521-dyn-property-read-keys.ts": 3510, - "5522-assert-throws-failure-properties.ts": 3814, - "5523-assert-class-options.js": 4920, - "5524-assert-class-skip-prototype.ts": 3993, - "5530-buffer-pool.ts": 4954, - "5531-buffer-pool-first-slab.ts": 4419, - "5532-buffer-pool-first-slab-untyped.mjs": 156958, - "5540-fs-callback-forms.cjs": 5033, - "5541-fs-stats-fields.cjs": 5031, - "5542-fs-promises-parity.cjs": 3782, - "5543-fs-promises-typed.ts": 4425, - "5544-fs-opendir.cjs": 4598, - "5545-fs-options-encoding.cjs": 3812, - "5546-fs-read-stream.cjs": 4053, - "5547-fs-write-stream.cjs": 5026, - "5548-fs-callback-arguments.cjs": 3447, - "5549-fs-callback-option-checks.cjs": 4220, - "5550-locale-compare-ascii-words.ts": 3391, - "5551-array-search-references.ts": 4559, - "5552-string-appends.ts": 3836, - "5553-string-append-char-code.ts": 3220, - "5554-fs-streams-typed.ts": 4826, - "5555-fs-callback-turns.cjs": 4160, - "5555-http-server-close-keep-alive.ts": 16562, - "5556-http-client-agent-connection.ts": 7869, - "5557-http-outgoing-header-values.ts": 4486, - "5558-http-incoming-duplicate-headers.ts": 3277, - "5559-http-expect-header.ts": 13540, - "5560-http-response-framing.ts": 11999, - "5561-http-max-header-size.ts": 4546, - "5562-https-verify-errors.ts": 5339, - "5563-http-keep-alive-timeout.ts": 18223, - "5564-http-request-signal.ts": 6038, - "5565-fs-dirent-untyped.mjs": 4190, - "5566-fs-dirent-dyn-boundaries/main.mjs": 4370, - "5567-fs-cpsync.ts": 4231, - "5568-fs-cp-errors.js": 4710, - "5569-fs-cp-symlinks.ts": 3975, - "5570-fs-cp-async.ts": 4871, - "5571-fs-cp-deep.ts": 4651, - "5585-record-results-inlined.ts": 3799, - "5595-net-ref-unref.ts": 2930, - "5600-dyn-cycle-self.ts": 2377, - "5601-dyn-cycle-mutual.ts": 3087, - "5602-dyn-cycle-arrays.ts": 3074, - "5603-dyn-cycle-identity.ts": 3151, - "5604-dyn-cycle-checks.ts": 4016, - "5605-dyn-cycle-containers.ts": 4827, - "5606-dyn-cycle-capsules.ts": 3409, - "5610-readable-from-sets-and-views.ts": 6055, - "5611-readable-from-class-iterables.ts": 4787, - "5612-readable-from-iterables.cjs": 4888, - "5613-readable-from-iterable-timing.cjs": 4572, - "5614-readable-from-iterable-errors.cjs": 4862, - "5615-next-tick-callback-phases.ts": 4035, - "5616-next-tick-callback-phases.cjs": 3650, - "5617-pipeline-function-ends.ts": 55330, - "5618-pipeline-function-ends-errors.ts": 9347, - "5619-pipeline-function-ends.cjs": 5502, - "5620-timers-promises-values.ts": 3441, - "5621-util-format-float.ts": 4023, - "5622-events-once.mjs": 2752, - "5623-events-once.ts": 3430, - "5624-timers-promises-unawaited.ts": 3337, - "5625-promisify-exec.ts": 7797, - "5626-promisify-forms.ts": 2892, - "5627-exec-callback.ts": 2500, - "5628-promisify-timers.ts": 4069, - "5629-promisify-stream.ts": 4133, - "5630-promisify-zlib.ts": 3777, - "5631-promisify-crypto.ts": 2600, - "5632-promisify-dns.ts": 2000, - "5644-net-socket-addresses.ts": 3299, - "5645-net-socket-callbacks.ts": 4363, - "5646-net-server-connections.ts": 4089, - "5647-net-is-ip.ts": 3406, - "5648-dns-lookup-forms.ts": 4891, - "5649-dns-service-servers.ts": 4574, - "5650-dns-lookup-errors-untyped.cjs": 4634, - "5651-tls-socket-protocol.ts": 4232, - "5652-http-client-trailer-overflow.ts": 3846, - "5653-net-socket-read-ahead.ts": 5725, - "5654-https-empty-servername.ts": 5753, - "5655-dgram-socket-options.ts": 5148, - "5656-dgram-option-states.ts": 4307, - "5657-net-reset-and-address.ts": 3700, - "5658-net-reset-dynamic.cjs": 3925, - "5659-net-blocklist-socketaddress.ts": 4339, - "5664-tls-client-identity.ts": 5675, - "5674-union-instanceof-array-arms.ts": 4342, - "5680-array-growth-after-copy.ts": 5326, - "5681-array-pop-and-length.ts": 4603, - "5682-publish-wide-objects.ts": 2847, - "5700-cycle-release-retained.ts": 2881, - "5701-cycle-release-old-edges.ts": 2910, - "5702-publish-candidate-buffers.ts": 3240, - "5703-lifetime-region-debug.ts": 2720, - "5704-publish-refused-restores-counts.ts": 3978, - "5710-map-number-keys-hashed.ts": 4622, - "5711-map-number-write-after-read.ts": 4051, - "5712-map-number-overwrite-at-growth.ts": 3797, - "5714-cycle-large-candidate-buffers.ts": 5014, - "5715-json-parse-fitted-tables.ts": 4538, - "5717-set-prototype-of-primitives.ts": 3446, - "5719-int32-fields-dynamic-operators.ts": 3704, - "5720-intern-table-basics.ts": 4156, - "5721-intern-table-values.ts": 4709, - "5722-intern-table-workers.ts": 39327, - "5723-intern-table-shared-types.ts": 5477, - "5724-intern-table-array-keys.ts": 5614, - "5725-intern-table-callbacks.ts": 3793, - "5726-intern-table-key-limits.ts": 4034, - "5740-atomics-operation-semantics.ts": 3727, - "5741-atomics-contended-counters.ts": 24517, - "5742-atomics-lock-ordering.ts": 5553, - "5743-atomics-wait-notify.ts": 29359, - "5744-atomics-ring-buffer.ts": 32353, - "5745-atomics-semaphore-stress.ts": 39374, - "5746-shared-bulk-operations.ts": 4179, - "5747-fs-stat-throw-if-no-entry.ts": 3952, - "5748-fs-stat-throw-if-no-entry-js.cjs": 4210, - "5752-string-number-concat.ts": 2959, - "5760-crypto-hash-stream.ts": 3973, - "5761-crypto-hash-stream-states.ts": 3637, - "5762-crypto-hash-stream.cjs": 3895, - "5763-crypto-sha-blocks.ts": 3916, - "5764-class-structural-view-writes.ts": 4447, - "5764-crypto-hmac-edges.cjs": 3134, - "5765-class-structural-view-identity.ts": 3804, - "5766-class-structural-view-callbacks.ts": 3899, - "5767-class-opaque-accessor-view.ts": 3629, - "5776-power-of-two-remainder-integer-path.ts": 4355, - "5780-readline-history-options.ts": 2574, - "5781-readline-history-options.cjs": 2685, - "5782-readline-terminal-editing.ts": 7458, - "5783-readline-terminal-completion.cjs": 9987, - "5784-readline-terminal-promises.ts": 7899, - "5785-readline-terminal-keys.ts": 8463, - "5786-readline-terminal-history.cjs": 4186, - "5787-readline-cursor-helpers.cjs": 4616, - "5788-readline-promises-readline.ts": 4151, - "5789-readline-cursor-pos.cjs": 8106, - "5790-readline-keypress-events.ts": 4768, - "5791-dyn-constant-key-read-sites.ts": 3912, - "5791-readline-keypress-interfaces.cjs": 4765, - "5792-json-parse-repeated-layouts.ts": 4527, - "5792-readline-keypress-listeners.ts": 5406, - "5793-worker-message-channel.ts": 5212, - "5794-worker-message-port-close-order.ts": 4655, - "5795-worker-message-port-batches.ts": 3502, - "5796-worker-message-channel.cjs": 4995, - "5797-worker-message-port-transfer.ts": 23371, - "5800-broadcast-channel.ts": 4829, - "5801-broadcast-channel.cjs": 36650, - "5802-broadcast-channel-workers.ts": 3203, - "5803-worker-environment-data.ts": 6261, - "5804-worker-environment-data.cjs": 3356, - "5805-worker-receive-message-parent-port.ts": 3933, - "5806-worker-resource-limits.ts": 22085, - "5807-worker-error-values.ts": 5689, - "5808-worker-unhandled-rejections.ts": 6775, - "5809-process-exit-and-rejections.cjs": 38724, - "5810-mock-method-records.ts": 6060, - "5811-mock-tracker-restore.ts": 5297, - "5812-dyn-box-async-fields.ts": 4153, - "5813-mock-timers-module.ts": 3845, - "5814-mock-timers-date.ts": 10489, - "5830-timers-promises-signal.ts": 5868, - "5831-util-types-brands.ts": 3846, - "5832-util-types-brands-dynamic.js": 3912, - "5833-url-search-params-iterators.ts": 3034, - "5834-url-search-params-iterators-dynamic.mjs": 3877, - "5835-util-format-integer-specifiers.ts": 2899, - "5836-url-search-params-tuple-pairs.ts": 2897, - "5837-util-format-json-circular.ts": 2745, - "5838-qs-stringify-bigint.ts": 2868, - "5839-timers-promises-scheduler.ts": 3136, - "5840-promise-with-resolvers-js.js": 2701, - "5841-json-typed-dyn-members.ts": 4508, - "5842-qs-parse-null-prototype.ts": 3749, - "5843-qs-parse-null-prototype-js.mjs": 3308, - "5844-date-unknown-values.ts": 3966, - "5845-groupby-null-prototype.ts": 3946, - "5846-events-esm-default-max.ts": 3102, - "5847-events-cjs-default-max.cjs": 3039, - "5849-class-view-observations.ts": 3234, - "5850-using-disposable-values.ts": 3491, - "5851-using-suppressed-error-values.ts": 4335, - "5852-using-disposable-values-js.js": 3438, - "5853-set-methods-map-arguments.ts": 3861, - "5854-array-from-async.ts": 4644, - "5855-array-from-async-js.js": 3880, - "5856-error-is-error.ts": 3947, - "5857-regexp-unicode-sets.ts": 3156, - "5858-disposable-stack.ts": 4000, - "5859-disposable-stack-js.js": 4197, - "5860-url-ipv4-hosts.ts": 3379, - "5870-worker-thread-names.ts": 5388, - "5871-worker-untransferable.cjs": 38904, - "5872-readline-positional-create-interface.mjs": 4683, - "5873-readline-promises-namespace.cjs": 3786, - "5874-worker-stdio-streams.ts": 8408, - "5875-worker-stdout-pipe.cjs": 36125, - "5879-worker-stdin.ts": 56815, - "5880-emitter-leak-warning-delivery.ts": 3928, - "5881-inspect-weak-collections.ts": 3161, - "5882-string-decoder-runtime-encoding.ts": 3686, - "5883-os-set-priority.ts": 2593, - "5884-inspect-layout-options.ts": 3958, - "5885-events-max-listener-helpers.ts": 3524, - "5886-inspect-dates.ts": 3606, - "5887-inspect-typed-arrays.ts": 3660, - "5888-inspect-sorted.ts": 2960, - "5889-timers-scheduler-signal.ts": 3671, - "5890-while-string-length-counters.ts": 3347, - "5892-buffer-write-utf16le-runs.ts": 3722, - "5900-float16-array.ts": 3748, - "5901-float16-array-js.js": 3979, - "5904-async-generator-completion.ts": 6741, - "5905-array-from-async-generator.ts": 4080, - "5906-array-from-async-generator-js.js": 3999, - "5907-regex-groups-match-rows.ts": 3750, - "5910-set-prototype-of-primitive-object-kinds.ts": 4285, - "5911-dyn-class-to-primitive.ts": 6260, - "5912-dyn-class-conversion-methods.ts": 4623, - "5913-prototype-type-error-messages.ts": 3542, - "5914-dyn-in-class-prototype-members.ts": 2963, - "5915-dyn-error-string-conversions.ts": 2860, - "5920-promise-try-args.ts": 2731, - "5921-promise-try-args-js.js": 2533, - "5922-matchall-groups-callbacks.ts": 4812, - "5923-matchall-groups-js.js": 4191, - "5924-js-literal-identity.js": 2661, - "5925-class-view-identity-observers.ts": 2640, - "5926-class-view-switch-js.js": 2843, - "5927-switch-object-identity.ts": 3333, - "5928-groupby-iterables.ts": 4581, - "5929-groupby-js.js": 3288, - "5930-contract-int32-arrays.ts": 4209, - "5930-method-census-asserted-number-keys.ts": 3405, - "5931-asserted-reads-keep-number-parameters.ts": 3441, - "5932-generic-class-observed-methods.ts": 4594, - "5933-class-fields-unknown-object.ts": 4036, - "5934-js-class-fields-property-order.js": 4840, - "5935-js-subclass-fields-and-element-calls.js": 4505, - "5936-checked-js-class-types.js": 3902, - "5937-override-narrowed-union-returns.ts": 3617, - "5938-object-literal-computed-keys-keep-methods.ts": 7194, - "5939-js-let-object-reassigned-wider.js": 3070, - "5940-callback-helper-specialization.ts": 5355, - "5941-callback-specialization-recursion.ts": 4385, - "5942-callback-specialization-throws.ts": 3535, - "5943-fields-read-before-assignment.ts": 72293, - "5944-js-fields-read-before-assignment.js": 40310, - "5945-local-class-observed-methods.ts": 6212, - "5946-nested-record-field-optional-writes.ts": 68117, - "5950-tuple-predicate-methods.ts": 5999, - "5951-result-never-widening.ts": 3370, - "5952-record-missing-keys.ts": 20400, - "5953-nan-coded-method-returns.ts": 15600, - "5955-any-promise-methods.js": 3616, - "5956-erased-generic-members.ts": 6191, - "5958-asserted-union-receiver.ts": 2929, - "5959-date-to-json.ts": 2856, - "5960-generic-mapped-types.ts": 3526, - "5970-net-connect-host-name.ts": 2998, - "5971-buffer-chunks-to-string.ts": 3483, - "5972-net-set-encoding-listeners.ts": 7935, - "5974-typeof-module-exports.cjs": 2121, - "5975-zlib-class-values.ts": 4200, - "5990-worker-uncloneable.mjs": 37308, - "5991-worker-async-dispose.mjs": 7506, - "5992-worker-thread-name-lifetime.mjs": 44550, + "2110-top-object-types.ts": 3870, + "2111-json-stringify-unknown.ts": 4435, + "2112-array-at-findlast.ts": 4707, + "2113-string-index-methods.js": 3454, + "212-string-aliasing-append.ts": 3894, + "2120-package-self-import/main.ts": 2683, + "2121-esm-cycle-inert-backedge/main.ts": 2391, + "2123-ambient-import-crash/main.ts": 3826, + "2124-imports-field-wildcard/main.ts": 4011, + "2140-uri-component-codecs.ts": 4495, + "2160-dc-tracing-channel.cjs": 5323, + "2161-js-object-literal-identity.cjs": 4357, + "2162-js-dyn-destructure.cjs": 3222, + "2163-js-selfref-const.cjs": 3731, + "2164-js-then-dyn-handler.cjs": 3928, + "2165-js-throw-dyn.cjs": 3594, + "2166-cjs-getter-this/main.cjs": 2580, + "2170-island-array-exits.ts": 5872, + "2171-island-json-stringify.ts": 3235, + "2172-island-regexp-boundary.ts": 4811, + "2190-new-object-and-string-wrappers.ts": 3881, + "2191-uri-encoders.ts": 2785, + "2192-object-default-tostring.ts": 3767, + "2193-discarded-stdlib-reads.ts": 2753, + "2194-ambient-undef-chains.ts": 3966, + "2195-require-missing-package/main.mjs": 3949, + "2196-island-computed-key-chain.ts": 3859, + "2210-dyn-promise-crossing.cjs": 5056, + "2211-dc-trace-promise.cjs": 4674, + "2212-unhandled-rejection-listener.cjs": 3832, + "2213-async-local-storage.cjs": 4800, + "2214-dc-bind-store.cjs": 4857, + "2215-process-emit-warning-exit.cjs": 4319, + "2240-width-class-into-record.ts": 4526, + "2241-width-record-into-class.ts": 3828, + "2242-width-statics-into-record.ts": 3590, + "2243-width-assert-satisfies-shapes.ts": 4657, + "2250-tagged-templates.ts": 3291, + "2252-class-iterators.ts": 4007, + "2253-union-coercions.ts": 2990, + "2260-http2-constants.cjs": 3422, + "2280-builtin-namespace-destructure.cjs": 3322, + "2281-domexception-atob-btoa.cjs": 3717, + "2282-queue-microtask.cjs": 4471, + "2283-structured-clone.cjs": 6184, + "2284-regexp-constructor.cjs": 3737, + "2285-iferror-dyn.cjs": 3898, + "2286-dyn-object-walks.cjs": 3663, + "2300-dyn-record-spread-and-keyed-access.cjs": 3720, + "2301-cjs-export-table-dom-attach.cjs": 3384, + "2310-process-next-tick.ts": 5910, + "2311-next-tick-js-callbacks.js": 2877, + "2312-stream-underscore-assign.ts": 8104, + "2313-stream-underscore-assign-js.cjs": 4045, + "2314-process-introspection.ts": 4555, + "2320-await-unit.ts": 3726, + "2321-emitter-static-setmax.cjs": 4139, + "2322-dyn-array-sort.cjs": 3726, + "2323-timer-callback-returns.ts": 3622, + "2330-tls-server-runtime-options.cjs": 27710, + "2331-tls-server-options-typed.ts": 27128, + "2350-nan-global.ts": 4123, + "2351-async-methods.ts": 4008, + "2352-void-coercions.ts": 4044, + "2353-decorators-member-ambient.ts": 3507, + "2354-decorators-expression-ambient.ts": 3756, + "2360-tuple-to-array.ts": 3301, + "2361-assign-index-record.ts": 4658, + "2362-execsync-inherit.ts": 3671, + "2363-nullish-retag.ts": 4322, + "2364-in-runtime-key.ts": 3872, + "2365-dyn-into-island.ts": 4202, + "2366-string-well-formed.ts": 4097, + "2367-regexp-escape.ts": 2500, + "2368-set-methods.ts": 4362, + "2369-promise-try.ts": 4105, + "2370-group-by.ts": 5234, + "2371-iterator-helpers.ts": 3705, + "2380-buffer-module-named-import.ts": 3866, + "2381-builtin-default-imports.js": 3690, + "2382-cycle-two-decl/main.ts": 3053, + "2383-cycle-assertdoc/main.js": 3424, + "2384-cycle-mixed-bindings/main.ts": 3805, + "2385-builtin-reexport-facade/main.ts": 3157, + "2386-string-to-chars.ts": 3939, + "2387-tonumber-argv.ts": 2788, + "2388-tonumber-grammar-zoo.ts": 3308, + "2389-tonumber-unary-plus.ts": 4585, + "2390-dot-requires/main.cjs": 3582, + "2391-default-builtin-imports/main.ts": 3597, + "2392-block-guard-alias-scope.ts": 3540, + "2393-loop-exit-guard-narrow.ts": 4327, + "2394-loop-narrow-containment.ts": 3359, + "2395-while-cond-guard.ts": 3736, + "2396-born-narrowed-decl.ts": 3669, + "2397-branch-kill-merge.ts": 3852, + "2398-switch-arm-kill.ts": 3957, + "2399-reassign-kill-polarity.ts": 3597, + "240-stdout-write.ts": 2582, + "2400-kill-return-edge.ts": 3990, + "2401-kill-break-staging.ts": 3661, + "2402-labeled-break-kill.ts": 3719, + "2403-kill-continue-backedge.ts": 3491, + "2404-kill-throw-catch.ts": 3664, + "2405-sibling-arm-narrow.ts": 3896, + "2406-switch-clause-sibling-narrow.ts": 3538, + "2407-infinite-loop-seal.ts": 3968, + "2408-loop-terminality-reopen.ts": 3262, + "2409-loop-body-return-not-terminal.ts": 3183, + "2410-stacked-cases-terminality.ts": 4213, + "2411-exhaustive-switch-terminality.ts": 4119, + "2412-dowhile-guard-trailing-test.ts": 2693, + "2413-dowhile-kill-renarrow.ts": 3480, + "2414-dowhile-continue-kill.ts": 3748, + "2415-dowhile-break-trailing-test.ts": 3696, + "2416-spread-ternary-positions.ts": 3541, + "2417-ternary-local-inference.ts": 4012, + "2418-wrapped-ternary-arms.ts": 3646, + "2419-selector-ternary-union.ts": 4650, + "2420-nullish-null-identity.ts": 4115, + "2421-float-lane-inference.ts": 3944, + "2422-ieee-div-rem-corners.ts": 4159, + "2423-param-null-reassign.ts": 2605, + "2424-ternary-miss-first-narrowing.ts": 4261, + "2425-elseif-head-exit-narrow.ts": 2714, + "2426-default-snapshot-mutable/main.ts": 3509, + "2427-perf-hooks-now.ts": 3643, + "2428-field-redeclare-inherited.ts": 3729, + "2429-destructure-class-instance.ts": 3764, + "2430-empty-literal-unknown-field.js": 3619, + "2431-primitive-ctor-values.ts": 2975, + "2432-generic-member-fields-async.ts": 3894, + "2433-as-const-command-tables.ts": 4279, + "2434-deferred-init-fields.ts": 3904, + "2435-loose-same-kind-equality.ts": 2449, + "2440-console-inspect-args.ts": 4983, + "2441-console-process-argv.ts": 3366, + "2442-union-literal-arm-widening.ts": 3510, + "2443-union-literal-shadow-narrowing.ts": 4296, + "2444-union-literal-reducer-spread.ts": 4322, + "2445-math-minmax-nary.ts": 4287, + "2446-performance-global.ts": 2765, + "2447-island-boundary-slots/main.ts": 30163, + "2448-entries-null-arms-regex-arrays.ts": 5050, + "2450-private-instance-methods.ts": 3745, + "2451-private-fields.ts": 4055, + "2452-private-statics.ts": 4122, + "2453-private-accessors.ts": 3729, + "2454-private-generator-methods.ts": 4591, + "2455-private-brand-checks.ts": 3790, + "2456-private-async-methods.ts": 4068, + "2457-private-members.js": 3733, + "2460-qs-parse-grammar.ts": 4511, + "2461-qs-parse-options.ts": 5074, + "2462-qs-stringify.ts": 5146, + "2463-qs-escape-unescape.ts": 4740, + "2464-qs-require-forms.cjs": 3706, + "2470-mockable-module-shape.js": 4001, + "2471-record-keyed-write-hasown.js": 4306, + "2472-string-regexp-union.ts": 4333, + "2473-option-table-widths.js": 4080, + "2474-island-literal-forms.ts": 3640, + "2475-variadic-wrapper-island.js": 3607, + "2476-map-regex-values.ts": 3840, + "2480-recursive-record-tree.ts": 3961, + "2481-mutual-recursive-records.ts": 3629, + "2482-recursive-union-tree.ts": 3442, + "2483-recursive-record-cycles.ts": 3728, + "2484-json-stringify-circular.ts": 3926, + "2485-inspect-circular-refs.ts": 4207, + "2486-recursive-record-boundaries.ts": 3631, + "2487-recursive-deep-equal.ts": 4488, + "2488-ast-walker.ts": 3489, + "2490-find-miss-null-compare.ts": 3128, + "2491-strict-unit-compare-no-arm.ts": 3378, + "2492-loose-null-compare-unions.ts": 3406, + "2493-switch-unit-cases.ts": 4046, + "2494-no-arm-compare-effects.ts": 3576, + "2500-net-autosel-timeout.ts": 6361, + "2510-dyn-evolving-array-map.ts": 4082, + "2511-dyn-evolving-array-filter-foreach.ts": 4487, + "2512-dyn-evolving-array-mixed-push.ts": 3602, + "2520-private-statics-class-name-calls.ts": 3443, + "2521-private-statics-class-expression.ts": 4261, + "2522-private-statics-decorated.ts": 3872, + "2523-private-statics-aliased-class.ts": 3793, + "2530-object-destructuring-decl.ts": 3717, + "2531-array-tuple-destructuring-decl.ts": 4697, + "2532-param-destructuring-options.ts": 4524, + "2533-forof-destructuring.ts": 4725, + "2534-object-rest-decl.ts": 4160, + "2535-destructuring-assign-basics.ts": 3008, + "2536-destructuring-assign-nested.ts": 3971, + "2537-destructuring-assign-member-targets.ts": 4117, + "2538-destructuring-assign-class-source.ts": 3926, + "2539-class-instance-rest.ts": 3983, + "2540-accessor-destructuring-defaults.ts": 2587, + "2541-destructuring-eval-order.ts": 4204, + "2550-generics-keyof-pick.ts": 4104, + "2551-generics-value-aliases.ts": 3651, + "2552-generics-iface-methods.ts": 3134, + "2553-generics-signature-bindings.ts": 4036, + "2554-generics-frontier-mix.ts": 4173, + "2555-generics-keyof-writes.ts": 3734, + "2556-crypto-introspection.ts": 3814, + "2556-width-hybrid-shapes.ts": 4554, + "2557-tls-ca-store.ts": 4247, + "2557-width-field-lifts.ts": 3310, + "2558-index-signature-func-values.ts": 3316, + "2558-rejection-events.cjs": 3816, + "2559-index-signature-container-values.ts": 4363, + "2560-arraybuffer-dataview-set.ts": 4259, + "2561-object-is.ts": 3615, + "2562-intl-numberformat-en-us.ts": 4400, + "2563-stream-promises-pipeline.ts": 3735, + "2564-stream-promises-finished.ts": 8470, + "2565-stream-promises-js.cjs": 4670, + "2566-promise-reject-dyn-reason.js": 3862, + "2567-rest-spread-forward.js": 4241, + "2568-rest-spread-forward-dynamic.js": 3805, + "2569-upcast-identity.ts": 2741, + "2570-buffer-arg-validation.cjs": 5723, + "2571-searchparams-arg-validation.cjs": 4325, + "2572-readable-emitted-readable-flag.cjs": 3665, + "2573-fs-url-arg-ladders.cjs": 3433, + "2574-emitter-max-listeners-ladders.cjs": 4082, + "2575-string-destructuring-decl.ts": 4618, + "2576-string-destructuring-assign.ts": 4254, + "2577-builtin-global-destructuring.js": 3582, + "2578-jsval-into-unknown-rows.ts": 4068, + "2579-jsval-object-param-crossing.js": 4185, + "2580-jsval-routed-keyed-ops.js": 4278, + "2581-jsval-routed-calls.js": 4541, + "2582-jsval-object-statics.js": 4272, + "2582-jsval-routed-keyed-ops.js": 3765, + "2583-dyn-nullish-coalesce.js": 3622, + "2583-jsval-routed-calls.js": 4186, + "2584-jsval-object-statics.js": 3517, + "2584-union-dyn-collapse.ts": 5179, + "2585-dyn-nullish-coalesce.js": 4450, + "2585-unknown-array.ts": 4082, + "2586-object-assign-spread.js": 3285, + "2587-array-entries-forof.ts": 4350, + "2588-array-entries-chains.ts": 4523, + "2589-object-create-null.cjs": 4020, + "2590-object-create-dynamic.js": 3068, + "2591-ambient-generic-traps.ts": 4200, + "2592-ambient-trap-uncaught.ts": 3460, + "2593-generic-inert-bindings.ts": 3588, + "2594-nullish-generic-bindings.ts": 3726, + "2595-fs-arg-ladders.cjs": 6740, + "2596-net-arg-ladders.cjs": 6682, + "2597-dgram-send-ladders.cjs": 5257, + "2598-tls-arg-ladders.cjs": 28958, + "2599-stream-arg-ladders.cjs": 4068, + "2600-dyn-keyed-write-harness.js": 4122, + "2601-dyn-keyed-write-ops.js": 3049, + "2602-dyn-array-destructure.js": 3757, + "2603-island-keyed-write-dyn.js": 3437, + "2604-cycle-classes-mutual/main.ts": 3996, + "2605-cycle-three-module/main.ts": 3537, + "2606-dynamic-import-cycle/main.ts": 3810, + "2608-regex-named-groups.ts": 4091, + "2609-regex-named-replace.ts": 2758, + "2610-regex-named-matchall.ts": 4465, + "2611-regex-named-groups-js.cjs": 6008, + "2613-for-init-uninitialized-let.ts": 3817, + "2614-trap-binding-later-writes.ts": 4020, + "2615-nullish-field-record-binding.ts": 3220, + "2616-js-collect-probe-defers.js": 3633, + "2617-enum-static-field-import/main.ts": 3698, + "2618-ee-emit-override.ts": 2900, + "2619-ee-override-chain.ts": 3741, + "2620-ee-override-once-order.ts": 3799, + "2621-ee-override-error-throw.ts": 3035, + "2622-ee-override-filter.ts": 3418, + "2623-ee-job-queue.ts": 3306, + "2624-ee-override-js.cjs": 4196, + "2625-bytes-views.ts": 4141, + "2626-stream-event-names.ts": 5209, + "2627-stream-ticks-are-nextticks.ts": 3902, + "2628-stream-push-encodings.cjs": 3828, + "2629-stream-consumers.ts": 5554, + "2630-stream-consumers-errors.ts": 4330, + "2631-create-require/main.ts": 4336, + "2632-dyn-jsval-iterate.js": 4764, + "2633-island-promise-crossing.js": 5106, + "2634-stream-pipeline-arg-ladders.cjs": 3877, + "2635-trap-binding-unmappable-written.ts": 3449, + "2636-trap-binding-ambient-rooted-rewrite.ts": 4109, + "2637-create-require-bare/main.ts": 3645, + "2638-http-dyn-res-compat.cjs": 7173, + "2639-http-dyn-req-pause.cjs": 7147, + "2640-net-dyn-socket-compat.cjs": 5745, + "2641-http-agent-surface.cjs": 7414, + "2642-http-agent-maxsockets.cjs": 4580, + "2643-or-default-retag.ts": 4099, + "2644-http-client-url-argument.ts": 4758, + "2645-https-client-url-argument.ts": 45938, + "2646-top-level-await.ts": 3701, + "2647-top-level-await-modules/main.ts": 4075, + "2648-top-level-await-rejection.ts": 3331, + "2649-top-level-await-pending.ts": 3587, + "2650-top-level-await-self-import.ts": 3982, + "2651-top-level-await-pending-unhandled.ts": 3896, + "2652-top-level-await-dynamic/main.ts": 3670, + "2653-top-level-await-rejection-stops-loop.ts": 3674, + "2654-top-level-await-unrelated-rejection.ts": 4358, + "2655-top-level-await-cycle/main.ts": 3663, + "2656-top-level-await-cycle-order/main.ts": 3641, + "2657-top-level-await-cycle-dynamic/main.ts": 3605, + "2658-top-level-await-sync-completion/main.ts": 3738, + "2659-top-level-await-dynamic-cycle/main.ts": 3937, + "2660-top-level-await-cycle-rejection/main.ts": 3839, + "2661-top-level-await-dynamic-runtime-root/main.ts": 4277, + "2662-top-level-await-cycle-external-wait/main.ts": 3840, + "2663-top-level-await-dependency-errors/main.ts": 4026, + "2664-top-level-await-same-checkpoint-rejection.ts": 3900, + "2665-top-level-await-unhandled-listener-liveness.ts": 3124, + "2666-array-to-sorted.ts": 7343, + "2668-stored-number-array-iterator.ts": 4155, + "2669-array-copying-methods.ts": 4893, + "2670-uint8array-copy-iterate.ts": 4534, + "2671-array-copying-js.cjs": 4071, + "2672-http-request-response-callback.ts": 25478, + "2673-top-level-await-implicit-module.ts": 3661, + "2674-top-level-for-await-implicit-module.ts": 4714, + "2675-create-require-nested-esm.js": 3731, + "2675-process-self-reexec.ts": 3793, + "2676-indexed-read-strict-equality.ts": 3177, + "2676-record-clone-overrides.ts": 3884, + "2676-top-level-await-ambiguous/main.ts": 3335, + "2677-runtime-optional-closure.ts": 4747, + "2677-top-level-await-module-scope/main.ts": 2879, + "2678-date-instances.ts": 3537, + "2678-large-string-sparse-index.ts": 3659, + "2678-util-parseargs.ts": 8501, + "2679-util-parseargs-cjs.cjs": 5362, + "2680-util-parseargs-default.ts": 3698, + "2681-util-parseargs-dynamic.js": 5047, + "2682-fs-rename.ts": 4318, + "2683-filter-truthy-predicate.ts": 4083, + "2683-fs-rename-js.cjs": 4168, + "2684-filter-no-predicate-dyn.cjs": 3139, + "2684-fs-rename-abort.ts": 3244, + "2685-array-unshift-reverse.ts": 3752, + "2685-fs-write-sync.ts": 3562, + "2686-fs-file-handle.ts": 5916, + "2687-fsp-write-file-options.ts": 4133, + "2687-process-write-args.ts": 3739, + "2688-fs-stats-disk-fields.ts": 4196, + "2689-http-server-timeout-properties.ts": 9510, + "2690-https-server-timeout-option.ts": 26255, + "2691-retained-lowering-record-order.ts": 5714, + "2692-inline-record-assert-index.ts": 4256, + "2692-string-accumulation.ts": 4000, + "2693-math-constants.ts": 3814, + "2700-array-sort-complexity.ts": 4128, + "2700-http-static-trailers.ts": 3673, + "2700-wasi-core.ts": 3941, + "2701-array-sort-snapshot.ts": 5063, + "2701-http-static-trailer-wire.ts": 4002, + "2701-import-meta/main.mjs": 4298, + "2702-http-static-trailer-end.ts": 4488, + "2702-type-import-link-static/main.ts": 3632, + "2702-uint8array-to-sorted.ts": 4201, + "2703-array-sparse-sort.ts": 7778, + "2703-type-import-link-static-reexport/main.ts": 3591, + "2704-array-sparse-to-sorted.ts": 8196, + "2704-type-import-link-static-success/main.ts": 3547, + "2705-array-sparse-sort-append.ts": 6478, + "2705-type-import-link-dynamic/main.ts": 3402, + "2706-array-search-missing-needle.ts": 4264, + "2706-type-import-link-dynamic-success/main.ts": 3801, + "2707-array-search-huge-sparse.ts": 45112, + "2707-type-import-link-static-default-reexport/main.ts": 3162, + "2708-type-import-link-dynamic/main.ts": 2849, + "2720-array-read-parity.ts": 4418, + "2721-array-nested-missing-receiver.ts": 4224, + "2750-array-sparse-foundation.ts": 3486, + "2751-buffer-concat-sparse-list.ts": 3809, + "2752-array-optional-stores.ts": 3893, + "2753-array-optional-method-values.ts": 4447, + "2754-array-property-undefined.ts": 3437, + "2755-array-optional-literal-forwarding.ts": 3309, + "2780-array-parity-composition.ts": 11152, + "2781-array-missing-value-escape.ts": 3766, + "2782-array-sparse-callbacks.ts": 4827, + "2783-array-defaults-rest.ts": 3752, + "2784-array-reduce-missing-result.ts": 3900, + "2785-array-missing-destructuring.ts": 4350, + "2786-array-sparse-serialization.ts": 4399, + "2787-array-missing-string-arithmetic.ts": 3532, + "2788-array-missing-builtin-conversions.ts": 2629, + "2789-array-missing-optional-tostring.ts": 4012, + "2790-dynamic-import-self-name/main.ts": 3567, + "2791-record-optional-keys.ts": 4180, + "2792-record-optional-spread-entries.ts": 3957, + "2793-union-conversion-identity-capture.ts": 4016, + "2794-array-generic-callback-values.ts": 3192, + "2795-array-optional-typedarray-source.ts": 39238, + "2796-array-sparse-class-value-instanceof.ts": 3057, + "2800-array-expression-consumers.ts": 3984, + "2801-array-switch-consumers.ts": 3844, + "2820-array-missing-method-receivers.ts": 4015, + "2821-array-optional-numeric-comparisons.ts": 3715, + "2830-cjs-require-self-name/main.cjs": 3843, + "2840-finally-completions.ts": 3843, + "2841-using-sync.ts": 3805, + "2842-await-using.ts": 3336, + "2843-using-suppressed-error.ts": 3417, + "2844-node-disposable-resources.ts": 4668, + "2845-for-using-of.ts": 3487, + "2846-generator-using.ts": 4293, + "2850-async-generators-protocol.ts": 4610, + "2851-async-generators-values.ts": 4267, + "2852-timers-promises-interval.ts": 3195, + "2854-leading-bom-literals.ts": 3717, + "2855-searchparams-sort-complexity.ts": 3679, + "2856-dynamic-any-local-operators.ts": 3601, + "2857-branded-primitives.ts": 3846, + "2858-import-meta-resolve/main.mjs": 3869, + "2859-import-meta-resolve-dynamic/main.mjs": 3441, + "2860-require-resolve/main.cjs": 3856, + "2861-readable-iterator-close.ts": 8658, + "2862-web-readable-async-iteration.ts": 60491, + "2863-class-async-iterator.ts": 3807, + "2864-array-class-method-receivers.ts": 3808, + "2865-cjs-process-alias.cjs": 3058, + "2866-dyn-switch.ts": 4091, + "2867-array-shift-length.js": 3560, + "2868-empty-record-promise-presence.js": 3622, + "2869-nullish-mixed-lazy.ts": 3214, + "2870-and-dropped-truthy-arm.ts": 3668, + "2871-optional-promise-to-unknown.ts": 3151, + "2872-unobserved-dynamic-event.ts": 3479, + "2873-optional-receiver-loop-lifetime.js": 3838, + "2874-nullable-callback-field-cycle.js": 3416, + "2875-evolving-let-read-before-write.js": 3393, + "2876-class-unknown-roundtrip.ts": 3172, + "2877-child-unknown-roundtrip.ts": 3088, + "2878-class-private-unknown.cjs": 3951, + "2880-cjs-module-graph/main.cjs": 4546, + "2890-crypto-static-utility.ts": 4147, + "2891-json-record-key-escapes.ts": 4489, + "2892-windows-console-unicode.ts": 3631, + "2893-child-stdin-duplex.ts": 4001, + "2894-child-stdin-backpressure.ts": 3911, + "2895-child-stdin-write-after-end.ts": 4040, + "2896-child-stdin-write-after-finish.ts": 4046, + "2897-child-stdin-destroy.ts": 4182, + "2898-child-stdin-spawn-failure.ts": 3819, + "2899-nested-mutual-recursion.ts": 3391, + "2900-float64array-static.ts": 4170, + "2900-void-conditional-arrow.ts": 2973, + "2901-bigint-core.ts": 3785, + "2902-bigint-bytes.ts": 3878, + "2903-bigint-storage.ts": 4174, + "2904-bigint-errors.ts": 3154, + "2905-bigint-edges.ts": 3535, + "2906-bigint-wasi-width.ts": 3636, + "2910-overloaded-callable-alias.ts": 3507, + "2911-execfile-callback.ts": 3775, + "2912-execfile-callback-options.ts": 3546, + "2912-promisify-fs-readfile.ts": 3527, + "2913-builtin-callable-alias.ts": 5224, + "2914-fixed-tuple-call-spread.ts": 4266, + "2915-path-function-values.ts": 4335, + "2916-path-function-values-cjs.ts": 3661, + "2917-builtin-callable-widths.ts": 4692, + "2918-builtin-callable-widths-cjs.ts": 3911, + "2919-fs-function-values.ts": 3993, + "2920-fs-promises-function-values.ts": 3700, + "2921-zlib-callbacks.ts": 4702, + "2922-dyn-bitwise-not.cjs": 3792, + "2923-cjs-factory-export/main.cjs": 3686, + "2930-union-receiver-calls.ts": 4496, + "2931-union-dynamic-field-call.js": 3249, + "2932-create-require-program/main.ts": 4121, + "2933-static-dynamic-import/main.ts": 3790, + "2934-static-import-stored.ts": 2637, + "2935-module-namespace-values/main.ts": 4033, + "2936-static-loose-equality.ts": 4807, + "2937-bitwise-hot-loop.ts": 3730, + "2938-fs-sync-overloads.cjs": 2978, + "2939-child-shell-text.ts": 4396, + "2940-date-parse.ts": 3909, + "2940-fsp-realpath.ts": 3670, + "2941-fsp-lstat-identity.ts": 4973, + "2941-process-exit-code.ts": 2597, + "2942-fsp-readdir-dirent.ts": 3959, + "2942-process-exit-code-override.ts": 3773, + "2943-process-exit-code-invalid.ts": 3459, + "2944-process-exit-code-wrap.ts": 4312, + "2945-url-origin-username.ts": 2754, + "2946-child-fork-ipc/main.ts": 4571, + "2946-url-port-hash.ts": 3017, + "2947-set-readonly-seeds.ts": 3976, + "2948-child-fork-eof-callback/main.ts": 4009, + "2948-stdio-callback-record.ts": 2902, + "2949-child-fork-default/main.mjs": 3935, + "2949-url-password.ts": 3040, + "2950-fs-descriptor-publication.ts": 2555, + "2951-math-static-analytic.ts": 4273, + "2952-math-static-remaining.ts": 3480, + "2953-http-header-validation.ts": 6668, + "2954-http-outgoing-headers.ts": 4292, + "2955-http-static-state.ts": 3942, + "2956-http-static-informational.ts": 8174, + "2957-http-static-response-controls.ts": 4254, + "2961-emitter-computed-names.cjs": 2876, + "2962-emitter-computed-optional.ts": 3963, + "2963-child-fork-dispatch/main.ts": 3170, + "2964-indexed-compound.ts": 4621, + "2966-numeric-array-read-fusion.ts": 3495, + "2967-numeric-array-read-lifetime.ts": 3370, + "2968-numeric-array-borrow.ts": 4623, + "2969-scalar-record-results.ts": 3919, + "2970-constant-numeric-tables.ts": 2953, + "2971-constant-table-modules/main.ts": 2780, + "2972-http-static-distinct-snapshots.ts": 7024, + "2972-math-receiver-borrow.ts": 4560, + "2973-http-static-agent.ts": 8993, + "2973-integer-bitwise-arithmetic.ts": 3843, + "2974-array-search-from-index.ts": 102834, + "2974-http-static-module-values.ts": 6368, + "2974-numeric-remainder.ts": 4108, + "2975-bigint-default-radix.ts": 3498, + "2975-http-static-client-controls.ts": 3623, + "2976-http-static-incoming-state.ts": 2971, + "2976-json-stringify-no-arguments.js": 3696, + "2977-http-static-incoming-timeout.ts": 4074, + "2977-nested-array-binding-defaults.js": 4142, + "2978-http-static-client-timeout.ts": 9714, + "2978-regexp-optional-subject.js": 49628, + "2979-array-search-mixed-needles.js": 4303, + "2979-http-static-server-timeout.ts": 6006, + "2980-http-static-server-timeout-default.ts": 7270, + "2980-string-position-arguments.js": 3086, + "2981-http-static-events.ts": 3123, + "2981-string-optional-positions.ts": 3368, + "2982-http-static-close-all.ts": 3822, + "2982-string-position-coercion-order.js": 3928, + "2983-http-static-close-idle.ts": 3614, + "2984-http-static-close-upgrade.ts": 3907, + "2985-http-static-message-destroy.ts": 3388, + "2986-http-static-client-socket-finish.ts": 3798, + "2987-http-static-timeout-errors.ts": 4096, + "2988-http-static-client-abort.ts": 2850, + "2989-http-static-response-timeout-handled.ts": 3345, + "2990-http-static-request-timeout-handled.ts": 4813, + "2991-array-indexed-equality.ts": 4275, + "2992-stream-rows.ts": 3533, + "2993-fiber-stack-lifetimes.ts": 4327, + "2994-fromcharcode-scalar.ts": 4187, + "2995-math-hyperbolic.ts": 4005, + "2996-math-near-one.ts": 4413, + "2997-math-integer-float.ts": 3945, + "300-if-else.ts": 4350, + "3001-caught-typeof-object.js": 3508, + "3002-promise-then-two.ts": 4636, + "301-while.ts": 3775, + "302-for.ts": 3729, + "3020-string-last-index-position.ts": 2972, + "3021-buffer-union-narrow-callback.ts": 3784, + "3022-string-affix-positions.ts": 3752, + "3023-string-affix-position-coercion.js": 3717, + "3024-string-number-narrow-for-in.ts": 4025, + "3025-string-search-position-coercion.js": 2818, + "3026-array-last-index-of.js": 4346, + "3027-array-last-index-of-records.ts": 2717, + "3028-string-search-dynamic-needle.js": 3694, + "3029-string-search-union-needle.js": 3379, + "303-break-continue.ts": 3648, + "3030-array-search-no-arg.js": 3591, + "3031-array-relative-index-coercion.js": 3587, + "3031-string-last-index-search-value.js": 4017, + "3032-string-search-value.js": 3564, + "3033-string-search-needle-coercion.js": 3378, + "3034-arguments-with-parameters.js": 3967, + "3035-string-positioned-search-value.js": 3417, + "3036-string-object-search-value.js": 3926, + "3037-number-nullish-conversion.js": 4703, + "3038-number-scalar-unions.ts": 3646, + "3039-string-repeat-count.js": 3646, + "304-compound-incdec.ts": 3722, + "3040-string-prototype-call.js": 4670, + "3041-string-prototype-object-call.js": 3431, + "3042-string-padding-coercion.js": 3284, + "3043-string-split-arguments.js": 3505, + "3044-array-slice-splice-positions.js": 3592, + "3045-array-indexed-mutation.js": 3564, + "3046-array-indexed-ref-identity.ts": 4051, + "3047-object-prototype-tag.js": 4202, + "3048-object-own-prototype.ts": 4672, + "3049-array-flat-depth.ts": 3327, + "305-truthiness.ts": 3686, + "3050-array-splice-insert.ts": 4238, + "3051-array-join-default.ts": 3649, + "3052-array-construction.ts": 5275, + "3053-array-construction-js.js": 4051, + "3054-dynamic-abort-record.ts": 31946, + "3055-default-builtin-nodenext/main.ts": 3742, + "3056-default-builtin-bundler/main.ts": 3900, + "3057-default-builtin-nodenext-dynamic/main.ts": 3548, + "3058-optional-array-chain-join.ts": 4351, + "3059-arguments-property-names.ts": 3823, + "3061-concurrent-fiber-stacks.ts": 4696, + "3062-runtime-optional-record-guards.ts": 4448, + "3063-runtime-optional-class-guards.ts": 4574, + "3064-installed-entry-imports/main.ts": 3681, + "3065-installed-entry-js/main.js": 3134, + "3066-source-debugging/main.ts": 3285, + "3067-cjs-function-export-require/main.cjs": 3758, + "3068-debug-variables/main.ts": 3691, + "3068-url-checked-identity.ts": 3668, + "3069-set-checked-seed.js": 3693, + "3069-tuple-spread.ts": 4624, + "3070-checked-object-accessors.js": 4486, + "3070-collection-views.ts": 3364, + "3071-checked-specialization-narrowing.js": 3480, + "3071-map-contextual-record-seeds.ts": 3949, + "3072-optional-union-receivers.ts": 5187, + "3072-weak-process-streams.js": 3596, + "3073-optional-callable-module.js": 2912, + "3073-union-keyed-reads.ts": 4086, + "3074-discriminated-intersections.ts": 3579, + "3075-recursive-contextual-literals.ts": 4053, + "3076-nullish-record-defaults.ts": 4277, + "3077-optional-union-array-reads.ts": 3951, + "3078-forward-mutable-captures.ts": 4480, + "3079-forward-mutable-tdz.ts": 4237, + "3080-exhaustive-never-bindings.ts": 3901, + "3081-recursive-array-destinations.ts": 4116, + "3082-forward-write-unwind.ts": 3019, + "3083-set-string-seed.ts": 4323, + "3084-record-own-membership.ts": 4601, + "3085-conditional-record-construction.ts": 4376, + "3086-error-constructor-options.ts": 4642, + "3087-error-options-lifetime.ts": 3925, + "3088-array-wide-callbacks.ts": 4497, + "3089-array-find-narrowing.ts": 4974, + "3090-json-discriminated-records.ts": 4438, + "3091-json-recursive-discriminants.ts": 5400, + "3092-number-union-predicates.ts": 3730, + "3093-error-option-data.ts": 2865, + "3094-json-replacer-traversal.ts": 4373, + "3095-json-reviver-traversal.ts": 4032, + "3096-json-callback-nonfinite.ts": 3197, + "3097-json-callback-reentrancy.ts": 3379, + "3098-json-callback-space.ts": 3597, + "3099-json-callback-functions.ts": 4206, + "3100-json-callback-holder.js": 4588, + "3101-json-callback-bytes.ts": 4349, + "3102-json-unknown-fields.ts": 3200, + "3103-scalar-record-nested-control-flow.ts": 4214, + "3104-native-analysis-tables-loops.ts": 2623, + "3105-nullable-collections.ts": 4138, + "3106-mixed-insertion-spreads.ts": 3715, + "3107-nullable-collection-lifetimes.ts": 4148, + "3108-for-await-sync-arrays.js": 6166, + "3108-identity-map-keys.ts": 4867, + "3109-destructuring-unknown-defaults.js": 4021, + "3109-identity-union-collections.ts": 5097, + "3110-builtin-error-families.ts": 3559, + "3110-identity-collection-mutation.ts": 3934, + "3111-identity-collection-cycles.ts": 3848, + "3112-union-switch-control-flow.ts": 3478, + "3113-union-array-removal.ts": 4714, + "3114-union-record-field-write.ts": 3240, + "3115-zlib-static-compression-levels.ts": 4206, + "3116-sequence-expression-lifetimes.ts": 4356, + "3117-unknown-switch-control-flow.ts": 3816, + "3118-recursive-union-spread.ts": 4372, + "3119-runtime-optional-spread.ts": 4825, + "3120-dynamic-property-descriptors.js": 3522, + "3120-generator-method-loop-bindings.ts": 4192, + "3120-ir-nonfinite-numbers.ts": 4200, + "3121-compound-assignment-values.js": 3684, + "3121-dynamic-accessor-descriptors.js": 4951, + "3122-dynamic-delete-descriptors.cjs": 4063, + "3122-dynamic-delete-descriptors.js": 3650, + "3122-js-async-class-methods.js": 4320, + "3123-destructured-global-tdz.js": 3748, + "3124-array-prototype-borrow.js": 4580, + "3125-regex-global-match.ts": 2619, + "3126-js-number-radix/main.ts": 4047, + "3127-spawn-runtime-options.ts": 4379, + "3128-regex-last-index.ts": 4682, + "3129-js-token-union/main.ts": 4567, + "3130-child-generic-streams.ts": 4888, + "3131-child-rest-listeners.js": 2682, + "3132-child-generic-stream-completion.ts": 9689, + "3133-text-decoder-streaming.ts": 21112, + "3134-fs-vectors.ts": 3917, + "3135-fs-file-handle-controls.ts": 5050, + "3136-fs-file-handle-options.ts": 5320, + "3137-fs-vector-callbacks.cjs": 5540, + "3138-array-large-storage.ts": 6344, + "3139-regex-native-deep-alternatives.ts": 31598, + "3140-array-dense-access.ts": 6506, + "3141-map-string-key-hash.ts": 4564, + "3150-integer-remainder.ts": 4200, + "3151-array-push-writes.ts": 4614, + "3170-number-conversion-fast-paths.ts": 4996, + "3171-method-census-data-writes.ts": 4891, + "400-fib.ts": 4470, + "401-mutual-recursion.ts": 3443, + "402-string-functions.ts": 3554, + "403-void-and-params.ts": 2749, + "4030-runtime-object-truthiness.ts": 2971, + "4031-event-emitter-long-tuples.ts": 3712, + "4032-inline-rc-fast-paths.ts": 6866, + "404-rc-stress.ts": 3585, + "4040-adapted-function-identity.ts": 3063, + "4041-adapted-function-properties.ts": 4165, + "4042-object-is-union-subclass.ts": 3846, + "4043-nonnull-missing-element.ts": 3736, + "4044-adapted-callback-modules/main.ts": 4121, + "4045-optional-element-projections.ts": 4159, + "4046-captured-parameter-values.ts": 3178, + "4047-captured-parameter-rebinding.ts": 4100, + "405-params-optional.ts": 3985, + "406-params-defaults.ts": 3592, + "4060-cycle-shared-instance/main.ts": 3695, + "4060-stack-union-reads.ts": 5003, + "4061-cycle-evaluation-order/main.ts": 3985, + "4061-nullable-ref-fields.ts": 7201, + "4062-cycle-tdz-read/main.ts": 3866, + "4063-cycle-hoisted-calls/main.ts": 3773, + "4064-cycle-classes-after-init/main.ts": 3673, + "4065-cycle-init-throws/main.ts": 3693, + "4066-cycle-top-level-tdz/main.ts": 3937, + "4067-dynamic-import-cycle-tdz/main.ts": 4237, + "407-params-rest.ts": 4125, + "408-params-ctors-inheritance.ts": 3692, + "4080-optional-read-presence-tests.ts": 3038, + "4080-string-index-bounds.ts": 3844, + "4081-hoisted-function-tdz.ts": 3262, + "4081-string-index-unproven.ts": 4125, + "4082-hoisted-function-tdz-uncaught.ts": 2818, + "4083-dynamic-import-failure/main.ts": 3160, + "4084-record-optional-field-copies.ts": 5146, + "4085-generator-loop-close.ts": 4113, + "4086-optional-capture-defaults.ts": 3684, + "4088-class-static-tdz.ts": 3477, + "4089-class-wrapper-tdz.js": 2771, + "409-params-async-generics.ts": 4030, + "4090-computed-key-tdz.js": 3578, + "4091-class-evaluation-deferred.ts": 4329, + "410-params-rc-stress.ts": 4376, + "4140-array-callback-split-visit.ts": 7471, + "4141-array-callback-ambient-receiver/main.ts": 3909, + "4142-array-callback-factories.ts": 3472, + "4143-union-refinement-intersection-arms.ts": 3347, + "420-dead-strip-modules/main.ts": 3742, + "4290-acyclic-immutable-trees.ts": 4974, + "4291-acyclic-constructor-escapes.ts": 4252, + "4292-acyclic-readonly-bypass.ts": 4530, + "4293-acyclic-dynamic-writes.ts": 4090, + "4294-console-line-sizes.ts": 7343, + "4295-console-template-parts.ts": 3542, + "4296-console-glued-long-parts.ts": 5181, + "4410-inline-object-allocation.ts": 4560, + "4411-nullable-ref-values.ts": 6207, + "4412-nullable-record-values.ts": 5237, + "4413-cycle-old-late-death.ts": 5172, + "4413-nullable-null-and-undefined.ts": 4068, + "4414-cycle-old-weak-keys.ts": 4401, + "4414-nullable-string-values.ts": 7453, + "4415-identity-borrowed-operands.ts": 3629, + "4415-nullable-container-values.ts": 5776, + "4431-exception-pending-contexts.ts": 4992, + "4432-checked-downcast-failures.ts": 4520, + "4451-int32-field-storage.ts": 4554, + "4452-int32-field-dynamic-writes.ts": 4987, + "4453-int32-closed-locals.ts": 4516, + "4454-int32-field-reflection-reads.ts": 3494, + "4455-live-view-reads-without-stores.ts": 4871, + "4471-unassigned-field-reads.ts": 3438, + "4476-string-ascii-header-fact.ts": 4141, + "4477-buffer-write-ascii-runs.ts": 4249, + "4478-string-large-index-reads.ts": 4215, + "4481-array-optional-push.ts": 3757, + "4482-instanceof-static-class-optional.ts": 3228, + "4483-array-splice-statement.ts": 4359, + "4484-array-length-reset.ts": 3824, + "4485-array-splice-optional-item.ts": 4447, + "4486-array-field-element-borrows.ts": 4170, + "4487-array-literal-optional-values.ts": 3597, + "4520-optional-guard-narrowing.ts": 4519, + "4521-array-callback-element-presence.ts": 6504, + "4522-captured-parameter-lifetimes.ts": 3501, + "4523-array-pop-removal.ts": 4310, + "4524-array-callback-supertype-params.ts": 4795, + "4541-nullable-wrap-borrows.ts": 4219, + "4542-preserving-call-borrows.ts": 4390, + "4543-walk-borrowed-locals.ts": 4424, + "4544-checked-cast-aliases.ts": 4017, + "4545-borrowed-returns.ts": 5010, + "4546-rebound-borrowed-params.ts": 4038, + "4560-field-store-borrowed-receivers.ts": 4292, + "4561-virtual-borrowed-parameters.ts": 3188, + "4562-string-self-concat-move.ts": 3258, + "4563-array-read-projection-receivers.ts": 4193, + "4564-literal-choice-strings.ts": 4376, + "4568-for-of-hole-elements.ts": 4040, + "4569-shorthand-missing-elements.ts": 5489, + "4570-map-lookup-default-record.ts": 4379, + "4591-weak-keys-union-records.ts": 3376, + "4592-cycle-const-from-import/main.ts": 3235, + "4593-weak-keys-empty-objects.ts": 4125, + "4594-union-class-field-mixed-types.ts": 6642, + "4595-union-class-field-optional-receiver.ts": 3958, + "4596-error-subclass-int-fields.ts": 3809, + "4596-tdz-nullable-forward-capture.ts": 5432, + "4597-callback-field-method-name.ts": 4265, + "4598-live-array-ref-element-access.ts": 9798, + "4598-map-set-clear-reuse.ts": 5772, + "4598-os-available-parallelism.ts": 3841, + "4598-publish-constructor-stores.ts": 4373, + "4599-construction-only-field-borrows.ts": 4185, + "4600-construction-only-fields-dynamic-writes.ts": 3870, + "4601-cycle-holders.ts": 3436, + "4602-constructor-escape-order.ts": 4107, + "4610-array-ext-dyn-refresh.ts": 4200, + "4620-optional-chain-borrowed-receivers.ts": 3633, + "4621-edge-preserving-callees/main.ts": 4459, + "4630-contract-int32.ts": 3693, + "4630-reference-write-call-arguments.ts": 3005, + "4631-contract-nothrow.ts": 3977, + "4631-reference-write-aliases.ts": 4000, + "4632-contract-immutable.ts": 4206, + "4632-reference-write-loops-and-walks.ts": 3622, + "4633-contract-program-lifetime.ts": 4928, + "4633-reference-write-callbacks-returns.ts": 4472, + "4634-contract-program-lifetime-publish.ts": 58146, + "4634-optional-element-borrowed-returns.ts": 3892, + "4640-bitwise-identity-ranges.ts": 3488, + "4641-nothrow-try-catch.ts": 3941, + "4642-acyclic-contract.ts": 4488, + "4650-stale-property-narrowing.ts": 5393, + "4651-map-string-get-entry.ts": 4850, + "4652-stale-closure-binding-narrowing.ts": 4646, + "4660-typed-rest-spread-forwarding.ts": 3964, + "4671-scoped-array-read-borrows.ts": 4659, + "4690-cycle-bypass-long-lived.ts": 6611, + "4691-publish-constructor-self-alias.ts": 32098, + "4692-borrowed-result-mutating-callees.ts": 4121, + "4720-cold-throw-paths.ts": 3462, + "4721-integer-induction-numbers.ts": 4315, + "4730-touint32-large-magnitudes.ts": 4331, + "4731-string-mixed-ascii-slices.ts": 4955, + "4732-buffer-write-utf16le-runs.ts": 4567, + "4733-typed-array-read-compares.ts": 4680, + "4750-map-string-absent-filter.ts": 3842, + "4751-string-search-multibyte-needles.ts": 4006, + "4795-published-untyped-member-reads.ts": 3280, + "4806-uint32-loop-accumulators.ts": 4561, + "4810-union-identity-retags.ts": 35042, + "4811-union-retag-checked-cast.ts": 4067, + "4812-int32-wrapping-sums.ts": 5061, + "4813-typed-array-read-equality-bindings.ts": 6041, + "4820-sort-comparator-lent-arguments.ts": 5459, + "4821-callback-lent-arguments.ts": 5557, + "4822-stable-capture-reads.ts": 4662, + "4823-array-store-receivers.ts": 3343, + "4830-typed-teardown-chains.ts": 4609, + "4831-cycle-bypass-probe-windows.ts": 6532, + "4840-array-hole-free-prefix.ts": 5275, + "4860-int32-local-storage.ts": 4493, + "4870-array-pipeline-fusion.ts": 9864, + "4871-array-pipeline-analytics.ts": 5983, + "4872-array-pipeline-temporaries.ts": 10585, + "4875-stream-consumers-array-buffer.ts": 5489, + "4876-array-buffer-inspect.ts": 4454, + "4880-await-call-turn-order.ts": 4340, + "4881-await-call-exceptions.ts": 3334, + "4882-await-call-request-chain.ts": 4240, + "4883-await-values-and-hops.ts": 3792, + "4884-await-call-unhandled-sibling.ts": 4171, + "4885-await-call-checkpoints.ts": 4125, + "4890-regex-literal-sites.ts": 3489, + "4891-regex-plain-text-patterns.ts": 3217, + "4892-regex-exec-read-captures.ts": 3864, + "4900-bigint-division-cross-check.ts": 4497, + "4900-console-instances.ts": 4959, + "4901-bigint-radix-text.ts": 4256, + "4901-console-instance-errors.ts": 2879, + "4902-bigint-compound-assign.ts": 3676, + "4903-bigint-fixed-width.ts": 3178, + "4904-bigint-large-products.ts": 3926, + "4905-bigint-fixed-width-fusion.ts": 5267, + "4906-bigint-small-value-trees.ts": 5678, + "4907-bigint-random-trees.ts": 7288, + "4910-hole-free-prefix-upkeep.ts": 4535, + "4920-string-literal-switch.ts": 4267, + "4930-typed-record-reflection.ts": 5782, + "4931-typed-data-generic-walks.ts": 6195, + "4932-typed-json-unknown.ts": 4431, + "4940-async-return-adoption.ts": 4857, + "4941-async-return-adoption-try.ts": 4613, + "4942-async-return-adoption-values.ts": 6005, + "4943-async-return-adoption-interleaved.ts": 3930, + "4950-regex-compiled-captures.ts": 5282, + "4951-regex-compiled-last-index.ts": 4338, + "4952-regex-compiled-anchors-classes.ts": 4435, + "4953-regex-compiled-backtracking.ts": 5380, + "4954-regex-log-report.ts": 5479, + "4955-regex-compiled-differential.ts": 20554, + "4970-int32-call-abi.ts": 4776, + "4980-generator-early-exit-finally.ts": 4365, + "4981-generator-delegation-iterables.ts": 5570, + "4982-generator-sent-values.ts": 4472, + "4983-generator-reuse-iterables.ts": 2952, + "4984-generator-exceptions.ts": 4164, + "4985-generator-lazy-pipeline.ts": 5491, + "4986-generator-default-channels.ts": 3496, + "4987-generator-closures-methods.ts": 4260, + "4988-generator-async-interplay.ts": 4288, + "4989-generator-step-drives.ts": 4530, + "4990-lone-surrogates.ts": 4508, + "4991-lone-surrogate-halves.ts": 4237, + "4992-lone-surrogate-search.ts": 4305, + "4993-lone-surrogate-json.ts": 4527, + "4994-lone-surrogate-uri.ts": 4891, + "4995-lone-surrogate-regex.ts": 4198, + "4996-lone-surrogate-stdio.ts": 3963, + "4997-lone-surrogate-stdout-patch.js": 4611, + "4998-lone-surrogate-buffers.ts": 4299, + "4999-lone-surrogate-io.ts": 4020, + "500-array-basics.ts": 4115, + "501-array-push-pop.ts": 4134, + "5010-lifetime-region-generations.ts": 4583, + "5011-lifetime-region-outside-references.ts": 3728, + "5012-lifetime-region-shapes.ts": 4853, + "5013-lifetime-region-async.ts": 5075, + "5014-lifetime-region-nesting.ts": 4021, + "5015-lifetime-region-publish.ts": 41998, + "5016-lifetime-region-weak-keys.ts": 3440, + "5017-lifetime-region-cycles.ts": 3981, + "5018-lifetime-region-hierarchies.ts": 5065, + "5019-lifetime-region-values.ts": 4354, + "502-array-for-of.ts": 3573, + "5020-lifetime-region-large.ts": 6813, + "5021-lifetime-region-opaque-holders.ts": 3165, + "5022-lifetime-region-workers.ts": 44993, + "5023-lifetime-region-await.ts": 5986, + "5024-lifetime-region-await-forms.ts": 5123, + "503-array-functions.ts": 4084, + "504-array-rc-stress.ts": 3791, + "5040-promise-all-race-turns.ts": 5348, + "5041-promise-all-turns.js": 4084, + "5042-async-generator-return-promise.ts": 4929, + "5043-async-generator-return-forms.ts": 3900, + "5045-generator-delegation-typed-next.ts": 4863, + "5046-generator-delegation-return-throw.ts": 4938, + "5047-generator-delegation-iterables-typed.ts": 4203, + "5048-generator-delegation-async.ts": 4733, + "5049-generator-delegation-edges.ts": 5078, + "5050-inherited-in-membership.ts": 4630, + "5051-typed-record-prototypes.ts": 4286, + "5052-class-for-in-unknown.ts": 4449, + "5053-json-replacer-arrays.ts": 4672, + "5054-required-field-delete.ts": 3969, + "5055-object-create-record-literal.ts": 3612, + "5056-generator-in-unknown.ts": 3544, + "5060-child-fork-exit-after-messages/main.ts": 3945, + "5061-child-fork-local-disconnect/main.ts": 3909, + "5062-child-fork-message-before-eof/main.ts": 4129, + "5065-global-increment-initializers.ts": 3769, + "5066-global-compound-updates.ts": 4136, + "5067-global-updates-in-functions.ts": 3795, + "5068-global-var-let-const-updates.ts": 3571, + "5069-global-update-modules/main.ts": 3587, + "5070-optional-read-bindings.ts": 3671, + "5071-optional-chain-scalars.ts": 4013, + "5072-optional-nullish-ternary.ts": 4374, + "5073-optional-results.ts": 4392, + "5074-optional-pop-shift.ts": 3500, + "5075-optional-reads-unchecked/main.ts": 3399, + "5076-optional-escapes.ts": 4284, + "5080-boolean-array-storage.ts": 10145, + "5081-boolean-array-dynamic-views.ts": 5152, + "5085-promise-allsettled-turns.ts": 5572, + "5086-promise-any-turns.ts": 4418, + "5087-promise-allsettled-any-dyn.js": 6479, + "5088-promise-combinator-thenables.js": 3786, + "5089-promise-settled-records.ts": 4701, + "5090-generator-finished-result-value.ts": 4294, + "5091-generator-delegation-arrays-strings.ts": 4885, + "5092-generator-delegation-sets-maps.ts": 3752, + "5095-console-count-group.ts": 4618, + "5096-console-assert-dir.ts": 5191, + "5097-console-table.ts": 3751, + "5098-console-time-warnings.ts": 9353, + "5099-console-methods-dynamic.cjs": 4255, + "510-array-map-filter-foreach.ts": 4191, + "511-array-indexof-includes.ts": 3499, + "5110-var-hoisting-early-reads.ts": 3823, + "5111-var-hoisting-closures-classes.ts": 4157, + "5112-var-hoisting-function-scope.ts": 3874, + "5113-tdz-let-const-class.ts": 3814, + "5114-var-hoisting-js.js": 3818, + "5115-regex-replace-compiled.ts": 3620, + "5116-regex-capture-reads.ts": 2873, + "5117-regex-log-report-spans.ts": 4784, + "5118-regex-replace-char-chains.ts": 3663, + "512-array-join-chains.ts": 2771, + "5120-frame-records.ts": 3939, + "5121-frame-objects.ts": 2783, + "5122-frame-result-slots.ts": 3197, + "5123-frame-reassigned.ts": 3173, + "5124-frame-objects-control.ts": 3904, + "5125-frame-mutating-methods.ts": 3799, + "5126-frame-returned-params.ts": 3813, + "5127-frame-loop-bindings.ts": 4488, + "513-array-methods-rc-stress.ts": 3775, + "5130-event-target-dispatch.js": 6111, + "5131-event-target-listener-errors.js": 4456, + "5132-event-target-typed.ts": 7166, + "5133-abort-signal-event-target.ts": 23098, + "5134-events-error-monitor.ts": 4010, + "5135-event-target-warnings.js": 31124, + "5136-events-error-monitor-string-name.ts": 4008, + "5137-events-error-monitor-computed-name.js": 4468, + "5138-events-error-monitor-shared-listener.ts": 3052, + "5139-event-target-listener-throw.ts": 4657, + "514-array-find-some-every.ts": 3980, + "5140-os-host-facts.ts": 3296, + "5141-os-constants.ts": 4894, + "5142-path-parse-format.ts": 4155, + "5145-path-matches-glob-basics.ts": 3777, + "5146-path-matches-glob-braces.ts": 5827, + "5147-path-matches-glob-extglob.ts": 4341, + "5148-path-matches-glob-classes.ts": 2888, + "5149-path-matches-glob-win32.ts": 4096, + "515-array-flatmap.ts": 4332, + "5150-small-array-inline-slots.ts": 3637, + "5155-cycle-header-types.ts": 43009, + "516-array-reduce.ts": 4514, + "5160-field-callback-receiver.ts": 4758, + "5161-field-callback-receiver-escape.ts": 3837, + "5162-field-method-reference-receiver.ts": 4262, + "5163-field-callback-receiver.cjs": 5679, + "5164-worker-field-callback-receiver.ts": 38682, + "5165-interface-method-dispatch.ts": 4568, + "5166-interface-method-values.ts": 5588, + "5167-interface-method-order.ts": 5287, + "5168-interface-method-hierarchy.ts": 6196, + "5169-interface-method-chains.ts": 4139, + "517-array-hof-index-args.ts": 4188, + "5170-string-scan-eviction.ts": 3592, + "5171-lone-surrogate-replace-seams.ts": 3960, + "5175-forin-typed-as-unknown.ts": 4247, + "5176-object-keys-typed-as-unknown.ts": 3688, + "5177-forin-dynamic-objects.ts": 4079, + "5178-forin-keys-js.js": 3608, + "5179-forin-typed-shapes.ts": 4197, + "518-array-sort.ts": 4624, + "518-promise-void-union-callbacks.ts": 4051, + "5180-interface-arrays.ts": 3814, + "5181-interface-array-methods.ts": 11031, + "5182-interface-array-boundaries.ts": 3743, + "5183-interface-property-reads.ts": 4427, + "5184-interface-property-objects.ts": 3309, + "5185-util-inherits.cjs": 5164, + "5186-util-inherits.ts": 4876, + "5187-util-deprecate.cjs": 4074, + "5188-util-deprecate-flags.cjs": 4955, + "5189-util-deprecate.ts": 5071, + "519-array-from-length.ts": 4423, + "519-promise-union-await-values.ts": 3904, + "5190-util-callbackify.cjs": 7841, + "5191-util-callbackify.ts": 6629, + "5192-util-debuglog.cjs": 6718, + "5193-util-debuglog.ts": 4689, + "5194-process-emit-warning-tick.cjs": 3727, + "5195-object-entries-typed-as-unknown.ts": 5084, + "5196-object-values-typed-as-unknown.ts": 3864, + "5197-object-entries-dynamic-objects.ts": 4955, + "5198-object-entries-values-js.js": 4220, + "5199-object-entries-identity.ts": 3999, + "520-map-basics.ts": 3545, + "5200-array-sort-keyed-numbers.ts": 5325, + "5201-array-sort-keyed-records.ts": 7394, + "5202-array-sort-keyed-lookalikes.ts": 5009, + "5203-typed-array-sort-default.ts": 8431, + "5204-typed-array-sort-comparators.ts": 5119, + "521-map-number-keys.ts": 3823, + "5210-process-memory-usage.ts": 4235, + "5211-process-identity.ts": 3797, + "5212-perf-marks-measures.ts": 5056, + "5213-perf-timing-errors.ts": 4031, + "5214-perf-entry-inspect.ts": 4809, + "5215-perf-timing-validation.js": 6147, + "5216-perf-spread-arguments.js": 4892, + "5217-perf-spread-typed.ts": 4228, + "522-map-foreach.ts": 4028, + "5220-url-parse-warnings.ts": 3469, + "5221-url-parse-shapes.ts": 6083, + "5222-url-parse-hosts.ts": 5268, + "5223-url-parse-query.ts": 5608, + "5224-url-format-objects.ts": 5477, + "5225-url-format-whatwg.ts": 3013, + "5226-url-resolve.ts": 6250, + "5227-url-legacy-dependency/main.ts": 6988, + "5228-url-domain-conversion.ts": 4749, + "5229-url-legacy-errors.cjs": 6936, + "523-map-ref-values.ts": 4339, + "5230-inline-union-fields.ts": 4733, + "5231-inline-union-field-kinds.ts": 5128, + "5232-inline-union-fields-dynamic.ts": 4858, + "5233-inline-union-fields-shapes.ts": 3241, + "5234-inline-union-class-fields.ts": 3221, + "5235-inline-union-fields-publish.ts": 3389, + "5236-inline-union-unchecked-reads.ts": 4250, + "5237-inline-union-frame-objects.ts": 4148, + "524-map-cycles.ts": 2484, + "5240-event-target-subclass.ts": 7308, + "5241-event-subclass.ts": 5029, + "5242-event-target-subclass-hierarchy.ts": 4680, + "5243-event-target-subclass-dynamic.ts": 6118, + "5244-event-target-subclass.js": 4898, + "5245-event-target-subclass-signals.ts": 8806, + "5246-event-target-subclass-listener-throw.ts": 3474, + "5247-event-target-subclass-lifetimes.ts": 5918, + "5248-event-target-subclass-warnings.ts": 4004, + "5249-event-target-subclass-unconstructed.ts": 3498, + "525-map-rc-stress.ts": 3774, + "5250-cipher-aes-gcm.ts": 8740, + "5251-cipher-aes-cbc.ts": 42449, + "5252-cipher-aes-ctr.ts": 26060, + "5253-cipher-chacha20-poly1305.ts": 8385, + "5254-cipher-errors.js": 28463, + "5255-cipher-encodings.cjs": 25164, + "5256-cipher-deprecation.cjs": 45696, + "5257-cipher-vectors.ts": 7138, + "5258-cipher-handles.js": 24870, + "5259-cipher-chunked.ts": 7052, + "526-set-basics.ts": 3756, + "5260-record-unknown-identity.ts": 4341, + "5261-optional-field-identity.ts": 3817, + "5262-record-unknown-many.ts": 3331, + "527-set-foreach.ts": 4129, + "5270-url-parse-no-deprecation.cjs": 5103, + "5271-url-parse-throw-deprecation.cjs": 6761, + "5275-http-end-callback-order.ts": 4622, + "5276-style-text-hex-colors.cjs": 4317, + "5277-fs-read-file-buffer-option.cjs": 3338, + "5278-host-null-bytes.cjs": 64320, + "5279-search-params-null-init.cjs": 2979, + "528-set-seeded.ts": 2529, + "5285-blob-construct.ts": 4818, + "5286-blob-readers.ts": 3080, + "5287-blob-inspect.ts": 3383, + "5288-blob-validation.js": 4818, + "5289-blob-read-order.ts": 4674, + "529-map-seeded.ts": 3233, + "5290-blob-dynamic.js": 4041, + "5295-readline-promises-question.ts": 3501, + "5296-readline-lines.ts": 5784, + "5297-readline-callback-events.cjs": 3985, + "5298-readline-abort.cjs": 10936, + "5299-readline-stdin.ts": 5881, + "530-record-arrays.ts": 4186, + "5300-stream-add-abort-signal.ts": 25846, + "5301-stream-add-abort-signal-errors.cjs": 8721, + "5302-stream-promises-options.ts": 13350, + "5303-stream-finished-callback-opts.cjs": 5087, + "5305-json-stringify-typed-arrays.ts": 6867, + "531-record-array-hofs.ts": 4059, + "5315-map-iterate-after-front-deletes.ts": 3530, + "5316-map-lru-eviction.ts": 3884, + "5317-map-iterate-while-mutating.ts": 4053, + "5318-set-iterate-after-deletes.ts": 4066, + "5319-map-iteration-values.ts": 4477, + "532-record-arrays-rc-stress.ts": 3905, + "5320-map-iterate-across-compaction.ts": 4243, + "5321-integer-closed-arithmetic-loops.ts": 3710, + "5321-json-parse-cycles.ts": 3383, + "5322-integer-variable-step-loops.ts": 3384, + "5322-json-stringify-parsed-trees.ts": 3838, + "5323-dyn-numeric-index-reads.ts": 3192, + "5323-int32-nonnegative-slot-facts.ts": 3774, + "5324-int32-initializer-locals.ts": 2663, + "5324-structured-clone-documents.ts": 4264, + "5325-record-boundary-returns.ts": 4089, + "5326-record-boundary-params.ts": 3793, + "5327-record-boundary-identity.ts": 3464, + "5328-record-boundary-open.ts": 4146, + "5329-record-boundary-recursion.ts": 3748, + "533-array-element-cycles.ts": 3379, + "5330-record-boundary-fields.ts": 2753, + "5331-record-boundary-methods.ts": 3914, + "5332-int32-narrowed-slot-facts.ts": 3588, + "5333-integer-guarded-while-counters.ts": 3896, + "5333-record-boundary-nullable-argument.ts": 3869, + "5334-fetch-mentions-without-calls.ts": 3676, + "5335-stream-operators-values.ts": 6378, + "5335-top-level-await-pending-exit-code.ts": 3377, + "5336-stream-operators-promise-timing.ts": 4282, + "5336-top-level-await-pending-exit-listener.ts": 3680, + "5337-dc-subscriber-throw-next-tick.cjs": 3947, + "5337-stream-operators-concurrency.ts": 8858, + "5338-js-tdz-function-element.js": 3181, + "5338-stream-operators-checks.cjs": 5284, + "5339-array-buffer-constructor.js": 4102, + "5339-stream-for-await-hops.ts": 5704, + "534-record-width-subtyping.ts": 3856, + "5340-readable-from-options.ts": 4031, + "5341-compound-any-operand.ts": 3905, + "5341-generator-callback-params.ts": 4564, + "5341-integer-recursion-boundaries.ts": 4375, + "5341-readable-from-dynamic.cjs": 5807, + "5342-compound-any-operand.cjs": 3381, + "5342-generator-scalar-channels.ts": 3638, + "5342-integer-recursion-stack-and-mutual.ts": 3513, + "5342-stream-compose.ts": 7562, + "5343-any-flow-compound.ts": 2631, + "5343-integer-recursion-array-index.ts": 4214, + "5343-iterator-result-records.ts": 2610, + "5343-stream-compose-edges.ts": 10326, + "5344-json-parse-undeclared-keys.ts": 5823, + "5344-stream-pipeline-timing.ts": 4092, + "5345-object-values-for-of-unknown.ts": 4269, + "5346-object-values-length-dynamic.ts": 3585, + "5347-object-values-loop-control.ts": 4004, + "5348-object-values-for-of-js.js": 4048, + "5349-object-entries-values-optional.ts": 3374, + "535-object-statics.ts": 4653, + "5350-object-values-wide-record.ts": 3999, + "5351-object-values-methods-index.ts": 3750, + "5352-final-field-loop-reads.ts": 4118, + "5353-captured-const-values.ts": 3887, + "5354-captured-const-tdz.ts": 3465, + "5355-captured-function-declarations.ts": 4030, + "5356-captured-tdz-ordering.ts": 4031, + "5357-init-only-module-bindings.ts": 3717, + "536-map-seed-array.ts": 3444, + "5360-array-sort-comparator-calls.ts": 3618, + "5361-array-sort-inconsistent-comparators.ts": 4844, + "5362-array-sort-comparator-throws.ts": 4204, + "5363-array-sort-comparator-writes.ts": 13543, + "5364-array-sort-union-and-boolean-elements.ts": 21219, + "5365-array-sort-dynamic-values.js": 3456, + "537-map-iter-drains.ts": 3991, + "5370-zlib-stream-roundtrip.ts": 4546, + "5371-zlib-stream-chunking.cjs": 6071, + "5372-zlib-stream-errors.cjs": 6496, + "5373-zlib-stream-options.cjs": 6767, + "5374-zlib-stream-flush-params.ts": 5113, + "5375-zlib-stream-promises.ts": 6129, + "5376-zlib-constants.cjs": 3393, + "5377-zlib-stream-backpressure.cjs": 4992, + "5378-zlib-sync-options.cjs": 4120, + "5379-zlib-callback-options.ts": 4524, + "538-map-set-for-of.ts": 3571, + "5390-interface-loop-element-lifetimes.ts": 3555, + "5391-interface-dispatch-hierarchies.ts": 5018, + "5392-interface-receiver-bindings.ts": 2922, + "5393-interface-array-holes.ts": 4247, + "5394-interface-implementers.ts": 4974, + "5395-locale-compare-ascii.ts": 3055, + "5396-locale-compare-latin.ts": 5056, + "5397-locale-compare-sorting.ts": 5049, + "540-tuples-basics.ts": 4222, + "5400-json-parse-typed-keys.ts": 5019, + "5405-buffer-arraybuffer-window.ts": 3206, + "5406-util-types-keys.ts": 3783, + "5407-http-header-field-limit.ts": 3678, + "5408-http-unread-request-end.ts": 4813, + "5409-http-held-request-body.ts": 4829, + "541-ref-array-json.ts": 4046, + "5410-inspect-class-values.ts": 3502, + "5411-inspect-class-hierarchies.ts": 3285, + "5412-inspect-dynamic-collections.ts": 3541, + "5413-inspect-class-values.cjs": 4035, + "5415-zlib-dynamic-inputs.cjs": 4054, + "542-union-element-arrays.ts": 4182, + "5420-readable-from-generators.ts": 5843, + "5421-readable-from-generators.cjs": 3752, + "5422-stream-async-push-wakeup.ts": 3679, + "5423-stream-end-and-eos-timing.ts": 4453, + "5424-stream-write-buffer-encoding.ts": 3204, + "5425-pipeline-generator-stage.ts": 3700, + "5426-pipeline-generator-errors.ts": 4597, + "5427-pipeline-generator-backpressure.ts": 4175, + "5428-pipeline-generator-stages.cjs": 9702, + "5429-pipeline-generator-buffers.ts": 6406, + "5430-dyn-number-string-boxes.ts": 3692, + "5435-crypto-hash-algorithms.ts": 4078, + "5436-crypto-hash-names.js": 3345, + "5437-crypto-hmac-algorithms.ts": 3794, + "5438-crypto-kdf-digests.ts": 3694, + "5439-crypto-kdf-callbacks.js": 3780, + "5440-crypto-hash-encodings.js": 4405, + "5441-crypto-hash-output-length.ts": 4754, + "5442-crypto-random-values.ts": 5239, + "5443-crypto-random-arguments.js": 4330, + "5444-crypto-timing-safe-equal.js": 2751, + "5445-crypto-secret-key-objects.ts": 4863, + "5445-stream-buffer-chunks.ts": 4296, + "5446-crypto-secret-key-errors.js": 4577, + "5446-stream-buffer-chunks-dynamic.js": 8609, + "5447-fs-readdir-order.ts": 3829, + "5448-fs-glob-patterns.ts": 3945, + "5449-fs-glob-options.ts": 5046, + "5450-fs-glob-validation.js": 3911, + "5451-fs-promises-glob.ts": 5150, + "5452-fs-glob-callback.ts": 4895, + "5455-power-of-two-remainder.ts": 3875, + "5456-remainder-large-integer-dividends.ts": 3066, + "5457-lcg-modulus.ts": 3468, + "5458-fractional-remainder.ts": 3767, + "5460-locale-compare-contractions.ts": 3556, + "5461-locale-compare-equivalents.ts": 4015, + "5462-locale-compare-probe-sweep.ts": 5293, + "5463-locale-compare-combining-letters.ts": 4084, + "5464-locale-compare-fractions.ts": 3409, + "5465-dyn-index-read-arrays.ts": 3798, + "5466-dyn-index-read-special.ts": 4384, + "5470-strip-vt-osc.cjs": 3494, + "5471-strip-vt-csi.cjs": 3770, + "5472-strip-vt-random.cjs": 3968, + "5473-strip-vt-unterminated.cjs": 4621, + "5474-strip-vt-surrogates.ts": 3567, + "5510-assert-error-properties.js": 5349, + "5511-assert-error-class.ts": 4329, + "5512-assert-error-options.js": 3469, + "5513-assert-deep-equal-loose.js": 4138, + "5514-assert-deep-equal-typed.ts": 3792, + "5515-assert-deep-strict-typed-messages.ts": 3601, + "5516-assert-deep-equal-edges.js": 4686, + "5517-assert-partial-deep-equal.js": 2953, + "5518-assert-partial-deep-typed.ts": 4685, + "5519-assert-partial-deep-typed-edges.ts": 4346, + "5520-assert-record-literal-failures.ts": 4088, + "5520-dyn-property-read-receivers.ts": 4057, + "5521-assert-empty-message.js": 3734, + "5521-dyn-property-read-keys.ts": 3703, + "5522-assert-throws-failure-properties.ts": 4256, + "5523-assert-class-options.js": 4903, + "5524-assert-class-skip-prototype.ts": 4411, + "5530-buffer-pool.ts": 4413, + "5531-buffer-pool-first-slab.ts": 5557, + "5532-buffer-pool-first-slab-untyped.mjs": 220640, + "5540-fs-callback-forms.cjs": 4591, + "5541-fs-stats-fields.cjs": 6904, + "5542-fs-promises-parity.cjs": 4673, + "5543-fs-promises-typed.ts": 5025, + "5544-fs-opendir.cjs": 4673, + "5545-fs-options-encoding.cjs": 5256, + "5546-fs-read-stream.cjs": 5295, + "5547-fs-write-stream.cjs": 6075, + "5548-fs-callback-arguments.cjs": 4982, + "5549-fs-callback-option-checks.cjs": 4309, + "5550-locale-compare-ascii-words.ts": 3614, + "5551-array-search-references.ts": 4656, + "5552-string-appends.ts": 3810, + "5553-string-append-char-code.ts": 4013, + "5554-fs-streams-typed.ts": 4873, + "5555-fs-callback-turns.cjs": 3708, + "5555-http-server-close-keep-alive.ts": 15618, + "5556-http-client-agent-connection.ts": 4177, + "5557-http-outgoing-header-values.ts": 4083, + "5558-http-incoming-duplicate-headers.ts": 2888, + "5559-http-expect-header.ts": 14863, + "5560-http-response-framing.ts": 11391, + "5561-http-max-header-size.ts": 4316, + "5562-https-verify-errors.ts": 4777, + "5563-http-keep-alive-timeout.ts": 17783, + "5564-http-request-signal.ts": 10735, + "5565-fs-dirent-untyped.mjs": 4337, + "5566-fs-dirent-dyn-boundaries/main.mjs": 4371, + "5567-fs-cpsync.ts": 4945, + "5568-fs-cp-errors.js": 4099, + "5569-fs-cp-symlinks.ts": 3686, + "5570-fs-cp-async.ts": 4176, + "5571-fs-cp-deep.ts": 5306, + "5585-record-results-inlined.ts": 3957, + "5595-net-ref-unref.ts": 5321, + "5600-dyn-cycle-self.ts": 3365, + "5601-dyn-cycle-mutual.ts": 4239, + "5602-dyn-cycle-arrays.ts": 3453, + "5603-dyn-cycle-identity.ts": 3497, + "5604-dyn-cycle-checks.ts": 3761, + "5605-dyn-cycle-containers.ts": 4084, + "5606-dyn-cycle-capsules.ts": 3095, + "5610-readable-from-sets-and-views.ts": 5921, + "5611-readable-from-class-iterables.ts": 3857, + "5612-readable-from-iterables.cjs": 5191, + "5613-readable-from-iterable-timing.cjs": 5131, + "5614-readable-from-iterable-errors.cjs": 4553, + "5615-next-tick-callback-phases.ts": 4347, + "5616-next-tick-callback-phases.cjs": 3259, + "5617-pipeline-function-ends.ts": 60581, + "5618-pipeline-function-ends-errors.ts": 13092, + "5619-pipeline-function-ends.cjs": 14768, + "5620-timers-promises-values.ts": 3726, + "5621-util-format-float.ts": 3395, + "5622-events-once.mjs": 3355, + "5623-events-once.ts": 4676, + "5624-timers-promises-unawaited.ts": 4420, + "5625-promisify-exec.ts": 8488, + "5626-promisify-forms.ts": 3100, + "5627-exec-callback.ts": 3311, + "5628-promisify-timers.ts": 3913, + "5629-promisify-stream.ts": 3357, + "5630-promisify-zlib.ts": 3392, + "5631-promisify-crypto.ts": 3727, + "5632-promisify-dns.ts": 5476, + "5644-net-socket-addresses.ts": 3677, + "5645-net-socket-callbacks.ts": 4544, + "5646-net-server-connections.ts": 3663, + "5647-net-is-ip.ts": 3569, + "5648-dns-lookup-forms.ts": 5746, + "5649-dns-service-servers.ts": 4846, + "5650-dns-lookup-errors-untyped.cjs": 4466, + "5651-tls-socket-protocol.ts": 30873, + "5652-http-client-trailer-overflow.ts": 3512, + "5653-net-socket-read-ahead.ts": 6212, + "5654-https-empty-servername.ts": 6322, + "5655-dgram-socket-options.ts": 5089, + "5656-dgram-option-states.ts": 4267, + "5657-net-reset-and-address.ts": 3588, + "5658-net-reset-dynamic.cjs": 4002, + "5659-net-blocklist-socketaddress.ts": 5090, + "5664-tls-client-identity.ts": 6340, + "5674-union-instanceof-array-arms.ts": 3943, + "5680-array-growth-after-copy.ts": 4581, + "5681-array-pop-and-length.ts": 4279, + "5682-publish-wide-objects.ts": 3376, + "5700-cycle-release-retained.ts": 3414, + "5701-cycle-release-old-edges.ts": 4210, + "5702-publish-candidate-buffers.ts": 3848, + "5703-lifetime-region-debug.ts": 2875, + "5704-publish-refused-restores-counts.ts": 3759, + "5710-map-number-keys-hashed.ts": 3686, + "5711-map-number-write-after-read.ts": 3642, + "5712-map-number-overwrite-at-growth.ts": 4057, + "5714-cycle-large-candidate-buffers.ts": 4303, + "5715-json-parse-fitted-tables.ts": 4861, + "5717-set-prototype-of-primitives.ts": 3977, + "5719-int32-fields-dynamic-operators.ts": 4013, + "5720-intern-table-basics.ts": 5183, + "5721-intern-table-values.ts": 4244, + "5722-intern-table-workers.ts": 37693, + "5723-intern-table-shared-types.ts": 25115, + "5724-intern-table-array-keys.ts": 43939, + "5725-intern-table-callbacks.ts": 3924, + "5726-intern-table-key-limits.ts": 3414, + "5740-atomics-operation-semantics.ts": 4541, + "5741-atomics-contended-counters.ts": 5176, + "5742-atomics-lock-ordering.ts": 44911, + "5743-atomics-wait-notify.ts": 25944, + "5744-atomics-ring-buffer.ts": 3295, + "5745-atomics-semaphore-stress.ts": 39641, + "5746-shared-bulk-operations.ts": 3506, + "5747-fs-stat-throw-if-no-entry.ts": 3747, + "5748-fs-stat-throw-if-no-entry-js.cjs": 4239, + "5752-string-number-concat.ts": 2903, + "5760-crypto-hash-stream.ts": 3720, + "5761-crypto-hash-stream-states.ts": 3947, + "5762-crypto-hash-stream.cjs": 3953, + "5763-crypto-sha-blocks.ts": 4280, + "5764-class-structural-view-writes.ts": 4359, + "5764-crypto-hmac-edges.cjs": 3178, + "5765-class-structural-view-identity.ts": 4251, + "5766-class-structural-view-callbacks.ts": 3950, + "5767-class-opaque-accessor-view.ts": 3507, + "5770-guarded-union-narrows.ts": 3945, + "5771-guarded-downcasts.ts": 3443, + "5772-guarded-catch-narrows.ts": 3695, + "5773-stale-narrowing-inherited.ts": 3758, + "5776-power-of-two-remainder-integer-path.ts": 3584, + "5780-readline-history-options.ts": 3008, + "5781-readline-history-options.cjs": 5419, + "5782-readline-terminal-editing.ts": 5323, + "5783-readline-terminal-completion.cjs": 5914, + "5784-readline-terminal-promises.ts": 8841, + "5785-readline-terminal-keys.ts": 7210, + "5786-readline-terminal-history.cjs": 5018, + "5787-readline-cursor-helpers.cjs": 4120, + "5788-readline-promises-readline.ts": 3931, + "5789-readline-cursor-pos.cjs": 10833, + "5790-readline-keypress-events.ts": 5781, + "5791-dyn-constant-key-read-sites.ts": 3910, + "5791-readline-keypress-interfaces.cjs": 10593, + "5792-json-parse-repeated-layouts.ts": 4520, + "5792-readline-keypress-listeners.ts": 3779, + "5793-worker-message-channel.ts": 6071, + "5794-worker-message-port-close-order.ts": 4996, + "5795-worker-message-port-batches.ts": 2995, + "5796-worker-message-channel.cjs": 3812, + "5797-worker-message-port-transfer.ts": 3633, + "5800-broadcast-channel.ts": 40203, + "5801-broadcast-channel.cjs": 5126, + "5802-broadcast-channel-workers.ts": 4593, + "5803-worker-environment-data.ts": 5183, + "5804-worker-environment-data.cjs": 3173, + "5805-worker-receive-message-parent-port.ts": 2696, + "5806-worker-resource-limits.ts": 3922, + "5807-worker-error-values.ts": 6807, + "5808-worker-unhandled-rejections.ts": 7138, + "5809-process-exit-and-rejections.cjs": 33202, + "5810-mock-method-records.ts": 6251, + "5811-mock-tracker-restore.ts": 6093, + "5812-dyn-box-async-fields.ts": 3948, + "5813-mock-timers-module.ts": 5361, + "5814-mock-timers-date.ts": 7472, + "5830-timers-promises-signal.ts": 4170, + "5831-util-types-brands.ts": 3902, + "5832-util-types-brands-dynamic.js": 4287, + "5833-url-search-params-iterators.ts": 3492, + "5834-url-search-params-iterators-dynamic.mjs": 3994, + "5835-util-format-integer-specifiers.ts": 3659, + "5836-url-search-params-tuple-pairs.ts": 3814, + "5837-util-format-json-circular.ts": 4225, + "5838-qs-stringify-bigint.ts": 5010, + "5839-timers-promises-scheduler.ts": 3897, + "5840-promise-with-resolvers-js.js": 3596, + "5841-json-typed-dyn-members.ts": 5082, + "5842-qs-parse-null-prototype.ts": 3325, + "5843-qs-parse-null-prototype-js.mjs": 3033, + "5844-date-unknown-values.ts": 4145, + "5845-groupby-null-prototype.ts": 4290, + "5846-events-esm-default-max.ts": 2759, + "5847-events-cjs-default-max.cjs": 3509, + "5849-class-view-observations.ts": 4659, + "5850-using-disposable-values.ts": 3072, + "5851-using-suppressed-error-values.ts": 3950, + "5852-using-disposable-values-js.js": 3905, + "5853-set-methods-map-arguments.ts": 3831, + "5854-array-from-async.ts": 5635, + "5855-array-from-async-js.js": 3433, + "5856-error-is-error.ts": 3928, + "5857-regexp-unicode-sets.ts": 3859, + "5858-disposable-stack.ts": 5135, + "5859-disposable-stack-js.js": 3801, + "5860-url-ipv4-hosts.ts": 4018, + "5870-worker-thread-names.ts": 7328, + "5871-worker-untransferable.cjs": 43661, + "5872-readline-positional-create-interface.mjs": 6166, + "5873-readline-promises-namespace.cjs": 3811, + "5874-worker-stdio-streams.ts": 50741, + "5875-worker-stdout-pipe.cjs": 50279, + "5879-worker-stdin.ts": 57033, + "5880-emitter-leak-warning-delivery.ts": 4319, + "5881-inspect-weak-collections.ts": 3631, + "5882-string-decoder-runtime-encoding.ts": 3362, + "5883-os-set-priority.ts": 3308, + "5884-inspect-layout-options.ts": 4849, + "5885-events-max-listener-helpers.ts": 3588, + "5886-inspect-dates.ts": 2966, + "5887-inspect-typed-arrays.ts": 3325, + "5888-inspect-sorted.ts": 3559, + "5889-timers-scheduler-signal.ts": 8928, + "5890-while-string-length-counters.ts": 3822, + "5892-buffer-write-utf16le-runs.ts": 3465, + "5900-float16-array.ts": 3954, + "5901-float16-array-js.js": 3925, + "5904-async-generator-completion.ts": 6639, + "5905-array-from-async-generator.ts": 4467, + "5906-array-from-async-generator-js.js": 4458, + "5907-regex-groups-match-rows.ts": 4698, + "5910-set-prototype-of-primitive-object-kinds.ts": 4445, + "5911-dyn-class-to-primitive.ts": 5410, + "5912-dyn-class-conversion-methods.ts": 4298, + "5913-prototype-type-error-messages.ts": 3454, + "5914-dyn-in-class-prototype-members.ts": 3792, + "5915-dyn-error-string-conversions.ts": 3851, + "5920-promise-try-args.ts": 3195, + "5921-promise-try-args-js.js": 3082, + "5922-matchall-groups-callbacks.ts": 5275, + "5923-matchall-groups-js.js": 4883, + "5924-js-literal-identity.js": 3065, + "5925-class-view-identity-observers.ts": 2685, + "5926-class-view-switch-js.js": 3057, + "5927-switch-object-identity.ts": 2661, + "5928-groupby-iterables.ts": 4500, + "5929-groupby-js.js": 3482, + "5930-contract-int32-arrays.ts": 4745, + "5930-method-census-asserted-number-keys.ts": 4815, + "5931-asserted-reads-keep-number-parameters.ts": 3015, + "5932-generic-class-observed-methods.ts": 5678, + "5933-class-fields-unknown-object.ts": 4834, + "5934-js-class-fields-property-order.js": 4883, + "5935-js-subclass-fields-and-element-calls.js": 4470, + "5936-checked-js-class-types.js": 4183, + "5937-override-narrowed-union-returns.ts": 3827, + "5938-object-literal-computed-keys-keep-methods.ts": 4019, + "5939-js-let-object-reassigned-wider.js": 4037, + "5940-callback-helper-specialization.ts": 4548, + "5941-callback-specialization-recursion.ts": 4448, + "5942-callback-specialization-throws.ts": 3443, + "5943-fields-read-before-assignment.ts": 4319, + "5944-js-fields-read-before-assignment.js": 3945, + "5945-local-class-observed-methods.ts": 4458, + "5946-nested-record-field-optional-writes.ts": 3537, + "5950-tuple-predicate-methods.ts": 4018, + "5951-result-never-widening.ts": 3970, + "5952-record-missing-keys.ts": 5020, + "5953-nan-coded-method-returns.ts": 2689, + "5955-any-promise-methods.js": 3182, + "5956-erased-generic-members.ts": 5824, + "5958-asserted-union-receiver.ts": 3206, + "5959-date-to-json.ts": 3819, + "5960-frame-records-own-references.ts": 3535, + "5960-generic-mapped-types.ts": 3052, + "5961-frame-spread-updates.ts": 3732, + "5962-frame-tuples.ts": 3372, + "5970-net-connect-host-name.ts": 3461, + "5971-buffer-chunks-to-string.ts": 4886, + "5972-net-set-encoding-listeners.ts": 4672, + "5973-large-closure-environment.ts": 5145, + "5974-typeof-module-exports.cjs": 3216, + "5975-zlib-class-values.ts": 4063, + "5990-worker-uncloneable.mjs": 4117, + "5991-worker-async-dispose.mjs": 40350, + "5992-worker-thread-name-lifetime.mjs": 47859, "5993-array-length-loop-resizing.ts": 4127, "5994-array-length-sparse-loops.ts": 2815, "5995-array-dense-loop-boundaries.ts": 4171, - "600-closures-basic.ts": 3477, - "601-closures-loops.ts": 2866, - "602-closures-identity-recursion.ts": 3704, - "6020-class-extends-function-constructor.js": 3671, - "6021-asserted-literal-union-arm.ts": 7200, - "603-closures-rc-stress.ts": 3096, - "604-closures-for-of.ts": 3045, - "605-closures-forward-capture-tdz.ts": 3323, - "700-classes-basic.ts": 2577, - "701-classes-composition.ts": 3154, - "702-classes-this-capture.ts": 2733, - "703-classes-rc-stress.ts": 3485, - "710-inheritance-basics.ts": 3238, - "711-inheritance-dispatch.ts": 3078, - "712-inheritance-instanceof.ts": 3534, - "713-inheritance-rc-stress.ts": 3301, - "720-accessors-basics.ts": 3158, - "721-accessors-eval-order.ts": 2971, - "722-accessors-inheritance.ts": 3316, - "723-accessors-rc-stress.ts": 3170, - "750-cycle-closure-box.ts": 2126, - "751-cycle-records-mutual.ts": 2363, - "752-cycle-classes.ts": 1960, - "753-cycle-owned-arrays.ts": 2692, - "754-cycle-external-ref.ts": 2903, - "755-cycle-async-promise.ts": 3043, - "756-cycle-inheritance.ts": 2972, - "757-cycle-cross-generation.ts": 2984, - "762-any-boundary.ts": 2786, - "764-any-async.ts": 3084, - "765-any-optional-chain.ts": 3008, - "766-any-union-boundary.ts": 3499, - "767-string-literal-keys.ts": 3514, - "768-any-uninitialized.ts": 3560, - "800-switch-basics.ts": 2767, - "801-switch-lazy-tests.ts": 2686, - "802-switch-loops.ts": 3125, - "803-switch-rc-stress.ts": 3547, - "804-switch-braced-blocks.ts": 2839, - "810-do-while.ts": 2218, - "820-multi-decl.ts": 3261, - "830-let-uninitialized.ts": 3097, - "900-records-basics.ts": 3422, - "901-records-eval-order.ts": 2695, - "902-records-functions-closures.ts": 3207, - "903-records-rc-stress.ts": 2631, - "904-records-optional-fields.ts": 2009, - "905-records-optional-rc-stress.ts": 2569, - "906-records-utility-types.ts": 3252, - "907-records-utility-generics.ts": 3311, - "908-records-index-signatures.ts": 3591, - "909-records-index-json.ts": 3947, - "910-records-index-rc-stress.ts": 3536, - "911-records-index-dot-access.ts": 3503, - "912-unknown-slots.ts": 3313, - "913-records-index-iteration.ts": 4350, + "600-closures-basic.ts": 3688, + "601-closures-loops.ts": 2905, + "602-closures-identity-recursion.ts": 3340, + "6020-class-extends-function-constructor.js": 3739, + "6021-asserted-literal-union-arm.ts": 3498, + "603-closures-rc-stress.ts": 2788, + "604-closures-for-of.ts": 3472, + "6041-error-cause-redeclared.ts": 4631, + "6042-regex-match-object-destructuring.ts": 3091, + "6043-string-index-narrowed-union.ts": 3627, + "605-closures-forward-capture-tdz.ts": 4043, + "6140-cjs-require-tdz-throws/main.js": 2989, + "6141-cjs-require-tdz-checked/main.js": 4062, + "6142-cjs-require-published-early/main.js": 5156, + "6143-cjs-require-json/main.js": 3050, + "6144-cjs-require-builtin-nested/main.js": 3329, + "6145-cjs-require-cycle/main.js": 4761, + "700-classes-basic.ts": 2717, + "701-classes-composition.ts": 3694, + "702-classes-this-capture.ts": 3151, + "703-classes-rc-stress.ts": 3285, + "710-inheritance-basics.ts": 2592, + "711-inheritance-dispatch.ts": 3301, + "712-inheritance-instanceof.ts": 3603, + "713-inheritance-rc-stress.ts": 2631, + "720-accessors-basics.ts": 2515, + "721-accessors-eval-order.ts": 3454, + "722-accessors-inheritance.ts": 3466, + "723-accessors-rc-stress.ts": 3570, + "750-cycle-closure-box.ts": 3720, + "751-cycle-records-mutual.ts": 2782, + "752-cycle-classes.ts": 3168, + "753-cycle-owned-arrays.ts": 3490, + "754-cycle-external-ref.ts": 3578, + "755-cycle-async-promise.ts": 3053, + "756-cycle-inheritance.ts": 2275, + "757-cycle-cross-generation.ts": 3630, + "762-any-boundary.ts": 3627, + "764-any-async.ts": 3271, + "765-any-optional-chain.ts": 2987, + "766-any-union-boundary.ts": 3659, + "767-string-literal-keys.ts": 3306, + "768-any-uninitialized.ts": 3041, + "800-switch-basics.ts": 3127, + "801-switch-lazy-tests.ts": 3237, + "802-switch-loops.ts": 3396, + "803-switch-rc-stress.ts": 3243, + "804-switch-braced-blocks.ts": 3060, + "810-do-while.ts": 3366, + "820-multi-decl.ts": 3412, + "830-let-uninitialized.ts": 2806, + "900-records-basics.ts": 2799, + "901-records-eval-order.ts": 3424, + "902-records-functions-closures.ts": 2868, + "903-records-rc-stress.ts": 3996, + "904-records-optional-fields.ts": 3692, + "905-records-optional-rc-stress.ts": 3288, + "906-records-utility-types.ts": 2706, + "907-records-utility-generics.ts": 2748, + "908-records-index-signatures.ts": 3143, + "909-records-index-json.ts": 3697, + "910-records-index-rc-stress.ts": 4050, + "911-records-index-dot-access.ts": 3683, + "912-unknown-slots.ts": 2923, + "913-records-index-iteration.ts": 4112, "914-records-from-entries.ts": 3768, - "915-unknown-tostring-eq.ts": 2630, - "916-unknown-bytes.ts": 3440, - "917-record-array-index-dot.ts": 3157, - "950-modules-basic/main.ts": 2848, - "951-modules-diamond/main.ts": 3198, - "952-modules-cross/main.ts": 3183, - "953-modules-default/main.ts": 3167, - "954-modules-reexport/main.ts": 2018, - "957-builtins-namespace.ts": 3430, - "960-generics-basics.ts": 3705, - "961-generics-recursion.ts": 2537, - "962-generics-closures.ts": 3548, - "963-generics-modules/main.ts": 2784, - "964-generics-rc-stress.ts": 3384, - "965-generics-async.ts": 2822, - "965-unions-retag.ts": 3386, - "966-unions-retag-rc-stress.ts": 2717, - "967-record-field-widening.ts": 2715, - "969-unions-arm-matrix.ts": 3012, - "970-unions-basics.ts": 2986, - "971-unions-switch.ts": 3685, - "972-unions-nested.ts": 3090, - "973-unions-rc-stress.ts": 3424, - "974-unions-modules/main.ts": 3121, - "975-unions-undefined.ts": 2840, - "976-unions-null.ts": 2783, - "977-unions-unit-rc-stress.ts": 3216, - "978-unions-nullish.ts": 3540, - "979-unions-optional-chaining.ts": 3197, - "980-exceptions-basics.ts": 3555, - "981-exceptions-values.ts": 3193, - "982-exceptions-rc-stress.ts": 2933, - "983-exceptions-control-flow.ts": 3085, - "984-exceptions-finally.ts": 3513, - "985-exceptions-call-chains.ts": 2381, - "986-exceptions-uncaught.ts": 2898, - "987-exceptions-result-unions.ts": 2879, - "990-process-basics.ts": 3199, - "991-process-exit.ts": 3081, - "992-fs-roundtrip.ts": 2369, - "993-fs-readdir.ts": 3082, - "994-fs-errors.ts": 3422, - "995-fs-uncaught.ts": 3294, - "996-fs-rc-stress.ts": 3471, - "997-fs-modules/main.ts": 2673, - "998-process-env.ts": 3051, - "abstract-property-dispatch.ts": 3176, - "arguments-arrow-capture.mjs": 3073, - "arguments-reexport/main.ts": 2672, - "array-argument-lifetimes-exits.ts": 3589, - "array-argument-lifetimes-mutation.ts": 3438, - "array-argument-lifetimes-strings.ts": 3059, - "array-argument-lifetimes-values.ts": 3883, - "array-buffer-conversions.js": 2989, - "array-buffer-storage.ts": 3822, - "array-checked-callback-results.mjs": 3408, - "array-checked-constructor.js": 3489, - "array-concat-widening.ts": 3866, - "array-deque-unshift.ts": 2667, - "array-element-compound-updates.ts": 5084, - "array-fill-unit-values.ts": 3524, - "array-from-checked.js": 4344, - "array-from-value.mjs": 3171, - "array-isarray-value/main.js": 2914, - "array-numeric-own-keys.ts": 3622, - "array-optional-number-write-index.ts": 2652, - "array-primitive-ordering.ts": 4006, - "array-queue-head-room.ts": 3597, - "array-read-helper-effects.ts": 3562, - "array-refined-storage.ts": 4149, - "array-sort-dense-effects.ts": 4479, - "array-sort-dense-values.ts": 4819, - "array-sort-holes-published.ts": 7708, - "array-sort-runs.ts": 7566, - "array-sort-runtime-comparator.ts": 6150, - "array-sort-unknown-comparator.ts": 2544, - "array-storage-transitions.ts": 3926, - "array-truncate-reuse.ts": 3660, - "async-backend-factory.mjs": 3134, - "async-local-typed-results.ts": 3527, - "atomics-integer-operations.ts": 4356, - "bigint-checked-casts.ts": 2554, - "bigint-checked-storage.js": 3784, - "bigint-union-conversion.ts": 3322, - "boxed-error-rethrows.mjs": 2897, - "buffer-codec-boundaries.ts": 3387, - "buffer-primitive-predicate.ts": 3237, - "builtin-prototype-method-values.mjs": 3628, - "byte-loop-bounds.ts": 3700, - "byte-number-pipeline.ts": 3420, - "byte-record-windows.ts": 3513, - "call-lifetimes-argument-order.ts": 3157, - "call-lifetimes-control-flow.ts": 3596, - "call-lifetimes-owned-boundaries.ts": 3515, - "call-lifetimes-projections.ts": 2258, - "call-lifetimes-union-values.ts": 3157, - "call-lifetimes-virtual-optionals.ts": 3774, - "callable-module-members.mjs": 3196, - "callable-properties.mjs": 3885, - "callable-property-cycles.js": 3532, - "callable-reexport/main.ts": 3427, - "captured-class-refinement.ts": 3597, - "catch-capture.ts": 2987, - "caught-class-identity.ts": 4072, - "caught-standalone-class.ts": 2672, - "caught-system-error-fields.ts": 3700, - "checked-addition.js": 3105, - "checked-any-addition.ts": 2239, - "checked-array-assignment.ts": 3049, - "checked-array-flat/main.ts": 3431, - "checked-bitwise/main.js": 3320, - "checked-builder-cycles.js": 2792, - "checked-byte-storage/main.ts": 3747, - "checked-callback-options.ts": 2687, - "checked-class-descriptors.mjs": 3712, - "checked-class-factory.mjs": 2771, - "checked-collection-iterators.ts": 3380, - "checked-collection-symbol-methods.ts": 2530, - "checked-dispatch-input-lifetimes.js": 3328, - "checked-increment/main.js": 3104, - "checked-inherited-fields.ts": 2621, - "checked-iterator-consumption.js": 4294, - "checked-numeric-arithmetic.js": 3111, - "checked-object-module-alias.js": 3420, - "checked-optional-calls.mjs": 3475, - "checked-promise-recovery.ts": 3214, - "checked-proxy-callback/main.ts": 2353, - "checked-record-constructor.ts": 3432, - "checked-renderer-defaults.js": 3283, - "checked-rest-function-adapters.js": 3083, - "checked-storage-transitions.js": 3622, - "checked-symbol-array.ts": 3310, - "checked-value-input-lifetimes.ts": 3545, - "class-accessor-returned-function.js": 3128, - "class-array-optional-return.ts": 2098, - "class-bracket-method-calls.js": 3772, - "class-brand-overload.js": 2492, - "class-callback-replacement.js": 4751, - "class-callback-storage.ts": 4435, - "class-checked-composites.ts": 2988, - "class-checked-upcast.ts": 3528, - "class-collection-insertion.ts": 3819, - "class-computed-presence.ts": 3069, - "class-computed-symbols.js": 4319, - "class-covariant-returns.ts": 2381, - "class-curried-factory.mjs": 4502, - "class-data-descriptors.js": 3422, - "class-factory-inherited-statics.mjs": 3137, - "class-factory-parameter-base.mjs": 3744, - "class-factory-record-base.mjs": 4712, - "class-factory-recursive-statics.mjs": 3419, - "class-factory-static-members.mjs": 3588, - "class-function-base/main.js": 3762, - "class-instance-constructor.js": 3074, - "class-interface-protocols.ts": 5102, - "class-interface-refinements.ts": 3720, - "class-json-checked.ts": 2934, - "class-local-function-base.mjs": 3255, - "class-method-spreads.ts": 4902, - "class-narrowed-views.ts": 3371, - "class-property-call-values.mjs": 4011, - "class-prototype-data.js": 3004, - "class-prototype-descriptor-copy.mjs": 3813, - "class-specialized-computed-base.mjs": 4267, - "class-static-data.js": 3151, - "class-subclass-assertions.ts": 3297, - "class-super-surplus-spread.mjs": 3182, - "class-symbol-accessors.ts": 3548, - "class-symbol-cache.mjs": 4032, - "class-value-constructor-exceptions.ts": 2673, - "closed-virtual-dispatch-modules/main.ts": 2555, - "closed-virtual-dispatch.ts": 3659, - "closure-nullable-union-return.ts": 3544, - "closure-union-locals.ts": 3476, - "collection-array-cycles.ts": 3864, - "collection-array-maps.ts": 4225, - "collection-array-missing.ts": 4159, - "collection-array-sets.ts": 4385, - "collection-copy-identities.ts": 2778, - "collection-data-unions.ts": 3634, - "collection-ingestion-mappers.ts": 3206, - "collection-ingestion-protocol/main.ts": 3833, - "collection-ingestion-references.ts": 3449, - "collection-ingestion.ts": 3258, - "collection-storage-copies.ts": 3108, - "collection-value-keys.ts": 4397, - "compound-field-receivers.ts": 3249, - "compound-presence-guards.ts": 2877, - "conditional-tuple-destructuring.ts": 2382, - "console-imports.cjs": 3167, - "console-native-value.js": 3394, - "const-enum-module-cycle/main.ts": 2006, - "constant-callback-dispatch.ts": 2991, - "constant-module-globals/main.ts": 2958, - "constant-number-remainders.ts": 3341, - "constructed-class-dispatch.ts": 2784, - "contextual-array-union-write.ts": 7276, - "contextual-return-layouts.ts": 3888, - "counted-loop-numbers.ts": 3637, - "counted-loop-storage.ts": 2691, - "crypto-hash-optional-input.ts": 3463, - "cycle-generations-long-lived.ts": 3441, - "cycle-growth-yield.ts": 3944, - "date-checked-native.js": 2845, - "declared-index-spread.ts": 4567, - "deep-reference-teardown.ts": 3926, - "default-undefined-parameters.ts": 3319, - "deferred-field-updates.ts": 3102, - "deferred-registry-many.ts": 3953, - "derived-numeric-updates.ts": 3389, - "destructure-call-assignment.js": 2983, - "destructure-inferred-row-defaults.js": 3512, - "destructure-union-arrays.ts": 2816, - "dynamic-function-descriptors.js": 3146, - "error-cause-writes.js": 3354, - "error-inherited-message.mjs": 3845, - "error-inherited-name.mjs": 2619, - "error-property-writes.mjs": 3158, - "error-prototype-tostring.js": 3672, - "error-stack-frames.ts": 3288, - "error-stack-limit.ts": 2624, - "error-tostring-overrides.ts": 3434, - "error-values-inspect.ts": 2196, - "exact-index-round-trip.ts": 3473, - "expression-runtime-values.ts": 3088, - "fiber-switch-stress.ts": 4040, - "fiberless-async-ordering.ts": 3692, - "fiberless-async-unhandled.ts": 2796, - "field-assignment-values.ts": 3175, - "file-handle-values.ts": 4245, - "file-read-storage.ts": 3850, - "file-url-percent-decoding.ts": 3346, - "final-field-borrows.ts": 4200, - "for-multiple-bindings.ts": 3350, - "for-multiple-lexical-bindings.ts": 2400, - "for-of-checked-iterator.js": 2766, - "for-of-subclass-elements.ts": 3269, - "forward-generic-signatures.ts": 3369, - "fresh-array-union-layout.js": 2566, - "frozen-checked-dictionaries.mjs": 3872, - "fs-native-realpath.ts": 3355, - "fs-null-byte-paths-js.cjs": 2643, - "fs-null-byte-paths.ts": 5975, - "fs-read-encodings.ts": 3730, - "fs-read-utf8-edges.ts": 4190, - "fs-read-utf8-handle-forms.ts": 3943, - "fs-remove-readonly.ts": 3417, - "fs-write-string-bytes-union.ts": 3274, - "function-apply-value.mjs": 3476, - "function-constructor-global.mjs": 3249, - "function-constructor-kinds/main.js": 3769, - "function-custom-prototype.js": 3876, - "function-custom-to-string.mjs": 3155, - "function-object-assign.js": 3527, - "function-own-prototype/main.js": 3460, - "generator-checked-protocol.ts": 2621, - "generator-checked-return.js": 3221, - "generator-custom-delegation/main.ts": 5126, - "generator-default-return-pattern.ts": 3182, - "generator-delegation-values.ts": 3197, - "generator-inferred-date.js": 3585, - "generator-mixed-checked-channels.ts": 3199, - "generator-untyped-consumer/main.ts": 3049, - "generic-base-specializations.ts": 3459, - "generic-binding-ownership.ts": 3288, - "generic-class-js-functions/main.ts": 2834, - "generic-class-recovery.ts": 3640, - "generic-namespace-factories/main.ts": 2618, - "generic-nullable-collections.ts": 3599, - "generic-pattern-bindings.ts": 3103, - "generic-record-index.ts": 3516, - "generic-visitor-void.ts": 3557, - "global-accumulator-loops.ts": 3302, - "global-error-subclasses.ts": 2292, - "global-runtime-probes.js": 3435, - "global-stored-probes.js": 2946, - "global-string-cache/main.js": 2368, - "global-symbol-cache/main.js": 2737, - "guarded-native-iterables.ts": 3541, - "heap-input-aliases.ts": 3756, - "heap-input-collections.ts": 4265, - "in-array-runtime-index.ts": 3804, - "indexed-assignment-values.js": 3469, - "indexed-assignment-values.ts": 2742, - "indexed-element-field-reads.ts": 3016, - "inferred-array-assignment-values.mjs": 2506, - "inferred-class-default.mjs": 2376, - "inferred-compound-values.mjs": 2280, - "inferred-conditional-class.mjs": 3032, - "inferred-error-fields.js": 3161, - "inferred-map-patterns.mjs": 3075, - "inferred-method-override.js": 3123, - "inferred-partial-destructuring.mjs": 3133, - "inferred-primitive-properties.mjs": 2211, - "inferred-record-return.mjs": 3298, - "inferred-recursive-record.mjs": 3328, - "inferred-undefined-field.mjs": 2721, - "input-lifetime-intervals.ts": 3442, - "input-lifetimes-modules/main.ts": 3449, - "instanceof-class-record-union.ts": 3488, - "integer-flow-arithmetic.ts": 3827, - "integer-loop-forms.ts": 3201, - "integer-view-control.ts": 3231, - "integer-view-numbers.ts": 3409, - "integer-view-storage.ts": 3994, - "intl-grapheme-conformance/main.ts": 3445, - "intl-grapheme.ts": 2906, - "iterator-typed-returns.ts": 4729, - "js-abort-portable.js": 27919, - "js-array-constructor.js": 3813, - "js-array-default-buffer.js": 2697, - "js-array-iterators.js": 3607, - "js-arrow-bind.cjs": 4009, - "js-buffer-callback-brand.cjs": 3617, - "js-callable-proxy.js": 4304, - "js-chained-native-results.mjs": 2822, - "js-checked-array-iterator.js": 3340, - "js-checked-array-reference.js": 3923, - "js-checked-number-negation.mjs": 2222, - "js-checked-sort-result.js": 3358, - "js-child-error-listener.cjs": 3277, - "js-cjs-callable-snapshots/main.cjs": 2133, - "js-class-added-parameters.js": 4197, - "js-class-checked-overrides.js": 3307, - "js-class-computed-fields.js": 2995, - "js-class-enumeration.js": 4227, - "js-class-field-accessor-override.js": 3739, - "js-class-fluent-overrides.js": 3694, - "js-class-late-method-values.js": 3823, - "js-class-member-dispatch.js": 2888, - "js-class-return-shapes.js": 4179, - "js-class-shadowed-methods.js": 3019, - "js-class-stored-method-receiver.js": 3182, - "js-class-subclass-properties.js": 4548, - "js-class-symbol-spread.cjs": 3271, - "js-computed-prototype-additions.js": 3652, - "js-constructor-returned-callable.js": 3080, - "js-constructor-spread.js": 3311, - "js-dataview-dispatch.js": 2584, - "js-declared-fields.cjs": 4858, - "js-default-listener-arguments.cjs": 2246, - "js-default-options/main.ts": 2763, - "js-deferred-field-initializers.js": 3209, - "js-deferred-registry-effects.js": 3112, - "js-derived-constructor-hoisting.js": 2435, - "js-dormant-array-write.js": 2504, - "js-dormant-overrides.js": 2426, - "js-expando-records.js": 2649, - "js-implicit-call-results.js": 2821, - "js-inferred-callback-exports/main.js": 4081, - "js-inferred-class-array-return.js": 3706, - "js-inferred-object-values.js": 2559, - "js-inherited-field-storage.js": 3955, - "js-inherited-parameter-abi.js": 2394, - "js-iterable-spread.js": 3349, - "js-loose-dynamic-primitives.js": 3110, - "js-map-object-seeds.js": 3942, - "js-member-increment.js": 4274, - "js-module-function-values.js": 3403, - "js-mutable-null-members.js": 2899, - "js-nested-native-descriptors.js": 3202, - "js-normalize-dispatch.js": 3282, - "js-nullish-inherited-fields.mjs": 2655, - "js-object-receiver-storage.js": 3904, - "js-object-returning-constructors.mjs": 2279, - "js-object-shared-arrays.js": 3613, - "js-omitted-typed-arguments.js": 2937, - "js-open-binding-writes.js": 2903, - "js-optional-class-fields.js": 3536, - "js-optional-member-call.js": 2325, - "js-primitive-union-addition.js": 3324, - "js-promise-all-values.js": 3699, - "js-promise-catch-handler.js": 3309, - "js-promise-finally-order.js": 3229, - "js-promise-pending-reactions.js": 3312, - "js-prototype-host-boundary.js": 3876, - "js-reflect-receivers.js": 2676, - "js-regex-record-captures.js": 3109, - "js-scalar-iterables.js": 3335, - "js-shared-method-dispatch.js": 3207, - "js-specialized-field-method.js": 3320, - "js-static-accessors.js": 3426, - "js-static-method-values.js": 3661, - "js-static-registries.cjs": 3718, - "js-super-accessor-initialization.js": 2555, - "js-uninitialized-native-fields.js": 3260, - "json-guarded-map-values.ts": 2760, - "json-output-bulk.ts": 3183, - "json-runtime-options.mjs": 3276, - "json-stringify-value.js": 3464, - "json-typed-parse-direct.ts": 4317, - "json-typed-parse-index-signatures.ts": 4012, - "json-typed-parse-optional-members.ts": 4377, - "json-typed-parse-union-members.ts": 4357, - "literal-switch-dispatch.ts": 2642, - "live-reference-shared-converters.ts": 5581, - "llvm-read-receiver-lifetime.ts": 3426, - "local-class-call-spreads.js": 3773, - "local-class-declaration.ts": 3293, - "local-class-evaluation.ts": 2921, - "local-class-inheritance.ts": 3273, - "local-class-lifetimes.ts": 3403, - "local-class-namespace/main.js": 4002, - "local-class-prototype-data.js": 3135, - "local-class-specialization.js": 3358, - "local-class-unknown.ts": 3386, - "local-class-values.ts": 3003, - "local-union-storage.ts": 3264, - "locale-compare-root-order.ts": 2579, - "logical-assignment-dynamic.js": 3596, - "logical-assignment-values.ts": 2685, - "logical-runtime-optional-record.ts": 3575, - "loop-reference-lifetimes.ts": 2726, - "map-checked-boundary/main.ts": 3371, - "map-checked-seed.js": 2974, - "map-get-set-fusion.ts": 3516, - "map-number-keys-dense.ts": 3426, - "map-read-lifetimes-exits.ts": 2870, - "map-read-lifetimes.ts": 2755, - "map-seeds-and-spreads.ts": 3696, - "map-typed-array-values.ts": 3121, - "math-function-values.js": 3080, - "missing-read-lambda-results.ts": 2590, - "missing-read-narrowed-storage.ts": 3503, - "missing-read-number-conversions.ts": 3648, - "module-byte-loops.ts": 3462, - "module-fallback-functions/main.js": 3043, - "narrowed-nullish-values.ts": 2912, - "native-any-timer-callback.ts": 1952, - "native-array-borrowed-find-last.js": 2795, - "native-array-borrowed-slice.js": 3711, - "native-array-copying-methods.js": 3069, - "native-array-fill-copywithin.js": 3430, - "native-array-frozen-noops.js": 3638, - "native-array-index-boundaries.js": 2630, - "native-array-integrity.js": 3935, - "native-array-length.js": 3375, - "native-array-named-properties.js": 3404, - "native-array-prototype/main.js": 3369, - "native-array-read-lifetimes.ts": 3688, - "native-array-reduce-find-last.js": 3264, - "native-array-search-from-index.js": 3220, - "native-array-splice-coercion.js": 3281, - "native-array-splice-flat.js": 3336, - "native-buffer-coercion.js": 2766, - "native-callback-dispatch.ts": 3779, - "native-class-array-boundaries.ts": 3630, - "native-class-cache.js": 3925, - "native-class-properties.cjs": 3940, - "native-class-property-cycles.cjs": 2802, - "native-class-property-order.cjs": 3298, - "native-class-type-predicates.ts": 3174, - "native-factory-records.js": 3338, - "native-method-values.js": 4444, - "native-method-values.ts": 3470, - "native-npm-imports/main.ts": 4028, - "native-object-descriptors.js": 2892, - "native-object-for-in-minimal.js": 2799, - "native-object-property-attributes.js": 3744, - "native-object-prototype.js": 2121, - "native-property-names.ts": 2951, - "native-proxy-env.js": 4417, - "native-worker-arena-reuse.ts": 38589, - "native-worker-bounded-errors.ts": 3955, - "native-worker-buffer-consumers.ts": 3076, - "native-worker-cancel-hot.ts": 3811, - "native-worker-class-fields.ts": 3737, - "native-worker-clone-errors.ts": 3557, - "native-worker-commonjs.cjs": 3258, - "native-worker-delayed-messages.ts": 3234, - "native-worker-discarded-heaps.ts": 8633, - "native-worker-environment.ts": 2690, - "native-worker-error.ts": 2115, - "native-worker-exception-state.ts": 37223, - "native-worker-exit-listeners.ts": 4215, - "native-worker-io.ts": 4024, - "native-worker-loop-cancellation.ts": 3683, - "native-worker-message-graphs.ts": 4038, - "native-worker-messages.ts": 2850, - "native-worker-poll-exceptions.ts": 3386, - "native-worker-port-lifetime.ts": 3672, - "native-worker-process-exit.ts": 4483, - "native-worker-publish-classes.ts": 43586, - "native-worker-publish-refusals.ts": 3568, - "native-worker-published-graphs.ts": 4341, - "native-worker-references.ts": 3658, - "native-worker-roots/main.ts": 3661, - "native-worker-shared-views.ts": 3873, - "native-worker-stack-overflow.ts": 3498, - "native-worker-terminate-exception-state.ts": 4768, - "native-worker-terminate-loop.ts": 3671, - "native-worker-terminate-recursion.ts": 2944, - "native-worker-terminate-suspended.ts": 4867, - "native-worker-terminate-tested-loops.ts": 3737, - "native-worker-terminate-wait.ts": 3200, - "native-worker-typed-arrays.ts": 2972, - "nested-map-cycles.ts": 3092, - "nested-map-values.ts": 3902, - "never-returning-calls.ts": 3512, - "next-tick-commonjs-entry.cjs": 3497, - "node24-buffer-encoding-errors.ts": 2874, - "node24-buffer-encoding.ts": 2697, - "node24-crypto-kdf-errors.ts": 3771, - "node24-crypto-kdf-options.ts": 2897, - "node24-crypto-kdf.ts": 3236, - "node24-crypto-sha2.ts": 3082, - "node24-deep-equality-properties.js": 3692, - "node24-deep-equality.cjs": 4490, - "node24-deep-equality.ts": 2856, - "node24-env-files-errors.ts": 2870, - "node24-env-files.ts": 3392, - "node24-env-imports.cjs": 2365, - "node24-env-parse-errors.ts": 3439, - "node24-env-parse.ts": 3033, - "node24-esm-metadata/main.mjs": 3209, - "node24-file-url-buffer.ts": 3465, - "node24-file-url-errors.js": 3937, - "node24-file-url-options.ts": 3735, - "node24-fs-links-callbacks.cjs": 3621, - "node24-fs-links-errors.cjs": 3404, - "node24-fs-links-options.cjs": 6459, - "node24-fs-links-promise-errors.cjs": 3319, - "node24-fs-links-promises.ts": 2636, - "node24-fs-links.ts": 3567, - "node24-fs-statfs-callbacks.cjs": 2515, - "node24-fs-statfs-errors.cjs": 2787, - "node24-fs-statfs-options.cjs": 3945, - "node24-fs-statfs.ts": 3105, - "node24-fs-timestamps-callbacks.cjs": 3550, - "node24-fs-timestamps-errors.cjs": 2070, - "node24-fs-timestamps-promises.ts": 3342, - "node24-fs-timestamps-symlinks.ts": 3375, - "node24-fs-timestamps.ts": 3308, - "node24-no-error-assertions-coercion.js": 3613, - "node24-no-error-assertions.cjs": 2851, - "node24-no-error-assertions.ts": 4400, - "node24-parseargs.js": 5202, - "node24-string-decoder.ts": 3402, - "node24-style-text-environment.js": 3896, - "node24-style-text-validation.js": 3092, - "node24-style-text.cjs": 3244, - "node24-style-text.ts": 2726, - "node24-system-error-validation.js": 3065, - "node24-system-errors.cjs": 2955, - "node24-system-errors.ts": 3258, - "node24-text-codec-properties.ts": 31240, - "node24-text-encode-into.ts": 2827, - "node24-text-utilities-coercion.js": 3019, - "node24-text-utilities-validation.js": 3576, - "node24-text-utilities.cjs": 3204, - "node24-text-utilities.ts": 2533, - "node24-url-authority-coercion.js": 3364, - "node24-url-authority.ts": 3386, - "node24-url-factories.ts": 3341, - "node24-url-factory-errors.ts": 3442, - "node24-url-mutation-coercion.js": 3344, - "node24-url-mutation.ts": 3264, - "node24-util-types.cjs": 3872, - "node24-util-types.js": 3533, - "node24-util-types.ts": 2848, - "non-null-class-iteration.ts": 2837, - "nonnull-element-arguments.ts": 3131, - "nonnull-forwarded-class-values.ts": 2449, - "nullable-object-extension.mjs": 3515, - "nullish-asserted-class-arms.ts": 3564, - "nullish-assignment-values.ts": 3337, - "nullish-long-chain.ts": 4149, - "number-parse-statics.ts": 2899, - "number-predicates-unknown.ts": 2922, - "numeric-call-specialization.ts": 2677, - "object-enumeration-array-reads.ts": 3480, - "object-from-checked-entries.js": 4289, - "object-inherited-to-string.js": 3243, - "object-key-indexes.js": 3558, - "object-prototype-identity.mjs": 3385, - "object-reexport/main.js": 2771, - "object-spread-computed.ts": 3307, - "opentui-byte-queue.js": 3572, - "optional-callback-arity.ts": 3027, - "optional-class-flows.ts": 3557, - "optional-element-defaults.ts": 3575, - "optional-flag-comparisons.ts": 3414, - "optional-native-callables.js": 3002, - "optional-node-list-iteration.ts": 2230, - "optional-string-index/main.ts": 3788, - "path-to-file-url-options.ts": 2444, - "performance-presence.ts": 2497, - "primitive-and-function-descriptors.js": 3169, - "primitive-union-string.ts": 2622, - "process-builtin-values.js": 3706, - "process-constrained-memory.ts": 2749, - "process-env-computed-keys.js": 3550, - "process-hrtime.js": 2677, - "process-named-signals.cjs": 3293, - "process-uncaught-handler-throws.cjs": 2718, - "process-uncaught-loop.cjs": 2801, - "process-uncaught-module.mjs": 3158, - "process-uncaught-monitor.cjs": 3031, - "process-uncaught-rejection.cjs": 3327, - "process-uncaught-sync.cjs": 2443, - "process-version-pin.ts": 2957, - "process-versions-storage.ts": 3651, - "projected-collection-lifetimes.ts": 3241, - "promise-checked-rejections.ts": 3404, - "promise-resolve-void.ts": 3343, - "prototype-method-overrides.mjs": 4289, - "prototype-named-data-records.ts": 3466, - "rc-last-use-moves.ts": 4113, - "rc-private-array-writes.ts": 4261, - "record-field-presence.ts": 4642, - "record-key-order.ts": 3034, - "record-optional-json-presence.ts": 3355, - "record-presence-copies.ts": 2764, - "record-presence-delete-json.ts": 2807, - "record-unchecked-read-presence.ts": 3073, - "record-unknown-values.ts": 4519, - "reflect-own-keys.mjs": 3709, - "reflect-record-union-keys.mjs": 2498, - "reflect-typed-record-keys.ts": 2697, - "regex-callback-replacements.ts": 3004, - "regex-callback-values.js": 2710, - "regex-checked-casts.ts": 3352, - "regex-checked-storage.js": 3330, - "regex-exec-long-subject.ts": 6176, - "regex-exec-result-arrays.ts": 3812, - "regex-fs-text-surfaces.ts": 4280, - "regex-input-lifetimes.ts": 3127, - "regex-native-matcher.ts": 5535, - "regex-optional-captures.ts": 3580, - "regex-optional-templates.ts": 3221, - "regex-split-captures.ts": 2939, - "regex-text-paths.ts": 3596, - "regexp-constructor-repeat.ts": 3069, - "regexp-optional-constructor.ts": 2996, - "regexp-string-coercion.js": 3263, - "renderer-export-dictionaries.js": 3616, - "renderer-null-state.js": 3037, - "renderer-specializations.js": 3634, - "repeat-and-typed-read-errors.ts": 2617, - "rest-optional-array-arguments.ts": 3777, - "rest-optional-elements.ts": 3195, - "return-void-through-finally.ts": 2410, - "runtime-optional-string-flows.ts": 3467, - "scalar-string-slices.ts": 3659, - "set-checked-methods.js": 2038, - "set-checked-storage.ts": 3153, - "set-iterator-seed-references.ts": 3637, - "set-iterator-seeds.ts": 3641, - "set-optional-seeds.ts": 3312, - "small-collection-transitions.ts": 3749, - "speculative-integer-globals.ts": 3132, - "speculative-integer-loops.ts": 3533, - "speculative-integer-reads.ts": 3953, - "stack-depth-async-bodies.ts": 3272, - "stack-overflow-async.ts": 2638, - "stack-overflow-caught.ts": 2219, - "stack-overflow-finally.ts": 3033, - "stack-overflow-shapes.ts": 4491, - "stack-overflow-uncaught.ts": 2225, - "stackless-async-concurrency.ts": 4361, - "stackless-async-context.ts": 2699, - "stackless-async-exceptions.ts": 3282, - "stackless-async-ordering.ts": 3335, - "stackless-async-unhandled.ts": 2784, - "static-field-updates/main.ts": 2292, - "static-method-receivers.ts": 3195, - "stdio-values.mjs": 3475, - "stdio-write-errors.mjs": 3473, - "stdio-write-overrides.mjs": 2782, - "stored-native-builtins.js": 3709, - "stored-object-helpers.js": 3602, - "stream-dynamic-entry-kinds.cjs": 4557, - "stream-dynamic-entry-kinds.ts": 4257, - "stream-encoded-from-entries.cjs": 4266, - "stream-encoded-from-entries.ts": 5622, - "string-char-code-integer-loops.ts": 2285, - "string-code-points.ts": 3745, - "string-concat-number-parts.ts": 3405, - "string-construction-order.ts": 3532, - "string-field-append.ts": 3568, - "string-lifetimes-boundaries.ts": 2538, - "string-lifetimes-evaluation.ts": 3059, - "string-lifetimes-iteration.ts": 2631, - "string-lifetimes-operations.ts": 3387, - "string-normalize.ts": 2789, - "string-pattern-replacement.ts": 3618, - "string-scan-fast-paths.ts": 3272, - "string-split-checked-separator.mjs": 3453, - "string-split-traversal.ts": 4337, - "structural-class-properties.ts": 3247, - "structured-text-boundaries.js": 3686, - "structured-text-storage.ts": 3429, - "switch-integer-dispatch.ts": 3032, - "symbol-checked-boundary/main.ts": 3536, - "symbol-class-fields.ts": 2762, - "symbol-class-fields/main.cjs": 3297, - "symbol-class-methods/main.ts": 3256, - "symbol-fields-deferred-factory.ts": 2417, - "symbol-fields-inferred.js": 3396, - "symbol-object-properties/main.js": 3134, - "synchronous-callback-lifetimes.ts": 3731, - "terminal-stream-properties.ts": 3204, - "text-codec-values/main.ts": 34352, - "text-codec-var.ts": 32460, - "text-encode-into-boundaries.ts": 3355, - "timers-clear-many.ts": 3559, - "tuple-and-string-search.ts": 3678, - "tuple-array-union.ts": 3569, - "tuple-callback-visitation.ts": 4765, - "tuple-forof-visitation.ts": 3560, - "typed-array-bulk-conversion.mjs": 5651, - "typed-array-byte-io.js": 4933, - "typed-array-checked-index.js": 3214, - "typed-array-constructor-alias.ts": 3116, - "typed-array-constructor-identity.js": 2735, - "typed-array-constructor-union.ts": 2841, - "typed-array-constructor-values.mjs": 3638, - "typed-array-dynamic-methods.js": 3255, - "typed-array-integer-widths.ts": 3434, - "typed-array-nan-coded-reads.ts": 3804, - "typed-array-numeric-import.ts": 2396, - "typed-array-present-reads.ts": 4348, - "typed-array-reversed-storage.ts": 3192, - "typed-array-unknown.ts": 2874, - "typed-collection-iterator-references.ts": 4029, - "typed-collection-iterators.ts": 4109, - "typed-collection-views/main.ts": 3005, - "typed-index-arguments.ts": 2798, - "typed-prototype-methods.ts": 3814, - "typed-rest-callables.ts": 2881, - "typed-rest-filtered-return.ts": 3723, - "typedarray-native-inputs.js": 2740, - "typeof-checked-comparison.js": 2277, - "uint8array-sort-domains.ts": 3386, - "unicode-case-paths.ts": 3002, - "unicode-process-argv.ts": 3272, - "union-discriminant-width.ts": 3302, - "union-literal-scalar-discriminants.ts": 2833, - "union-literal-slot-conversion.ts": 4058, - "union-nested-layout-discriminant.ts": 3205, - "union-optional-semantic-identity.ts": 3833, - "union-record-clone.ts": 3862, - "union-record-structural-copy.ts": 3756, - "union-reference-comparison.ts": 2883, - "unknown-array-holes.ts": 2863, - "unknown-collections.ts": 4132, - "unknown-object-enumeration.ts": 4976, - "unknown-record-views.ts": 4014, - "url-runtime-base.ts": 3421, - "utf8-span-decoding.ts": 3446, - "util-parseargs-wrapped/main.ts": 3987, - "virtual-runtime-optional-returns.ts": 4683, - "weak-map-array-buffer.ts": 3291, - "weak-map-fresh-array.js": 2703, - "weak-map-native.js": 3899, - "weak-native-class-identity.ts": 2332, - "weak-set-native.js": 2464, - "worker-class-instance-clone.ts": 46305 + "915-unknown-tostring-eq.ts": 3915, + "916-unknown-bytes.ts": 3466, + "917-record-array-index-dot.ts": 3287, + "950-modules-basic/main.ts": 3531, + "951-modules-diamond/main.ts": 3176, + "952-modules-cross/main.ts": 2507, + "953-modules-default/main.ts": 2473, + "954-modules-reexport/main.ts": 2897, + "957-builtins-namespace.ts": 3213, + "960-generics-basics.ts": 2743, + "961-generics-recursion.ts": 3759, + "962-generics-closures.ts": 3551, + "963-generics-modules/main.ts": 3745, + "964-generics-rc-stress.ts": 3697, + "965-generics-async.ts": 3911, + "965-unions-retag.ts": 2955, + "966-unions-retag-rc-stress.ts": 3416, + "967-record-field-widening.ts": 3252, + "969-unions-arm-matrix.ts": 3502, + "970-unions-basics.ts": 3588, + "971-unions-switch.ts": 3755, + "972-unions-nested.ts": 2659, + "973-unions-rc-stress.ts": 3021, + "974-unions-modules/main.ts": 3329, + "975-unions-undefined.ts": 3414, + "976-unions-null.ts": 3240, + "977-unions-unit-rc-stress.ts": 3807, + "978-unions-nullish.ts": 3471, + "979-unions-optional-chaining.ts": 2680, + "980-exceptions-basics.ts": 3823, + "981-exceptions-values.ts": 3366, + "982-exceptions-rc-stress.ts": 3526, + "983-exceptions-control-flow.ts": 3306, + "984-exceptions-finally.ts": 3693, + "985-exceptions-call-chains.ts": 3523, + "986-exceptions-uncaught.ts": 3377, + "987-exceptions-result-unions.ts": 3446, + "990-process-basics.ts": 3175, + "991-process-exit.ts": 3461, + "992-fs-roundtrip.ts": 3411, + "993-fs-readdir.ts": 3612, + "994-fs-errors.ts": 3748, + "995-fs-uncaught.ts": 3089, + "996-fs-rc-stress.ts": 3714, + "997-fs-modules/main.ts": 3327, + "998-process-env.ts": 2498, + "abstract-property-dispatch.ts": 4365, + "arguments-arrow-capture.mjs": 3544, + "arguments-reexport/main.ts": 3373, + "array-argument-lifetimes-exits.ts": 2870, + "array-argument-lifetimes-mutation.ts": 3721, + "array-argument-lifetimes-strings.ts": 3794, + "array-argument-lifetimes-values.ts": 4076, + "array-buffer-conversions.js": 3267, + "array-buffer-storage.ts": 3982, + "array-checked-callback-results.mjs": 3822, + "array-checked-constructor.js": 3361, + "array-concat-widening.ts": 3515, + "array-deque-unshift.ts": 4273, + "array-element-compound-updates.ts": 5390, + "array-fill-unit-values.ts": 3744, + "array-from-checked.js": 4644, + "array-from-value.mjs": 3261, + "array-isarray-value/main.js": 3569, + "array-numeric-own-keys.ts": 3719, + "array-optional-number-write-index.ts": 3067, + "array-primitive-ordering.ts": 4670, + "array-queue-head-room.ts": 5069, + "array-read-helper-effects.ts": 3808, + "array-refined-storage.ts": 3910, + "array-sort-dense-effects.ts": 4754, + "array-sort-dense-values.ts": 4991, + "array-sort-holes-published.ts": 12914, + "array-sort-runs.ts": 11006, + "array-sort-runtime-comparator.ts": 7044, + "array-sort-unknown-comparator.ts": 2921, + "array-storage-transitions.ts": 4555, + "array-truncate-reuse.ts": 3342, + "async-backend-factory.mjs": 3685, + "async-local-typed-results.ts": 4110, + "atomics-integer-operations.ts": 4324, + "bigint-checked-casts.ts": 3538, + "bigint-checked-storage.js": 3582, + "bigint-union-conversion.ts": 3627, + "boxed-error-rethrows.mjs": 3074, + "buffer-codec-boundaries.ts": 2997, + "buffer-primitive-predicate.ts": 3212, + "builtin-prototype-method-values.mjs": 4169, + "byte-loop-bounds.ts": 3289, + "byte-number-pipeline.ts": 3830, + "byte-record-windows.ts": 4084, + "call-lifetimes-argument-order.ts": 2814, + "call-lifetimes-control-flow.ts": 3242, + "call-lifetimes-owned-boundaries.ts": 3884, + "call-lifetimes-projections.ts": 3960, + "call-lifetimes-union-values.ts": 3288, + "call-lifetimes-virtual-optionals.ts": 4204, + "callable-module-members.mjs": 3631, + "callable-properties.mjs": 3358, + "callable-property-cycles.js": 2892, + "callable-reexport/main.ts": 3566, + "captured-class-refinement.ts": 3716, + "catch-capture.ts": 3398, + "caught-class-identity.ts": 4607, + "caught-standalone-class.ts": 3366, + "caught-system-error-fields.ts": 3842, + "checked-addition.js": 3129, + "checked-any-addition.ts": 3239, + "checked-array-assignment.ts": 3271, + "checked-array-flat/main.ts": 3753, + "checked-bitwise/main.js": 3435, + "checked-builder-cycles.js": 2781, + "checked-byte-storage/main.ts": 3695, + "checked-callback-options.ts": 3641, + "checked-class-descriptors.mjs": 4373, + "checked-class-factory.mjs": 3282, + "checked-collection-iterators.ts": 3261, + "checked-collection-symbol-methods.ts": 2592, + "checked-dispatch-input-lifetimes.js": 2966, + "checked-increment/main.js": 3466, + "checked-inherited-fields.ts": 3091, + "checked-iterator-consumption.js": 4432, + "checked-numeric-arithmetic.js": 3676, + "checked-object-module-alias.js": 3750, + "checked-optional-calls.mjs": 2819, + "checked-promise-recovery.ts": 3546, + "checked-proxy-callback/main.ts": 3548, + "checked-record-constructor.ts": 3491, + "checked-renderer-defaults.js": 2925, + "checked-rest-function-adapters.js": 3233, + "checked-storage-transitions.js": 2999, + "checked-symbol-array.ts": 3209, + "checked-value-input-lifetimes.ts": 2736, + "class-accessor-returned-function.js": 3222, + "class-array-optional-return.ts": 3320, + "class-bracket-method-calls.js": 3856, + "class-brand-overload.js": 3204, + "class-callback-replacement.js": 4854, + "class-callback-storage.ts": 4827, + "class-checked-composites.ts": 3368, + "class-checked-upcast.ts": 3815, + "class-collection-insertion.ts": 5133, + "class-computed-presence.ts": 4064, + "class-computed-symbols.js": 4475, + "class-covariant-returns.ts": 3062, + "class-curried-factory.mjs": 3903, + "class-data-descriptors.js": 4613, + "class-factory-inherited-statics.mjs": 3165, + "class-factory-parameter-base.mjs": 4404, + "class-factory-record-base.mjs": 5117, + "class-factory-recursive-statics.mjs": 3656, + "class-factory-static-members.mjs": 3238, + "class-function-base/main.js": 3349, + "class-instance-constructor.js": 4347, + "class-interface-protocols.ts": 5479, + "class-interface-refinements.ts": 4411, + "class-json-checked.ts": 3478, + "class-local-function-base.mjs": 2889, + "class-method-spreads.ts": 5065, + "class-narrowed-views.ts": 2591, + "class-property-call-values.mjs": 3049, + "class-prototype-data.js": 3914, + "class-prototype-descriptor-copy.mjs": 3673, + "class-specialized-computed-base.mjs": 4340, + "class-static-data.js": 3321, + "class-subclass-assertions.ts": 3532, + "class-super-surplus-spread.mjs": 3433, + "class-symbol-accessors.ts": 3674, + "class-symbol-cache.mjs": 4312, + "class-value-constructor-exceptions.ts": 2729, + "closed-virtual-dispatch-modules/main.ts": 3375, + "closed-virtual-dispatch.ts": 4025, + "closure-nullable-union-return.ts": 4235, + "closure-union-locals.ts": 3743, + "collection-array-cycles.ts": 3119, + "collection-array-maps.ts": 3580, + "collection-array-missing.ts": 3529, + "collection-array-sets.ts": 3755, + "collection-copy-identities.ts": 3108, + "collection-data-unions.ts": 3651, + "collection-ingestion-mappers.ts": 3521, + "collection-ingestion-protocol/main.ts": 4669, + "collection-ingestion-references.ts": 4710, + "collection-ingestion.ts": 3512, + "collection-storage-copies.ts": 3878, + "collection-value-keys.ts": 3854, + "compound-field-receivers.ts": 3456, + "compound-presence-guards.ts": 3018, + "conditional-tuple-destructuring.ts": 3519, + "console-imports.cjs": 3565, + "console-native-value.js": 2620, + "const-enum-module-cycle/main.ts": 2768, + "constant-callback-dispatch.ts": 3226, + "constant-module-globals/main.ts": 3076, + "constant-number-remainders.ts": 3457, + "constructed-class-dispatch.ts": 3935, + "contextual-array-union-write.ts": 5322, + "contextual-return-layouts.ts": 4143, + "counted-loop-numbers.ts": 3668, + "counted-loop-storage.ts": 2925, + "crypto-hash-optional-input.ts": 3821, + "cycle-generations-long-lived.ts": 2954, + "cycle-growth-yield.ts": 4304, + "date-checked-native.js": 3239, + "declared-index-spread.ts": 4205, + "deep-reference-teardown.ts": 3431, + "default-undefined-parameters.ts": 4155, + "deferred-field-updates.ts": 2817, + "deferred-registry-many.ts": 4413, + "derived-numeric-updates.ts": 3113, + "destructure-call-assignment.js": 2699, + "destructure-inferred-row-defaults.js": 3698, + "destructure-union-arrays.ts": 3868, + "dynamic-function-descriptors.js": 3825, + "error-cause-writes.js": 3664, + "error-inherited-message.mjs": 4115, + "error-inherited-name.mjs": 4088, + "error-property-writes.mjs": 3831, + "error-prototype-tostring.js": 3723, + "error-stack-frames.ts": 3316, + "error-stack-limit.ts": 3521, + "error-tostring-overrides.ts": 2788, + "error-values-inspect.ts": 2913, + "exact-index-round-trip.ts": 3953, + "expression-runtime-values.ts": 3293, + "fiber-switch-stress.ts": 4327, + "fiberless-async-ordering.ts": 4160, + "fiberless-async-unhandled.ts": 2861, + "field-assignment-values.ts": 3670, + "file-handle-values.ts": 3758, + "file-read-storage.ts": 5381, + "file-url-percent-decoding.ts": 3379, + "final-field-borrows.ts": 3428, + "for-multiple-bindings.ts": 2948, + "for-multiple-lexical-bindings.ts": 3036, + "for-of-checked-iterator.js": 3188, + "for-of-subclass-elements.ts": 3369, + "forward-generic-signatures.ts": 3512, + "fresh-array-union-layout.js": 3601, + "frozen-checked-dictionaries.mjs": 2948, + "fs-native-realpath.ts": 3654, + "fs-null-byte-paths-js.cjs": 3914, + "fs-null-byte-paths.ts": 5084, + "fs-read-encodings.ts": 3336, + "fs-read-utf8-edges.ts": 4161, + "fs-read-utf8-handle-forms.ts": 3562, + "fs-remove-readonly.ts": 3293, + "fs-write-string-bytes-union.ts": 2935, + "function-apply-value.mjs": 3607, + "function-constructor-global.mjs": 3295, + "function-constructor-kinds/main.js": 2837, + "function-custom-prototype.js": 3522, + "function-custom-to-string.mjs": 3399, + "function-object-assign.js": 3758, + "function-own-prototype/main.js": 2807, + "generator-checked-protocol.ts": 3503, + "generator-checked-return.js": 3369, + "generator-custom-delegation/main.ts": 5410, + "generator-default-return-pattern.ts": 2666, + "generator-delegation-values.ts": 3515, + "generator-inferred-date.js": 3280, + "generator-mixed-checked-channels.ts": 3467, + "generator-untyped-consumer/main.ts": 2805, + "generic-base-specializations.ts": 3523, + "generic-binding-ownership.ts": 4463, + "generic-class-js-functions/main.ts": 2699, + "generic-class-recovery.ts": 4031, + "generic-namespace-factories/main.ts": 3082, + "generic-nullable-collections.ts": 3376, + "generic-pattern-bindings.ts": 3388, + "generic-record-index.ts": 3789, + "generic-visitor-void.ts": 3751, + "global-accumulator-loops.ts": 3531, + "global-error-subclasses.ts": 2383, + "global-runtime-probes.js": 3149, + "global-stored-probes.js": 3656, + "global-string-cache/main.js": 2944, + "global-symbol-cache/main.js": 3152, + "guarded-native-iterables.ts": 3442, + "heap-input-aliases.ts": 3338, + "heap-input-collections.ts": 3866, + "in-array-runtime-index.ts": 4870, + "indexed-assignment-values.js": 3555, + "indexed-assignment-values.ts": 3263, + "indexed-element-field-reads.ts": 3648, + "inferred-array-assignment-values.mjs": 2599, + "inferred-class-default.mjs": 2738, + "inferred-compound-values.mjs": 3388, + "inferred-conditional-class.mjs": 2376, + "inferred-error-fields.js": 2452, + "inferred-map-patterns.mjs": 3504, + "inferred-method-override.js": 2889, + "inferred-partial-destructuring.mjs": 3489, + "inferred-primitive-properties.mjs": 2842, + "inferred-record-return.mjs": 3292, + "inferred-recursive-record.mjs": 3932, + "inferred-undefined-field.mjs": 2401, + "input-lifetime-intervals.ts": 3651, + "input-lifetimes-modules/main.ts": 3648, + "instanceof-class-record-union.ts": 3935, + "integer-flow-arithmetic.ts": 3336, + "integer-loop-forms.ts": 3549, + "integer-view-control.ts": 2594, + "integer-view-numbers.ts": 3585, + "integer-view-storage.ts": 3667, + "intl-grapheme-conformance/main.ts": 4680, + "intl-grapheme.ts": 4135, + "iterator-typed-returns.ts": 4766, + "js-abort-portable.js": 3961, + "js-array-constructor.js": 3335, + "js-array-default-buffer.js": 2734, + "js-array-iterators.js": 3671, + "js-arrow-bind.cjs": 5214, + "js-buffer-callback-brand.cjs": 4283, + "js-callable-proxy.js": 3329, + "js-chained-native-results.mjs": 3307, + "js-checked-array-iterator.js": 3738, + "js-checked-array-reference.js": 3849, + "js-checked-number-negation.mjs": 3465, + "js-checked-sort-result.js": 2437, + "js-child-error-listener.cjs": 2606, + "js-cjs-callable-snapshots/main.cjs": 3122, + "js-class-added-parameters.js": 3654, + "js-class-checked-overrides.js": 3726, + "js-class-computed-fields.js": 3260, + "js-class-enumeration.js": 4284, + "js-class-field-accessor-override.js": 3902, + "js-class-fluent-overrides.js": 3667, + "js-class-late-method-values.js": 3068, + "js-class-member-dispatch.js": 4117, + "js-class-return-shapes.js": 3935, + "js-class-shadowed-methods.js": 4040, + "js-class-stored-method-receiver.js": 2904, + "js-class-subclass-properties.js": 5036, + "js-class-symbol-spread.cjs": 3637, + "js-computed-prototype-additions.js": 2620, + "js-constructor-returned-callable.js": 2532, + "js-constructor-spread.js": 3024, + "js-dataview-dispatch.js": 3608, + "js-declared-fields.cjs": 5015, + "js-default-listener-arguments.cjs": 2326, + "js-default-options/main.ts": 3910, + "js-deferred-field-initializers.js": 2418, + "js-deferred-registry-effects.js": 3462, + "js-derived-constructor-hoisting.js": 2798, + "js-dormant-array-write.js": 3572, + "js-dormant-overrides.js": 2747, + "js-expando-records.js": 3967, + "js-implicit-call-results.js": 2920, + "js-inferred-callback-exports/main.js": 4360, + "js-inferred-class-array-return.js": 3664, + "js-inferred-object-values.js": 3561, + "js-inherited-field-storage.js": 2906, + "js-inherited-parameter-abi.js": 2442, + "js-iterable-spread.js": 2766, + "js-loose-dynamic-primitives.js": 3050, + "js-map-object-seeds.js": 3816, + "js-member-increment.js": 4372, + "js-module-function-values.js": 3724, + "js-mutable-null-members.js": 3894, + "js-nested-native-descriptors.js": 3332, + "js-normalize-dispatch.js": 3662, + "js-nullish-inherited-fields.mjs": 3226, + "js-object-receiver-storage.js": 3635, + "js-object-returning-constructors.mjs": 3324, + "js-object-shared-arrays.js": 3926, + "js-omitted-typed-arguments.js": 3274, + "js-open-binding-writes.js": 3161, + "js-optional-class-fields.js": 3414, + "js-optional-member-call.js": 3623, + "js-primitive-union-addition.js": 3186, + "js-promise-all-values.js": 3364, + "js-promise-catch-handler.js": 2469, + "js-promise-finally-order.js": 3631, + "js-promise-pending-reactions.js": 3621, + "js-prototype-host-boundary.js": 40863, + "js-reflect-receivers.js": 3717, + "js-regex-record-captures.js": 4129, + "js-scalar-iterables.js": 3831, + "js-shared-method-dispatch.js": 3185, + "js-specialized-field-method.js": 2772, + "js-static-accessors.js": 3403, + "js-static-method-values.js": 3866, + "js-static-registries.cjs": 3795, + "js-super-accessor-initialization.js": 3887, + "js-uninitialized-native-fields.js": 3361, + "json-guarded-map-values.ts": 3542, + "json-output-bulk.ts": 3334, + "json-runtime-options.mjs": 2995, + "json-stringify-value.js": 3147, + "json-typed-parse-direct.ts": 3768, + "json-typed-parse-index-signatures.ts": 3707, + "json-typed-parse-optional-members.ts": 4645, + "json-typed-parse-union-members.ts": 2884, + "literal-switch-dispatch.ts": 3317, + "live-reference-shared-converters.ts": 9504, + "llvm-read-receiver-lifetime.ts": 4439, + "local-class-call-spreads.js": 3630, + "local-class-declaration.ts": 3068, + "local-class-evaluation.ts": 3450, + "local-class-inheritance.ts": 3339, + "local-class-lifetimes.ts": 3623, + "local-class-namespace/main.js": 3916, + "local-class-prototype-data.js": 3797, + "local-class-specialization.js": 3033, + "local-class-unknown.ts": 2900, + "local-class-values.ts": 2584, + "local-union-storage.ts": 3820, + "locale-compare-root-order.ts": 3234, + "logical-assignment-dynamic.js": 3066, + "logical-assignment-values.ts": 3751, + "logical-runtime-optional-record.ts": 3473, + "loop-reference-lifetimes.ts": 2819, + "map-checked-boundary/main.ts": 3663, + "map-checked-seed.js": 3370, + "map-get-set-fusion.ts": 3638, + "map-number-keys-dense.ts": 4412, + "map-read-lifetimes-exits.ts": 2579, + "map-read-lifetimes.ts": 3849, + "map-seeds-and-spreads.ts": 3171, + "map-typed-array-values.ts": 3666, + "math-function-values.js": 2486, + "missing-read-lambda-results.ts": 3345, + "missing-read-narrowed-storage.ts": 3729, + "missing-read-number-conversions.ts": 3696, + "module-byte-loops.ts": 3029, + "module-fallback-functions/main.js": 3321, + "narrowed-nullish-values.ts": 3184, + "native-any-timer-callback.ts": 2884, + "native-array-borrowed-find-last.js": 3352, + "native-array-borrowed-slice.js": 3286, + "native-array-copying-methods.js": 2464, + "native-array-fill-copywithin.js": 2771, + "native-array-frozen-noops.js": 3256, + "native-array-index-boundaries.js": 2917, + "native-array-integrity.js": 2583, + "native-array-length.js": 2372, + "native-array-named-properties.js": 3684, + "native-array-prototype/main.js": 3743, + "native-array-read-lifetimes.ts": 3932, + "native-array-reduce-find-last.js": 2450, + "native-array-search-from-index.js": 2847, + "native-array-splice-coercion.js": 3405, + "native-array-splice-flat.js": 3104, + "native-buffer-coercion.js": 3322, + "native-callback-dispatch.ts": 3832, + "native-class-array-boundaries.ts": 3342, + "native-class-cache.js": 3840, + "native-class-properties.cjs": 5572, + "native-class-property-cycles.cjs": 3155, + "native-class-property-order.cjs": 3170, + "native-class-type-predicates.ts": 3052, + "native-factory-records.js": 3387, + "native-method-values.js": 4924, + "native-method-values.ts": 3868, + "native-npm-imports/main.ts": 3901, + "native-object-descriptors.js": 3247, + "native-object-for-in-minimal.js": 3446, + "native-object-property-attributes.js": 3224, + "native-object-prototype.js": 2952, + "native-property-names.ts": 2920, + "native-proxy-env.js": 4531, + "native-worker-arena-reuse.ts": 9740, + "native-worker-bounded-errors.ts": 3428, + "native-worker-buffer-consumers.ts": 4341, + "native-worker-cancel-hot.ts": 3046, + "native-worker-class-fields.ts": 3987, + "native-worker-clone-errors.ts": 3205, + "native-worker-commonjs.cjs": 3563, + "native-worker-delayed-messages.ts": 3820, + "native-worker-discarded-heaps.ts": 9491, + "native-worker-environment.ts": 3678, + "native-worker-error.ts": 3443, + "native-worker-exception-state.ts": 3795, + "native-worker-exit-listeners.ts": 3786, + "native-worker-io.ts": 3497, + "native-worker-loop-cancellation.ts": 3485, + "native-worker-message-graphs.ts": 3324, + "native-worker-messages.ts": 3248, + "native-worker-poll-exceptions.ts": 3463, + "native-worker-port-lifetime.ts": 3679, + "native-worker-process-exit.ts": 25459, + "native-worker-publish-classes.ts": 39360, + "native-worker-publish-refusals.ts": 3725, + "native-worker-published-graphs.ts": 3934, + "native-worker-references.ts": 4072, + "native-worker-roots/main.ts": 3317, + "native-worker-shared-views.ts": 34203, + "native-worker-stack-overflow.ts": 3534, + "native-worker-terminate-exception-state.ts": 4664, + "native-worker-terminate-loop.ts": 3303, + "native-worker-terminate-recursion.ts": 4325, + "native-worker-terminate-suspended.ts": 3580, + "native-worker-terminate-tested-loops.ts": 3001, + "native-worker-terminate-wait.ts": 3399, + "native-worker-typed-arrays.ts": 3056, + "nested-map-cycles.ts": 2892, + "nested-map-values.ts": 4020, + "never-returning-calls.ts": 3353, + "next-tick-commonjs-entry.cjs": 3537, + "node24-buffer-encoding-errors.ts": 3190, + "node24-buffer-encoding.ts": 3056, + "node24-crypto-kdf-errors.ts": 3983, + "node24-crypto-kdf-options.ts": 3444, + "node24-crypto-kdf.ts": 3815, + "node24-crypto-sha2.ts": 3261, + "node24-deep-equality-properties.js": 3213, + "node24-deep-equality.cjs": 4348, + "node24-deep-equality.ts": 4931, + "node24-env-files-errors.ts": 3190, + "node24-env-files.ts": 3237, + "node24-env-imports.cjs": 2806, + "node24-env-parse-errors.ts": 3175, + "node24-env-parse.ts": 2442, + "node24-esm-metadata/main.mjs": 3178, + "node24-file-url-buffer.ts": 2578, + "node24-file-url-errors.js": 3662, + "node24-file-url-options.ts": 3335, + "node24-fs-links-callbacks.cjs": 2914, + "node24-fs-links-errors.cjs": 2718, + "node24-fs-links-options.cjs": 5212, + "node24-fs-links-promise-errors.cjs": 3623, + "node24-fs-links-promises.ts": 3653, + "node24-fs-links.ts": 2754, + "node24-fs-statfs-callbacks.cjs": 3304, + "node24-fs-statfs-errors.cjs": 3642, + "node24-fs-statfs-options.cjs": 3933, + "node24-fs-statfs.ts": 3769, + "node24-fs-timestamps-callbacks.cjs": 3563, + "node24-fs-timestamps-errors.cjs": 3595, + "node24-fs-timestamps-promises.ts": 4047, + "node24-fs-timestamps-symlinks.ts": 2514, + "node24-fs-timestamps.ts": 3364, + "node24-no-error-assertions-coercion.js": 3593, + "node24-no-error-assertions.cjs": 2425, + "node24-no-error-assertions.ts": 4527, + "node24-parseargs.js": 5067, + "node24-string-decoder.ts": 2945, + "node24-style-text-environment.js": 3145, + "node24-style-text-validation.js": 4525, + "node24-style-text.cjs": 3538, + "node24-style-text.ts": 3894, + "node24-system-error-validation.js": 3199, + "node24-system-errors.cjs": 2805, + "node24-system-errors.ts": 3782, + "node24-text-codec-properties.ts": 3181, + "node24-text-encode-into.ts": 2752, + "node24-text-utilities-coercion.js": 2713, + "node24-text-utilities-validation.js": 3711, + "node24-text-utilities.cjs": 3142, + "node24-text-utilities.ts": 3686, + "node24-url-authority-coercion.js": 3699, + "node24-url-authority.ts": 3174, + "node24-url-factories.ts": 3606, + "node24-url-factory-errors.ts": 3314, + "node24-url-mutation-coercion.js": 3050, + "node24-url-mutation.ts": 2529, + "node24-util-types.cjs": 2859, + "node24-util-types.js": 3337, + "node24-util-types.ts": 3883, + "non-null-class-iteration.ts": 3145, + "nonnull-element-arguments.ts": 2747, + "nonnull-forwarded-class-values.ts": 3637, + "nullable-object-extension.mjs": 3028, + "nullish-asserted-class-arms.ts": 2996, + "nullish-assignment-values.ts": 3685, + "nullish-long-chain.ts": 4539, + "number-parse-statics.ts": 2378, + "number-predicates-unknown.ts": 3263, + "numeric-call-specialization.ts": 3397, + "object-enumeration-array-reads.ts": 3721, + "object-from-checked-entries.js": 4400, + "object-inherited-to-string.js": 3338, + "object-key-indexes.js": 4004, + "object-prototype-identity.mjs": 3277, + "object-reexport/main.js": 3532, + "object-spread-computed.ts": 3618, + "opentui-byte-queue.js": 2761, + "optional-callback-arity.ts": 2368, + "optional-class-flows.ts": 2553, + "optional-element-defaults.ts": 3275, + "optional-flag-comparisons.ts": 3105, + "optional-native-callables.js": 3200, + "optional-node-list-iteration.ts": 3422, + "optional-string-index/main.ts": 2937, + "path-to-file-url-options.ts": 3680, + "performance-presence.ts": 3328, + "primitive-and-function-descriptors.js": 3559, + "primitive-union-string.ts": 3162, + "process-builtin-values.js": 4636, + "process-constrained-memory.ts": 2246, + "process-env-computed-keys.js": 3276, + "process-hrtime.js": 3203, + "process-named-signals.cjs": 3440, + "process-uncaught-handler-throws.cjs": 2812, + "process-uncaught-loop.cjs": 2427, + "process-uncaught-module.mjs": 2982, + "process-uncaught-monitor.cjs": 3049, + "process-uncaught-rejection.cjs": 2978, + "process-uncaught-sync.cjs": 2919, + "process-version-pin.ts": 3275, + "process-versions-storage.ts": 3558, + "projected-collection-lifetimes.ts": 3501, + "promise-checked-rejections.ts": 2387, + "promise-resolve-void.ts": 2676, + "prototype-method-overrides.mjs": 7058, + "prototype-named-data-records.ts": 3518, + "rc-last-use-moves.ts": 4127, + "rc-private-array-writes.ts": 4075, + "record-field-presence.ts": 4445, + "record-key-order.ts": 2786, + "record-optional-json-presence.ts": 3499, + "record-presence-copies.ts": 4175, + "record-presence-delete-json.ts": 2958, + "record-unchecked-read-presence.ts": 3597, + "record-unknown-values.ts": 4381, + "reflect-own-keys.mjs": 2660, + "reflect-record-union-keys.mjs": 2359, + "reflect-typed-record-keys.ts": 2855, + "regex-callback-replacements.ts": 3541, + "regex-callback-values.js": 3624, + "regex-checked-casts.ts": 3867, + "regex-checked-storage.js": 3704, + "regex-exec-long-subject.ts": 8130, + "regex-exec-result-arrays.ts": 4036, + "regex-fs-text-surfaces.ts": 4013, + "regex-input-lifetimes.ts": 2860, + "regex-native-matcher.ts": 4866, + "regex-optional-captures.ts": 3208, + "regex-optional-templates.ts": 3554, + "regex-split-captures.ts": 3707, + "regex-text-paths.ts": 2943, + "regexp-constructor-repeat.ts": 3471, + "regexp-optional-constructor.ts": 3547, + "regexp-string-coercion.js": 2902, + "renderer-export-dictionaries.js": 2853, + "renderer-null-state.js": 3392, + "renderer-specializations.js": 3361, + "repeat-and-typed-read-errors.ts": 3813, + "rest-optional-array-arguments.ts": 4116, + "rest-optional-elements.ts": 3072, + "return-void-through-finally.ts": 2672, + "runtime-optional-string-flows.ts": 3420, + "scalar-string-slices.ts": 3228, + "set-checked-methods.js": 3654, + "set-checked-storage.ts": 3542, + "set-iterator-seed-references.ts": 3832, + "set-iterator-seeds.ts": 3864, + "set-optional-seeds.ts": 3189, + "small-collection-transitions.ts": 3703, + "speculative-integer-globals.ts": 2999, + "speculative-integer-loops.ts": 4097, + "speculative-integer-reads.ts": 3960, + "stack-depth-async-bodies.ts": 3593, + "stack-overflow-async.ts": 3327, + "stack-overflow-caught.ts": 3619, + "stack-overflow-finally.ts": 4048, + "stack-overflow-shapes.ts": 4840, + "stack-overflow-uncaught.ts": 3019, + "stackless-async-concurrency.ts": 5553, + "stackless-async-context.ts": 3712, + "stackless-async-exceptions.ts": 4059, + "stackless-async-ordering.ts": 4230, + "stackless-async-unhandled.ts": 3409, + "static-field-updates/main.ts": 3160, + "static-method-receivers.ts": 3269, + "stdio-values.mjs": 3241, + "stdio-write-errors.mjs": 3357, + "stdio-write-overrides.mjs": 3279, + "stored-native-builtins.js": 3593, + "stored-object-helpers.js": 3366, + "stream-dynamic-entry-kinds.cjs": 8165, + "stream-dynamic-entry-kinds.ts": 2619, + "stream-encoded-from-entries.cjs": 4394, + "stream-encoded-from-entries.ts": 4716, + "string-char-code-integer-loops.ts": 3604, + "string-code-points.ts": 2747, + "string-concat-number-parts.ts": 3145, + "string-construction-order.ts": 3430, + "string-field-append.ts": 3228, + "string-lifetimes-boundaries.ts": 3759, + "string-lifetimes-evaluation.ts": 3595, + "string-lifetimes-iteration.ts": 2950, + "string-lifetimes-operations.ts": 3231, + "string-normalize.ts": 3407, + "string-pattern-replacement.ts": 3745, + "string-scan-fast-paths.ts": 3455, + "string-split-checked-separator.mjs": 3539, + "string-split-traversal.ts": 4073, + "structural-class-properties.ts": 3685, + "structured-text-boundaries.js": 4089, + "structured-text-storage.ts": 3938, + "switch-integer-dispatch.ts": 3542, + "symbol-checked-boundary/main.ts": 3823, + "symbol-class-fields.ts": 3105, + "symbol-class-fields/main.cjs": 3306, + "symbol-class-methods/main.ts": 3168, + "symbol-fields-deferred-factory.ts": 2465, + "symbol-fields-inferred.js": 2781, + "symbol-object-properties/main.js": 2729, + "synchronous-callback-lifetimes.ts": 3805, + "terminal-stream-properties.ts": 2859, + "text-codec-values/main.ts": 24961, + "text-codec-var.ts": 35233, + "text-encode-into-boundaries.ts": 2835, + "timers-clear-many.ts": 3438, + "tuple-and-string-search.ts": 3771, + "tuple-array-union.ts": 3450, + "tuple-callback-visitation.ts": 3975, + "tuple-forof-visitation.ts": 3491, + "typed-array-bulk-conversion.mjs": 5922, + "typed-array-byte-io.js": 9466, + "typed-array-checked-index.js": 3008, + "typed-array-constructor-alias.ts": 3321, + "typed-array-constructor-identity.js": 3143, + "typed-array-constructor-union.ts": 2529, + "typed-array-constructor-values.mjs": 3170, + "typed-array-dynamic-methods.js": 4053, + "typed-array-integer-widths.ts": 3519, + "typed-array-nan-coded-reads.ts": 3945, + "typed-array-numeric-import.ts": 4121, + "typed-array-present-reads.ts": 3332, + "typed-array-reversed-storage.ts": 2465, + "typed-array-unknown.ts": 3664, + "typed-collection-iterator-references.ts": 4059, + "typed-collection-iterators.ts": 4014, + "typed-collection-views/main.ts": 2915, + "typed-index-arguments.ts": 3055, + "typed-prototype-methods.ts": 3929, + "typed-rest-callables.ts": 2298, + "typed-rest-filtered-return.ts": 3531, + "typedarray-native-inputs.js": 3581, + "typeof-checked-comparison.js": 2656, + "uint8array-sort-domains.ts": 3223, + "unicode-case-paths.ts": 2409, + "unicode-process-argv.ts": 3053, + "union-discriminant-width.ts": 4248, + "union-literal-scalar-discriminants.ts": 4306, + "union-literal-slot-conversion.ts": 3424, + "union-nested-layout-discriminant.ts": 3343, + "union-optional-semantic-identity.ts": 4104, + "union-record-clone.ts": 3572, + "union-record-structural-copy.ts": 2990, + "union-reference-comparison.ts": 4026, + "unknown-array-holes.ts": 3098, + "unknown-collections.ts": 4172, + "unknown-object-enumeration.ts": 5046, + "unknown-record-views.ts": 2982, + "url-runtime-base.ts": 2879, + "utf8-span-decoding.ts": 37919, + "util-parseargs-wrapped/main.ts": 4014, + "virtual-runtime-optional-returns.ts": 4644, + "weak-map-array-buffer.ts": 3584, + "weak-map-fresh-array.js": 2803, + "weak-map-native.js": 3743, + "weak-native-class-identity.ts": 3008, + "weak-set-native.js": 2800, + "worker-class-instance-clone.ts": 39705 } } From 29c8ad237cdf3c0b70299497b7e76233755ccc83 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 11:36:13 -0500 Subject: [PATCH 105/117] Throw when nm cannot list an executable's symbols in the zero-cost gate The gate read an empty symbol list when nm could not start, was killed by a signal, or exited with a non-zero status, so the dynamic-tier symbol check and the executable comparison passed without any symbols. nmOutput now throws with the binary, the reason and nm's stderr. --- scripts/zero-cost-compare.mjs | 15 +++++++++++++++ scripts/zero-cost-gate.mjs | 3 ++- tests/harness/zero-cost-gate.test.ts | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/scripts/zero-cost-compare.mjs b/scripts/zero-cost-compare.mjs index 5367c2957..a89fe4650 100644 --- a/scripts/zero-cost-compare.mjs +++ b/scripts/zero-cost-compare.mjs @@ -232,6 +232,21 @@ export function compareArtifact(kind, baseline, candidate) { /* ── executables ───────────────────────────────────────────────────────── */ +/** The output of `nm` for `binary`, from its spawnSync result. Throws when + * nm could not start, was killed by a signal, or exited with a non-zero + * status, because the symbol checks would otherwise read an empty list. */ +export function nmOutput(binary, result) { + if (result.error) throw new Error(`nm ${binary}: ${result.error.message}`); + if (result.signal) throw new Error(`nm ${binary}: killed by ${result.signal}`); + if (result.status !== 0) { + const detail = typeof result.stderr === "string" ? result.stderr.trim() : ""; + throw new Error( + `nm ${binary}: exited with status ${result.status}${detail ? `: ${detail}` : ""}`, + ); + } + return result.stdout; +} + /** Defined symbols from `nm -S` output (GNU/LLVM nm, address size type * name) or `nm` output without sizes (Apple, address type name). */ export function parseNm(text) { diff --git a/scripts/zero-cost-gate.mjs b/scripts/zero-cost-gate.mjs index db98bf249..f4272ac6a 100644 --- a/scripts/zero-cost-gate.mjs +++ b/scripts/zero-cost-gate.mjs @@ -34,6 +34,7 @@ import { compareExecutables, dynamicTierSymbols, median, + nmOutput, parseNm, programVerdict, timeRatio, @@ -300,7 +301,7 @@ function nm(binary) { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, }); - const text = result.status === 0 ? result.stdout : ""; + const text = nmOutput(binary, result); nmCache.set(binary, text); return text; } diff --git a/tests/harness/zero-cost-gate.test.ts b/tests/harness/zero-cost-gate.test.ts index c75a115c8..0b08da748 100644 --- a/tests/harness/zero-cost-gate.test.ts +++ b/tests/harness/zero-cost-gate.test.ts @@ -1,3 +1,4 @@ +import { spawnSync } from "node:child_process"; import { expect, test } from "vitest"; import { cachegrindCounts, @@ -5,6 +6,7 @@ import { compareCounts, compareExecutables, dynamicTierSymbols, + nmOutput, programVerdict, } from "../../scripts/zero-cost-compare.mjs"; @@ -112,6 +114,19 @@ test("the zero-cost gate compares executables and instruction counts per functio }); }); +test("the zero-cost gate throws when nm does not list a binary's symbols", () => { + const ok = { status: 0, signal: null, stdout: "0000000000001000 T main\n", stderr: "" }; + expect(nmOutput("prog", ok)).toBe(ok.stdout); + const missing = spawnSync("scriptc-missing-nm", ["prog"], { encoding: "utf8" }); + expect(() => nmOutput("prog", missing)).toThrow(/^nm prog: .*ENOENT/); + expect(() => + nmOutput("prog", { status: null, signal: "SIGKILL", stdout: "", stderr: "" }), + ).toThrow("nm prog: killed by SIGKILL"); + expect(() => + nmOutput("prog", { status: 1, signal: null, stdout: "", stderr: "nm: prog: no symbols\n" }), + ).toThrow("nm prog: exited with status 1: nm: prog: no symbols"); +}); + test("the zero-cost gate recognizes dynamic-tier runtime symbols", () => { expect( dynamicTierSymbols([ From da1af7437f6f2c07bb6b65ab6793227cd5975dbb Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 12:20:36 -0500 Subject: [PATCH 106/117] Revert "Read fields as undefined before their assignment (#1292)" This reverts commit ff90245b27862eeec38687df9c8f4c078ffc12d0. --- .../frontend/lowering/construction-escapes.ts | 9 - .../src/frontend/lowering/lower-classes.ts | 208 +++++------------- .../src/frontend/lowering/lower-exprs.ts | 94 -------- .../compiler/src/frontend/lowering/lowerer.ts | 12 - .../test/class-early-field-reads.test.ts | 93 -------- ...5943-fields-read-before-assignment.ts.json | 6 - ...4-js-fields-read-before-assignment.js.json | 6 - .../5943-fields-read-before-assignment.ts | 181 --------------- .../5944-js-fields-read-before-assignment.js | 28 --- tests/harness/corpus-costs.json | 4 - 10 files changed, 58 insertions(+), 583 deletions(-) delete mode 100644 packages/compiler/test/class-early-field-reads.test.ts delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json delete mode 100644 tests/corpus/5943-fields-read-before-assignment.ts delete mode 100644 tests/corpus/5944-js-fields-read-before-assignment.js diff --git a/packages/compiler/src/frontend/lowering/construction-escapes.ts b/packages/compiler/src/frontend/lowering/construction-escapes.ts index a1626f12d..484920a1c 100644 --- a/packages/compiler/src/frontend/lowering/construction-escapes.ts +++ b/packages/compiler/src/frontend/lowering/construction-escapes.ts @@ -124,15 +124,6 @@ export function constructionEscape(inputs: ConstructionInputs): ConstructionEsca continue; } if (ts.isExpressionStatement(stmt) && !exposes(stmt.expression, depth)) continue; - // A check that only reads assigned fields and throws or does nothing - // with the receiver (`if (this.size < 0) throw new RangeError()`) - // does not expose the instance; assignments in its branches are not - // definite and still count as exposures. - if ( - (ts.isIfStatement(stmt) || ts.isThrowStatement(stmt) || ts.isBlock(stmt)) && - !exposes(stmt, depth) - ) - continue; return false; } return true; diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 7b2d176c3..f70499e6f 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -143,7 +143,7 @@ import { lowerObjectFactoryNew } from "./object-factory-new.js"; import { tryLowerExpression } from "./expressions/try-lower-expression.js"; import { lowerInstanceConstructorNew } from "./class-instance-constructor.js"; import { classPrototypeData } from "./class-prototypes.js"; -import { constructionEscape, mentionsReceiver } from "./construction-escapes.js"; +import { constructionEscape } from "./construction-escapes.js"; import { checkedClassConstruction, checkedClassConstructionPacked } from "./class-construction.js"; import { initializeRuntimeStatics, hasRuntimeStatics } from "./class-runtime-statics.js"; import { reflectedClassStaticMethodValue } from "./class-method-values.js"; @@ -468,11 +468,6 @@ export interface ClassInfo { * unassigned read throws the catchable TypeError instead of yielding * an undefined the declared type cannot hold (SEMANTICS.md). */ deferredInitFields?: Set; - /** Fields (inherited included) that code construction exposes the - * instance to can read before their assignment: the slot is the - * undefined-armed union, allocation writes undefined, and reads yield the - * union value, so an early read sees undefined as in Node. */ - earlyReadFields?: Set; /** True when construction may hand the instance to other code (a method * call, an argument, a callback, or a base constructor that does) — a * subclass's own fields can then be read before their assignment. */ @@ -3507,54 +3502,55 @@ export function collectClassShapeInner( const derived = decl.heritageClauses?.some((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword) ?? false; - // A generic family is not emitted; its instances and each mixin - // application analyze their own construction with their actual base. - const escape: { escapes: boolean; assigned: Set | null } = familyMode - ? { escapes: derived, assigned: null } - : constructionEscape({ - ctor, - fields: fieldOrder.flatMap((f) => - paramProps.some((pp) => pp.name === f.name) - ? [] - : [{ name: f.name, initializer: f.initializer }], - ), - paramProps: paramProps.map((pp) => pp.name), - derived, - baseEscapes: - base === null || - callableBase !== undefined || - factoryBaseExpression !== undefined || - base.constructionEscapes === true, - isField: (name) => - fields.has(name) && - !methods.has(`set:${name}`) && - !lowerer.findMethodOn(base, `set:${name}`), - privateMethodBody: (call) => { - const callee = call.expression; - if (!ts.isPropertyAccessExpression(callee)) return null; - const name = callee.name.text; - const declaration = decl.members.find( - (member): member is ts.MethodDeclaration => - ts.isMethodDeclaration(member) && - member.body !== undefined && - (ts.isIdentifier(member.name) || ts.isPrivateIdentifier(member.name)) && - member.name.text === name, - ); - if (!declaration?.body || declaration.asteriskToken) return null; - const modifiers = ts.getModifiers(declaration) ?? []; - if ( - modifiers.some( - (m) => - m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.AsyncKeyword, + // Generic instances and mixins share layouts across declarations, so + // they only report whether construction exposes the instance. + const escape: { escapes: boolean; assigned: Set | null } = + familyMode || mixin + ? { escapes: derived, assigned: null } + : constructionEscape({ + ctor, + fields: fieldOrder.flatMap((f) => + paramProps.some((pp) => pp.name === f.name) + ? [] + : [{ name: f.name, initializer: f.initializer }], + ), + paramProps: paramProps.map((pp) => pp.name), + derived, + baseEscapes: + base === null || + callableBase !== undefined || + factoryBaseExpression !== undefined || + base.constructionEscapes === true, + isField: (name) => + fields.has(name) && + !methods.has(`set:${name}`) && + !lowerer.findMethodOn(base, `set:${name}`), + privateMethodBody: (call) => { + const callee = call.expression; + if (!ts.isPropertyAccessExpression(callee)) return null; + const name = callee.name.text; + const declaration = decl.members.find( + (member): member is ts.MethodDeclaration => + ts.isMethodDeclaration(member) && + member.body !== undefined && + (ts.isIdentifier(member.name) || ts.isPrivateIdentifier(member.name)) && + member.name.text === name, + ); + if (!declaration?.body || declaration.asteriskToken) return null; + const modifiers = ts.getModifiers(declaration) ?? []; + if ( + modifiers.some( + (m) => + m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.AsyncKeyword, + ) ) - ) - return null; - const isPrivate = - ts.isPrivateIdentifier(declaration.name) || - modifiers.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword); - return isPrivate ? declaration.body : null; - }, - }); + return null; + const isPrivate = + ts.isPrivateIdentifier(declaration.name) || + modifiers.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword); + return isPrivate ? declaration.body : null; + }, + }); // The deferred definite-assignment check: a field on the unguarded // list passes only with an unconditional `this.x = ...` at the // constructor's TOP LEVEL — the same standard the JS-class path @@ -3610,30 +3606,18 @@ export function collectClassShapeInner( } } - // Fields assigned after construction can expose the instance (a method - // call, a base constructor that calls an override) can be read while - // Node still holds undefined. Their slots admit undefined, allocation - // writes it, and reads yield it, as in Node. - const earlyReadFields = new Set(base?.earlyReadFields ?? []); - if (escape.assigned && escape.escapes) { + if (escape.assigned && !inst) { for (const f of fieldOrder) { if (f.redeclared || escape.assigned.has(f.name) || deferredInitFields.has(f.name)) continue; + if (paramProps.some((pp) => pp.name === f.name)) continue; const declared = fields.get(f.name); - if (declared === undefined || !earlyReadable(lowerer, declared)) continue; - // A declared `T | undefined` field already starts undefined. - if (declared.kind === "union" && lowerer.armTag(declared.unionId, UNDEFINED_T) >= 0) + if (declared?.kind !== "object" || lowerer.classes.get(declared.className)?.def.runtime) continue; - const armed = lowerer.runtimeOptionalType(declared); - if (armed.kind !== "union") continue; + const armed = lowerer.withUndefinedArm(declared); + if (armed === null || armed.kind !== "union") continue; fields.set(f.name, armed); f.type = armed; - // Primitive and union slots yield the undefined value itself. - // Reference slots keep the deferred-init reads: consumers that - // observe undefined (printing, equality, typeof, nullish defaults) - // see it, and member access on it throws a TypeError, as in Node. - if (declared.kind === "union" || PRIMITIVE_EARLY_READS.has(declared.kind)) - earlyReadFields.add(f.name); - else deferredInitFields.add(f.name); + deferredInitFields.add(f.name); } } @@ -3738,43 +3722,6 @@ export function collectClassShapeInner( (name) => !hasAccessor(name) && !methods.has(name) && !lowerer.findMethodOn(base, name), ) : null; - // Constructor statements that run after the instance may have been - // exposed (a method call, `this` passed along, a base constructor - // that exposes it): a field they create can be read before its - // assignment, while Node holds undefined. - const exposedBefore = new Set(); - { - let exposed = false; - for (const stmt of ctor?.body?.statements ?? []) { - const expression = ts.isExpressionStatement(stmt) ? stmt.expression : null; - if ( - expression && - ts.isCallExpression(expression) && - expression.expression.kind === ts.SyntaxKind.SuperKeyword - ) { - if (base?.constructionEscapes === true || expression.arguments.some(mentionsReceiver)) - exposed = true; - continue; - } - const assigned = - expression && - ts.isBinaryExpression(expression) && - expression.operatorToken.kind === ts.SyntaxKind.EqualsToken && - ts.isPropertyAccessExpression(expression.left) && - expression.left.expression.kind === ts.SyntaxKind.ThisKeyword - ? expression - : null; - if (exposed || (assigned && mentionsReceiver(assigned.right))) exposedBefore.add(stmt); - const plainAssignment = - assigned !== null && - ts.isPropertyAccessExpression(assigned.left) && - !mentionsReceiver(assigned.right) && - !hasAccessor(assigned.left.name.text) && - !methods.has(assigned.left.name.text) && - !lowerer.findMethodOn(base, assigned.left.name.text); - if (!plainAssignment && mentionsReceiver(stmt)) exposed = true; - } - } if (ctor?.body) { for (const stmt of ctor.body.statements) { const lhs = @@ -3845,15 +3792,8 @@ export function collectClassShapeInner( type = inheritedJsFieldType(lowerer, decl, name, type); // super() can invoke a subclass setter or method before its // constructor assignments run. These slots start undefined. - const sealed = sealedPrefix?.created.has(name) === true; - if (base && lowerer.dynConvertible(type) && !sealed) type = DYN; - if (exposedBefore.has(stmt) && !sealed && earlyReadable(lowerer, type)) { - const armed = lowerer.runtimeOptionalType(type); - if (armed.kind === "union") { - type = armed; - earlyReadFields.add(name); - } - } + if (base && lowerer.dynConvertible(type) && !sealedPrefix?.created.has(name)) + type = DYN; fields.set(name, type); fieldOrder.push({ name, type, initializer: undefined }); continue; @@ -4114,7 +4054,6 @@ export function collectClassShapeInner( ? { classDecorators: { nodes: classDecoratorNodes } } : {}), ...(deferredInitFields.size > 0 ? { deferredInitFields } : {}), - ...(earlyReadFields.size > 0 ? { earlyReadFields } : {}), ...(escape.escapes ? { constructionEscapes: true as const } : {}), }; // GENERIC members get their declaring-class backlink now that the @@ -6289,33 +6228,6 @@ function overrideReturnAbi( return declared; } -/** Field kinds whose early reads yield the undefined value (earlyReadFields). */ -const PRIMITIVE_EARLY_READS: ReadonlySet = new Set([ - "f64", - "bool", - "string", - "bigint", -]); - -/** Field types whose slot can admit undefined for reads before the field's - * assignment. Date values are scalars, so their unassigned slot is memory - * safe; checked-dynamic slots already hold undefined. */ -function earlyReadable(lowerer: Lowerer, type: IrType): boolean { - if (isUnitType(type)) return false; - switch (type.kind) { - case "dyn": - case "void": - case "date": - case "generator": - case "caught": - return false; - case "object": - return lowerer.classes.get(type.className)?.def.runtime !== true; - default: - return true; - } -} - /** The nearest declaration of `name` at or above `info` — the method a * receiver of that static class runs when nothing below overrides it. */ export function findMethodOn( @@ -7753,11 +7665,7 @@ function paramPropInitStmts(lowerer: Lowerer, info: ClassInfo, thisLocal: IrLoca obj: { kind: "varRef", localId: thisLocal.id, type: thisType, loc }, className: info.def.name, field: pp.name, - // An early-readable field's slot admits undefined (earlyReadFields). - value: lowerer.coerceToExpected( - { kind: "varRef", localId: local!.id, type: local!.type, loc }, - info.fields.get(pp.name) ?? local!.type, - ), + value: { kind: "varRef", localId: local!.id, type: local!.type, loc }, loc, }); } diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 4ef139293..c108ceb71 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -3161,51 +3161,6 @@ export function lowerTernary( * the same union (unnarrowed use), to a SUB-union (partial narrowing — * unrepresentable without a re-tag), or to nothing (`never` in an * exhaustive default) leaves the expression union-typed. */ -/** Uses that read an early-read field's value as Node does when it is - * undefined: printing, templates, operators, tests, member access, calls of - * program functions (whose parameters the optional-value analysis widens), - * and stores into bindings, fields and returns. Other uses, such as library - * arguments, extract the declared type with a check. */ -function observesEarlyRead(node: ts.Node): boolean { - let child = node; - let parent = node.parent; - while (parent && ts.isParenthesizedExpression(parent)) { - child = parent; - parent = parent.parent; - } - if (!parent) return false; - if ( - ts.isTemplateSpan(parent) || - ts.isBinaryExpression(parent) || - ts.isPrefixUnaryExpression(parent) || - ts.isPostfixUnaryExpression(parent) || - ts.isTypeOfExpression(parent) || - ts.isConditionalExpression(parent) || - ts.isIfStatement(parent) || - ts.isWhileStatement(parent) || - ts.isReturnStatement(parent) || - ts.isVariableDeclaration(parent) || - ts.isPropertyAssignment(parent) || - ts.isArrayLiteralExpression(parent) || - (ts.isPropertyAccessExpression(parent) && parent.expression === child) || - (ts.isElementAccessExpression(parent) && parent.expression === child) - ) - return true; - if (ts.isCallExpression(parent) && parent.arguments.includes(child as ts.Expression)) { - const callee = parent.expression; - if ( - ts.isPropertyAccessExpression(callee) && - ts.isIdentifier(callee.expression) && - callee.expression.text === "console" - ) - return true; - return ( - !ts.isPropertyAccessExpression(callee) || callee.expression.kind === ts.SyntaxKind.ThisKeyword - ); - } - return false; -} - export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrExpr { if ( (expr.type.kind === "union" || expr.type.kind === "dyn") && @@ -3416,25 +3371,6 @@ export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrEx if (expr.type.kind !== "union") return expr; if (ts.isPropertyAccessExpression(node) && isOptionalProcessStreamProperty(lowerer, node)) return expr; - // A field read before its assignment holds undefined although its - // declared type omits it; the declared type is no narrowing proof. A flow - // narrowing past the declared type (`if (this.x !== null)`) extracts the - // narrowed arm with a check, since the slot may still hold undefined. - if ( - expr.kind === "fieldGet" && - lowerer.classes.get(expr.className)?.earlyReadFields?.has(expr.field) === true - ) { - const symbol = ts.isPropertyAccessExpression(node) - ? lowerer.checker.getSymbolAtLocation(node.name) - : undefined; - const declared = symbol ? lowerer.mapTypeOf(lowerer.checker.getTypeOfSymbol(symbol)) : null; - const narrowedArm = lowerer.mapTypeOf(lowerer.typeOf(node)); - if (narrowedArm === null || narrowedArm.kind === "union") return expr; - if (declared !== null && typeEquals(declared, narrowedArm) && observesEarlyRead(node)) - return expr; - const helper = lowerer.narrowedArmHelper(expr.type.unionId, narrowedArm, expr.loc); - return helper ? lowerer.checkedNarrowCall(helper, expr, narrowedArm, expr.loc) : expr; - } // Represented fields and index values can include undefined even when // checker inference or lib.d.ts declares strings (RegExp captures). @@ -15465,20 +15401,6 @@ export function fieldGetExpr( const helper = lowerer.deferredReadHelper(target.fieldType.unionId, inner, loc); if (helper) return { kind: "call", callee: helper, args: [read], type: inner, loc }; } - // An early-read field (ClassInfo.earlyReadFields) yields its undefined - // where the use reads it as Node does; elsewhere the declared type is - // extracted with a check. - if ( - target.fieldType.kind === "union" && - lowerer.classes.get(target.className)?.earlyReadFields?.has(target.field) === true && - !observesEarlyRead(blame) - ) { - const declared = lowerer.mapTypeOf(lowerer.typeOf(blame)); - if (declared && declared.kind !== "union") { - const helper = lowerer.narrowedArmHelper(target.fieldType.unionId, declared, loc); - if (helper) return lowerer.checkedNarrowCall(helper, read, declared, loc); - } - } return read; } return { @@ -16019,22 +15941,6 @@ function lowerFieldCompoundValue( if (op === "+" && read.type.kind === "string") { appended = lowerer.ensureString(rhs, rhsNode ?? access); value = { kind: "strConcat", left: read, right: appended, type: STRING, loc }; - } else if ( - op === "+" && - read.type.kind === "union" && - lowerer.stripUndefinedArm(read.type).kind === "string" && - target.container === "class" && - lowerer.classes.get(target.className)?.earlyReadFields?.has(target.field) === true - ) { - // A string field read before its assignment holds undefined, which - // concatenates as "undefined". - value = { - kind: "strConcat", - left: lowerer.ensureString(read, access), - right: lowerer.ensureString(rhs, rhsNode ?? access), - type: STRING, - loc, - }; } else if (numericRead.type.kind === "f64" && numericRhs.type.kind === "f64") { value = { kind: "bin", op, left: numericRead, right: numericRhs, type: F64, loc }; } else if (bigintValue) { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index b77768c28..33dfcfb19 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -3976,18 +3976,6 @@ export class Lowerer { if (!s) return null; return s.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(s) : s; }; - // Fields that can be read before their assignment hold undefined then; - // their reads are runtime-optional values like missing array reads. - for (const info of this.classes.values()) { - if (!info.earlyReadFields || !info.decl?.name) continue; - const classSymbol = symbolOf(info.decl.name); - if (!classSymbol) continue; - const instance = this.checker.getDeclaredTypeOfSymbol(classSymbol); - for (const name of info.earlyReadFields) { - const property = this.checker.getPropertyOfType(instance, name); - if (property) optionalSymbols.add(property); - } - } const signatureOf = (node: ts.Identifier): FnSig | null => { const symbol = symbolOf(node); if (!symbol) return null; diff --git a/packages/compiler/test/class-early-field-reads.test.ts b/packages/compiler/test/class-early-field-reads.test.ts deleted file mode 100644 index c602a2f42..000000000 --- a/packages/compiler/test/class-early-field-reads.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { expect, test } from "vitest"; -import { compile, deserializeModule, validateModule } from "../src/index.js"; -import type { IrModule } from "../src/ir/ir.js"; - -async function lower(source: string, file = "main.ts"): Promise { - const dir = await mkdtemp(join(tmpdir(), "scriptc-early-field-reads-")); - try { - const entry = join(dir, file), - output = join(dir, "main.ir.json"); - await writeFile(entry, source); - const result = await compile(entry, { outDir: dir, outPath: output, outputKind: "ir" }); - if (!result.ok) - throw new Error(result.diagnostics.map((item) => `${item.code}: ${item.message}`).join("\n")); - const module = deserializeModule(await readFile(output, "utf8")); - expect(validateModule(module)).toEqual([]); - return module; - } finally { - await rm(dir, { recursive: true, force: true }); - } -} - -/** Field name → IR kind for a class. */ -function fields(module: IrModule, name: string): string { - const cls = module.classes.find((candidate) => candidate.name === name); - expect(cls, name).toBeDefined(); - return cls!.fields - .filter((field) => !field.name.startsWith("%")) - .map((field) => `${field.name}:${field.type.kind}`) - .join(" "); -} - -test("fields assigned after construction can call an override admit undefined", async () => { - const module = await lower(` -abstract class Base { - constructor() { - this.describe(); - } - abstract describe(): void; -} -class Panel extends Base { - label: string; - width: number; - count = 0; - constructor() { - super(); - this.label = "panel"; - this.width = 2; - } - describe(): void { - console.log(this.label, this.width, this.count); - } -} -class Plain { - label: string; - width: number; - constructor() { - this.label = "plain"; - this.width = 1; - this.describe(); - } - describe(): void { - console.log(this.label, this.width); - } -} -new Panel(); -new Plain(); -`); - expect(fields(module, "Panel")).toBe("label:union width:union count:union"); - expect(fields(module, "Plain")).toBe("label:string width:f64"); -}); - -test("JavaScript fields created after the constructor calls a method admit undefined", async () => { - const module = await lower( - ` -class Widget { - constructor() { - this.ready = true; - this.render(); - this.title = "widget"; - } - render() { - console.log(this.ready, this.title); - } -} -new Widget(); -`, - "main.js", - ); - expect(fields(module, "Widget")).toBe("ready:bool title:union"); -}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json deleted file mode 100644 index d2dcdcc24..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5943-fields-read-before-assignment.ts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/corpus/5943-fields-read-before-assignment.ts" - ], - "diags": [] -} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json deleted file mode 100644 index e9800b71d..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5944-js-fields-read-before-assignment.js.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/corpus/5944-js-fields-read-before-assignment.js" - ], - "diags": [] -} diff --git a/tests/corpus/5943-fields-read-before-assignment.ts b/tests/corpus/5943-fields-read-before-assignment.ts deleted file mode 100644 index 922b3c34d..000000000 --- a/tests/corpus/5943-fields-read-before-assignment.ts +++ /dev/null @@ -1,181 +0,0 @@ -// @transform-types -// Fields that a base constructor (or the constructor itself) can read -// through an override or a method call before they are assigned hold -// undefined then, as in Node, for every field kind. After construction -// the fields read and update normally. -class Point { - x: number; - constructor(x: number) { - this.x = x; - } -} -function show(label: string, value: number): string { - return `${label}=${value}`; -} -abstract class Widget { - log: string[] = []; - constructor() { - this.describe("base"); - } - abstract describe(when: string): void; -} -class Panel extends Widget { - label: string; - width: number; - visible: boolean; - origin: Point; - items: number[]; - options: { depth: number }; - key: string | number; - index: Map; - tags: Set; - count = 5; - constructor(label: string, readonly id: string) { - super(); - this.label = label; - this.width = 10; - this.visible = true; - this.origin = new Point(1); - this.items = [1, 2]; - this.options = { depth: 2 }; - this.key = 7; - this.index = new Map([["a", 1]]); - this.tags = new Set(["t"]); - this.describe("ctor"); - } - describe(when: string): void { - console.log(when, this.label, this.width, this.visible, this.origin, this.items, this.options, this.key, this.count, this.id); - console.log(when, `${this.label}:${this.width}`, this.width + 1, this.count * 2, this.label === undefined, typeof this.items, this.origin?.x, this.options?.depth ?? -1, this.index?.size, this.tags?.has("t")); - console.log(when, show(this.label, this.width), String(this.key), [this.label].length); - try { - console.log(this.label.length, this.items.length); - } catch (error) { - console.log(when, (error as Error).message); - } - } - grow(): number { - this.count++; - this.width += 5; - this.label += "!"; - this.items.push(this.width); - return this.count + this.width + this.items.length; - } -} -const panel = new Panel("main", "p1"); -console.log(panel.grow(), panel.label, panel.items, panel.count, panel.width); - -class Plain { - total: number; - name: string; - constructor() { - this.total = 1; - this.name = "plain"; - this.bump(); - } - bump(): void { - this.total++; - } -} -const plain = new Plain(); -console.log(plain.total, plain.name); - -class Toucher { - constructor() { - this.touch(); - } - touch(): void {} -} -class Counter extends Toucher { - count = 0; - label: string; - items: string[]; - constructor() { - super(); - this.label = "c"; - this.items = []; - } - override touch(): void { - this.count++; - this.label += "x"; - console.log(this.count, this.label, Number.isNaN(this.count)); - try { - this.items.push("a"); - } catch (error) { - console.log(error instanceof TypeError); - } - } -} -const c = new Counter(); -c.touch(); -console.log(c.count, c.label, c.items); - -class Shower { - constructor() { - this.show(); - } - show(): void {} -} -class Box extends Shower { - label: string; - value: T; - constructor(value: T) { - super(); - this.label = "box"; - this.value = value; - } - override show(): void { - console.log("show", this.label, this.value); - } -} -new Box(3).show(); -new Box("s").show(); - -type Ctor = new (...args: any[]) => T; -class Viewer { - constructor() { - this.show(); - } - show(): void {} -} -function Labeled>(Parent: B) { - return class extends Parent { - label = "mixed"; - override show(): void { - console.log("show", this.label); - } - }; -} -const L = Labeled(Viewer); -new L().show(); - -interface Crash { loc: number; message: string } -class Setupper { - constructor() { - this.setup(); - } - setup(): void {} -} -class Host extends Setupper { - crash: Crash | null; - name: string | null; - constructor(c: Crash | null) { - super(); - this.crash = c; - this.name = "host"; - } - override setup(): void { - console.log("setup", this.crash, this.name); - if (this.crash !== null) { - try { - console.log(this.crash.loc); - } catch (error) { - console.log(error instanceof TypeError); - } - } - } - report(): string { - if (this.crash) return `${this.crash.message} at ${this.crash.loc}`; - return this.name === null ? "none" : this.name.toUpperCase(); - } -} -console.log(new Host({ loc: 3, message: "boom" }).report(), new Host(null).report()); diff --git a/tests/corpus/5944-js-fields-read-before-assignment.js b/tests/corpus/5944-js-fields-read-before-assignment.js deleted file mode 100644 index e313a12b0..000000000 --- a/tests/corpus/5944-js-fields-read-before-assignment.js +++ /dev/null @@ -1,28 +0,0 @@ -// JavaScript class fields that the constructor creates after it calls a -// method, or after a base constructor that does, hold undefined until -// they are assigned, as in Node. -class Widget { - constructor(name) { - this.render(); - this.name = name; - this.size = 3; - this.title = "widget"; - this.parts = ["a"]; - this.meta = { id: 1 }; - } - render() { - console.log("render", this.name, this.title, this.size, this.parts, this.meta, this.size + 1, `${this.name}!`); - } -} -class Big extends Widget { - constructor() { - super("big"); - this.extra = 2; - } - render() { - super.render(); - console.log("big", this.extra); - } -} -new Widget("w").render(); -new Big().render(); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index e4dd020cd..09e45ea7f 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -2160,8 +2160,6 @@ "5940-callback-helper-specialization.ts": 3109, "5941-callback-specialization-recursion.ts": 3112, "5942-callback-specialization-throws.ts": 3221, - "5943-fields-read-before-assignment.ts": 3902, - "5944-js-fields-read-before-assignment.js": 2868, "5945-local-class-observed-methods.ts": 2284, "5946-nested-record-field-optional-writes.ts": 2987, "5950-tuple-predicate-methods.ts": 4611, @@ -5173,8 +5171,6 @@ "5940-callback-helper-specialization.ts": 4548, "5941-callback-specialization-recursion.ts": 4448, "5942-callback-specialization-throws.ts": 3443, - "5943-fields-read-before-assignment.ts": 4319, - "5944-js-fields-read-before-assignment.js": 3945, "5945-local-class-observed-methods.ts": 4458, "5946-nested-record-field-optional-writes.ts": 3537, "5950-tuple-predicate-methods.ts": 4018, From 7cfb6b16d207294bedb546f1476f9ea756a6df33 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 12:47:01 -0500 Subject: [PATCH 107/117] Report unhandled rejections between timers and between immediates Node runs runNextTicks after each timer and each immediate callback, which reports the unhandled rejections the callback left before the next one runs. The event loop now leaves the timer phase when a callback leaves the rejection ledger non-empty, the check phase waits for that report, and the check phase reports the ledger after each immediate's checkpoint. When several timers expired in the same turn, a later timer ran before an earlier timer's rejection was reported. On macOS the 2 ms and 3 ms timers in 5809-process-exit-and-rejections.cjs expire together, so its uncaught 'thrown string' was printed before the TypeError rejection. 5996-rejections-between-macrotasks.cjs makes five timers expire in the same turn and checks the order across three immediates. --- ...996-rejections-between-macrotasks.cjs.json | 6 + packages/runtime/src/scr_async.c | 13 +- .../5996-rejections-between-macrotasks.cjs | 33 + tests/harness/corpus-costs.json | 10836 ++++++++-------- 4 files changed, 5471 insertions(+), 5417 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5996-rejections-between-macrotasks.cjs.json create mode 100644 tests/corpus/5996-rejections-between-macrotasks.cjs diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5996-rejections-between-macrotasks.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5996-rejections-between-macrotasks.cjs.json new file mode 100644 index 000000000..0e719fe78 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5996-rejections-between-macrotasks.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5996-rejections-between-macrotasks.cjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index 308c9198d..48f3a5329 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -4464,7 +4464,9 @@ static bool scr_loop_run_pass(ScrPromise *top_level, bool first_checkpoint) { } scr_firing_id = 0; if (scr_exc_pending()) return false; /* uncaught throw in a callback: main handles it */ - if (scr_ready_len > 0 || scr_nt_head != NULL) break; /* drain ticks and microtasks before more timers */ + /* Drain ticks and microtasks, and report the rejections the callback + * left, before more timers (Node's runNextTicks between timers). */ + if (scr_ready_len > 0 || scr_nt_head != NULL || scr_nunhandled > 0) break; } /* The check phase: immediates queued BEFORE this phase started run * now, FIFO; ones a callback queues wait for the next turn (the end @@ -4474,7 +4476,7 @@ static bool scr_loop_run_pass(ScrPromise *top_level, bool first_checkpoint) { * every macrotask; pending ticks or a woken fiber restart the turn * first (the timer loop's break above), so the phase only runs on a * drained checkpoint. */ - if (scr_ready_len == 0 && scr_nt_head == NULL && scr_pending_immediates > 0) { + if (scr_ready_len == 0 && scr_nt_head == NULL && scr_nunhandled == 0 && scr_pending_immediates > 0) { size_t end = scr_nimmediates; while (scr_immediates_head < end) { size_t i = scr_immediates_head++; @@ -4490,6 +4492,13 @@ static bool scr_loop_run_pass(ScrPromise *top_level, bool first_checkpoint) { scr_closure_release(cb); if (scr_exc_pending()) return false; /* uncaught throw: main handles it */ if (!scr_loop_run_checkpoint()) return false; + /* Node's runNextTicks between immediates also reports the + * rejections the callback left before the next one runs; a + * listener's jobs drain before the next report. */ + while (scr_nunhandled > 0 && (top_level == NULL || top_level->state != SCR_PROM_REJECTED)) { + if (scr_report_unhandled_rejections()) return true; + if (!scr_loop_run_checkpoint()) return false; + } if (top_level != NULL && top_level->state == SCR_PROM_REJECTED) break; } /* Fully drained: reset the cursor so the array reuses its slots. */ diff --git a/tests/corpus/5996-rejections-between-macrotasks.cjs b/tests/corpus/5996-rejections-between-macrotasks.cjs new file mode 100644 index 000000000..1afd8c8e8 --- /dev/null +++ b/tests/corpus/5996-rejections-between-macrotasks.cjs @@ -0,0 +1,33 @@ +'use strict'; +// Unhandled rejections are reported after the callback that left them, +// before the next due timer or the next immediate runs (Node's +// runNextTicks between macrotasks), also when several timers expire in +// the same turn. +process.on('unhandledRejection', (reason) => { + console.log('unhandledRejection', reason instanceof Error ? reason.message : JSON.stringify(reason)); +}); +process.on('uncaughtException', (err, origin) => console.log(origin, err)); + +const start = Date.now(); +setTimeout(() => void Promise.reject({ a: 1 }), 1); +setTimeout(() => void Promise.reject(new TypeError('typed reason')), 2); +setTimeout(() => { + throw 'thrown string'; +}, 3); +setTimeout(() => { + console.log('timer 4'); + Promise.reject('handled later').catch((e) => console.log('caught', e)); +}, 4); +setTimeout(() => console.log('timer 5'), 5); +// Every timer above is due once this returns. +while (Date.now() - start < 20) {} + +setTimeout(() => { + setImmediate(() => void Promise.reject('first immediate')); + setImmediate(() => { + console.log('second immediate'); + process.nextTick(() => console.log('tick')); + void Promise.reject('second immediate'); + }); + setImmediate(() => console.log('third immediate')); +}, 30); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index ea2d8da87..7d8030e95 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1,1699 +1,1699 @@ { "note": "Milliseconds per corpus program on a GitHub-hosted ubuntu-24.04 runner: its differential plus llvm-differential case, per flavor (medians of green main runs). scripts/ci-corpus-costs.mjs refreshes it from CI logs.", "plain": { - "001-hello.ts": 4256, - "002-log-args.ts": 4431, - "100-number-format.ts": 4288, - "1000-json-stringify-basics.ts": 5132, - "1001-json-escapes-unicode.ts": 3267, - "1002-json-parse-cast.ts": 5058, - "1003-json-parse-unions.ts": 4949, - "1004-json-parse-errors.ts": 3893, - "1005-json-nested.ts": 4163, - "1006-json-fs-config.ts": 3643, - "1007-json-rc-stress.ts": 4310, - "1008-json-null-arms.ts": 3701, - "1009-json-optional-fields.ts": 5156, - "101-arithmetic.ts": 3674, - "1010-json-stringify-space.ts": 4817, - "1011-json-unknown-typeof.ts": 3898, - "102-comparisons.ts": 4171, - "1020-async-basics.ts": 2636, - "1021-async-ordering.ts": 3263, - "1022-async-exceptions.ts": 3483, - "1023-async-rc-stress.ts": 4371, - "1024-async-pending-exit.ts": 3071, - "1025-async-promise-capture.ts": 3271, - "1026-throw-promise.ts": 3956, - "1027-async-return-promise.ts": 2933, - "1028-async-return-record-literals.ts": 3384, - "1029-async-eager-chains.ts": 2879, - "103-ternary.ts": 2774, - "104-ternary-empty-arrays.ts": 3724, - "1050-comptime-tables.ts": 3691, - "1051-comptime-strings.ts": 2389, - "1052-comptime-records.ts": 3840, - "1053-comptime-json.ts": 4536, - "1054-comptime-modules/main.ts": 3656, - "110-number-radix.ts": 2382, - "111-record-entries.ts": 4655, - "1110-math-members.ts": 4248, - "1111-math-random.ts": 3457, - "1113-string-methods.ts": 3364, - "1114-string-unicode-island.ts": 3366, - "1115-parse-globals.ts": 2591, - "1116-island-static-mix.ts": 3058, - "1117-typeof-static-union.ts": 3667, - "1118-object-spread-conditional.ts": 3693, - "1119-switch-union.ts": 3739, - "112-class-descriptor-key.js": 3492, - "1121-infinity-number-tostring.ts": 3539, - "1122-any-captures.ts": 3596, - "1124-union-narrowed-retag.ts": 3745, - "113-promise-checked-exits.ts": 2180, - "114-live-record-delete.ts": 3506, - "115-array-compound.js": 2722, - "116-text-decoder-runtime.js": 3978, - "117-weak-cache-cycle.js": 2417, - "118-fs-stored-callbacks.cjs": 4105, - "119-native-patterns.js": 4047, - "1200-regex-test-basics.ts": 2828, - "1201-regex-replace.ts": 3118, - "1202-regex-substitutions.ts": 2460, - "1203-regex-split.ts": 3529, - "1204-regex-empty-unicode.ts": 2746, - "1205-regex-rc-stress.ts": 3472, - "1300-errors-basics.ts": 3642, - "1301-errors-subclass.ts": 3871, - "1302-errors-typed-catch.ts": 3598, - "1303-errors-rc-stress.ts": 2806, - "1304-errors-uncaught.ts": 2053, - "1305-errors-async-rejections.ts": 3710, - "1306-errors-runtime-instances.ts": 2540, - "1350-path-normalize-join.ts": 2427, - "1351-path-parts.ts": 2680, - "1352-path-resolve-relative.ts": 3325, - "1353-os-basics.ts": 3345, - "1354-builtin-bare-specifiers.ts": 3282, - "1355-url-parse.ts": 2902, - "1356-url-file-bridge.ts": 2530, - "1357-fsp-roundtrip.ts": 2551, - "1358-crypto-random.ts": 3328, - "1359-json-module/main.ts": 3223, - "1360-spawn-sync.ts": 3535, - "1361-spawn-events.ts": 2778, - "1362-spawn-timers.ts": 8421, - "1363-spawn-unhandled-error.ts": 2559, - "1364-union-truthiness.ts": 2999, - "1365-union-logical.ts": 3464, - "1366-union-equality.ts": 3482, - "1367-destructuring.ts": 3491, - "1368-constructor-functions.ts": 3392, - "1369-promise-union.ts": 3326, - "1370-spread.ts": 2384, - "1371-union-template-tostring.ts": 3754, - "1372-loose-null-tests.ts": 3218, - "1373-union-array-arms.ts": 4066, - "140-bitwise-operators.ts": 2496, - "1400-typedarray-basics.ts": 3520, - "1401-typedarray-slice-set.ts": 3865, - "1402-buffer-encodings.ts": 2493, - "1403-buffer-fs.ts": 2658, - "1404-zlib-crypto-bytes.ts": 2380, - "1405-bytes-unions-arrays.ts": 2532, - "1406-dataview-mp4.ts": 3915, - "1407-dataview-bounds.ts": 3752, - "1408-string-indexing.ts": 3470, - "1409-typedarray-integer-loops.ts": 2071, - "1420-number-statics.ts": 3136, - "1421-number-parse-strings.ts": 2476, - "1422-date-iso.ts": 2600, - "1423-text-codec.ts": 4597, - "1424-fs-options.ts": 3300, - "1425-stdin-tty.ts": 3063, - "1426-stdin-read.ts": 2925, - "1427-fromcharcode-lastindexof.ts": 3413, - "1428-settled-await-order.ts": 2724, - "1429-promise-catch-finally.ts": 2634, - "1430-promise-race.ts": 4554, - "1431-caught-tostring.ts": 2091, - "1432-destructured-params.ts": 3338, - "1433-filter-narrow.ts": 3904, - "1434-async-never.ts": 3174, - "1435-math-spread.ts": 3092, - "1436-default-undef-param.ts": 3956, - "1437-pad-default.ts": 3383, - "1438-promise-all.ts": 6011, - "1440-interval-basics.ts": 4575, - "1441-interval-clear-cross.ts": 6244, - "1442-interval-throw.ts": 3389, - "1443-signal-handlers.ts": 6258, - "1444-exit-listeners.ts": 3211, - "1445-exit-process-exit.ts": 3320, - "1446-exit-uncaught.ts": 2360, - "1447-stdin-closed-events.ts": 2750, - "1448-stream-columns.ts": 2209, - "1450-incdec-expression.ts": 3228, - "1451-instanceof-uint8array-unknown.ts": 2957, - "1452-return-through-finally.ts": 3660, - "1453-pmap-settled.ts": 3618, - "1454-nonnull-narrow-and-fcc-bytes.ts": 3317, - "1455-lambda-union-return-adoption.ts": 2774, - "1460-console-error-warn.ts": 3320, - "1461-process-pid-getuid-kill.ts": 3247, - "1462-exec-sync.ts": 3282, - "1463-timeout-unref.ts": 3251, - "1464-env-writes.ts": 2987, - "1465-env-value.ts": 3024, - "1466-child-containers.ts": 3422, - "1467-string-match.ts": 3346, - "1468-exec-path.ts": 2301, - "1469-remove-listener.ts": 3606, - "1470-child-lifecycle.ts": 3256, - "1471-child-unref.ts": 7451, - "1472-errno-code.ts": 3295, - "1473-promisify-execfile.ts": 2595, - "1474-string-decoder.ts": 3611, - "1475-readline-closed-stdin.ts": 3112, - "1476-assign-expression.ts": 3030, - "1477-in-expressions.ts": 2996, - "1478-promise-reject.ts": 3812, - "1479-destructuring-assign.ts": 3356, - "1480-os-network-interfaces.ts": 4196, - "1481-string-case-static.ts": 3245, - "1482-spawnsync-error.ts": 3565, - "1483-array-slice.ts": 3674, - "1520-fs-wider-surface.ts": 3471, - "1520-string-split-static.ts": 2773, - "1521-fs-lstat-lock.ts": 3726, - "1521-string-trim-pad-static.ts": 3379, - "1522-parseint-static.ts": 3352, - "1522-spawnsync-options.ts": 5275, - "1523-isnan-floor-static.ts": 3491, - "1523-spawn-options.ts": 3565, - "1524-atomics-sleep-static.ts": 3559, - "1524-catch-narrowing.ts": 3222, - "1525-child-exit-signal.ts": 3428, - "1525-unknown-typeof-validation.ts": 3170, - "1526-set-spread.ts": 3383, - "1527-logical-mixed-operands.ts": 3407, - "1528-delete-records-env.ts": 3353, - "1529-class-with-statics.ts": 2988, - "1530-array-push-variadic.ts": 3122, - "1530-spread-override-completion.ts": 2849, - "1531-delete-optional-fields.ts": 3199, - "1531-process-arch-versions.ts": 3354, - "1532-array-splice-shift.ts": 2767, - "1532-union-shared-field-read.ts": 3248, - "1533-bool-equality.ts": 3299, - "1533-path-platform-namespaces.ts": 3213, - "1534-crypto-hash-chain.ts": 3265, - "1534-union-as-arm-cast.ts": 2201, - "1535-spawn-fd-stdio.ts": 3518, - "1535-union-param-defaults.ts": 2934, - "1536-destructuring-defaults.ts": 3325, - "1536-string-array-sweep.ts": 3492, - "1537-chalk-hybrid/main.ts": 2721, - "1537-os-release-spawnsync-stdio.ts": 3013, - "1538-await-promiselike-return.ts": 3514, - "1538-math-static-scalar.ts": 2646, - "1539-readonly-set-map.ts": 2440, - "1539-unknown-truthiness.ts": 3020, - "1540-os-userinfo.ts": 2759, - "1540-void-statement.ts": 3146, - "1541-fs-readdir-dirent.ts": 3308, - "1541-union-keyed-reads.ts": 2673, - "1542-map-promise-values.ts": 3263, - "1542-record-literal-into-union.ts": 3421, - "1543-rest-destructuring.ts": 2387, - "1543-set-server-handles.ts": 3383, - "1544-dyn-json-reads.ts": 4211, - "1544-string-matchall.ts": 3589, - "1545-spread-order-and-optional.ts": 3635, - "1546-union-element-reads.ts": 3551, - "1547-computed-key-fold.ts": 3124, - "1548-boolean-condition-forms.ts": 3319, - "1549-array-isarray-unions.ts": 3931, - "1550-param-defaults-func-set.ts": 3236, - "1551-dyn-receiver-methods.ts": 4427, - "1552-exec-options-record.ts": 3644, - "1553-truthy-hof-predicates.ts": 3271, - "1554-caught-into-unknown.ts": 3523, - "1555-index-spread-into-declared.ts": 4108, - "1556-union-retag-width-arms.ts": 2796, - "1557-url-host.ts": 3260, - "1558-any-joins-and-dyn-validation.ts": 2875, - "1559-conditional-spread-index-merge.ts": 2528, - "1560-forof-homogeneous-tuples.ts": 2537, - "1561-forof-strings.ts": 2246, - "1561-promise-then.ts": 3068, - "1562-optional-chain-tails.ts": 2705, - "1562-spawn-conditional-spread.ts": 3287, - "1563-forof-iterator-projections.ts": 2707, - "1563-string-raw-fold.ts": 2255, - "1564-fs-watch.ts": 3802, - "1564-string-raw.ts": 2918, - "1565-spawn-pipe-streams.ts": 3630, - "1565-union-element-join.ts": 3683, - "1566-child-duck-interface.ts": 3169, - "1567-server-close-override.ts": 2292, - "1568-x509-fingerprint.ts": 3260, - "1569-fsp-mkdir-unlink-chmod.ts": 2151, - "1570-child-unref-kill-reffed.ts": 8153, - "1571-optional-call-tostring-tail.ts": 2977, - "1571-stdin-set-raw-mode-non-tty.ts": 2223, - "1572-promise-reject-all-tuple.ts": 3566, - "1572-x509-validity-date-gettime.ts": 2517, - "1573-promisify-execfile-env-spread.ts": 3520, - "1573-tdz-scalar-forward-capture.ts": 2526, - "1574-dyn-optional-method-number-keys.ts": 3924, - "1574-promise-all-tuple-literal.ts": 2676, - "1575-unknown-assert-into-record.ts": 3519, - "1576-width-coercions.ts": 2683, - "1577-url-hostname.ts": 2337, - "1578-exec-input-optional.ts": 3059, - "1579-matchall-index.ts": 2856, - "1580-exec-env-conditional-spread.ts": 2426, - "1581-declare-const-read.ts": 3033, - "1582-timer-sleep-resolve.ts": 3454, - "1583-loops-and-stream-captures.ts": 2185, - "1584-union-field-unassigned.ts": 2354, - "1585-union-field-conditional-ctor.ts": 2702, - "1586-derived-field-before-super-init.ts": 2376, - "1590-js-unannotated.js": 2299, - "1591-js-closures.js": 3459, - "1592-js-classes.js": 3000, - "1593-js-jsdoc-records.js": 2837, - "1594-js-async.js": 3183, - "1595-js-island-gap/main.js": 3402, - "1596-cjs-modules/main.js": 2196, - "1597-mjs-graph/main.mjs": 3071, - "1598-cjs-builtin-require/main.js": 2199, - "1599-js-uncaught-throw.js": 2702, - "1600-assert-passing.ts": 3435, - "1601-assert-fail-exit.ts": 2059, - "1602-assert-caught-error.ts": 3377, - "1603-assert-scalar-messages.ts": 3468, - "1604-assert-deep-structures.ts": 3981, - "1605-assert-import-forms.ts": 3304, - "1606-assert-strict-module.ts": 3605, - "1607-assert-throws-match.ts": 2614, - "1608-cjs-assert/main.js": 3331, - "1609-assert-async.ts": 3158, - "1610-path-win32-full.ts": 3354, - "1611-url-file-bridge-neutral.ts": 2896, - "1612-cjs-module-globals.cjs": 1926, - "1613-cjs-esm-proxy-named/main.mjs": 2400, - "1614-js-fence-dodges.cjs": 2746, - "1615-cjs-export-shapes/main.cjs": 3057, - "1616-cjs-esm-lexer-invisible/main.mjs": 2969, - "1617-cjs-esm-lexer-visible/main.mjs": 3072, - "1618-cjs-esm-poisoned-tail/main.mjs": 2562, - "1619-cjs-esm-reexport-invisible/main.mjs": 2897, - "1620-cjs-require-effects-order/main.js": 3000, - "1621-cjs-require-cache-hit/main.js": 2851, - "1622-cjs-require-conditional/main.js": 3013, - "1623-cjs-require-diamond/main.js": 2407, - "1624-cjs-require-dir-mid-file/main.js": 2600, - "1625-cjs-require-lazy-fn/main.js": 2150, - "1626-cjs-require-mjs/main.js": 2871, - "1627-mjs-import-cjs-requires/main.mjs": 1644, - "1628-checked-dynamic-builtin-args.cjs": 3084, - "1629-require-main-filename.cjs": 2697, - "1630-inspect-scalars.ts": 2908, - "1630-rmsync-retry-options.cjs": 2250, - "1631-inspect-arrays.ts": 3807, - "1632-inspect-records.ts": 3072, - "1633-inspect-map-set.ts": 3749, - "1634-inspect-classes.ts": 3647, - "1635-inspect-buffer.ts": 2966, - "1636-util-format.ts": 2790, - "1637-inspect-dyn.ts": 3304, - "1638-inspect-cjs.cjs": 2542, - "1639-versions-openssl-probe.ts": 2867, - "1640-fd-read-decode.ts": 2932, - "1641-string-search.ts": 2902, - "1642-object-fromentries-rows.ts": 3493, - "1643-metadata-dyn-return.cjs": 3745, - "1644-ee-basics.ts": 2848, - "1645-ee-extends.ts": 2459, - "1646-ee-once-remove.ts": 3027, - "1647-ee-meta-events.ts": 2585, - "1648-ee-error-event.ts": 2283, - "1649-ee-names-counts.ts": 2675, - "1650-ee-prepend.ts": 2768, - "1651-ee-max-listeners.ts": 2226, - "1652-ee-snapshot.ts": 2979, - "1653-ee-cjs.cjs": 2570, - "1654-ee-namespace.ts": 2090, - "1655-spawnsync-neutral.ts": 4974, - "1656-execsync-neutral.ts": 2907, - "1657-spawn-async-neutral.ts": 3429, - "1660-buffer-read-write-num.ts": 3576, - "1661-buffer-encodings-full.ts": 3754, - "1662-string-decoder-encodings.ts": 3115, - "1663-buffer-compare-search-fill.ts": 3954, - "1664-dyn-fn-boundary.cjs": 3077, - "1665-dyn-fn-mustcall/main.cjs": 2296, - "1666-dyn-fn-identity.ts": 1815, - "1667-dyn-fn-not-callable.cjs": 3076, - "1668-dyn-fn-throws.cjs": 2849, - "1669-symbol-identity.ts": 2663, - "1670-symbol-registry.ts": 2947, - "1671-symbol-typeof.ts": 3427, - "1672-symbol-containers.ts": 2913, - "1673-symbol-cjs.cjs": 2504, - "1674-symbol-inspect.ts": 2841, - "1676-func-array-surface.ts": 3070, - "1677-emitter-listeners.ts": 3184, - "1678-emitter-dyn-listeners.cjs": 4068, - "1679-console-dyn.js": 3572, - "1680-assert-bytes.ts": 2927, - "1681-assert-funcs.ts": 3461, - "1685-stream-readable-basics.ts": 3135, - "1686-stream-readable-paused.ts": 2443, - "1687-stream-readable-flow-control.ts": 3237, - "1688-stream-writable-basics.ts": 2329, - "1689-stream-writable-async-drain.ts": 2789, - "1690-stream-duplex.ts": 2966, - "1691-stream-transform.ts": 2618, - "1692-stream-pipe.ts": 1917, - "1693-stream-pipe-backpressure.ts": 2276, - "1694-stream-destroy.ts": 3398, - "1695-stream-props.ts": 3260, - "1696-stream-read-inside-read.ts": 2732, - "1697-stream-tick-vs-timer.ts": 2767, - "1698-stream-uncaught-error.ts": 2710, - "1699-stream-callback-shapes.ts": 5108, - "1700-mustcall-common/main.cjs": 2603, - "1701-mustcall-exit-report/main.cjs": 3638, - "1702-dyn-proto-dispatch.cjs": 3719, - "1703-arguments-rest-props.cjs": 3420, - "1710-cjs-export-class/main.js": 3197, - "1711-cjs-export-single-values/main.js": 1720, - "1712-field-incdec.ts": 2250, - "1713-js-dyn-fields.js": 2301, - "1720-assert-throws-shape.ts": 3820, - "1721-assert-throws-regex-class.ts": 3123, - "1722-assert-rejects.ts": 3400, - "1723-assert-does-not-reject.ts": 2181, - "1724-assert-iferror.ts": 2290, - "1725-assert-symbols.ts": 2728, - "1726-promise-with-resolvers.ts": 3835, - "1727-assert-throws-shape-exit.ts": 2906, - "1730-countdown-symbol-keys/main.js": 3476, - "1731-symbol-field-shapes.cjs": 2330, - "1732-symbol-field-cross-module/main.js": 2189, - "1740-stream-extends-readable.ts": 2897, - "1741-stream-extends-writable.ts": 2368, - "1742-stream-extends-duplex-transform.ts": 2283, - "1743-stream-extends-vt-dispatch.ts": 3339, - "1744-stream-set-encoding.ts": 3916, - "1745-stream-encoding-js.cjs": 2742, - "1746-stream-for-await.ts": 3433, - "1747-stream-for-await-js.cjs": 2649, - "1750-http-agent-options.ts": 3028, - "1751-options-record-stance.ts": 3136, - "1760-surplus-args-drop.cjs": 2857, - "1761-emitter-special-event-names.cjs": 2907, - "1770-assert-dyn-strict.ts": 2622, - "1771-assert-dyn-deep.ts": 3046, - "1772-assert-dyn-js.cjs": 2864, - "1773-assert-dyn-exit.ts": 3097, - "1780-http-res-surface.ts": 3598, - "1781-http-server-shapes.cjs": 3736, - "1790-computed-key-folds.ts": 2845, - "1791-searchparams-core.ts": 3126, - "1792-searchparams-encoding.ts": 2170, - "1793-searchparams-iteration.ts": 2956, - "1794-searchparams-url-live.ts": 2603, - "1795-dyn-handle-request.cjs": 2396, - "1796-dyn-handle-body.cjs": 3535, - "1797-dyn-handle-socket.cjs": 3460, - "1798-dyn-handle-typed-box.ts": 2566, - "1800-immediate-basics.ts": 2566, - "1801-immediate-handle.ts": 2028, - "1802-immediate-unref-exit.ts": 3806, - "1803-timeout-refresh.ts": 2342, - "1804-timers-module.ts": 2401, - "1805-timer-callback-args.ts": 2781, - "1806-timer-delay-trunc.ts": 2824, - "1810-stream-options-const-record.ts": 2399, - "1811-stream-option-value-callbacks.cjs": 2961, - "1812-stream-super-options-forwarding.cjs": 3737, - "1813-stream-finished.ts": 3060, - "1814-stream-pipeline.cjs": 3701, - "1815-stream-state-reads.cjs": 2427, - "1820-static-block-basics.ts": 2518, - "1821-static-block-order.ts": 1976, - "1822-static-block-js.js": 3002, - "1823-static-instance-method-names.ts": 2691, - "1824-for-of-destructuring-defaults.ts": 2461, - "1825-exhaustive-typeof-switch.ts": 2514, - "1826-settimeout-arguments-callback.js": 2251, - "1830-enum-numeric-basics.ts": 2064, - "1831-enum-string-const-reverse.ts": 2264, - "1832-enum-modules/main.ts": 1833, - "1835-var-basics.ts": 2710, - "1836-var-loop-capture.ts": 3374, - "1837-var-undefined-hoisting.ts": 2917, - "1838-var-modules/main.ts": 2984, - "1839-var-js/main.cjs": 2891, - "1840-jsdoc-import-type-only/main.js": 1993, - "1850-overload-basics.ts": 2300, - "1851-overload-return-narrowing.ts": 2471, - "1852-overload-class-members.ts": 3006, - "1853-overload-modules/main.ts": 2503, - "1854-ambient-declare-fn.ts": 2630, - "1855-ambient-declare-fn-uncaught.ts": 3114, - "1870-unit-type-values.ts": 3109, - "1871-empty-array-never.ts": 2887, - "1872-template-tostring-composite.ts": 3584, - "1880-json-declared-field-order.ts": 3331, - "1881-default-anon/main.ts": 2353, - "1882-default-cjs-interop/main.ts": 2739, - "1883-default-exports/main.ts": 2650, - "1890-ns-imports/main.ts": 2779, - "1891-ns-reexport/main.ts": 2711, - "1940-class-values-basics.ts": 2460, - "1941-class-values-registry.ts": 3025, - "1942-class-expressions.ts": 2872, - "1943-class-statics-expanded.ts": 2580, - "1944-class-values-modules/main.ts": 2749, - "1950-generic-fn-values.ts": 2970, - "1951-generic-classes-basics.ts": 2980, - "1952-generic-class-statics-values.ts": 3062, - "1953-generic-class-hierarchy.ts": 2835, - "1954-generic-modules/main.ts": 1880, - "1960-namespace-basics.ts": 2265, - "1961-namespace-nested.ts": 2468, - "1962-namespace-classes.ts": 2516, - "1963-namespace-aliases.ts": 2375, - "1964-namespace-type-only.ts": 2816, - "1965-namespace-ambient.ts": 2803, - "1966-namespace-modules/main.ts": 3021, - "1967-namespace-alias-typeonly.ts": 2847, - "1968-namespace-import-eq-snapshot.ts": 2494, - "1970-decorators-basics.ts": 2822, - "1971-decorators-rebinding.ts": 2744, - "1972-decorators-throwing.ts": 2170, - "1973-decorators-ambient.ts": 2056, - "1980-primitive-proto-statics.ts": 2953, - "1981-date-utc.ts": 3276, - "1982-freeze-resolve-passthrough.ts": 2464, - "1983-array-tuple-surfaces.ts": 2644, - "1990-labels-basics.ts": 2635, - "1991-for-in-loops.ts": 3295, - "1992-small-syntax.ts": 3144, - "200-strings.ts": 2045, - "2000-generic-methods-basic.ts": 2851, - "2001-generic-methods-generic-class.ts": 2303, - "2002-generic-methods-inheritance.ts": 2257, - "2003-generic-methods-object-literal.ts": 3223, - "2004-generic-methods-statics.ts": 2748, - "201-templates.ts": 2400, - "2010-generators-basics.ts": 2273, - "2011-generators-forof.ts": 2704, - "2012-generators-return-throw.ts": 3247, - "2013-generators-sent-values.ts": 2662, - "2014-generators-values.ts": 3279, - "2015-generators-yieldstar.ts": 2320, - "2016-generators-rc-stress.ts": 2649, - "2017-generators-async.ts": 1806, - "2018-generators-uncaught.ts": 2418, - "2019-generators-loops.ts": 2694, - "2020-generic-value-bindings.ts": 3269, - "2021-generic-value-binding-modules/main.ts": 2143, - "2022-width-index-capture.ts": 3286, - "2023-width-readonly.ts": 2938, - "2024-width-array-elems.ts": 3159, - "2025-width-union-compose.ts": 3090, - "2026-width-spread.ts": 2628, - "2030-width-nested.ts": 3229, - "2031-width-tuples.ts": 2339, - "2032-cjs-export-assigned-class-expression/main.cjs": 2543, - "2033-property-assigned-class-extends.cjs": 1959, - "2035-ternary-array-retag.cjs": 2840, - "2036-evolving-array-decl.cjs": 2905, - "2037-fn-decl-hoisting.cjs": 2710, - "2038-evolving-array-js.cjs": 2879, - "2040-any-bindings.ts": 1964, - "2040-mixin-heritage.ts": 3294, - "2041-any-params-returns.ts": 2494, - "2041-mixin-values.ts": 3171, - "2042-any-flow-loops.ts": 2765, - "2042-mixin-modules/main.ts": 2821, - "2043-any-dom-values.ts": 1989, - "2043-mixin-rc-stress.ts": 2763, - "2044-vtable-sibling-slots.ts": 3156, - "2045-objlit-accessors-basic.ts": 2839, - "2045-parameter-properties.ts": 2262, - "2046-abstract-classes.ts": 2943, - "2046-objlit-accessors-effects.ts": 3238, - "2047-objlit-accessors-shapes.ts": 2962, - "2047-optional-class-fields.ts": 2352, - "2050-dynamic-import-own-module/main.ts": 2258, - "2051-dynamic-import-then/main.ts": 2628, - "2052-dynamic-import-self.ts": 2111, - "2053-typeof-static-fold.ts": 2331, - "2054-destructuring-island-source.ts": 2721, - "2060-empty-tuple.ts": 2638, - "2070-computed-key-folds.ts": 2482, - "2071-integer-key-enumeration-order.ts": 1999, - "2072-expando-function-members.ts": 2249, - "2073-destructuring-assignment.ts": 3060, - "2074-island-destructuring.ts": 3490, - "2075-index-signature-runtime-keys.ts": 3003, - "2080-destructuring-defaults.ts": 2782, - "2081-destructuring-rest.ts": 2626, - "2082-destructuring-assignment.ts": 2395, - "2085-destructuring-heads-rest-params.ts": 3137, - "2087-destructuring-for-heads.ts": 1934, - "2090-index-signature-number-keys.ts": 3257, - "2091-index-signature-string-intersection.ts": 2929, - "2092-package-imports/main.ts": 2114, - "2093-timers-promises.ts": 2678, - "2094-diagnostics-channel.ts": 3068, - "2095-js-catch-unknown.js": 2369, - "2096-os-type.ts": 2451, - "2097-js-evolving-globals.js": 2097, - "210-string-methods.ts": 2359, - "2100-stream-default-hwm.ts": 3022, - "2101-dyn-param-defaults.ts": 3172, - "2102-empty-pattern-decls.ts": 2881, - "2105-computed-key-static-folds.ts": 2838, - "2106-comma-expressions.ts": 1834, - "211-string-unicode.ts": 2972, - "2110-top-object-types.ts": 2238, - "2111-json-stringify-unknown.ts": 3135, - "2112-array-at-findlast.ts": 3283, - "2113-string-index-methods.js": 2879, - "212-string-aliasing-append.ts": 2677, - "2120-package-self-import/main.ts": 2837, - "2121-esm-cycle-inert-backedge/main.ts": 2507, - "2123-ambient-import-crash/main.ts": 2934, - "2124-imports-field-wildcard/main.ts": 2541, - "2140-uri-component-codecs.ts": 2133, - "2160-dc-tracing-channel.cjs": 2230, - "2161-js-object-literal-identity.cjs": 2537, - "2162-js-dyn-destructure.cjs": 2853, - "2163-js-selfref-const.cjs": 2693, - "2164-js-then-dyn-handler.cjs": 3004, - "2165-js-throw-dyn.cjs": 2225, - "2166-cjs-getter-this/main.cjs": 2804, - "2170-island-array-exits.ts": 2101, - "2171-island-json-stringify.ts": 2821, - "2172-island-regexp-boundary.ts": 2351, - "2190-new-object-and-string-wrappers.ts": 1908, - "2191-uri-encoders.ts": 3002, - "2192-object-default-tostring.ts": 2457, - "2193-discarded-stdlib-reads.ts": 2611, - "2194-ambient-undef-chains.ts": 1952, - "2195-require-missing-package/main.mjs": 3141, - "2196-island-computed-key-chain.ts": 2827, - "2210-dyn-promise-crossing.cjs": 3139, - "2211-dc-trace-promise.cjs": 2409, - "2212-unhandled-rejection-listener.cjs": 3057, - "2213-async-local-storage.cjs": 3299, - "2214-dc-bind-store.cjs": 3410, - "2215-process-emit-warning-exit.cjs": 3115, - "2240-width-class-into-record.ts": 2461, - "2241-width-record-into-class.ts": 2711, - "2242-width-statics-into-record.ts": 2854, - "2243-width-assert-satisfies-shapes.ts": 2928, - "2250-tagged-templates.ts": 2744, - "2252-class-iterators.ts": 3258, - "2253-union-coercions.ts": 3096, - "2260-http2-constants.cjs": 2383, - "2280-builtin-namespace-destructure.cjs": 2801, - "2281-domexception-atob-btoa.cjs": 2886, - "2282-queue-microtask.cjs": 2614, - "2283-structured-clone.cjs": 3700, - "2284-regexp-constructor.cjs": 2429, - "2285-iferror-dyn.cjs": 2807, - "2286-dyn-object-walks.cjs": 2926, - "2300-dyn-record-spread-and-keyed-access.cjs": 2890, - "2301-cjs-export-table-dom-attach.cjs": 2512, - "2310-process-next-tick.ts": 3216, - "2311-next-tick-js-callbacks.js": 2966, - "2312-stream-underscore-assign.ts": 3290, - "2313-stream-underscore-assign-js.cjs": 2122, - "2314-process-introspection.ts": 2917, - "2320-await-unit.ts": 2292, - "2321-emitter-static-setmax.cjs": 2256, - "2322-dyn-array-sort.cjs": 2432, - "2323-timer-callback-returns.ts": 2842, - "2330-tls-server-runtime-options.cjs": 2815, - "2331-tls-server-options-typed.ts": 3087, - "2350-nan-global.ts": 3034, - "2351-async-methods.ts": 2783, - "2352-void-coercions.ts": 3060, - "2353-decorators-member-ambient.ts": 2052, - "2354-decorators-expression-ambient.ts": 1987, - "2360-tuple-to-array.ts": 3001, - "2361-assign-index-record.ts": 2918, - "2362-execsync-inherit.ts": 2884, - "2363-nullish-retag.ts": 3048, - "2364-in-runtime-key.ts": 2311, - "2365-dyn-into-island.ts": 2070, - "2366-string-well-formed.ts": 2331, - "2367-regexp-escape.ts": 3110, - "2368-set-methods.ts": 2456, - "2369-promise-try.ts": 2986, - "2370-group-by.ts": 3578, - "2371-iterator-helpers.ts": 4030, - "2380-buffer-module-named-import.ts": 2871, - "2381-builtin-default-imports.js": 2605, - "2382-cycle-two-decl/main.ts": 2659, - "2383-cycle-assertdoc/main.js": 2644, - "2384-cycle-mixed-bindings/main.ts": 2274, - "2385-builtin-reexport-facade/main.ts": 2047, - "2386-string-to-chars.ts": 2950, - "2387-tonumber-argv.ts": 2189, - "2388-tonumber-grammar-zoo.ts": 2227, - "2389-tonumber-unary-plus.ts": 2546, - "2390-dot-requires/main.cjs": 2258, - "2391-default-builtin-imports/main.ts": 3224, - "2392-block-guard-alias-scope.ts": 2115, - "2393-loop-exit-guard-narrow.ts": 2686, - "2394-loop-narrow-containment.ts": 2464, - "2395-while-cond-guard.ts": 2793, - "2396-born-narrowed-decl.ts": 2989, - "2397-branch-kill-merge.ts": 2557, - "2398-switch-arm-kill.ts": 2776, - "2399-reassign-kill-polarity.ts": 2005, - "240-stdout-write.ts": 2170, - "2400-kill-return-edge.ts": 2417, - "2401-kill-break-staging.ts": 2710, - "2402-labeled-break-kill.ts": 2048, - "2403-kill-continue-backedge.ts": 2629, - "2404-kill-throw-catch.ts": 1738, - "2405-sibling-arm-narrow.ts": 2542, - "2406-switch-clause-sibling-narrow.ts": 1729, - "2407-infinite-loop-seal.ts": 2732, - "2408-loop-terminality-reopen.ts": 2758, - "2409-loop-body-return-not-terminal.ts": 2649, - "2410-stacked-cases-terminality.ts": 2587, - "2411-exhaustive-switch-terminality.ts": 2117, - "2412-dowhile-guard-trailing-test.ts": 2829, - "2413-dowhile-kill-renarrow.ts": 2634, - "2414-dowhile-continue-kill.ts": 2056, - "2415-dowhile-break-trailing-test.ts": 2838, - "2416-spread-ternary-positions.ts": 2794, - "2417-ternary-local-inference.ts": 1836, - "2418-wrapped-ternary-arms.ts": 2376, - "2419-selector-ternary-union.ts": 1886, - "2420-nullish-null-identity.ts": 2382, - "2421-float-lane-inference.ts": 2567, - "2422-ieee-div-rem-corners.ts": 2214, - "2423-param-null-reassign.ts": 2589, - "2424-ternary-miss-first-narrowing.ts": 2704, - "2425-elseif-head-exit-narrow.ts": 2085, - "2426-default-snapshot-mutable/main.ts": 2501, - "2427-perf-hooks-now.ts": 2322, - "2428-field-redeclare-inherited.ts": 2811, - "2429-destructure-class-instance.ts": 2113, - "2430-empty-literal-unknown-field.js": 2775, - "2431-primitive-ctor-values.ts": 2709, - "2432-generic-member-fields-async.ts": 3359, - "2433-as-const-command-tables.ts": 3152, - "2434-deferred-init-fields.ts": 2675, - "2435-loose-same-kind-equality.ts": 2929, - "2440-console-inspect-args.ts": 3616, - "2441-console-process-argv.ts": 2729, - "2442-union-literal-arm-widening.ts": 2394, - "2443-union-literal-shadow-narrowing.ts": 2878, - "2444-union-literal-reducer-spread.ts": 2611, - "2445-math-minmax-nary.ts": 2928, - "2446-performance-global.ts": 1959, - "2447-island-boundary-slots/main.ts": 3526, - "2448-entries-null-arms-regex-arrays.ts": 3606, - "2450-private-instance-methods.ts": 3040, - "2451-private-fields.ts": 2458, - "2452-private-statics.ts": 2875, - "2453-private-accessors.ts": 2477, - "2454-private-generator-methods.ts": 3086, - "2455-private-brand-checks.ts": 2830, - "2456-private-async-methods.ts": 3027, - "2457-private-members.js": 2823, - "2460-qs-parse-grammar.ts": 2369, - "2461-qs-parse-options.ts": 2633, - "2462-qs-stringify.ts": 2904, - "2463-qs-escape-unescape.ts": 2627, - "2464-qs-require-forms.cjs": 2308, - "2470-mockable-module-shape.js": 3113, - "2471-record-keyed-write-hasown.js": 3326, - "2472-string-regexp-union.ts": 2731, - "2473-option-table-widths.js": 3152, - "2474-island-literal-forms.ts": 2479, - "2475-variadic-wrapper-island.js": 3198, - "2476-map-regex-values.ts": 2520, - "2480-recursive-record-tree.ts": 2079, - "2481-mutual-recursive-records.ts": 2753, - "2482-recursive-union-tree.ts": 2627, - "2483-recursive-record-cycles.ts": 3056, - "2484-json-stringify-circular.ts": 3122, - "2485-inspect-circular-refs.ts": 2852, - "2486-recursive-record-boundaries.ts": 3348, - "2487-recursive-deep-equal.ts": 2661, - "2488-ast-walker.ts": 3060, - "2490-find-miss-null-compare.ts": 1733, - "2491-strict-unit-compare-no-arm.ts": 2221, - "2492-loose-null-compare-unions.ts": 2888, - "2493-switch-unit-cases.ts": 2663, - "2494-no-arm-compare-effects.ts": 2604, - "2500-net-autosel-timeout.ts": 2518, - "2510-dyn-evolving-array-map.ts": 2547, - "2511-dyn-evolving-array-filter-foreach.ts": 2095, - "2512-dyn-evolving-array-mixed-push.ts": 1858, - "2520-private-statics-class-name-calls.ts": 2236, - "2521-private-statics-class-expression.ts": 2886, - "2522-private-statics-decorated.ts": 2242, - "2523-private-statics-aliased-class.ts": 2547, - "2530-object-destructuring-decl.ts": 2810, - "2531-array-tuple-destructuring-decl.ts": 2637, - "2532-param-destructuring-options.ts": 1880, - "2533-forof-destructuring.ts": 2933, - "2534-object-rest-decl.ts": 2924, - "2535-destructuring-assign-basics.ts": 2850, - "2536-destructuring-assign-nested.ts": 3192, - "2537-destructuring-assign-member-targets.ts": 2938, - "2538-destructuring-assign-class-source.ts": 2800, - "2539-class-instance-rest.ts": 3105, - "2540-accessor-destructuring-defaults.ts": 2832, - "2541-destructuring-eval-order.ts": 2813, - "2550-generics-keyof-pick.ts": 2927, - "2551-generics-value-aliases.ts": 2674, - "2552-generics-iface-methods.ts": 2402, - "2553-generics-signature-bindings.ts": 3014, - "2554-generics-frontier-mix.ts": 2966, - "2555-generics-keyof-writes.ts": 2779, - "2556-crypto-introspection.ts": 3064, - "2556-width-hybrid-shapes.ts": 1985, - "2557-tls-ca-store.ts": 3012, - "2557-width-field-lifts.ts": 3351, - "2558-index-signature-func-values.ts": 3392, - "2558-rejection-events.cjs": 2929, - "2559-index-signature-container-values.ts": 3437, - "2560-arraybuffer-dataview-set.ts": 3189, - "2561-object-is.ts": 2016, - "2562-intl-numberformat-en-us.ts": 2324, - "2563-stream-promises-pipeline.ts": 2778, - "2564-stream-promises-finished.ts": 2282, - "2565-stream-promises-js.cjs": 2174, - "2566-promise-reject-dyn-reason.js": 2837, - "2567-rest-spread-forward.js": 3053, - "2568-rest-spread-forward-dynamic.js": 3336, - "2569-upcast-identity.ts": 2549, - "2570-buffer-arg-validation.cjs": 3495, - "2571-searchparams-arg-validation.cjs": 3289, - "2572-readable-emitted-readable-flag.cjs": 2702, - "2573-fs-url-arg-ladders.cjs": 2908, - "2574-emitter-max-listeners-ladders.cjs": 2125, - "2575-string-destructuring-decl.ts": 3056, - "2576-string-destructuring-assign.ts": 2769, - "2577-builtin-global-destructuring.js": 2592, - "2578-jsval-into-unknown-rows.ts": 3507, - "2579-jsval-object-param-crossing.js": 2689, - "2580-jsval-routed-keyed-ops.js": 3049, - "2581-jsval-routed-calls.js": 2613, - "2582-jsval-object-statics.js": 3028, - "2582-jsval-routed-keyed-ops.js": 2927, - "2583-dyn-nullish-coalesce.js": 2319, - "2583-jsval-routed-calls.js": 3227, - "2584-jsval-object-statics.js": 2921, - "2584-union-dyn-collapse.ts": 2532, - "2585-dyn-nullish-coalesce.js": 3154, - "2585-unknown-array.ts": 3043, - "2586-object-assign-spread.js": 3635, - "2587-array-entries-forof.ts": 2696, - "2588-array-entries-chains.ts": 2632, - "2589-object-create-null.cjs": 3471, - "2590-object-create-dynamic.js": 2856, - "2591-ambient-generic-traps.ts": 2325, - "2592-ambient-trap-uncaught.ts": 2711, - "2593-generic-inert-bindings.ts": 2516, - "2594-nullish-generic-bindings.ts": 2446, - "2595-fs-arg-ladders.cjs": 3442, - "2596-net-arg-ladders.cjs": 3131, - "2597-dgram-send-ladders.cjs": 3331, - "2598-tls-arg-ladders.cjs": 3733, - "2599-stream-arg-ladders.cjs": 2976, - "2600-dyn-keyed-write-harness.js": 3406, - "2601-dyn-keyed-write-ops.js": 2727, - "2602-dyn-array-destructure.js": 2959, - "2603-island-keyed-write-dyn.js": 2708, - "2604-cycle-classes-mutual/main.ts": 2723, - "2605-cycle-three-module/main.ts": 1625, - "2606-dynamic-import-cycle/main.ts": 2126, - "2608-regex-named-groups.ts": 2860, - "2609-regex-named-replace.ts": 2148, - "2610-regex-named-matchall.ts": 2297, - "2611-regex-named-groups-js.cjs": 2862, - "2613-for-init-uninitialized-let.ts": 2631, - "2614-trap-binding-later-writes.ts": 2032, - "2615-nullish-field-record-binding.ts": 2520, - "2616-js-collect-probe-defers.js": 2218, - "2617-enum-static-field-import/main.ts": 2916, - "2618-ee-emit-override.ts": 2896, - "2619-ee-override-chain.ts": 2889, - "2620-ee-override-once-order.ts": 2166, - "2621-ee-override-error-throw.ts": 2609, - "2622-ee-override-filter.ts": 3169, - "2623-ee-job-queue.ts": 3061, - "2624-ee-override-js.cjs": 2641, - "2625-bytes-views.ts": 2414, - "2626-stream-event-names.ts": 3336, - "2627-stream-ticks-are-nextticks.ts": 2921, - "2628-stream-push-encodings.cjs": 2936, - "2629-stream-consumers.ts": 2548, - "2630-stream-consumers-errors.ts": 2549, - "2631-create-require/main.ts": 3179, - "2632-dyn-jsval-iterate.js": 2810, - "2633-island-promise-crossing.js": 3789, - "2634-stream-pipeline-arg-ladders.cjs": 3204, - "2635-trap-binding-unmappable-written.ts": 2573, - "2636-trap-binding-ambient-rooted-rewrite.ts": 2836, - "2637-create-require-bare/main.ts": 3077, - "2638-http-dyn-res-compat.cjs": 3513, - "2639-http-dyn-req-pause.cjs": 3242, - "2640-net-dyn-socket-compat.cjs": 3276, - "2641-http-agent-surface.cjs": 2546, - "2642-http-agent-maxsockets.cjs": 2399, - "2643-or-default-retag.ts": 2038, - "2644-http-client-url-argument.ts": 3141, - "2645-https-client-url-argument.ts": 3327, - "2646-top-level-await.ts": 1674, - "2647-top-level-await-modules/main.ts": 2735, - "2648-top-level-await-rejection.ts": 2839, - "2649-top-level-await-pending.ts": 2632, - "2650-top-level-await-self-import.ts": 2130, - "2651-top-level-await-pending-unhandled.ts": 2661, - "2652-top-level-await-dynamic/main.ts": 2738, - "2653-top-level-await-rejection-stops-loop.ts": 2112, - "2654-top-level-await-unrelated-rejection.ts": 2041, - "2655-top-level-await-cycle/main.ts": 1850, - "2656-top-level-await-cycle-order/main.ts": 2731, - "2657-top-level-await-cycle-dynamic/main.ts": 2538, - "2658-top-level-await-sync-completion/main.ts": 2977, - "2659-top-level-await-dynamic-cycle/main.ts": 2760, - "2660-top-level-await-cycle-rejection/main.ts": 2805, - "2661-top-level-await-dynamic-runtime-root/main.ts": 2535, - "2662-top-level-await-cycle-external-wait/main.ts": 2399, - "2663-top-level-await-dependency-errors/main.ts": 2147, - "2664-top-level-await-same-checkpoint-rejection.ts": 2912, - "2665-top-level-await-unhandled-listener-liveness.ts": 2595, - "2666-array-to-sorted.ts": 5539, - "2668-stored-number-array-iterator.ts": 3042, - "2669-array-copying-methods.ts": 2580, - "2670-uint8array-copy-iterate.ts": 3366, - "2671-array-copying-js.cjs": 2250, - "2672-http-request-response-callback.ts": 2816, - "2673-top-level-await-implicit-module.ts": 2785, - "2674-top-level-for-await-implicit-module.ts": 1961, - "2675-create-require-nested-esm.js": 2652, - "2675-process-self-reexec.ts": 2948, - "2676-indexed-read-strict-equality.ts": 2688, - "2676-record-clone-overrides.ts": 2029, - "2676-top-level-await-ambiguous/main.ts": 2537, - "2677-runtime-optional-closure.ts": 3484, - "2677-top-level-await-module-scope/main.ts": 2041, - "2678-date-instances.ts": 2275, - "2678-large-string-sparse-index.ts": 2301, - "2678-util-parseargs.ts": 5332, - "2679-util-parseargs-cjs.cjs": 2235, - "2680-util-parseargs-default.ts": 2688, - "2681-util-parseargs-dynamic.js": 3031, - "2682-fs-rename.ts": 3590, - "2683-filter-truthy-predicate.ts": 3261, - "2683-fs-rename-js.cjs": 2894, - "2684-filter-no-predicate-dyn.cjs": 2218, - "2684-fs-rename-abort.ts": 2755, - "2685-array-unshift-reverse.ts": 2996, - "2685-fs-write-sync.ts": 3069, - "2686-fs-file-handle.ts": 4210, - "2687-fsp-write-file-options.ts": 2069, - "2687-process-write-args.ts": 2527, - "2688-fs-stats-disk-fields.ts": 2259, - "2689-http-server-timeout-properties.ts": 2541, - "2690-https-server-timeout-option.ts": 1835, - "2691-retained-lowering-record-order.ts": 3261, - "2692-inline-record-assert-index.ts": 2994, - "2692-string-accumulation.ts": 2802, - "2693-math-constants.ts": 2159, - "2700-array-sort-complexity.ts": 3020, - "2700-http-static-trailers.ts": 2315, - "2700-wasi-core.ts": 2595, - "2701-array-sort-snapshot.ts": 2502, - "2701-http-static-trailer-wire.ts": 2176, - "2701-import-meta/main.mjs": 3392, - "2702-http-static-trailer-end.ts": 2071, - "2702-type-import-link-static/main.ts": 2443, - "2702-uint8array-to-sorted.ts": 2965, - "2703-array-sparse-sort.ts": 3909, - "2703-type-import-link-static-reexport/main.ts": 2704, - "2704-array-sparse-to-sorted.ts": 3697, - "2704-type-import-link-static-success/main.ts": 2487, - "2705-array-sparse-sort-append.ts": 4843, - "2705-type-import-link-dynamic/main.ts": 2701, - "2706-array-search-missing-needle.ts": 2539, - "2706-type-import-link-dynamic-success/main.ts": 2462, - "2707-array-search-huge-sparse.ts": 45317, - "2707-type-import-link-static-default-reexport/main.ts": 2670, - "2708-type-import-link-dynamic/main.ts": 2350, - "2720-array-read-parity.ts": 1959, - "2721-array-nested-missing-receiver.ts": 2561, - "2750-array-sparse-foundation.ts": 2117, - "2751-buffer-concat-sparse-list.ts": 1676, - "2752-array-optional-stores.ts": 2649, - "2753-array-optional-method-values.ts": 2199, - "2754-array-property-undefined.ts": 2439, - "2755-array-optional-literal-forwarding.ts": 2745, - "2780-array-parity-composition.ts": 7200, - "2781-array-missing-value-escape.ts": 2902, - "2782-array-sparse-callbacks.ts": 3115, - "2783-array-defaults-rest.ts": 2837, - "2784-array-reduce-missing-result.ts": 2800, - "2785-array-missing-destructuring.ts": 3065, - "2786-array-sparse-serialization.ts": 2409, - "2787-array-missing-string-arithmetic.ts": 2854, - "2788-array-missing-builtin-conversions.ts": 2132, - "2789-array-missing-optional-tostring.ts": 1804, - "2790-dynamic-import-self-name/main.ts": 2534, - "2791-record-optional-keys.ts": 2401, - "2792-record-optional-spread-entries.ts": 2956, - "2793-union-conversion-identity-capture.ts": 3189, - "2794-array-generic-callback-values.ts": 2738, - "2795-array-optional-typedarray-source.ts": 3311, - "2796-array-sparse-class-value-instanceof.ts": 2925, - "2800-array-expression-consumers.ts": 2649, - "2801-array-switch-consumers.ts": 2865, - "2820-array-missing-method-receivers.ts": 1887, - "2821-array-optional-numeric-comparisons.ts": 2197, - "2830-cjs-require-self-name/main.cjs": 2632, - "2840-finally-completions.ts": 3271, - "2841-using-sync.ts": 2134, - "2842-await-using.ts": 1855, - "2843-using-suppressed-error.ts": 1631, - "2844-node-disposable-resources.ts": 2377, - "2845-for-using-of.ts": 2775, - "2846-generator-using.ts": 2854, - "2850-async-generators-protocol.ts": 2671, - "2851-async-generators-values.ts": 2378, - "2852-timers-promises-interval.ts": 2688, - "2854-leading-bom-literals.ts": 2637, - "2855-searchparams-sort-complexity.ts": 1784, - "2856-dynamic-any-local-operators.ts": 2953, - "2857-branded-primitives.ts": 2640, - "2858-import-meta-resolve/main.mjs": 2725, - "2859-import-meta-resolve-dynamic/main.mjs": 1820, + "001-hello.ts": 3069, + "002-log-args.ts": 2728, + "100-number-format.ts": 3733, + "1000-json-stringify-basics.ts": 4746, + "1001-json-escapes-unicode.ts": 3114, + "1002-json-parse-cast.ts": 4816, + "1003-json-parse-unions.ts": 3373, + "1004-json-parse-errors.ts": 2257, + "1005-json-nested.ts": 3430, + "1006-json-fs-config.ts": 3508, + "1007-json-rc-stress.ts": 4738, + "1008-json-null-arms.ts": 3237, + "1009-json-optional-fields.ts": 3598, + "101-arithmetic.ts": 2904, + "1010-json-stringify-space.ts": 4663, + "1011-json-unknown-typeof.ts": 2914, + "102-comparisons.ts": 2408, + "1020-async-basics.ts": 2514, + "1021-async-ordering.ts": 2150, + "1022-async-exceptions.ts": 2155, + "1023-async-rc-stress.ts": 3249, + "1024-async-pending-exit.ts": 3248, + "1025-async-promise-capture.ts": 4134, + "1026-throw-promise.ts": 2862, + "1027-async-return-promise.ts": 3195, + "1028-async-return-record-literals.ts": 2979, + "1029-async-eager-chains.ts": 3200, + "103-ternary.ts": 2586, + "104-ternary-empty-arrays.ts": 3925, + "1050-comptime-tables.ts": 3449, + "1051-comptime-strings.ts": 4033, + "1052-comptime-records.ts": 4539, + "1053-comptime-json.ts": 2953, + "1054-comptime-modules/main.ts": 2477, + "110-number-radix.ts": 2253, + "111-record-entries.ts": 4124, + "1110-math-members.ts": 3859, + "1111-math-random.ts": 2956, + "1113-string-methods.ts": 3292, + "1114-string-unicode-island.ts": 2830, + "1115-parse-globals.ts": 2990, + "1116-island-static-mix.ts": 3032, + "1117-typeof-static-union.ts": 2965, + "1118-object-spread-conditional.ts": 2667, + "1119-switch-union.ts": 3067, + "112-class-descriptor-key.js": 2522, + "1121-infinity-number-tostring.ts": 3370, + "1122-any-captures.ts": 3176, + "1124-union-narrowed-retag.ts": 2492, + "113-promise-checked-exits.ts": 2859, + "114-live-record-delete.ts": 2500, + "115-array-compound.js": 3135, + "116-text-decoder-runtime.js": 2862, + "117-weak-cache-cycle.js": 2266, + "118-fs-stored-callbacks.cjs": 3485, + "119-native-patterns.js": 3500, + "1200-regex-test-basics.ts": 3223, + "1201-regex-replace.ts": 3086, + "1202-regex-substitutions.ts": 3684, + "1203-regex-split.ts": 3320, + "1204-regex-empty-unicode.ts": 2968, + "1205-regex-rc-stress.ts": 2448, + "1300-errors-basics.ts": 2709, + "1301-errors-subclass.ts": 3447, + "1302-errors-typed-catch.ts": 3128, + "1303-errors-rc-stress.ts": 2776, + "1304-errors-uncaught.ts": 2907, + "1305-errors-async-rejections.ts": 2863, + "1306-errors-runtime-instances.ts": 2803, + "1350-path-normalize-join.ts": 2394, + "1351-path-parts.ts": 2228, + "1352-path-resolve-relative.ts": 3019, + "1353-os-basics.ts": 2682, + "1354-builtin-bare-specifiers.ts": 2284, + "1355-url-parse.ts": 2467, + "1356-url-file-bridge.ts": 3063, + "1357-fsp-roundtrip.ts": 3440, + "1358-crypto-random.ts": 2124, + "1359-json-module/main.ts": 2889, + "1360-spawn-sync.ts": 3158, + "1361-spawn-events.ts": 3000, + "1362-spawn-timers.ts": 8505, + "1363-spawn-unhandled-error.ts": 2724, + "1364-union-truthiness.ts": 2131, + "1365-union-logical.ts": 2948, + "1366-union-equality.ts": 2233, + "1367-destructuring.ts": 3492, + "1368-constructor-functions.ts": 2941, + "1369-promise-union.ts": 2048, + "1370-spread.ts": 2658, + "1371-union-template-tostring.ts": 2681, + "1372-loose-null-tests.ts": 2819, + "1373-union-array-arms.ts": 2414, + "140-bitwise-operators.ts": 3378, + "1400-typedarray-basics.ts": 3056, + "1401-typedarray-slice-set.ts": 2697, + "1402-buffer-encodings.ts": 3146, + "1403-buffer-fs.ts": 3327, + "1404-zlib-crypto-bytes.ts": 3318, + "1405-bytes-unions-arrays.ts": 2463, + "1406-dataview-mp4.ts": 2536, + "1407-dataview-bounds.ts": 3301, + "1408-string-indexing.ts": 2027, + "1409-typedarray-integer-loops.ts": 2940, + "1420-number-statics.ts": 2894, + "1421-number-parse-strings.ts": 2645, + "1422-date-iso.ts": 2686, + "1423-text-codec.ts": 4188, + "1424-fs-options.ts": 2662, + "1425-stdin-tty.ts": 2638, + "1426-stdin-read.ts": 2379, + "1427-fromcharcode-lastindexof.ts": 2109, + "1428-settled-await-order.ts": 2663, + "1429-promise-catch-finally.ts": 3486, + "1430-promise-race.ts": 4032, + "1431-caught-tostring.ts": 2082, + "1432-destructured-params.ts": 3251, + "1433-filter-narrow.ts": 3353, + "1434-async-never.ts": 2711, + "1435-math-spread.ts": 2665, + "1436-default-undef-param.ts": 2896, + "1437-pad-default.ts": 3003, + "1438-promise-all.ts": 6347, + "1440-interval-basics.ts": 3004, + "1441-interval-clear-cross.ts": 5524, + "1442-interval-throw.ts": 3148, + "1443-signal-handlers.ts": 5739, + "1444-exit-listeners.ts": 3270, + "1445-exit-process-exit.ts": 2515, + "1446-exit-uncaught.ts": 2709, + "1447-stdin-closed-events.ts": 2034, + "1448-stream-columns.ts": 2668, + "1450-incdec-expression.ts": 3189, + "1451-instanceof-uint8array-unknown.ts": 3003, + "1452-return-through-finally.ts": 2097, + "1453-pmap-settled.ts": 3863, + "1454-nonnull-narrow-and-fcc-bytes.ts": 2192, + "1455-lambda-union-return-adoption.ts": 3144, + "1460-console-error-warn.ts": 2229, + "1461-process-pid-getuid-kill.ts": 2853, + "1462-exec-sync.ts": 3145, + "1463-timeout-unref.ts": 2935, + "1464-env-writes.ts": 2594, + "1465-env-value.ts": 3233, + "1466-child-containers.ts": 2674, + "1467-string-match.ts": 2677, + "1468-exec-path.ts": 2974, + "1469-remove-listener.ts": 4038, + "1470-child-lifecycle.ts": 1948, + "1471-child-unref.ts": 6913, + "1472-errno-code.ts": 2768, + "1473-promisify-execfile.ts": 3155, + "1474-string-decoder.ts": 3057, + "1475-readline-closed-stdin.ts": 2826, + "1476-assign-expression.ts": 2557, + "1477-in-expressions.ts": 2740, + "1478-promise-reject.ts": 3143, + "1479-destructuring-assign.ts": 2933, + "1480-os-network-interfaces.ts": 3749, + "1481-string-case-static.ts": 1949, + "1482-spawnsync-error.ts": 2332, + "1483-array-slice.ts": 3329, + "1520-fs-wider-surface.ts": 3206, + "1520-string-split-static.ts": 2787, + "1521-fs-lstat-lock.ts": 2868, + "1521-string-trim-pad-static.ts": 2727, + "1522-parseint-static.ts": 2059, + "1522-spawnsync-options.ts": 3990, + "1523-isnan-floor-static.ts": 2552, + "1523-spawn-options.ts": 2955, + "1524-atomics-sleep-static.ts": 3221, + "1524-catch-narrowing.ts": 2221, + "1525-child-exit-signal.ts": 2022, + "1525-unknown-typeof-validation.ts": 2311, + "1526-set-spread.ts": 3277, + "1527-logical-mixed-operands.ts": 2920, + "1528-delete-records-env.ts": 3318, + "1529-class-with-statics.ts": 2626, + "1530-array-push-variadic.ts": 2272, + "1530-spread-override-completion.ts": 2333, + "1531-delete-optional-fields.ts": 2822, + "1531-process-arch-versions.ts": 2409, + "1532-array-splice-shift.ts": 2440, + "1532-union-shared-field-read.ts": 2449, + "1533-bool-equality.ts": 3130, + "1533-path-platform-namespaces.ts": 2472, + "1534-crypto-hash-chain.ts": 3303, + "1534-union-as-arm-cast.ts": 2773, + "1535-spawn-fd-stdio.ts": 3617, + "1535-union-param-defaults.ts": 2848, + "1536-destructuring-defaults.ts": 2783, + "1536-string-array-sweep.ts": 2930, + "1537-chalk-hybrid/main.ts": 3161, + "1537-os-release-spawnsync-stdio.ts": 2411, + "1538-await-promiselike-return.ts": 2433, + "1538-math-static-scalar.ts": 2674, + "1539-readonly-set-map.ts": 2573, + "1539-unknown-truthiness.ts": 2629, + "1540-os-userinfo.ts": 2636, + "1540-void-statement.ts": 2658, + "1541-fs-readdir-dirent.ts": 3093, + "1541-union-keyed-reads.ts": 4144, + "1542-map-promise-values.ts": 2657, + "1542-record-literal-into-union.ts": 3004, + "1543-rest-destructuring.ts": 2897, + "1543-set-server-handles.ts": 2927, + "1544-dyn-json-reads.ts": 3602, + "1544-string-matchall.ts": 2940, + "1545-spread-order-and-optional.ts": 2963, + "1546-union-element-reads.ts": 2716, + "1547-computed-key-fold.ts": 4334, + "1548-boolean-condition-forms.ts": 4675, + "1549-array-isarray-unions.ts": 3420, + "1550-param-defaults-func-set.ts": 3314, + "1551-dyn-receiver-methods.ts": 4271, + "1552-exec-options-record.ts": 3353, + "1553-truthy-hof-predicates.ts": 2475, + "1554-caught-into-unknown.ts": 2996, + "1555-index-spread-into-declared.ts": 3100, + "1556-union-retag-width-arms.ts": 2198, + "1557-url-host.ts": 2745, + "1558-any-joins-and-dyn-validation.ts": 2600, + "1559-conditional-spread-index-merge.ts": 3037, + "1560-forof-homogeneous-tuples.ts": 2478, + "1561-forof-strings.ts": 2503, + "1561-promise-then.ts": 3156, + "1562-optional-chain-tails.ts": 3390, + "1562-spawn-conditional-spread.ts": 3006, + "1563-forof-iterator-projections.ts": 3054, + "1563-string-raw-fold.ts": 2666, + "1564-fs-watch.ts": 3415, + "1564-string-raw.ts": 2651, + "1565-spawn-pipe-streams.ts": 3154, + "1565-union-element-join.ts": 2733, + "1566-child-duck-interface.ts": 2463, + "1567-server-close-override.ts": 2863, + "1568-x509-fingerprint.ts": 2419, + "1569-fsp-mkdir-unlink-chmod.ts": 2704, + "1570-child-unref-kill-reffed.ts": 8818, + "1571-optional-call-tostring-tail.ts": 4280, + "1571-stdin-set-raw-mode-non-tty.ts": 2435, + "1572-promise-reject-all-tuple.ts": 3046, + "1572-x509-validity-date-gettime.ts": 2933, + "1573-promisify-execfile-env-spread.ts": 3140, + "1573-tdz-scalar-forward-capture.ts": 2068, + "1574-dyn-optional-method-number-keys.ts": 3318, + "1574-promise-all-tuple-literal.ts": 3025, + "1575-unknown-assert-into-record.ts": 3248, + "1576-width-coercions.ts": 2888, + "1577-url-hostname.ts": 2352, + "1578-exec-input-optional.ts": 3178, + "1579-matchall-index.ts": 3025, + "1580-exec-env-conditional-spread.ts": 3275, + "1581-declare-const-read.ts": 2341, + "1582-timer-sleep-resolve.ts": 2315, + "1583-loops-and-stream-captures.ts": 3154, + "1584-union-field-unassigned.ts": 2858, + "1585-union-field-conditional-ctor.ts": 2073, + "1586-derived-field-before-super-init.ts": 2823, + "1590-js-unannotated.js": 2965, + "1591-js-closures.js": 2113, + "1592-js-classes.js": 4260, + "1593-js-jsdoc-records.js": 3366, + "1594-js-async.js": 2772, + "1595-js-island-gap/main.js": 2168, + "1596-cjs-modules/main.js": 2751, + "1597-mjs-graph/main.mjs": 2858, + "1598-cjs-builtin-require/main.js": 2109, + "1599-js-uncaught-throw.js": 1870, + "1600-assert-passing.ts": 3321, + "1601-assert-fail-exit.ts": 2842, + "1602-assert-caught-error.ts": 2041, + "1603-assert-scalar-messages.ts": 2650, + "1604-assert-deep-structures.ts": 3035, + "1605-assert-import-forms.ts": 3128, + "1606-assert-strict-module.ts": 2927, + "1607-assert-throws-match.ts": 2731, + "1608-cjs-assert/main.js": 3193, + "1609-assert-async.ts": 1990, + "1610-path-win32-full.ts": 1939, + "1611-url-file-bridge-neutral.ts": 2575, + "1612-cjs-module-globals.cjs": 2846, + "1613-cjs-esm-proxy-named/main.mjs": 2282, + "1614-js-fence-dodges.cjs": 2910, + "1615-cjs-export-shapes/main.cjs": 3349, + "1616-cjs-esm-lexer-invisible/main.mjs": 2499, + "1617-cjs-esm-lexer-visible/main.mjs": 2355, + "1618-cjs-esm-poisoned-tail/main.mjs": 2404, + "1619-cjs-esm-reexport-invisible/main.mjs": 2675, + "1620-cjs-require-effects-order/main.js": 2586, + "1621-cjs-require-cache-hit/main.js": 2101, + "1622-cjs-require-conditional/main.js": 2194, + "1623-cjs-require-diamond/main.js": 2241, + "1624-cjs-require-dir-mid-file/main.js": 2559, + "1625-cjs-require-lazy-fn/main.js": 2333, + "1626-cjs-require-mjs/main.js": 2430, + "1627-mjs-import-cjs-requires/main.mjs": 2803, + "1628-checked-dynamic-builtin-args.cjs": 2085, + "1629-require-main-filename.cjs": 2419, + "1630-inspect-scalars.ts": 2701, + "1630-rmsync-retry-options.cjs": 2427, + "1631-inspect-arrays.ts": 3949, + "1632-inspect-records.ts": 3013, + "1633-inspect-map-set.ts": 2316, + "1634-inspect-classes.ts": 3062, + "1635-inspect-buffer.ts": 2271, + "1636-util-format.ts": 2132, + "1637-inspect-dyn.ts": 3164, + "1638-inspect-cjs.cjs": 2023, + "1639-versions-openssl-probe.ts": 2845, + "1640-fd-read-decode.ts": 3219, + "1641-string-search.ts": 3172, + "1642-object-fromentries-rows.ts": 2713, + "1643-metadata-dyn-return.cjs": 3460, + "1644-ee-basics.ts": 2495, + "1645-ee-extends.ts": 2603, + "1646-ee-once-remove.ts": 2849, + "1647-ee-meta-events.ts": 2040, + "1648-ee-error-event.ts": 2703, + "1649-ee-names-counts.ts": 2487, + "1650-ee-prepend.ts": 2672, + "1651-ee-max-listeners.ts": 2331, + "1652-ee-snapshot.ts": 2031, + "1653-ee-cjs.cjs": 2472, + "1654-ee-namespace.ts": 2390, + "1655-spawnsync-neutral.ts": 4056, + "1656-execsync-neutral.ts": 2824, + "1657-spawn-async-neutral.ts": 3268, + "1660-buffer-read-write-num.ts": 3727, + "1661-buffer-encodings-full.ts": 2670, + "1662-string-decoder-encodings.ts": 2362, + "1663-buffer-compare-search-fill.ts": 3956, + "1664-dyn-fn-boundary.cjs": 2792, + "1665-dyn-fn-mustcall/main.cjs": 2827, + "1666-dyn-fn-identity.ts": 2623, + "1667-dyn-fn-not-callable.cjs": 2618, + "1668-dyn-fn-throws.cjs": 2216, + "1669-symbol-identity.ts": 2335, + "1670-symbol-registry.ts": 1852, + "1671-symbol-typeof.ts": 2343, + "1672-symbol-containers.ts": 2800, + "1673-symbol-cjs.cjs": 2407, + "1674-symbol-inspect.ts": 1818, + "1676-func-array-surface.ts": 2784, + "1677-emitter-listeners.ts": 2400, + "1678-emitter-dyn-listeners.cjs": 2358, + "1679-console-dyn.js": 2880, + "1680-assert-bytes.ts": 3465, + "1681-assert-funcs.ts": 2454, + "1685-stream-readable-basics.ts": 2506, + "1686-stream-readable-paused.ts": 2711, + "1687-stream-readable-flow-control.ts": 2359, + "1688-stream-writable-basics.ts": 2613, + "1689-stream-writable-async-drain.ts": 2671, + "1690-stream-duplex.ts": 2112, + "1691-stream-transform.ts": 1780, + "1692-stream-pipe.ts": 3345, + "1693-stream-pipe-backpressure.ts": 2344, + "1694-stream-destroy.ts": 1870, + "1695-stream-props.ts": 2766, + "1696-stream-read-inside-read.ts": 3023, + "1697-stream-tick-vs-timer.ts": 2275, + "1698-stream-uncaught-error.ts": 2523, + "1699-stream-callback-shapes.ts": 1972, + "1700-mustcall-common/main.cjs": 3401, + "1701-mustcall-exit-report/main.cjs": 3316, + "1702-dyn-proto-dispatch.cjs": 2744, + "1703-arguments-rest-props.cjs": 2431, + "1710-cjs-export-class/main.js": 2997, + "1711-cjs-export-single-values/main.js": 2866, + "1712-field-incdec.ts": 1828, + "1713-js-dyn-fields.js": 2492, + "1720-assert-throws-shape.ts": 2372, + "1721-assert-throws-regex-class.ts": 2125, + "1722-assert-rejects.ts": 2761, + "1723-assert-does-not-reject.ts": 2536, + "1724-assert-iferror.ts": 2883, + "1725-assert-symbols.ts": 2626, + "1726-promise-with-resolvers.ts": 2320, + "1727-assert-throws-shape-exit.ts": 2580, + "1730-countdown-symbol-keys/main.js": 2657, + "1731-symbol-field-shapes.cjs": 3005, + "1732-symbol-field-cross-module/main.js": 2509, + "1740-stream-extends-readable.ts": 2167, + "1741-stream-extends-writable.ts": 2479, + "1742-stream-extends-duplex-transform.ts": 2640, + "1743-stream-extends-vt-dispatch.ts": 2388, + "1744-stream-set-encoding.ts": 2886, + "1745-stream-encoding-js.cjs": 2861, + "1746-stream-for-await.ts": 2864, + "1747-stream-for-await-js.cjs": 2685, + "1750-http-agent-options.ts": 2435, + "1751-options-record-stance.ts": 3010, + "1760-surplus-args-drop.cjs": 2845, + "1761-emitter-special-event-names.cjs": 2672, + "1770-assert-dyn-strict.ts": 2841, + "1771-assert-dyn-deep.ts": 2098, + "1772-assert-dyn-js.cjs": 2493, + "1773-assert-dyn-exit.ts": 2809, + "1780-http-res-surface.ts": 3019, + "1781-http-server-shapes.cjs": 2697, + "1790-computed-key-folds.ts": 2567, + "1791-searchparams-core.ts": 2632, + "1792-searchparams-encoding.ts": 2548, + "1793-searchparams-iteration.ts": 2977, + "1794-searchparams-url-live.ts": 2027, + "1795-dyn-handle-request.cjs": 2079, + "1796-dyn-handle-body.cjs": 3120, + "1797-dyn-handle-socket.cjs": 2724, + "1798-dyn-handle-typed-box.ts": 2104, + "1800-immediate-basics.ts": 2313, + "1801-immediate-handle.ts": 2272, + "1802-immediate-unref-exit.ts": 2368, + "1803-timeout-refresh.ts": 2346, + "1804-timers-module.ts": 2379, + "1805-timer-callback-args.ts": 2475, + "1806-timer-delay-trunc.ts": 2847, + "1810-stream-options-const-record.ts": 2576, + "1811-stream-option-value-callbacks.cjs": 2945, + "1812-stream-super-options-forwarding.cjs": 3075, + "1813-stream-finished.ts": 2644, + "1814-stream-pipeline.cjs": 2915, + "1815-stream-state-reads.cjs": 2499, + "1820-static-block-basics.ts": 2475, + "1821-static-block-order.ts": 2605, + "1822-static-block-js.js": 1831, + "1823-static-instance-method-names.ts": 2522, + "1824-for-of-destructuring-defaults.ts": 2238, + "1825-exhaustive-typeof-switch.ts": 1814, + "1826-settimeout-arguments-callback.js": 2356, + "1830-enum-numeric-basics.ts": 2431, + "1831-enum-string-const-reverse.ts": 2780, + "1832-enum-modules/main.ts": 2343, + "1835-var-basics.ts": 2924, + "1836-var-loop-capture.ts": 2857, + "1837-var-undefined-hoisting.ts": 2785, + "1838-var-modules/main.ts": 2572, + "1839-var-js/main.cjs": 2766, + "1840-jsdoc-import-type-only/main.js": 2328, + "1850-overload-basics.ts": 2354, + "1851-overload-return-narrowing.ts": 2268, + "1852-overload-class-members.ts": 2874, + "1853-overload-modules/main.ts": 2339, + "1854-ambient-declare-fn.ts": 2384, + "1855-ambient-declare-fn-uncaught.ts": 2441, + "1870-unit-type-values.ts": 2730, + "1871-empty-array-never.ts": 2177, + "1872-template-tostring-composite.ts": 2526, + "1880-json-declared-field-order.ts": 2276, + "1881-default-anon/main.ts": 2233, + "1882-default-cjs-interop/main.ts": 2407, + "1883-default-exports/main.ts": 2358, + "1890-ns-imports/main.ts": 2428, + "1891-ns-reexport/main.ts": 2422, + "1940-class-values-basics.ts": 2483, + "1941-class-values-registry.ts": 2632, + "1942-class-expressions.ts": 2765, + "1943-class-statics-expanded.ts": 2459, + "1944-class-values-modules/main.ts": 2440, + "1950-generic-fn-values.ts": 2561, + "1951-generic-classes-basics.ts": 2197, + "1952-generic-class-statics-values.ts": 2662, + "1953-generic-class-hierarchy.ts": 3001, + "1954-generic-modules/main.ts": 2756, + "1960-namespace-basics.ts": 2647, + "1961-namespace-nested.ts": 2257, + "1962-namespace-classes.ts": 2660, + "1963-namespace-aliases.ts": 2070, + "1964-namespace-type-only.ts": 2445, + "1965-namespace-ambient.ts": 2332, + "1966-namespace-modules/main.ts": 2434, + "1967-namespace-alias-typeonly.ts": 2455, + "1968-namespace-import-eq-snapshot.ts": 2251, + "1970-decorators-basics.ts": 2885, + "1971-decorators-rebinding.ts": 2022, + "1972-decorators-throwing.ts": 2312, + "1973-decorators-ambient.ts": 2390, + "1980-primitive-proto-statics.ts": 3122, + "1981-date-utc.ts": 3440, + "1982-freeze-resolve-passthrough.ts": 2302, + "1983-array-tuple-surfaces.ts": 3057, + "1990-labels-basics.ts": 2548, + "1991-for-in-loops.ts": 2966, + "1992-small-syntax.ts": 1927, + "200-strings.ts": 2314, + "2000-generic-methods-basic.ts": 2743, + "2001-generic-methods-generic-class.ts": 2632, + "2002-generic-methods-inheritance.ts": 3264, + "2003-generic-methods-object-literal.ts": 2644, + "2004-generic-methods-statics.ts": 2578, + "201-templates.ts": 2516, + "2010-generators-basics.ts": 1908, + "2011-generators-forof.ts": 2574, + "2012-generators-return-throw.ts": 2779, + "2013-generators-sent-values.ts": 2065, + "2014-generators-values.ts": 2940, + "2015-generators-yieldstar.ts": 1953, + "2016-generators-rc-stress.ts": 2595, + "2017-generators-async.ts": 2715, + "2018-generators-uncaught.ts": 2356, + "2019-generators-loops.ts": 2496, + "2020-generic-value-bindings.ts": 2351, + "2021-generic-value-binding-modules/main.ts": 2687, + "2022-width-index-capture.ts": 2751, + "2023-width-readonly.ts": 2800, + "2024-width-array-elems.ts": 2726, + "2025-width-union-compose.ts": 2851, + "2026-width-spread.ts": 2485, + "2030-width-nested.ts": 2774, + "2031-width-tuples.ts": 2693, + "2032-cjs-export-assigned-class-expression/main.cjs": 2477, + "2033-property-assigned-class-extends.cjs": 2618, + "2035-ternary-array-retag.cjs": 2404, + "2036-evolving-array-decl.cjs": 2542, + "2037-fn-decl-hoisting.cjs": 2645, + "2038-evolving-array-js.cjs": 3054, + "2040-any-bindings.ts": 2984, + "2040-mixin-heritage.ts": 2131, + "2041-any-params-returns.ts": 2687, + "2041-mixin-values.ts": 2744, + "2042-any-flow-loops.ts": 2769, + "2042-mixin-modules/main.ts": 1924, + "2043-any-dom-values.ts": 2778, + "2043-mixin-rc-stress.ts": 2775, + "2044-vtable-sibling-slots.ts": 2571, + "2045-objlit-accessors-basic.ts": 2640, + "2045-parameter-properties.ts": 2113, + "2046-abstract-classes.ts": 3000, + "2046-objlit-accessors-effects.ts": 2795, + "2047-objlit-accessors-shapes.ts": 2983, + "2047-optional-class-fields.ts": 2949, + "2050-dynamic-import-own-module/main.ts": 2608, + "2051-dynamic-import-then/main.ts": 2467, + "2052-dynamic-import-self.ts": 2449, + "2053-typeof-static-fold.ts": 2181, + "2054-destructuring-island-source.ts": 2707, + "2060-empty-tuple.ts": 2373, + "2070-computed-key-folds.ts": 2645, + "2071-integer-key-enumeration-order.ts": 3006, + "2072-expando-function-members.ts": 2512, + "2073-destructuring-assignment.ts": 2535, + "2074-island-destructuring.ts": 2609, + "2075-index-signature-runtime-keys.ts": 1981, + "2080-destructuring-defaults.ts": 2417, + "2081-destructuring-rest.ts": 2774, + "2082-destructuring-assignment.ts": 2489, + "2085-destructuring-heads-rest-params.ts": 2668, + "2087-destructuring-for-heads.ts": 2521, + "2090-index-signature-number-keys.ts": 1958, + "2091-index-signature-string-intersection.ts": 2567, + "2092-package-imports/main.ts": 2340, + "2093-timers-promises.ts": 2743, + "2094-diagnostics-channel.ts": 1983, + "2095-js-catch-unknown.js": 2499, + "2096-os-type.ts": 2709, + "2097-js-evolving-globals.js": 2560, + "210-string-methods.ts": 2593, + "2100-stream-default-hwm.ts": 2961, + "2101-dyn-param-defaults.ts": 2737, + "2102-empty-pattern-decls.ts": 2787, + "2105-computed-key-static-folds.ts": 2507, + "2106-comma-expressions.ts": 2500, + "211-string-unicode.ts": 1823, + "2110-top-object-types.ts": 1971, + "2111-json-stringify-unknown.ts": 2830, + "2112-array-at-findlast.ts": 2001, + "2113-string-index-methods.js": 2989, + "212-string-aliasing-append.ts": 1909, + "2120-package-self-import/main.ts": 1825, + "2121-esm-cycle-inert-backedge/main.ts": 1748, + "2123-ambient-import-crash/main.ts": 1870, + "2124-imports-field-wildcard/main.ts": 2082, + "2140-uri-component-codecs.ts": 1955, + "2160-dc-tracing-channel.cjs": 2212, + "2161-js-object-literal-identity.cjs": 2587, + "2162-js-dyn-destructure.cjs": 2628, + "2163-js-selfref-const.cjs": 2533, + "2164-js-then-dyn-handler.cjs": 2503, + "2165-js-throw-dyn.cjs": 2509, + "2166-cjs-getter-this/main.cjs": 2420, + "2170-island-array-exits.ts": 3096, + "2171-island-json-stringify.ts": 2652, + "2172-island-regexp-boundary.ts": 2763, + "2190-new-object-and-string-wrappers.ts": 1860, + "2191-uri-encoders.ts": 2586, + "2192-object-default-tostring.ts": 2607, + "2193-discarded-stdlib-reads.ts": 2445, + "2194-ambient-undef-chains.ts": 2022, + "2195-require-missing-package/main.mjs": 2412, + "2196-island-computed-key-chain.ts": 2831, + "2210-dyn-promise-crossing.cjs": 1918, + "2211-dc-trace-promise.cjs": 2793, + "2212-unhandled-rejection-listener.cjs": 2511, + "2213-async-local-storage.cjs": 2825, + "2214-dc-bind-store.cjs": 2651, + "2215-process-emit-warning-exit.cjs": 2666, + "2240-width-class-into-record.ts": 2573, + "2241-width-record-into-class.ts": 2686, + "2242-width-statics-into-record.ts": 2654, + "2243-width-assert-satisfies-shapes.ts": 2411, + "2250-tagged-templates.ts": 2617, + "2252-class-iterators.ts": 3448, + "2253-union-coercions.ts": 2899, + "2260-http2-constants.cjs": 2471, + "2280-builtin-namespace-destructure.cjs": 2645, + "2281-domexception-atob-btoa.cjs": 2853, + "2282-queue-microtask.cjs": 2526, + "2283-structured-clone.cjs": 3050, + "2284-regexp-constructor.cjs": 1945, + "2285-iferror-dyn.cjs": 2665, + "2286-dyn-object-walks.cjs": 2662, + "2300-dyn-record-spread-and-keyed-access.cjs": 2261, + "2301-cjs-export-table-dom-attach.cjs": 2384, + "2310-process-next-tick.ts": 2843, + "2311-next-tick-js-callbacks.js": 2254, + "2312-stream-underscore-assign.ts": 2790, + "2313-stream-underscore-assign-js.cjs": 2842, + "2314-process-introspection.ts": 2971, + "2320-await-unit.ts": 2748, + "2321-emitter-static-setmax.cjs": 2272, + "2322-dyn-array-sort.cjs": 1886, + "2323-timer-callback-returns.ts": 2523, + "2330-tls-server-runtime-options.cjs": 2677, + "2331-tls-server-options-typed.ts": 2790, + "2350-nan-global.ts": 2734, + "2351-async-methods.ts": 2622, + "2352-void-coercions.ts": 1788, + "2353-decorators-member-ambient.ts": 2547, + "2354-decorators-expression-ambient.ts": 2465, + "2360-tuple-to-array.ts": 2471, + "2361-assign-index-record.ts": 3021, + "2362-execsync-inherit.ts": 2693, + "2363-nullish-retag.ts": 2801, + "2364-in-runtime-key.ts": 2572, + "2365-dyn-into-island.ts": 1996, + "2366-string-well-formed.ts": 2147, + "2367-regexp-escape.ts": 2470, + "2368-set-methods.ts": 2846, + "2369-promise-try.ts": 2170, + "2370-group-by.ts": 2298, + "2371-iterator-helpers.ts": 2730, + "2380-buffer-module-named-import.ts": 2400, + "2381-builtin-default-imports.js": 2365, + "2382-cycle-two-decl/main.ts": 1682, + "2383-cycle-assertdoc/main.js": 2760, + "2384-cycle-mixed-bindings/main.ts": 1815, + "2385-builtin-reexport-facade/main.ts": 1834, + "2386-string-to-chars.ts": 2748, + "2387-tonumber-argv.ts": 2345, + "2388-tonumber-grammar-zoo.ts": 2619, + "2389-tonumber-unary-plus.ts": 2473, + "2390-dot-requires/main.cjs": 2365, + "2391-default-builtin-imports/main.ts": 3036, + "2392-block-guard-alias-scope.ts": 2477, + "2393-loop-exit-guard-narrow.ts": 2791, + "2394-loop-narrow-containment.ts": 2749, + "2395-while-cond-guard.ts": 2574, + "2396-born-narrowed-decl.ts": 2435, + "2397-branch-kill-merge.ts": 2334, + "2398-switch-arm-kill.ts": 2438, + "2399-reassign-kill-polarity.ts": 2238, + "240-stdout-write.ts": 2820, + "2400-kill-return-edge.ts": 2315, + "2401-kill-break-staging.ts": 2347, + "2402-labeled-break-kill.ts": 2610, + "2403-kill-continue-backedge.ts": 2391, + "2404-kill-throw-catch.ts": 2611, + "2405-sibling-arm-narrow.ts": 2300, + "2406-switch-clause-sibling-narrow.ts": 1885, + "2407-infinite-loop-seal.ts": 2596, + "2408-loop-terminality-reopen.ts": 2452, + "2409-loop-body-return-not-terminal.ts": 1860, + "2410-stacked-cases-terminality.ts": 2588, + "2411-exhaustive-switch-terminality.ts": 2704, + "2412-dowhile-guard-trailing-test.ts": 2401, + "2413-dowhile-kill-renarrow.ts": 2389, + "2414-dowhile-continue-kill.ts": 2546, + "2415-dowhile-break-trailing-test.ts": 2461, + "2416-spread-ternary-positions.ts": 2790, + "2417-ternary-local-inference.ts": 2737, + "2418-wrapped-ternary-arms.ts": 2485, + "2419-selector-ternary-union.ts": 2554, + "2420-nullish-null-identity.ts": 2418, + "2421-float-lane-inference.ts": 2337, + "2422-ieee-div-rem-corners.ts": 2498, + "2423-param-null-reassign.ts": 2447, + "2424-ternary-miss-first-narrowing.ts": 2373, + "2425-elseif-head-exit-narrow.ts": 2194, + "2426-default-snapshot-mutable/main.ts": 2194, + "2427-perf-hooks-now.ts": 2489, + "2428-field-redeclare-inherited.ts": 2204, + "2429-destructure-class-instance.ts": 2362, + "2430-empty-literal-unknown-field.js": 2633, + "2431-primitive-ctor-values.ts": 2702, + "2432-generic-member-fields-async.ts": 2679, + "2433-as-const-command-tables.ts": 2271, + "2434-deferred-init-fields.ts": 2673, + "2435-loose-same-kind-equality.ts": 2441, + "2440-console-inspect-args.ts": 3150, + "2441-console-process-argv.ts": 2027, + "2442-union-literal-arm-widening.ts": 2300, + "2443-union-literal-shadow-narrowing.ts": 2799, + "2444-union-literal-reducer-spread.ts": 2545, + "2445-math-minmax-nary.ts": 2355, + "2446-performance-global.ts": 2453, + "2447-island-boundary-slots/main.ts": 3241, + "2448-entries-null-arms-regex-arrays.ts": 3215, + "2450-private-instance-methods.ts": 2581, + "2451-private-fields.ts": 2918, + "2452-private-statics.ts": 2431, + "2453-private-accessors.ts": 2589, + "2454-private-generator-methods.ts": 2809, + "2455-private-brand-checks.ts": 2369, + "2456-private-async-methods.ts": 2625, + "2457-private-members.js": 2014, + "2460-qs-parse-grammar.ts": 2706, + "2461-qs-parse-options.ts": 2139, + "2462-qs-stringify.ts": 2756, + "2463-qs-escape-unescape.ts": 2677, + "2464-qs-require-forms.cjs": 2768, + "2470-mockable-module-shape.js": 3152, + "2471-record-keyed-write-hasown.js": 2699, + "2472-string-regexp-union.ts": 2532, + "2473-option-table-widths.js": 2095, + "2474-island-literal-forms.ts": 2881, + "2475-variadic-wrapper-island.js": 2240, + "2476-map-regex-values.ts": 2431, + "2480-recursive-record-tree.ts": 2075, + "2481-mutual-recursive-records.ts": 2525, + "2482-recursive-union-tree.ts": 2633, + "2483-recursive-record-cycles.ts": 2479, + "2484-json-stringify-circular.ts": 2869, + "2485-inspect-circular-refs.ts": 2957, + "2486-recursive-record-boundaries.ts": 2857, + "2487-recursive-deep-equal.ts": 2516, + "2488-ast-walker.ts": 2925, + "2490-find-miss-null-compare.ts": 2051, + "2491-strict-unit-compare-no-arm.ts": 2381, + "2492-loose-null-compare-unions.ts": 2451, + "2493-switch-unit-cases.ts": 2503, + "2494-no-arm-compare-effects.ts": 2501, + "2500-net-autosel-timeout.ts": 2202, + "2510-dyn-evolving-array-map.ts": 2611, + "2511-dyn-evolving-array-filter-foreach.ts": 2729, + "2512-dyn-evolving-array-mixed-push.ts": 2656, + "2520-private-statics-class-name-calls.ts": 2568, + "2521-private-statics-class-expression.ts": 2429, + "2522-private-statics-decorated.ts": 2492, + "2523-private-statics-aliased-class.ts": 2618, + "2530-object-destructuring-decl.ts": 2513, + "2531-array-tuple-destructuring-decl.ts": 2504, + "2532-param-destructuring-options.ts": 2714, + "2533-forof-destructuring.ts": 2583, + "2534-object-rest-decl.ts": 2277, + "2535-destructuring-assign-basics.ts": 2758, + "2536-destructuring-assign-nested.ts": 2761, + "2537-destructuring-assign-member-targets.ts": 2552, + "2538-destructuring-assign-class-source.ts": 2658, + "2539-class-instance-rest.ts": 2852, + "2540-accessor-destructuring-defaults.ts": 2732, + "2541-destructuring-eval-order.ts": 2121, + "2550-generics-keyof-pick.ts": 2790, + "2551-generics-value-aliases.ts": 2489, + "2552-generics-iface-methods.ts": 2118, + "2553-generics-signature-bindings.ts": 2838, + "2554-generics-frontier-mix.ts": 2857, + "2555-generics-keyof-writes.ts": 2600, + "2556-crypto-introspection.ts": 2362, + "2556-width-hybrid-shapes.ts": 3063, + "2557-tls-ca-store.ts": 2877, + "2557-width-field-lifts.ts": 2899, + "2558-index-signature-func-values.ts": 2980, + "2558-rejection-events.cjs": 2741, + "2559-index-signature-container-values.ts": 2921, + "2560-arraybuffer-dataview-set.ts": 2985, + "2561-object-is.ts": 3314, + "2562-intl-numberformat-en-us.ts": 1713, + "2563-stream-promises-pipeline.ts": 2673, + "2564-stream-promises-finished.ts": 2596, + "2565-stream-promises-js.cjs": 2121, + "2566-promise-reject-dyn-reason.js": 2527, + "2567-rest-spread-forward.js": 3263, + "2568-rest-spread-forward-dynamic.js": 2990, + "2569-upcast-identity.ts": 1878, + "2570-buffer-arg-validation.cjs": 4190, + "2571-searchparams-arg-validation.cjs": 2897, + "2572-readable-emitted-readable-flag.cjs": 2583, + "2573-fs-url-arg-ladders.cjs": 2789, + "2574-emitter-max-listeners-ladders.cjs": 2728, + "2575-string-destructuring-decl.ts": 2831, + "2576-string-destructuring-assign.ts": 2718, + "2577-builtin-global-destructuring.js": 2482, + "2578-jsval-into-unknown-rows.ts": 2821, + "2579-jsval-object-param-crossing.js": 2723, + "2580-jsval-routed-keyed-ops.js": 2125, + "2581-jsval-routed-calls.js": 3090, + "2582-jsval-object-statics.js": 2972, + "2582-jsval-routed-keyed-ops.js": 2851, + "2583-dyn-nullish-coalesce.js": 2185, + "2583-jsval-routed-calls.js": 2972, + "2584-jsval-object-statics.js": 2832, + "2584-union-dyn-collapse.ts": 2220, + "2585-dyn-nullish-coalesce.js": 2398, + "2585-unknown-array.ts": 2751, + "2586-object-assign-spread.js": 3004, + "2587-array-entries-forof.ts": 2555, + "2588-array-entries-chains.ts": 3001, + "2589-object-create-null.cjs": 2994, + "2590-object-create-dynamic.js": 3188, + "2591-ambient-generic-traps.ts": 2461, + "2592-ambient-trap-uncaught.ts": 2508, + "2593-generic-inert-bindings.ts": 2003, + "2594-nullish-generic-bindings.ts": 2473, + "2595-fs-arg-ladders.cjs": 3590, + "2596-net-arg-ladders.cjs": 2708, + "2597-dgram-send-ladders.cjs": 3185, + "2598-tls-arg-ladders.cjs": 3457, + "2599-stream-arg-ladders.cjs": 2639, + "2600-dyn-keyed-write-harness.js": 2645, + "2601-dyn-keyed-write-ops.js": 2850, + "2602-dyn-array-destructure.js": 3140, + "2603-island-keyed-write-dyn.js": 2307, + "2604-cycle-classes-mutual/main.ts": 2453, + "2605-cycle-three-module/main.ts": 2707, + "2606-dynamic-import-cycle/main.ts": 2783, + "2608-regex-named-groups.ts": 3177, + "2609-regex-named-replace.ts": 2707, + "2610-regex-named-matchall.ts": 2590, + "2611-regex-named-groups-js.cjs": 2302, + "2613-for-init-uninitialized-let.ts": 2413, + "2614-trap-binding-later-writes.ts": 2362, + "2615-nullish-field-record-binding.ts": 2480, + "2616-js-collect-probe-defers.js": 2756, + "2617-enum-static-field-import/main.ts": 2551, + "2618-ee-emit-override.ts": 2613, + "2619-ee-override-chain.ts": 2034, + "2620-ee-override-once-order.ts": 2930, + "2621-ee-override-error-throw.ts": 2533, + "2622-ee-override-filter.ts": 2677, + "2623-ee-job-queue.ts": 2500, + "2624-ee-override-js.cjs": 2183, + "2625-bytes-views.ts": 2152, + "2626-stream-event-names.ts": 2499, + "2627-stream-ticks-are-nextticks.ts": 2708, + "2628-stream-push-encodings.cjs": 2440, + "2629-stream-consumers.ts": 2913, + "2630-stream-consumers-errors.ts": 2991, + "2631-create-require/main.ts": 3044, + "2632-dyn-jsval-iterate.js": 2878, + "2633-island-promise-crossing.js": 3370, + "2634-stream-pipeline-arg-ladders.cjs": 2714, + "2635-trap-binding-unmappable-written.ts": 2160, + "2636-trap-binding-ambient-rooted-rewrite.ts": 2374, + "2637-create-require-bare/main.ts": 2239, + "2638-http-dyn-res-compat.cjs": 3131, + "2639-http-dyn-req-pause.cjs": 2921, + "2640-net-dyn-socket-compat.cjs": 2968, + "2641-http-agent-surface.cjs": 3429, + "2642-http-agent-maxsockets.cjs": 2699, + "2643-or-default-retag.ts": 2845, + "2644-http-client-url-argument.ts": 2453, + "2645-https-client-url-argument.ts": 2836, + "2646-top-level-await.ts": 2403, + "2647-top-level-await-modules/main.ts": 2235, + "2648-top-level-await-rejection.ts": 1959, + "2649-top-level-await-pending.ts": 2384, + "2650-top-level-await-self-import.ts": 1987, + "2651-top-level-await-pending-unhandled.ts": 2002, + "2652-top-level-await-dynamic/main.ts": 2598, + "2653-top-level-await-rejection-stops-loop.ts": 2523, + "2654-top-level-await-unrelated-rejection.ts": 2015, + "2655-top-level-await-cycle/main.ts": 2308, + "2656-top-level-await-cycle-order/main.ts": 4054, + "2657-top-level-await-cycle-dynamic/main.ts": 2392, + "2658-top-level-await-sync-completion/main.ts": 2314, + "2659-top-level-await-dynamic-cycle/main.ts": 2467, + "2660-top-level-await-cycle-rejection/main.ts": 2494, + "2661-top-level-await-dynamic-runtime-root/main.ts": 2327, + "2662-top-level-await-cycle-external-wait/main.ts": 2397, + "2663-top-level-await-dependency-errors/main.ts": 2080, + "2664-top-level-await-same-checkpoint-rejection.ts": 2543, + "2665-top-level-await-unhandled-listener-liveness.ts": 2570, + "2666-array-to-sorted.ts": 6667, + "2668-stored-number-array-iterator.ts": 2876, + "2669-array-copying-methods.ts": 3089, + "2670-uint8array-copy-iterate.ts": 2885, + "2671-array-copying-js.cjs": 2315, + "2672-http-request-response-callback.ts": 2962, + "2673-top-level-await-implicit-module.ts": 2333, + "2674-top-level-for-await-implicit-module.ts": 2353, + "2675-create-require-nested-esm.js": 2188, + "2675-process-self-reexec.ts": 2836, + "2676-indexed-read-strict-equality.ts": 2408, + "2676-record-clone-overrides.ts": 2543, + "2676-top-level-await-ambiguous/main.ts": 2576, + "2677-runtime-optional-closure.ts": 4255, + "2677-top-level-await-module-scope/main.ts": 2463, + "2678-date-instances.ts": 2194, + "2678-large-string-sparse-index.ts": 2586, + "2678-util-parseargs.ts": 4462, + "2679-util-parseargs-cjs.cjs": 4905, + "2680-util-parseargs-default.ts": 1889, + "2681-util-parseargs-dynamic.js": 2618, + "2682-fs-rename.ts": 3414, + "2683-filter-truthy-predicate.ts": 3055, + "2683-fs-rename-js.cjs": 4058, + "2684-filter-no-predicate-dyn.cjs": 2608, + "2684-fs-rename-abort.ts": 2639, + "2685-array-unshift-reverse.ts": 3540, + "2685-fs-write-sync.ts": 2779, + "2686-fs-file-handle.ts": 3096, + "2687-fsp-write-file-options.ts": 2864, + "2687-process-write-args.ts": 2396, + "2688-fs-stats-disk-fields.ts": 3953, + "2689-http-server-timeout-properties.ts": 2717, + "2690-https-server-timeout-option.ts": 2702, + "2691-retained-lowering-record-order.ts": 2988, + "2692-inline-record-assert-index.ts": 2526, + "2692-string-accumulation.ts": 2081, + "2693-math-constants.ts": 1991, + "2700-array-sort-complexity.ts": 2921, + "2700-http-static-trailers.ts": 2864, + "2700-wasi-core.ts": 2423, + "2701-array-sort-snapshot.ts": 2953, + "2701-http-static-trailer-wire.ts": 4541, + "2701-import-meta/main.mjs": 2520, + "2702-http-static-trailer-end.ts": 2827, + "2702-type-import-link-static/main.ts": 2535, + "2702-uint8array-to-sorted.ts": 2284, + "2703-array-sparse-sort.ts": 4504, + "2703-type-import-link-static-reexport/main.ts": 3626, + "2704-array-sparse-to-sorted.ts": 4339, + "2704-type-import-link-static-success/main.ts": 2363, + "2705-array-sparse-sort-append.ts": 4401, + "2705-type-import-link-dynamic/main.ts": 1851, + "2706-array-search-missing-needle.ts": 2603, + "2706-type-import-link-dynamic-success/main.ts": 2413, + "2707-array-search-huge-sparse.ts": 45742, + "2707-type-import-link-static-default-reexport/main.ts": 2437, + "2708-type-import-link-dynamic/main.ts": 2892, + "2720-array-read-parity.ts": 3049, + "2721-array-nested-missing-receiver.ts": 2315, + "2750-array-sparse-foundation.ts": 3742, + "2751-buffer-concat-sparse-list.ts": 4185, + "2752-array-optional-stores.ts": 2347, + "2753-array-optional-method-values.ts": 3965, + "2754-array-property-undefined.ts": 2255, + "2755-array-optional-literal-forwarding.ts": 2583, + "2780-array-parity-composition.ts": 6251, + "2781-array-missing-value-escape.ts": 2554, + "2782-array-sparse-callbacks.ts": 3284, + "2783-array-defaults-rest.ts": 2724, + "2784-array-reduce-missing-result.ts": 2691, + "2785-array-missing-destructuring.ts": 2806, + "2786-array-sparse-serialization.ts": 2888, + "2787-array-missing-string-arithmetic.ts": 1877, + "2788-array-missing-builtin-conversions.ts": 1930, + "2789-array-missing-optional-tostring.ts": 1731, + "2790-dynamic-import-self-name/main.ts": 2308, + "2791-record-optional-keys.ts": 2478, + "2792-record-optional-spread-entries.ts": 2703, + "2793-union-conversion-identity-capture.ts": 1753, + "2794-array-generic-callback-values.ts": 2420, + "2795-array-optional-typedarray-source.ts": 1737, + "2796-array-sparse-class-value-instanceof.ts": 2296, + "2800-array-expression-consumers.ts": 2565, + "2801-array-switch-consumers.ts": 2471, + "2820-array-missing-method-receivers.ts": 2123, + "2821-array-optional-numeric-comparisons.ts": 2408, + "2830-cjs-require-self-name/main.cjs": 2633, + "2840-finally-completions.ts": 2505, + "2841-using-sync.ts": 2632, + "2842-await-using.ts": 1790, + "2843-using-suppressed-error.ts": 2235, + "2844-node-disposable-resources.ts": 2658, + "2845-for-using-of.ts": 4410, + "2846-generator-using.ts": 2392, + "2850-async-generators-protocol.ts": 3002, + "2851-async-generators-values.ts": 4379, + "2852-timers-promises-interval.ts": 2511, + "2854-leading-bom-literals.ts": 2528, + "2855-searchparams-sort-complexity.ts": 2416, + "2856-dynamic-any-local-operators.ts": 1839, + "2857-branded-primitives.ts": 1736, + "2858-import-meta-resolve/main.mjs": 2679, + "2859-import-meta-resolve-dynamic/main.mjs": 2295, "2860-require-resolve/main.cjs": 2780, - "2861-readable-iterator-close.ts": 3397, - "2862-web-readable-async-iteration.ts": 3414, - "2863-class-async-iterator.ts": 2684, - "2864-array-class-method-receivers.ts": 2886, - "2865-cjs-process-alias.cjs": 2940, - "2866-dyn-switch.ts": 2042, - "2867-array-shift-length.js": 1841, - "2868-empty-record-promise-presence.js": 1948, - "2869-nullish-mixed-lazy.ts": 2998, - "2870-and-dropped-truthy-arm.ts": 1701, - "2871-optional-promise-to-unknown.ts": 2708, - "2872-unobserved-dynamic-event.ts": 1982, - "2873-optional-receiver-loop-lifetime.js": 2129, - "2874-nullable-callback-field-cycle.js": 2941, - "2875-evolving-let-read-before-write.js": 2038, - "2876-class-unknown-roundtrip.ts": 3117, - "2877-child-unknown-roundtrip.ts": 2838, - "2878-class-private-unknown.cjs": 2816, - "2880-cjs-module-graph/main.cjs": 2623, - "2890-crypto-static-utility.ts": 3216, - "2891-json-record-key-escapes.ts": 3136, - "2892-windows-console-unicode.ts": 2711, - "2893-child-stdin-duplex.ts": 2652, - "2894-child-stdin-backpressure.ts": 3049, - "2895-child-stdin-write-after-end.ts": 2813, - "2896-child-stdin-write-after-finish.ts": 1947, - "2897-child-stdin-destroy.ts": 3101, - "2898-child-stdin-spawn-failure.ts": 3024, - "2899-nested-mutual-recursion.ts": 2834, - "2900-float64array-static.ts": 2695, - "2900-void-conditional-arrow.ts": 2641, - "2901-bigint-core.ts": 2912, - "2902-bigint-bytes.ts": 2182, - "2903-bigint-storage.ts": 2897, - "2904-bigint-errors.ts": 2971, - "2905-bigint-edges.ts": 2917, - "2906-bigint-wasi-width.ts": 2941, - "2910-overloaded-callable-alias.ts": 2710, - "2911-execfile-callback.ts": 3076, - "2912-execfile-callback-options.ts": 1918, - "2912-promisify-fs-readfile.ts": 2767, - "2913-builtin-callable-alias.ts": 2872, - "2914-fixed-tuple-call-spread.ts": 2555, - "2915-path-function-values.ts": 2085, - "2916-path-function-values-cjs.ts": 2881, - "2917-builtin-callable-widths.ts": 2912, - "2918-builtin-callable-widths-cjs.ts": 1902, - "2919-fs-function-values.ts": 2935, - "2920-fs-promises-function-values.ts": 2882, - "2921-zlib-callbacks.ts": 2124, - "2922-dyn-bitwise-not.cjs": 2707, - "2923-cjs-factory-export/main.cjs": 2830, - "2930-union-receiver-calls.ts": 2484, - "2931-union-dynamic-field-call.js": 2846, - "2932-create-require-program/main.ts": 3067, - "2933-static-dynamic-import/main.ts": 2168, - "2934-static-import-stored.ts": 3004, - "2935-module-namespace-values/main.ts": 2141, - "2936-static-loose-equality.ts": 3392, - "2937-bitwise-hot-loop.ts": 2114, - "2938-fs-sync-overloads.cjs": 1863, - "2939-child-shell-text.ts": 3119, - "2940-date-parse.ts": 2606, - "2940-fsp-realpath.ts": 2319, - "2941-fsp-lstat-identity.ts": 3102, - "2941-process-exit-code.ts": 2025, - "2942-fsp-readdir-dirent.ts": 2835, - "2942-process-exit-code-override.ts": 2255, - "2943-process-exit-code-invalid.ts": 2733, - "2944-process-exit-code-wrap.ts": 1969, - "2945-url-origin-username.ts": 1974, - "2946-child-fork-ipc/main.ts": 3772, - "2946-url-port-hash.ts": 2074, - "2947-set-readonly-seeds.ts": 3071, - "2948-child-fork-eof-callback/main.ts": 3013, - "2948-stdio-callback-record.ts": 2065, - "2949-child-fork-default/main.mjs": 2829, - "2949-url-password.ts": 2408, - "2950-fs-descriptor-publication.ts": 2677, - "2951-math-static-analytic.ts": 2349, - "2952-math-static-remaining.ts": 2335, - "2953-http-header-validation.ts": 2772, - "2954-http-outgoing-headers.ts": 3428, - "2955-http-static-state.ts": 2945, - "2956-http-static-informational.ts": 2218, - "2957-http-static-response-controls.ts": 2590, - "2961-emitter-computed-names.cjs": 2830, - "2962-emitter-computed-optional.ts": 2777, - "2963-child-fork-dispatch/main.ts": 3250, - "2964-indexed-compound.ts": 3270, - "2966-numeric-array-read-fusion.ts": 2442, - "2967-numeric-array-read-lifetime.ts": 2772, - "2968-numeric-array-borrow.ts": 3227, - "2969-scalar-record-results.ts": 3038, - "2970-constant-numeric-tables.ts": 2771, - "2971-constant-table-modules/main.ts": 1871, - "2972-http-static-distinct-snapshots.ts": 3053, - "2972-math-receiver-borrow.ts": 2947, - "2973-http-static-agent.ts": 3397, - "2973-integer-bitwise-arithmetic.ts": 2920, - "2974-array-search-from-index.ts": 124091, - "2974-http-static-module-values.ts": 2984, - "2974-numeric-remainder.ts": 3296, - "2975-bigint-default-radix.ts": 2470, - "2975-http-static-client-controls.ts": 2919, - "2976-http-static-incoming-state.ts": 2589, - "2976-json-stringify-no-arguments.js": 2303, - "2977-http-static-incoming-timeout.ts": 2944, - "2977-nested-array-binding-defaults.js": 2175, - "2978-http-static-client-timeout.ts": 2391, - "2978-regexp-optional-subject.js": 2308, - "2979-array-search-mixed-needles.js": 2358, - "2979-http-static-server-timeout.ts": 1739, - "2980-http-static-server-timeout-default.ts": 2883, - "2980-string-position-arguments.js": 2832, - "2981-http-static-events.ts": 2774, - "2981-string-optional-positions.ts": 2352, - "2982-http-static-close-all.ts": 2171, - "2982-string-position-coercion-order.js": 2155, - "2983-http-static-close-idle.ts": 3021, - "2984-http-static-close-upgrade.ts": 2125, - "2985-http-static-message-destroy.ts": 2402, - "2986-http-static-client-socket-finish.ts": 2843, - "2987-http-static-timeout-errors.ts": 3151, - "2988-http-static-client-abort.ts": 2768, - "2989-http-static-response-timeout-handled.ts": 2766, - "2990-http-static-request-timeout-handled.ts": 3159, - "2991-array-indexed-equality.ts": 2285, - "2992-stream-rows.ts": 2873, - "2993-fiber-stack-lifetimes.ts": 3425, - "2994-fromcharcode-scalar.ts": 3028, - "2995-math-hyperbolic.ts": 2938, - "2996-math-near-one.ts": 3222, - "2997-math-integer-float.ts": 2299, - "300-if-else.ts": 2867, - "3001-caught-typeof-object.js": 2563, - "3002-promise-then-two.ts": 3204, - "301-while.ts": 2926, - "302-for.ts": 2606, - "3020-string-last-index-position.ts": 2319, - "3021-buffer-union-narrow-callback.ts": 2195, - "3022-string-affix-positions.ts": 2341, - "3023-string-affix-position-coercion.js": 2752, - "3024-string-number-narrow-for-in.ts": 1609, - "3025-string-search-position-coercion.js": 2728, - "3026-array-last-index-of.js": 2413, - "3027-array-last-index-of-records.ts": 2116, - "3028-string-search-dynamic-needle.js": 1998, - "3029-string-search-union-needle.js": 2405, - "303-break-continue.ts": 2031, - "3030-array-search-no-arg.js": 3128, - "3031-array-relative-index-coercion.js": 2454, - "3031-string-last-index-search-value.js": 2375, - "3032-string-search-value.js": 2888, - "3033-string-search-needle-coercion.js": 2002, - "3034-arguments-with-parameters.js": 3443, - "3035-string-positioned-search-value.js": 2991, - "3036-string-object-search-value.js": 2678, - "3037-number-nullish-conversion.js": 2958, - "3038-number-scalar-unions.ts": 2263, - "3039-string-repeat-count.js": 2105, - "304-compound-incdec.ts": 2747, - "3040-string-prototype-call.js": 3083, - "3041-string-prototype-object-call.js": 2578, - "3042-string-padding-coercion.js": 2198, - "3043-string-split-arguments.js": 2450, - "3044-array-slice-splice-positions.js": 3038, - "3045-array-indexed-mutation.js": 3285, - "3046-array-indexed-ref-identity.ts": 1964, - "3047-object-prototype-tag.js": 2750, - "3048-object-own-prototype.ts": 3516, - "3049-array-flat-depth.ts": 2507, - "305-truthiness.ts": 3022, - "3050-array-splice-insert.ts": 3679, - "3051-array-join-default.ts": 2848, - "3052-array-construction.ts": 2982, - "3053-array-construction-js.js": 3024, - "3054-dynamic-abort-record.ts": 2146, - "3055-default-builtin-nodenext/main.ts": 2904, - "3056-default-builtin-bundler/main.ts": 2933, - "3057-default-builtin-nodenext-dynamic/main.ts": 2973, - "3058-optional-array-chain-join.ts": 2285, - "3059-arguments-property-names.ts": 2296, - "3061-concurrent-fiber-stacks.ts": 1843, - "3062-runtime-optional-record-guards.ts": 3177, - "3063-runtime-optional-class-guards.ts": 2891, - "3064-installed-entry-imports/main.ts": 2942, - "3065-installed-entry-js/main.js": 2574, - "3066-source-debugging/main.ts": 2037, - "3067-cjs-function-export-require/main.cjs": 2917, - "3068-debug-variables/main.ts": 2538, - "3068-url-checked-identity.ts": 2749, - "3069-set-checked-seed.js": 2271, - "3069-tuple-spread.ts": 2404, - "3070-checked-object-accessors.js": 3199, - "3070-collection-views.ts": 3106, - "3071-checked-specialization-narrowing.js": 2927, - "3071-map-contextual-record-seeds.ts": 3315, - "3072-optional-union-receivers.ts": 3294, - "3072-weak-process-streams.js": 2924, - "3073-optional-callable-module.js": 2944, - "3073-union-keyed-reads.ts": 2310, - "3074-discriminated-intersections.ts": 2137, - "3075-recursive-contextual-literals.ts": 3075, - "3076-nullish-record-defaults.ts": 2013, - "3077-optional-union-array-reads.ts": 3340, - "3078-forward-mutable-captures.ts": 3407, - "3079-forward-mutable-tdz.ts": 3267, - "3080-exhaustive-never-bindings.ts": 2952, - "3081-recursive-array-destinations.ts": 2842, - "3082-forward-write-unwind.ts": 2956, - "3083-set-string-seed.ts": 2684, - "3084-record-own-membership.ts": 3434, - "3085-conditional-record-construction.ts": 2128, - "3086-error-constructor-options.ts": 2138, - "3087-error-options-lifetime.ts": 2004, - "3088-array-wide-callbacks.ts": 2257, - "3089-array-find-narrowing.ts": 2620, - "3090-json-discriminated-records.ts": 2285, - "3091-json-recursive-discriminants.ts": 2190, - "3092-number-union-predicates.ts": 2281, - "3093-error-option-data.ts": 2642, - "3094-json-replacer-traversal.ts": 3187, - "3095-json-reviver-traversal.ts": 2938, - "3096-json-callback-nonfinite.ts": 2858, - "3097-json-callback-reentrancy.ts": 2787, - "3098-json-callback-space.ts": 3229, - "3099-json-callback-functions.ts": 3214, - "3100-json-callback-holder.js": 2206, - "3101-json-callback-bytes.ts": 2646, - "3102-json-unknown-fields.ts": 3086, - "3103-scalar-record-nested-control-flow.ts": 2112, - "3104-native-analysis-tables-loops.ts": 2780, - "3105-nullable-collections.ts": 3028, - "3106-mixed-insertion-spreads.ts": 2007, - "3107-nullable-collection-lifetimes.ts": 3338, - "3108-for-await-sync-arrays.js": 2682, - "3108-identity-map-keys.ts": 2227, - "3109-destructuring-unknown-defaults.js": 2915, - "3109-identity-union-collections.ts": 3423, - "3110-builtin-error-families.ts": 2570, - "3110-identity-collection-mutation.ts": 2678, - "3111-identity-collection-cycles.ts": 2997, - "3112-union-switch-control-flow.ts": 2901, - "3113-union-array-removal.ts": 3399, - "3114-union-record-field-write.ts": 2336, - "3115-zlib-static-compression-levels.ts": 2528, - "3116-sequence-expression-lifetimes.ts": 3297, - "3117-unknown-switch-control-flow.ts": 2618, - "3118-recursive-union-spread.ts": 3545, - "3119-runtime-optional-spread.ts": 2406, - "3120-dynamic-property-descriptors.js": 3089, - "3120-generator-method-loop-bindings.ts": 3317, - "3120-ir-nonfinite-numbers.ts": 1849, - "3121-compound-assignment-values.js": 2286, - "3121-dynamic-accessor-descriptors.js": 4553, - "3122-dynamic-delete-descriptors.cjs": 1796, - "3122-dynamic-delete-descriptors.js": 2168, - "3122-js-async-class-methods.js": 2287, - "3123-destructured-global-tdz.js": 2851, - "3124-array-prototype-borrow.js": 3706, - "3125-regex-global-match.ts": 3004, - "3126-js-number-radix/main.ts": 3034, - "3127-spawn-runtime-options.ts": 2691, - "3128-regex-last-index.ts": 2151, - "3129-js-token-union/main.ts": 2990, - "3130-child-generic-streams.ts": 3199, - "3131-child-rest-listeners.js": 1690, - "3132-child-generic-stream-completion.ts": 5607, - "3133-text-decoder-streaming.ts": 3055, - "3134-fs-vectors.ts": 3055, - "3135-fs-file-handle-controls.ts": 3371, - "3136-fs-file-handle-options.ts": 2897, - "3137-fs-vector-callbacks.cjs": 3277, - "3138-array-large-storage.ts": 3756, - "3139-regex-native-deep-alternatives.ts": 28435, - "3140-array-dense-access.ts": 3894, - "3141-map-string-key-hash.ts": 3167, - "3150-integer-remainder.ts": 3353, - "3151-array-push-writes.ts": 3497, - "3170-number-conversion-fast-paths.ts": 3302, - "3171-method-census-data-writes.ts": 2848, - "400-fib.ts": 2397, - "401-mutual-recursion.ts": 2469, - "402-string-functions.ts": 2915, - "403-void-and-params.ts": 1930, - "4030-runtime-object-truthiness.ts": 2360, - "4031-event-emitter-long-tuples.ts": 1978, - "4032-inline-rc-fast-paths.ts": 4391, - "404-rc-stress.ts": 2580, - "4040-adapted-function-identity.ts": 3640, - "4041-adapted-function-properties.ts": 3228, - "4042-object-is-union-subclass.ts": 1738, - "4043-nonnull-missing-element.ts": 3185, - "4044-adapted-callback-modules/main.ts": 2445, - "4045-optional-element-projections.ts": 2663, - "4046-captured-parameter-values.ts": 3523, - "4047-captured-parameter-rebinding.ts": 2990, - "405-params-optional.ts": 2128, - "406-params-defaults.ts": 2785, - "4060-cycle-shared-instance/main.ts": 2724, - "4060-stack-union-reads.ts": 3544, - "4061-cycle-evaluation-order/main.ts": 2941, - "4061-nullable-ref-fields.ts": 4633, - "4062-cycle-tdz-read/main.ts": 2132, - "4063-cycle-hoisted-calls/main.ts": 2837, - "4064-cycle-classes-after-init/main.ts": 2919, - "4065-cycle-init-throws/main.ts": 2003, - "4066-cycle-top-level-tdz/main.ts": 2633, - "4067-dynamic-import-cycle-tdz/main.ts": 2814, - "407-params-rest.ts": 3063, - "408-params-ctors-inheritance.ts": 2314, - "4080-optional-read-presence-tests.ts": 2434, - "4080-string-index-bounds.ts": 2754, - "4081-hoisted-function-tdz.ts": 3289, - "4081-string-index-unproven.ts": 2424, - "4082-hoisted-function-tdz-uncaught.ts": 2711, - "4083-dynamic-import-failure/main.ts": 3307, - "4084-record-optional-field-copies.ts": 3992, - "4085-generator-loop-close.ts": 2360, - "4086-optional-capture-defaults.ts": 2000, - "4088-class-static-tdz.ts": 2016, - "4089-class-wrapper-tdz.js": 2230, - "409-params-async-generics.ts": 2900, - "4090-computed-key-tdz.js": 2345, - "4091-class-evaluation-deferred.ts": 2676, - "410-params-rc-stress.ts": 2904, - "4140-array-callback-split-visit.ts": 4145, - "4141-array-callback-ambient-receiver/main.ts": 3151, - "4142-array-callback-factories.ts": 3774, - "4143-union-refinement-intersection-arms.ts": 1858, - "420-dead-strip-modules/main.ts": 2735, - "4290-acyclic-immutable-trees.ts": 3335, - "4291-acyclic-constructor-escapes.ts": 2796, - "4292-acyclic-readonly-bypass.ts": 2522, - "4293-acyclic-dynamic-writes.ts": 2365, - "4294-console-line-sizes.ts": 6187, - "4295-console-template-parts.ts": 2942, - "4296-console-glued-long-parts.ts": 4142, - "4410-inline-object-allocation.ts": 2124, - "4411-nullable-ref-values.ts": 4400, - "4412-nullable-record-values.ts": 4209, - "4413-cycle-old-late-death.ts": 2986, - "4413-nullable-null-and-undefined.ts": 2888, - "4414-cycle-old-weak-keys.ts": 3194, - "4414-nullable-string-values.ts": 4815, - "4415-identity-borrowed-operands.ts": 2337, - "4415-nullable-container-values.ts": 4436, - "4431-exception-pending-contexts.ts": 2184, - "4432-checked-downcast-failures.ts": 3797, - "4451-int32-field-storage.ts": 3817, - "4452-int32-field-dynamic-writes.ts": 3773, - "4453-int32-closed-locals.ts": 2395, + "2861-readable-iterator-close.ts": 3207, + "2862-web-readable-async-iteration.ts": 3375, + "2863-class-async-iterator.ts": 2531, + "2864-array-class-method-receivers.ts": 1837, + "2865-cjs-process-alias.cjs": 2734, + "2866-dyn-switch.ts": 1772, + "2867-array-shift-length.js": 2411, + "2868-empty-record-promise-presence.js": 2531, + "2869-nullish-mixed-lazy.ts": 2433, + "2870-and-dropped-truthy-arm.ts": 2606, + "2871-optional-promise-to-unknown.ts": 2387, + "2872-unobserved-dynamic-event.ts": 2191, + "2873-optional-receiver-loop-lifetime.js": 2453, + "2874-nullable-callback-field-cycle.js": 2707, + "2875-evolving-let-read-before-write.js": 3668, + "2876-class-unknown-roundtrip.ts": 2817, + "2877-child-unknown-roundtrip.ts": 2660, + "2878-class-private-unknown.cjs": 4040, + "2880-cjs-module-graph/main.cjs": 2924, + "2890-crypto-static-utility.ts": 2261, + "2891-json-record-key-escapes.ts": 2705, + "2892-windows-console-unicode.ts": 2266, + "2893-child-stdin-duplex.ts": 3340, + "2894-child-stdin-backpressure.ts": 3131, + "2895-child-stdin-write-after-end.ts": 2384, + "2896-child-stdin-write-after-finish.ts": 2871, + "2897-child-stdin-destroy.ts": 2871, + "2898-child-stdin-spawn-failure.ts": 2549, + "2899-nested-mutual-recursion.ts": 2721, + "2900-float64array-static.ts": 2799, + "2900-void-conditional-arrow.ts": 2537, + "2901-bigint-core.ts": 2424, + "2902-bigint-bytes.ts": 2498, + "2903-bigint-storage.ts": 2708, + "2904-bigint-errors.ts": 2577, + "2905-bigint-edges.ts": 2439, + "2906-bigint-wasi-width.ts": 1786, + "2910-overloaded-callable-alias.ts": 2648, + "2911-execfile-callback.ts": 2191, + "2912-execfile-callback-options.ts": 2127, + "2912-promisify-fs-readfile.ts": 2460, + "2913-builtin-callable-alias.ts": 2481, + "2914-fixed-tuple-call-spread.ts": 2974, + "2915-path-function-values.ts": 2177, + "2916-path-function-values-cjs.ts": 2451, + "2917-builtin-callable-widths.ts": 2149, + "2918-builtin-callable-widths-cjs.ts": 2749, + "2919-fs-function-values.ts": 2635, + "2920-fs-promises-function-values.ts": 1999, + "2921-zlib-callbacks.ts": 2825, + "2922-dyn-bitwise-not.cjs": 2337, + "2923-cjs-factory-export/main.cjs": 2557, + "2930-union-receiver-calls.ts": 3403, + "2931-union-dynamic-field-call.js": 3002, + "2932-create-require-program/main.ts": 2467, + "2933-static-dynamic-import/main.ts": 2896, + "2934-static-import-stored.ts": 2404, + "2935-module-namespace-values/main.ts": 2608, + "2936-static-loose-equality.ts": 3140, + "2937-bitwise-hot-loop.ts": 2268, + "2938-fs-sync-overloads.cjs": 1857, + "2939-child-shell-text.ts": 3041, + "2940-date-parse.ts": 2483, + "2940-fsp-realpath.ts": 2587, + "2941-fsp-lstat-identity.ts": 2657, + "2941-process-exit-code.ts": 1743, + "2942-fsp-readdir-dirent.ts": 2911, + "2942-process-exit-code-override.ts": 1751, + "2943-process-exit-code-invalid.ts": 2583, + "2944-process-exit-code-wrap.ts": 2435, + "2945-url-origin-username.ts": 1863, + "2946-child-fork-ipc/main.ts": 3271, + "2946-url-port-hash.ts": 2587, + "2947-set-readonly-seeds.ts": 2456, + "2948-child-fork-eof-callback/main.ts": 3043, + "2948-stdio-callback-record.ts": 2421, + "2949-child-fork-default/main.mjs": 2736, + "2949-url-password.ts": 2744, + "2950-fs-descriptor-publication.ts": 2681, + "2951-math-static-analytic.ts": 3121, + "2952-math-static-remaining.ts": 2862, + "2953-http-header-validation.ts": 2956, + "2954-http-outgoing-headers.ts": 2822, + "2955-http-static-state.ts": 2955, + "2956-http-static-informational.ts": 3085, + "2957-http-static-response-controls.ts": 2273, + "2961-emitter-computed-names.cjs": 2632, + "2962-emitter-computed-optional.ts": 2051, + "2963-child-fork-dispatch/main.ts": 2809, + "2964-indexed-compound.ts": 2982, + "2966-numeric-array-read-fusion.ts": 2045, + "2967-numeric-array-read-lifetime.ts": 3048, + "2968-numeric-array-borrow.ts": 2914, + "2969-scalar-record-results.ts": 2620, + "2970-constant-numeric-tables.ts": 2078, + "2971-constant-table-modules/main.ts": 2587, + "2972-http-static-distinct-snapshots.ts": 2220, + "2972-math-receiver-borrow.ts": 3503, + "2973-http-static-agent.ts": 3163, + "2973-integer-bitwise-arithmetic.ts": 2756, + "2974-array-search-from-index.ts": 120636, + "2974-http-static-module-values.ts": 2696, + "2974-numeric-remainder.ts": 2784, + "2975-bigint-default-radix.ts": 1741, + "2975-http-static-client-controls.ts": 2204, + "2976-http-static-incoming-state.ts": 2949, + "2976-json-stringify-no-arguments.js": 2583, + "2977-http-static-incoming-timeout.ts": 2724, + "2977-nested-array-binding-defaults.js": 2760, + "2978-http-static-client-timeout.ts": 3060, + "2978-regexp-optional-subject.js": 2540, + "2979-array-search-mixed-needles.js": 2011, + "2979-http-static-server-timeout.ts": 2740, + "2980-http-static-server-timeout-default.ts": 2671, + "2980-string-position-arguments.js": 2246, + "2981-http-static-events.ts": 1817, + "2981-string-optional-positions.ts": 1836, + "2982-http-static-close-all.ts": 2421, + "2982-string-position-coercion-order.js": 3081, + "2983-http-static-close-idle.ts": 2006, + "2984-http-static-close-upgrade.ts": 2129, + "2985-http-static-message-destroy.ts": 2630, + "2986-http-static-client-socket-finish.ts": 1940, + "2987-http-static-timeout-errors.ts": 2737, + "2988-http-static-client-abort.ts": 2025, + "2989-http-static-response-timeout-handled.ts": 2928, + "2990-http-static-request-timeout-handled.ts": 2599, + "2991-array-indexed-equality.ts": 2993, + "2992-stream-rows.ts": 2556, + "2993-fiber-stack-lifetimes.ts": 3202, + "2994-fromcharcode-scalar.ts": 2833, + "2995-math-hyperbolic.ts": 2687, + "2996-math-near-one.ts": 2252, + "2997-math-integer-float.ts": 3190, + "300-if-else.ts": 2219, + "3001-caught-typeof-object.js": 2450, + "3002-promise-then-two.ts": 2484, + "301-while.ts": 2153, + "302-for.ts": 1918, + "3020-string-last-index-position.ts": 2434, + "3021-buffer-union-narrow-callback.ts": 2866, + "3022-string-affix-positions.ts": 2229, + "3023-string-affix-position-coercion.js": 3333, + "3024-string-number-narrow-for-in.ts": 2650, + "3025-string-search-position-coercion.js": 2447, + "3026-array-last-index-of.js": 2579, + "3027-array-last-index-of-records.ts": 2304, + "3028-string-search-dynamic-needle.js": 2564, + "3029-string-search-union-needle.js": 1657, + "303-break-continue.ts": 2442, + "3030-array-search-no-arg.js": 3027, + "3031-array-relative-index-coercion.js": 2940, + "3031-string-last-index-search-value.js": 2407, + "3032-string-search-value.js": 2579, + "3033-string-search-needle-coercion.js": 2232, + "3034-arguments-with-parameters.js": 2126, + "3035-string-positioned-search-value.js": 2449, + "3036-string-object-search-value.js": 1849, + "3037-number-nullish-conversion.js": 2478, + "3038-number-scalar-unions.ts": 1881, + "3039-string-repeat-count.js": 2372, + "304-compound-incdec.ts": 2266, + "3040-string-prototype-call.js": 2389, + "3041-string-prototype-object-call.js": 2679, + "3042-string-padding-coercion.js": 2923, + "3043-string-split-arguments.js": 3247, + "3044-array-slice-splice-positions.js": 2966, + "3045-array-indexed-mutation.js": 2960, + "3046-array-indexed-ref-identity.ts": 2358, + "3047-object-prototype-tag.js": 2265, + "3048-object-own-prototype.ts": 3162, + "3049-array-flat-depth.ts": 2904, + "305-truthiness.ts": 2588, + "3050-array-splice-insert.ts": 2779, + "3051-array-join-default.ts": 2220, + "3052-array-construction.ts": 2520, + "3053-array-construction-js.js": 2821, + "3054-dynamic-abort-record.ts": 2818, + "3055-default-builtin-nodenext/main.ts": 2044, + "3056-default-builtin-bundler/main.ts": 2874, + "3057-default-builtin-nodenext-dynamic/main.ts": 1912, + "3058-optional-array-chain-join.ts": 2986, + "3059-arguments-property-names.ts": 1856, + "3061-concurrent-fiber-stacks.ts": 2766, + "3062-runtime-optional-record-guards.ts": 3210, + "3063-runtime-optional-class-guards.ts": 2677, + "3064-installed-entry-imports/main.ts": 1867, + "3065-installed-entry-js/main.js": 2294, + "3066-source-debugging/main.ts": 2276, + "3067-cjs-function-export-require/main.cjs": 1963, + "3068-debug-variables/main.ts": 2578, + "3068-url-checked-identity.ts": 2207, + "3069-set-checked-seed.js": 2608, + "3069-tuple-spread.ts": 2969, + "3070-checked-object-accessors.js": 2496, + "3070-collection-views.ts": 2799, + "3071-checked-specialization-narrowing.js": 2715, + "3071-map-contextual-record-seeds.ts": 3095, + "3072-optional-union-receivers.ts": 2303, + "3072-weak-process-streams.js": 2885, + "3073-optional-callable-module.js": 2520, + "3073-union-keyed-reads.ts": 2905, + "3074-discriminated-intersections.ts": 2460, + "3075-recursive-contextual-literals.ts": 3335, + "3076-nullish-record-defaults.ts": 2894, + "3077-optional-union-array-reads.ts": 2500, + "3078-forward-mutable-captures.ts": 3097, + "3079-forward-mutable-tdz.ts": 2796, + "3080-exhaustive-never-bindings.ts": 2704, + "3081-recursive-array-destinations.ts": 2667, + "3082-forward-write-unwind.ts": 2538, + "3083-set-string-seed.ts": 2595, + "3084-record-own-membership.ts": 2879, + "3085-conditional-record-construction.ts": 2874, + "3086-error-constructor-options.ts": 2970, + "3087-error-options-lifetime.ts": 2675, + "3088-array-wide-callbacks.ts": 2690, + "3089-array-find-narrowing.ts": 2833, + "3090-json-discriminated-records.ts": 3066, + "3091-json-recursive-discriminants.ts": 2220, + "3092-number-union-predicates.ts": 2324, + "3093-error-option-data.ts": 2104, + "3094-json-replacer-traversal.ts": 2818, + "3095-json-reviver-traversal.ts": 2804, + "3096-json-callback-nonfinite.ts": 2753, + "3097-json-callback-reentrancy.ts": 2198, + "3098-json-callback-space.ts": 2839, + "3099-json-callback-functions.ts": 3102, + "3100-json-callback-holder.js": 2748, + "3101-json-callback-bytes.ts": 2087, + "3102-json-unknown-fields.ts": 2238, + "3103-scalar-record-nested-control-flow.ts": 2806, + "3104-native-analysis-tables-loops.ts": 2680, + "3105-nullable-collections.ts": 2913, + "3106-mixed-insertion-spreads.ts": 3159, + "3107-nullable-collection-lifetimes.ts": 3025, + "3108-for-await-sync-arrays.js": 3537, + "3108-identity-map-keys.ts": 3249, + "3109-destructuring-unknown-defaults.js": 2565, + "3109-identity-union-collections.ts": 3588, + "3110-builtin-error-families.ts": 2812, + "3110-identity-collection-mutation.ts": 2831, + "3111-identity-collection-cycles.ts": 2915, + "3112-union-switch-control-flow.ts": 2075, + "3113-union-array-removal.ts": 3111, + "3114-union-record-field-write.ts": 2886, + "3115-zlib-static-compression-levels.ts": 2667, + "3116-sequence-expression-lifetimes.ts": 2953, + "3117-unknown-switch-control-flow.ts": 2388, + "3118-recursive-union-spread.ts": 3091, + "3119-runtime-optional-spread.ts": 3563, + "3120-dynamic-property-descriptors.js": 2806, + "3120-generator-method-loop-bindings.ts": 2970, + "3120-ir-nonfinite-numbers.ts": 2756, + "3121-compound-assignment-values.js": 2784, + "3121-dynamic-accessor-descriptors.js": 2889, + "3122-dynamic-delete-descriptors.cjs": 2435, + "3122-dynamic-delete-descriptors.js": 2554, + "3122-js-async-class-methods.js": 2294, + "3123-destructured-global-tdz.js": 2755, + "3124-array-prototype-borrow.js": 2322, + "3125-regex-global-match.ts": 2783, + "3126-js-number-radix/main.ts": 2820, + "3127-spawn-runtime-options.ts": 3072, + "3128-regex-last-index.ts": 1823, + "3129-js-token-union/main.ts": 2769, + "3130-child-generic-streams.ts": 2981, + "3131-child-rest-listeners.js": 2627, + "3132-child-generic-stream-completion.ts": 5669, + "3133-text-decoder-streaming.ts": 2916, + "3134-fs-vectors.ts": 2782, + "3135-fs-file-handle-controls.ts": 3077, + "3136-fs-file-handle-options.ts": 3203, + "3137-fs-vector-callbacks.cjs": 3063, + "3138-array-large-storage.ts": 4112, + "3139-regex-native-deep-alternatives.ts": 26910, + "3140-array-dense-access.ts": 3431, + "3141-map-string-key-hash.ts": 3132, + "3150-integer-remainder.ts": 3203, + "3151-array-push-writes.ts": 3025, + "3170-number-conversion-fast-paths.ts": 2101, + "3171-method-census-data-writes.ts": 3216, + "400-fib.ts": 2634, + "401-mutual-recursion.ts": 2541, + "402-string-functions.ts": 2183, + "403-void-and-params.ts": 2239, + "4030-runtime-object-truthiness.ts": 2407, + "4031-event-emitter-long-tuples.ts": 2624, + "4032-inline-rc-fast-paths.ts": 3924, + "404-rc-stress.ts": 2608, + "4040-adapted-function-identity.ts": 3296, + "4041-adapted-function-properties.ts": 2613, + "4042-object-is-union-subclass.ts": 2694, + "4043-nonnull-missing-element.ts": 2672, + "4044-adapted-callback-modules/main.ts": 2828, + "4045-optional-element-projections.ts": 2963, + "4046-captured-parameter-values.ts": 3070, + "4047-captured-parameter-rebinding.ts": 2848, + "405-params-optional.ts": 1924, + "406-params-defaults.ts": 1978, + "4060-cycle-shared-instance/main.ts": 2198, + "4060-stack-union-reads.ts": 3362, + "4061-cycle-evaluation-order/main.ts": 2399, + "4061-nullable-ref-fields.ts": 4246, + "4062-cycle-tdz-read/main.ts": 2254, + "4063-cycle-hoisted-calls/main.ts": 2402, + "4064-cycle-classes-after-init/main.ts": 2048, + "4065-cycle-init-throws/main.ts": 2640, + "4066-cycle-top-level-tdz/main.ts": 2245, + "4067-dynamic-import-cycle-tdz/main.ts": 2515, + "407-params-rest.ts": 2698, + "408-params-ctors-inheritance.ts": 2092, + "4080-optional-read-presence-tests.ts": 2936, + "4080-string-index-bounds.ts": 2863, + "4081-hoisted-function-tdz.ts": 2788, + "4081-string-index-unproven.ts": 2335, + "4082-hoisted-function-tdz-uncaught.ts": 1949, + "4083-dynamic-import-failure/main.ts": 2717, + "4084-record-optional-field-copies.ts": 2527, + "4085-generator-loop-close.ts": 2591, + "4086-optional-capture-defaults.ts": 2395, + "4088-class-static-tdz.ts": 2363, + "4089-class-wrapper-tdz.js": 2402, + "409-params-async-generics.ts": 2098, + "4090-computed-key-tdz.js": 2605, + "4091-class-evaluation-deferred.ts": 2199, + "410-params-rc-stress.ts": 2565, + "4140-array-callback-split-visit.ts": 4386, + "4141-array-callback-ambient-receiver/main.ts": 2299, + "4142-array-callback-factories.ts": 3208, + "4143-union-refinement-intersection-arms.ts": 2685, + "420-dead-strip-modules/main.ts": 2527, + "4290-acyclic-immutable-trees.ts": 3246, + "4291-acyclic-constructor-escapes.ts": 2909, + "4292-acyclic-readonly-bypass.ts": 3024, + "4293-acyclic-dynamic-writes.ts": 2956, + "4294-console-line-sizes.ts": 5873, + "4295-console-template-parts.ts": 2597, + "4296-console-glued-long-parts.ts": 2868, + "4410-inline-object-allocation.ts": 3093, + "4411-nullable-ref-values.ts": 4434, + "4412-nullable-record-values.ts": 3635, + "4413-cycle-old-late-death.ts": 2102, + "4413-nullable-null-and-undefined.ts": 2783, + "4414-cycle-old-weak-keys.ts": 2960, + "4414-nullable-string-values.ts": 3874, + "4415-identity-borrowed-operands.ts": 2087, + "4415-nullable-container-values.ts": 3581, + "4431-exception-pending-contexts.ts": 3035, + "4432-checked-downcast-failures.ts": 3246, + "4451-int32-field-storage.ts": 3457, + "4452-int32-field-dynamic-writes.ts": 3861, + "4453-int32-closed-locals.ts": 2280, "4454-int32-field-reflection-reads.ts": 3951, "4455-live-view-reads-without-stores.ts": 3598, - "4471-unassigned-field-reads.ts": 2666, - "4476-string-ascii-header-fact.ts": 2214, - "4477-buffer-write-ascii-runs.ts": 3271, - "4478-string-large-index-reads.ts": 2510, - "4481-array-optional-push.ts": 3023, - "4482-instanceof-static-class-optional.ts": 2810, - "4483-array-splice-statement.ts": 3482, - "4484-array-length-reset.ts": 2127, - "4485-array-splice-optional-item.ts": 2800, - "4486-array-field-element-borrows.ts": 3650, - "4487-array-literal-optional-values.ts": 3286, - "4520-optional-guard-narrowing.ts": 2046, - "4521-array-callback-element-presence.ts": 4687, - "4522-captured-parameter-lifetimes.ts": 2497, - "4523-array-pop-removal.ts": 3081, - "4524-array-callback-supertype-params.ts": 3932, - "4541-nullable-wrap-borrows.ts": 2389, - "4542-preserving-call-borrows.ts": 3360, - "4543-walk-borrowed-locals.ts": 3391, - "4544-checked-cast-aliases.ts": 3252, - "4545-borrowed-returns.ts": 3896, - "4546-rebound-borrowed-params.ts": 1833, - "4560-field-store-borrowed-receivers.ts": 2735, - "4561-virtual-borrowed-parameters.ts": 3750, - "4562-string-self-concat-move.ts": 2152, - "4563-array-read-projection-receivers.ts": 2323, - "4564-literal-choice-strings.ts": 2445, - "4568-for-of-hole-elements.ts": 3409, - "4569-shorthand-missing-elements.ts": 2920, - "4570-map-lookup-default-record.ts": 3442, - "4591-weak-keys-union-records.ts": 3061, - "4592-cycle-const-from-import/main.ts": 2838, - "4593-weak-keys-empty-objects.ts": 3425, - "4594-union-class-field-mixed-types.ts": 3724, - "4595-union-class-field-optional-receiver.ts": 3074, - "4596-error-subclass-int-fields.ts": 2744, - "4596-tdz-nullable-forward-capture.ts": 3971, - "4597-callback-field-method-name.ts": 2791, - "4598-live-array-ref-element-access.ts": 5033, - "4598-map-set-clear-reuse.ts": 4347, - "4598-os-available-parallelism.ts": 2628, - "4598-publish-constructor-stores.ts": 3091, - "4599-construction-only-field-borrows.ts": 3355, - "4600-construction-only-fields-dynamic-writes.ts": 2213, - "4601-cycle-holders.ts": 2024, - "4602-constructor-escape-order.ts": 2992, - "4610-array-ext-dyn-refresh.ts": 3195, - "4620-optional-chain-borrowed-receivers.ts": 3095, - "4621-edge-preserving-callees/main.ts": 3779, - "4630-contract-int32.ts": 2865, - "4630-reference-write-call-arguments.ts": 2202, - "4631-contract-nothrow.ts": 2128, - "4631-reference-write-aliases.ts": 3078, - "4632-contract-immutable.ts": 2740, - "4632-reference-write-loops-and-walks.ts": 3256, - "4633-contract-program-lifetime.ts": 2525, - "4633-reference-write-callbacks-returns.ts": 3120, - "4634-contract-program-lifetime-publish.ts": 5678, - "4634-optional-element-borrowed-returns.ts": 2332, - "4640-bitwise-identity-ranges.ts": 3148, - "4641-nothrow-try-catch.ts": 3252, - "4642-acyclic-contract.ts": 2463, - "4650-stale-property-narrowing.ts": 3973, - "4651-map-string-get-entry.ts": 2471, - "4652-stale-closure-binding-narrowing.ts": 3516, - "4660-typed-rest-spread-forwarding.ts": 3181, - "4671-scoped-array-read-borrows.ts": 2667, - "4690-cycle-bypass-long-lived.ts": 4305, - "4691-publish-constructor-self-alias.ts": 2372, - "4692-borrowed-result-mutating-callees.ts": 1719, - "4720-cold-throw-paths.ts": 3494, - "4721-integer-induction-numbers.ts": 2519, - "4730-touint32-large-magnitudes.ts": 3115, - "4731-string-mixed-ascii-slices.ts": 3544, - "4732-buffer-write-utf16le-runs.ts": 3493, - "4733-typed-array-read-compares.ts": 3222, - "4750-map-string-absent-filter.ts": 2733, - "4751-string-search-multibyte-needles.ts": 2428, - "4795-published-untyped-member-reads.ts": 3850, - "4806-uint32-loop-accumulators.ts": 3676, - "4810-union-identity-retags.ts": 4908, - "4811-union-retag-checked-cast.ts": 2426, - "4812-int32-wrapping-sums.ts": 3340, - "4813-typed-array-read-equality-bindings.ts": 4912, - "4820-sort-comparator-lent-arguments.ts": 4229, - "4821-callback-lent-arguments.ts": 4442, - "4822-stable-capture-reads.ts": 3053, - "4823-array-store-receivers.ts": 3132, - "4830-typed-teardown-chains.ts": 2523, - "4831-cycle-bypass-probe-windows.ts": 2952, - "4840-array-hole-free-prefix.ts": 3114, - "4860-int32-local-storage.ts": 4294, - "4870-array-pipeline-fusion.ts": 4815, - "4871-array-pipeline-analytics.ts": 3642, - "4872-array-pipeline-temporaries.ts": 8318, - "4875-stream-consumers-array-buffer.ts": 2209, - "4876-array-buffer-inspect.ts": 3069, - "4880-await-call-turn-order.ts": 2111, - "4881-await-call-exceptions.ts": 3319, - "4882-await-call-request-chain.ts": 2496, - "4883-await-values-and-hops.ts": 2868, - "4884-await-call-unhandled-sibling.ts": 2184, - "4885-await-call-checkpoints.ts": 3054, - "4890-regex-literal-sites.ts": 2434, - "4891-regex-plain-text-patterns.ts": 2078, - "4892-regex-exec-read-captures.ts": 2821, - "4900-bigint-division-cross-check.ts": 3490, - "4900-console-instances.ts": 3829, - "4901-bigint-radix-text.ts": 2425, - "4901-console-instance-errors.ts": 2457, - "4902-bigint-compound-assign.ts": 2147, - "4903-bigint-fixed-width.ts": 2614, - "4904-bigint-large-products.ts": 3572, - "4905-bigint-fixed-width-fusion.ts": 3509, - "4906-bigint-small-value-trees.ts": 3794, - "4907-bigint-random-trees.ts": 4702, - "4910-hole-free-prefix-upkeep.ts": 2383, - "4920-string-literal-switch.ts": 2483, - "4930-typed-record-reflection.ts": 5024, - "4931-typed-data-generic-walks.ts": 4893, - "4932-typed-json-unknown.ts": 3278, - "4940-async-return-adoption.ts": 3536, - "4941-async-return-adoption-try.ts": 2995, - "4942-async-return-adoption-values.ts": 4513, - "4943-async-return-adoption-interleaved.ts": 2479, - "4950-regex-compiled-captures.ts": 4860, - "4951-regex-compiled-last-index.ts": 3606, - "4952-regex-compiled-anchors-classes.ts": 3738, - "4953-regex-compiled-backtracking.ts": 2856, - "4954-regex-log-report.ts": 4801, - "4955-regex-compiled-differential.ts": 24475, - "4970-int32-call-abi.ts": 3417, - "4980-generator-early-exit-finally.ts": 3144, - "4981-generator-delegation-iterables.ts": 4656, - "4982-generator-sent-values.ts": 2721, - "4983-generator-reuse-iterables.ts": 3420, - "4984-generator-exceptions.ts": 3409, - "4985-generator-lazy-pipeline.ts": 3627, - "4986-generator-default-channels.ts": 3616, - "4987-generator-closures-methods.ts": 2884, - "4988-generator-async-interplay.ts": 2217, - "4989-generator-step-drives.ts": 3530, - "4990-lone-surrogates.ts": 2833, - "4991-lone-surrogate-halves.ts": 2382, - "4992-lone-surrogate-search.ts": 2602, - "4993-lone-surrogate-json.ts": 2479, - "4994-lone-surrogate-uri.ts": 3069, - "4995-lone-surrogate-regex.ts": 3486, - "4996-lone-surrogate-stdio.ts": 3232, - "4997-lone-surrogate-stdout-patch.js": 2640, - "4998-lone-surrogate-buffers.ts": 2452, - "4999-lone-surrogate-io.ts": 2454, - "500-array-basics.ts": 2089, - "501-array-push-pop.ts": 2391, - "5010-lifetime-region-generations.ts": 2818, - "5011-lifetime-region-outside-references.ts": 3377, - "5012-lifetime-region-shapes.ts": 3312, - "5013-lifetime-region-async.ts": 3967, - "5014-lifetime-region-nesting.ts": 3224, - "5015-lifetime-region-publish.ts": 3866, - "5016-lifetime-region-weak-keys.ts": 2328, - "5017-lifetime-region-cycles.ts": 2417, - "5018-lifetime-region-hierarchies.ts": 4028, - "5019-lifetime-region-values.ts": 3115, - "502-array-for-of.ts": 2081, - "5020-lifetime-region-large.ts": 4189, - "5021-lifetime-region-opaque-holders.ts": 2035, - "5022-lifetime-region-workers.ts": 3716, + "4471-unassigned-field-reads.ts": 3309, + "4476-string-ascii-header-fact.ts": 2846, + "4477-buffer-write-ascii-runs.ts": 2125, + "4478-string-large-index-reads.ts": 3334, + "4481-array-optional-push.ts": 3059, + "4482-instanceof-static-class-optional.ts": 2994, + "4483-array-splice-statement.ts": 3331, + "4484-array-length-reset.ts": 2664, + "4485-array-splice-optional-item.ts": 2526, + "4486-array-field-element-borrows.ts": 2341, + "4487-array-literal-optional-values.ts": 2248, + "4520-optional-guard-narrowing.ts": 2281, + "4521-array-callback-element-presence.ts": 4131, + "4522-captured-parameter-lifetimes.ts": 2903, + "4523-array-pop-removal.ts": 2536, + "4524-array-callback-supertype-params.ts": 3251, + "4541-nullable-wrap-borrows.ts": 2882, + "4542-preserving-call-borrows.ts": 3130, + "4543-walk-borrowed-locals.ts": 3034, + "4544-checked-cast-aliases.ts": 2574, + "4545-borrowed-returns.ts": 3551, + "4546-rebound-borrowed-params.ts": 2811, + "4560-field-store-borrowed-receivers.ts": 3116, + "4561-virtual-borrowed-parameters.ts": 3237, + "4562-string-self-concat-move.ts": 2061, + "4563-array-read-projection-receivers.ts": 2512, + "4564-literal-choice-strings.ts": 2795, + "4568-for-of-hole-elements.ts": 2661, + "4569-shorthand-missing-elements.ts": 3064, + "4570-map-lookup-default-record.ts": 2901, + "4591-weak-keys-union-records.ts": 2778, + "4592-cycle-const-from-import/main.ts": 2529, + "4593-weak-keys-empty-objects.ts": 2806, + "4594-union-class-field-mixed-types.ts": 3153, + "4595-union-class-field-optional-receiver.ts": 1997, + "4596-error-subclass-int-fields.ts": 2606, + "4596-tdz-nullable-forward-capture.ts": 3433, + "4597-callback-field-method-name.ts": 2519, + "4598-live-array-ref-element-access.ts": 4363, + "4598-map-set-clear-reuse.ts": 4118, + "4598-os-available-parallelism.ts": 2474, + "4598-publish-constructor-stores.ts": 2635, + "4599-construction-only-field-borrows.ts": 3147, + "4600-construction-only-fields-dynamic-writes.ts": 2319, + "4601-cycle-holders.ts": 2904, + "4602-constructor-escape-order.ts": 2703, + "4610-array-ext-dyn-refresh.ts": 3049, + "4620-optional-chain-borrowed-receivers.ts": 3006, + "4621-edge-preserving-callees/main.ts": 2464, + "4630-contract-int32.ts": 2586, + "4630-reference-write-call-arguments.ts": 2892, + "4631-contract-nothrow.ts": 2842, + "4631-reference-write-aliases.ts": 2922, + "4632-contract-immutable.ts": 2582, + "4632-reference-write-loops-and-walks.ts": 2399, + "4633-contract-program-lifetime.ts": 3449, + "4633-reference-write-callbacks-returns.ts": 2678, + "4634-contract-program-lifetime-publish.ts": 4573, + "4634-optional-element-borrowed-returns.ts": 2111, + "4640-bitwise-identity-ranges.ts": 2671, + "4641-nothrow-try-catch.ts": 2141, + "4642-acyclic-contract.ts": 2859, + "4650-stale-property-narrowing.ts": 2759, + "4651-map-string-get-entry.ts": 3114, + "4652-stale-closure-binding-narrowing.ts": 3092, + "4660-typed-rest-spread-forwarding.ts": 2331, + "4671-scoped-array-read-borrows.ts": 2575, + "4690-cycle-bypass-long-lived.ts": 4228, + "4691-publish-constructor-self-alias.ts": 2964, + "4692-borrowed-result-mutating-callees.ts": 2766, + "4720-cold-throw-paths.ts": 3228, + "4721-integer-induction-numbers.ts": 2974, + "4730-touint32-large-magnitudes.ts": 2198, + "4731-string-mixed-ascii-slices.ts": 3160, + "4732-buffer-write-utf16le-runs.ts": 3120, + "4733-typed-array-read-compares.ts": 2977, + "4750-map-string-absent-filter.ts": 3464, + "4751-string-search-multibyte-needles.ts": 2454, + "4795-published-untyped-member-reads.ts": 3340, + "4806-uint32-loop-accumulators.ts": 2740, + "4810-union-identity-retags.ts": 4045, + "4811-union-retag-checked-cast.ts": 2819, + "4812-int32-wrapping-sums.ts": 3339, + "4813-typed-array-read-equality-bindings.ts": 3997, + "4820-sort-comparator-lent-arguments.ts": 2782, + "4821-callback-lent-arguments.ts": 3485, + "4822-stable-capture-reads.ts": 2483, + "4823-array-store-receivers.ts": 2858, + "4830-typed-teardown-chains.ts": 3292, + "4831-cycle-bypass-probe-windows.ts": 3738, + "4840-array-hole-free-prefix.ts": 3550, + "4860-int32-local-storage.ts": 3699, + "4870-array-pipeline-fusion.ts": 6694, + "4871-array-pipeline-analytics.ts": 4274, + "4872-array-pipeline-temporaries.ts": 7763, + "4875-stream-consumers-array-buffer.ts": 3017, + "4876-array-buffer-inspect.ts": 2569, + "4880-await-call-turn-order.ts": 2784, + "4881-await-call-exceptions.ts": 2757, + "4882-await-call-request-chain.ts": 2151, + "4883-await-values-and-hops.ts": 2520, + "4884-await-call-unhandled-sibling.ts": 2379, + "4885-await-call-checkpoints.ts": 2128, + "4890-regex-literal-sites.ts": 3484, + "4891-regex-plain-text-patterns.ts": 2502, + "4892-regex-exec-read-captures.ts": 3120, + "4900-bigint-division-cross-check.ts": 3532, + "4900-console-instances.ts": 3723, + "4901-bigint-radix-text.ts": 3090, + "4901-console-instance-errors.ts": 3055, + "4902-bigint-compound-assign.ts": 2449, + "4903-bigint-fixed-width.ts": 2818, + "4904-bigint-large-products.ts": 2953, + "4905-bigint-fixed-width-fusion.ts": 3047, + "4906-bigint-small-value-trees.ts": 3132, + "4907-bigint-random-trees.ts": 4068, + "4910-hole-free-prefix-upkeep.ts": 3149, + "4920-string-literal-switch.ts": 4588, + "4930-typed-record-reflection.ts": 4183, + "4931-typed-data-generic-walks.ts": 4062, + "4932-typed-json-unknown.ts": 3239, + "4940-async-return-adoption.ts": 2845, + "4941-async-return-adoption-try.ts": 3156, + "4942-async-return-adoption-values.ts": 3620, + "4943-async-return-adoption-interleaved.ts": 2831, + "4950-regex-compiled-captures.ts": 5723, + "4951-regex-compiled-last-index.ts": 3059, + "4952-regex-compiled-anchors-classes.ts": 2426, + "4953-regex-compiled-backtracking.ts": 3365, + "4954-regex-log-report.ts": 3193, + "4955-regex-compiled-differential.ts": 24862, + "4970-int32-call-abi.ts": 2508, + "4980-generator-early-exit-finally.ts": 2836, + "4981-generator-delegation-iterables.ts": 4874, + "4982-generator-sent-values.ts": 2242, + "4983-generator-reuse-iterables.ts": 3066, + "4984-generator-exceptions.ts": 2959, + "4985-generator-lazy-pipeline.ts": 2708, + "4986-generator-default-channels.ts": 3119, + "4987-generator-closures-methods.ts": 2675, + "4988-generator-async-interplay.ts": 2141, + "4989-generator-step-drives.ts": 4185, + "4990-lone-surrogates.ts": 3319, + "4991-lone-surrogate-halves.ts": 2978, + "4992-lone-surrogate-search.ts": 2759, + "4993-lone-surrogate-json.ts": 2994, + "4994-lone-surrogate-uri.ts": 2786, + "4995-lone-surrogate-regex.ts": 3169, + "4996-lone-surrogate-stdio.ts": 2201, + "4997-lone-surrogate-stdout-patch.js": 2754, + "4998-lone-surrogate-buffers.ts": 3060, + "4999-lone-surrogate-io.ts": 4219, + "500-array-basics.ts": 2646, + "501-array-push-pop.ts": 2128, + "5010-lifetime-region-generations.ts": 2950, + "5011-lifetime-region-outside-references.ts": 2816, + "5012-lifetime-region-shapes.ts": 3847, + "5013-lifetime-region-async.ts": 3198, + "5014-lifetime-region-nesting.ts": 2741, + "5015-lifetime-region-publish.ts": 2749, + "5016-lifetime-region-weak-keys.ts": 2541, + "5017-lifetime-region-cycles.ts": 2989, + "5018-lifetime-region-hierarchies.ts": 3642, + "5019-lifetime-region-values.ts": 2516, + "502-array-for-of.ts": 2614, + "5020-lifetime-region-large.ts": 3840, + "5021-lifetime-region-opaque-holders.ts": 2702, + "5022-lifetime-region-workers.ts": 3127, "5023-lifetime-region-await.ts": 3656, "5024-lifetime-region-await-forms.ts": 3342, - "503-array-functions.ts": 2924, - "504-array-rc-stress.ts": 3242, - "5040-promise-all-race-turns.ts": 4173, - "5041-promise-all-turns.js": 2741, - "5042-async-generator-return-promise.ts": 3826, - "5043-async-generator-return-forms.ts": 2473, - "5045-generator-delegation-typed-next.ts": 4238, - "5046-generator-delegation-return-throw.ts": 3793, - "5047-generator-delegation-iterables-typed.ts": 4942, - "5048-generator-delegation-async.ts": 3582, - "5049-generator-delegation-edges.ts": 2876, - "5050-inherited-in-membership.ts": 3767, - "5051-typed-record-prototypes.ts": 3580, - "5052-class-for-in-unknown.ts": 3587, - "5053-json-replacer-arrays.ts": 2213, - "5054-required-field-delete.ts": 2545, - "5055-object-create-record-literal.ts": 2467, - "5056-generator-in-unknown.ts": 2333, - "5060-child-fork-exit-after-messages/main.ts": 2415, - "5061-child-fork-local-disconnect/main.ts": 3036, - "5062-child-fork-message-before-eof/main.ts": 2882, - "5065-global-increment-initializers.ts": 2801, - "5066-global-compound-updates.ts": 3218, - "5067-global-updates-in-functions.ts": 3110, - "5068-global-var-let-const-updates.ts": 2271, - "5069-global-update-modules/main.ts": 2850, - "5070-optional-read-bindings.ts": 2832, - "5071-optional-chain-scalars.ts": 2863, - "5072-optional-nullish-ternary.ts": 2578, - "5073-optional-results.ts": 3429, - "5074-optional-pop-shift.ts": 2389, - "5075-optional-reads-unchecked/main.ts": 2697, - "5076-optional-escapes.ts": 2437, - "5080-boolean-array-storage.ts": 6485, - "5081-boolean-array-dynamic-views.ts": 2359, - "5085-promise-allsettled-turns.ts": 3904, - "5086-promise-any-turns.ts": 3934, - "5087-promise-allsettled-any-dyn.js": 5476, - "5088-promise-combinator-thenables.js": 3403, - "5089-promise-settled-records.ts": 3102, - "5090-generator-finished-result-value.ts": 3342, - "5091-generator-delegation-arrays-strings.ts": 4412, - "5092-generator-delegation-sets-maps.ts": 3102, - "5095-console-count-group.ts": 3177, - "5096-console-assert-dir.ts": 3849, - "5097-console-table.ts": 3057, - "5098-console-time-warnings.ts": 6642, - "5099-console-methods-dynamic.cjs": 3356, - "510-array-map-filter-foreach.ts": 3363, - "511-array-indexof-includes.ts": 3037, - "5110-var-hoisting-early-reads.ts": 2475, - "5111-var-hoisting-closures-classes.ts": 3177, - "5112-var-hoisting-function-scope.ts": 2961, - "5113-tdz-let-const-class.ts": 3714, - "5114-var-hoisting-js.js": 2962, - "5115-regex-replace-compiled.ts": 3348, - "5116-regex-capture-reads.ts": 3537, - "5117-regex-log-report-spans.ts": 2918, - "5118-regex-replace-char-chains.ts": 2863, - "512-array-join-chains.ts": 2158, - "5120-frame-records.ts": 2742, - "5121-frame-objects.ts": 2716, - "5122-frame-result-slots.ts": 2032, - "5123-frame-reassigned.ts": 2738, - "5124-frame-objects-control.ts": 2735, - "5125-frame-mutating-methods.ts": 2979, - "5126-frame-returned-params.ts": 2879, - "5127-frame-loop-bindings.ts": 3193, - "513-array-methods-rc-stress.ts": 2584, - "5130-event-target-dispatch.js": 3996, - "5131-event-target-listener-errors.js": 2992, - "5132-event-target-typed.ts": 2663, - "5133-abort-signal-event-target.ts": 3726, - "5134-events-error-monitor.ts": 3026, - "5135-event-target-warnings.js": 3015, - "5136-events-error-monitor-string-name.ts": 1974, - "5137-events-error-monitor-computed-name.js": 2881, - "5138-events-error-monitor-shared-listener.ts": 1863, - "5139-event-target-listener-throw.ts": 2263, - "514-array-find-some-every.ts": 3260, - "5140-os-host-facts.ts": 3684, - "5141-os-constants.ts": 3492, - "5142-path-parse-format.ts": 2821, - "5145-path-matches-glob-basics.ts": 2871, - "5146-path-matches-glob-braces.ts": 4793, - "5147-path-matches-glob-extglob.ts": 3097, - "5148-path-matches-glob-classes.ts": 3036, - "5149-path-matches-glob-win32.ts": 3100, - "515-array-flatmap.ts": 3003, - "5150-small-array-inline-slots.ts": 3147, - "5155-cycle-header-types.ts": 3920, - "516-array-reduce.ts": 3545, - "5160-field-callback-receiver.ts": 2905, - "5161-field-callback-receiver-escape.ts": 2883, - "5162-field-method-reference-receiver.ts": 2527, - "5163-field-callback-receiver.cjs": 3464, - "5164-worker-field-callback-receiver.ts": 3434, - "5165-interface-method-dispatch.ts": 3679, - "5166-interface-method-values.ts": 3253, - "5167-interface-method-order.ts": 3399, - "5168-interface-method-hierarchy.ts": 3873, - "5169-interface-method-chains.ts": 4165, - "517-array-hof-index-args.ts": 2228, - "5170-string-scan-eviction.ts": 2996, - "5171-lone-surrogate-replace-seams.ts": 3136, - "5175-forin-typed-as-unknown.ts": 2043, - "5176-object-keys-typed-as-unknown.ts": 3098, - "5177-forin-dynamic-objects.ts": 3236, - "5178-forin-keys-js.js": 3163, - "5179-forin-typed-shapes.ts": 3384, - "518-array-sort.ts": 2963, - "518-promise-void-union-callbacks.ts": 3093, - "5180-interface-arrays.ts": 3147, - "5181-interface-array-methods.ts": 8906, - "5182-interface-array-boundaries.ts": 2573, - "5183-interface-property-reads.ts": 3303, - "5184-interface-property-objects.ts": 2438, - "5185-util-inherits.cjs": 3986, - "5186-util-inherits.ts": 3513, - "5187-util-deprecate.cjs": 3994, - "5188-util-deprecate-flags.cjs": 2993, - "5189-util-deprecate.ts": 3292, - "519-array-from-length.ts": 2634, - "519-promise-union-await-values.ts": 2998, - "5190-util-callbackify.cjs": 2477, - "5191-util-callbackify.ts": 3362, - "5192-util-debuglog.cjs": 3445, - "5193-util-debuglog.ts": 3383, - "5194-process-emit-warning-tick.cjs": 2282, - "5195-object-entries-typed-as-unknown.ts": 3460, - "5196-object-values-typed-as-unknown.ts": 3267, - "5197-object-entries-dynamic-objects.ts": 3904, - "5198-object-entries-values-js.js": 2966, - "5199-object-entries-identity.ts": 3380, - "520-map-basics.ts": 2986, - "5200-array-sort-keyed-numbers.ts": 3421, - "5201-array-sort-keyed-records.ts": 5202, - "5202-array-sort-keyed-lookalikes.ts": 3629, - "5203-typed-array-sort-default.ts": 5027, - "5204-typed-array-sort-comparators.ts": 3154, - "521-map-number-keys.ts": 2975, - "5210-process-memory-usage.ts": 2993, - "5211-process-identity.ts": 2460, - "5212-perf-marks-measures.ts": 3807, - "5213-perf-timing-errors.ts": 2266, - "5214-perf-entry-inspect.ts": 4135, - "5215-perf-timing-validation.js": 3297, - "5216-perf-spread-arguments.js": 2533, - "5217-perf-spread-typed.ts": 2686, - "522-map-foreach.ts": 3042, - "5220-url-parse-warnings.ts": 2728, - "5221-url-parse-shapes.ts": 3405, - "5222-url-parse-hosts.ts": 3159, - "5223-url-parse-query.ts": 3506, - "5224-url-format-objects.ts": 3987, - "5225-url-format-whatwg.ts": 3370, - "5226-url-resolve.ts": 3030, - "5227-url-legacy-dependency/main.ts": 2891, - "5228-url-domain-conversion.ts": 2727, - "5229-url-legacy-errors.cjs": 3507, - "523-map-ref-values.ts": 2648, - "5230-inline-union-fields.ts": 3279, - "5231-inline-union-field-kinds.ts": 2225, - "5232-inline-union-fields-dynamic.ts": 4075, - "5233-inline-union-fields-shapes.ts": 3388, - "5234-inline-union-class-fields.ts": 3532, - "5235-inline-union-fields-publish.ts": 2491, - "5236-inline-union-unchecked-reads.ts": 3193, - "5237-inline-union-frame-objects.ts": 3058, - "524-map-cycles.ts": 2269, - "5240-event-target-subclass.ts": 4204, - "5241-event-subclass.ts": 2870, - "5242-event-target-subclass-hierarchy.ts": 2589, - "5243-event-target-subclass-dynamic.ts": 3729, - "5244-event-target-subclass.js": 3769, - "5245-event-target-subclass-signals.ts": 3471, - "5246-event-target-subclass-listener-throw.ts": 3466, - "5247-event-target-subclass-lifetimes.ts": 4294, - "5248-event-target-subclass-warnings.ts": 3036, - "5249-event-target-subclass-unconstructed.ts": 2612, - "525-map-rc-stress.ts": 2418, + "503-array-functions.ts": 2610, + "504-array-rc-stress.ts": 2247, + "5040-promise-all-race-turns.ts": 3415, + "5041-promise-all-turns.js": 5156, + "5042-async-generator-return-promise.ts": 3112, + "5043-async-generator-return-forms.ts": 3029, + "5045-generator-delegation-typed-next.ts": 3463, + "5046-generator-delegation-return-throw.ts": 2606, + "5047-generator-delegation-iterables-typed.ts": 4378, + "5048-generator-delegation-async.ts": 4885, + "5049-generator-delegation-edges.ts": 2538, + "5050-inherited-in-membership.ts": 3142, + "5051-typed-record-prototypes.ts": 3140, + "5052-class-for-in-unknown.ts": 2653, + "5053-json-replacer-arrays.ts": 4713, + "5054-required-field-delete.ts": 2632, + "5055-object-create-record-literal.ts": 2065, + "5056-generator-in-unknown.ts": 3903, + "5060-child-fork-exit-after-messages/main.ts": 2572, + "5061-child-fork-local-disconnect/main.ts": 3248, + "5062-child-fork-message-before-eof/main.ts": 4732, + "5065-global-increment-initializers.ts": 3985, + "5066-global-compound-updates.ts": 2635, + "5067-global-updates-in-functions.ts": 2589, + "5068-global-var-let-const-updates.ts": 2726, + "5069-global-update-modules/main.ts": 2372, + "5070-optional-read-bindings.ts": 2144, + "5071-optional-chain-scalars.ts": 2192, + "5072-optional-nullish-ternary.ts": 2587, + "5073-optional-results.ts": 2727, + "5074-optional-pop-shift.ts": 2568, + "5075-optional-reads-unchecked/main.ts": 4996, + "5076-optional-escapes.ts": 2735, + "5080-boolean-array-storage.ts": 5236, + "5081-boolean-array-dynamic-views.ts": 2815, + "5085-promise-allsettled-turns.ts": 3332, + "5086-promise-any-turns.ts": 3297, + "5087-promise-allsettled-any-dyn.js": 3767, + "5088-promise-combinator-thenables.js": 4248, + "5089-promise-settled-records.ts": 3528, + "5090-generator-finished-result-value.ts": 2964, + "5091-generator-delegation-arrays-strings.ts": 2768, + "5092-generator-delegation-sets-maps.ts": 3565, + "5095-console-count-group.ts": 2753, + "5096-console-assert-dir.ts": 4648, + "5097-console-table.ts": 2620, + "5098-console-time-warnings.ts": 6302, + "5099-console-methods-dynamic.cjs": 2644, + "510-array-map-filter-foreach.ts": 2991, + "511-array-indexof-includes.ts": 2657, + "5110-var-hoisting-early-reads.ts": 2806, + "5111-var-hoisting-closures-classes.ts": 2117, + "5112-var-hoisting-function-scope.ts": 2614, + "5113-tdz-let-const-class.ts": 3154, + "5114-var-hoisting-js.js": 4536, + "5115-regex-replace-compiled.ts": 2608, + "5116-regex-capture-reads.ts": 3064, + "5117-regex-log-report-spans.ts": 3404, + "5118-regex-replace-char-chains.ts": 2444, + "512-array-join-chains.ts": 2376, + "5120-frame-records.ts": 2615, + "5121-frame-objects.ts": 2616, + "5122-frame-result-slots.ts": 2622, + "5123-frame-reassigned.ts": 2564, + "5124-frame-objects-control.ts": 3061, + "5125-frame-mutating-methods.ts": 2527, + "5126-frame-returned-params.ts": 2697, + "5127-frame-loop-bindings.ts": 2824, + "513-array-methods-rc-stress.ts": 2641, + "5130-event-target-dispatch.js": 3752, + "5131-event-target-listener-errors.js": 3003, + "5132-event-target-typed.ts": 3341, + "5133-abort-signal-event-target.ts": 3302, + "5134-events-error-monitor.ts": 2664, + "5135-event-target-warnings.js": 2890, + "5136-events-error-monitor-string-name.ts": 2380, + "5137-events-error-monitor-computed-name.js": 3077, + "5138-events-error-monitor-shared-listener.ts": 2001, + "5139-event-target-listener-throw.ts": 1965, + "514-array-find-some-every.ts": 2998, + "5140-os-host-facts.ts": 3248, + "5141-os-constants.ts": 2402, + "5142-path-parse-format.ts": 2850, + "5145-path-matches-glob-basics.ts": 2904, + "5146-path-matches-glob-braces.ts": 4866, + "5147-path-matches-glob-extglob.ts": 2653, + "5148-path-matches-glob-classes.ts": 2765, + "5149-path-matches-glob-win32.ts": 2754, + "515-array-flatmap.ts": 3015, + "5150-small-array-inline-slots.ts": 3276, + "5155-cycle-header-types.ts": 3561, + "516-array-reduce.ts": 3293, + "5160-field-callback-receiver.ts": 3482, + "5161-field-callback-receiver-escape.ts": 2665, + "5162-field-method-reference-receiver.ts": 2779, + "5163-field-callback-receiver.cjs": 2875, + "5164-worker-field-callback-receiver.ts": 3147, + "5165-interface-method-dispatch.ts": 2641, + "5166-interface-method-values.ts": 4036, + "5167-interface-method-order.ts": 3679, + "5168-interface-method-hierarchy.ts": 4400, + "5169-interface-method-chains.ts": 2934, + "517-array-hof-index-args.ts": 2918, + "5170-string-scan-eviction.ts": 2885, + "5171-lone-surrogate-replace-seams.ts": 3463, + "5175-forin-typed-as-unknown.ts": 3333, + "5176-object-keys-typed-as-unknown.ts": 3148, + "5177-forin-dynamic-objects.ts": 2926, + "5178-forin-keys-js.js": 2135, + "5179-forin-typed-shapes.ts": 3197, + "518-array-sort.ts": 2699, + "518-promise-void-union-callbacks.ts": 1929, + "5180-interface-arrays.ts": 3267, + "5181-interface-array-methods.ts": 7443, + "5182-interface-array-boundaries.ts": 3225, + "5183-interface-property-reads.ts": 3018, + "5184-interface-property-objects.ts": 3161, + "5185-util-inherits.cjs": 3120, + "5186-util-inherits.ts": 3012, + "5187-util-deprecate.cjs": 3705, + "5188-util-deprecate-flags.cjs": 2866, + "5189-util-deprecate.ts": 2361, + "519-array-from-length.ts": 3817, + "519-promise-union-await-values.ts": 2296, + "5190-util-callbackify.cjs": 3512, + "5191-util-callbackify.ts": 2893, + "5192-util-debuglog.cjs": 3224, + "5193-util-debuglog.ts": 4346, + "5194-process-emit-warning-tick.cjs": 2199, + "5195-object-entries-typed-as-unknown.ts": 2787, + "5196-object-values-typed-as-unknown.ts": 2984, + "5197-object-entries-dynamic-objects.ts": 3371, + "5198-object-entries-values-js.js": 2819, + "5199-object-entries-identity.ts": 3133, + "520-map-basics.ts": 2629, + "5200-array-sort-keyed-numbers.ts": 3636, + "5201-array-sort-keyed-records.ts": 3559, + "5202-array-sort-keyed-lookalikes.ts": 3148, + "5203-typed-array-sort-default.ts": 6169, + "5204-typed-array-sort-comparators.ts": 4152, + "521-map-number-keys.ts": 2529, + "5210-process-memory-usage.ts": 3044, + "5211-process-identity.ts": 2815, + "5212-perf-marks-measures.ts": 2925, + "5213-perf-timing-errors.ts": 3203, + "5214-perf-entry-inspect.ts": 3164, + "5215-perf-timing-validation.js": 4384, + "5216-perf-spread-arguments.js": 3711, + "5217-perf-spread-typed.ts": 3324, + "522-map-foreach.ts": 2813, + "5220-url-parse-warnings.ts": 2906, + "5221-url-parse-shapes.ts": 2400, + "5222-url-parse-hosts.ts": 2972, + "5223-url-parse-query.ts": 2190, + "5224-url-format-objects.ts": 2681, + "5225-url-format-whatwg.ts": 2885, + "5226-url-resolve.ts": 2184, + "5227-url-legacy-dependency/main.ts": 3291, + "5228-url-domain-conversion.ts": 2624, + "5229-url-legacy-errors.cjs": 3698, + "523-map-ref-values.ts": 2904, + "5230-inline-union-fields.ts": 2318, + "5231-inline-union-field-kinds.ts": 3614, + "5232-inline-union-fields-dynamic.ts": 3502, + "5233-inline-union-fields-shapes.ts": 3338, + "5234-inline-union-class-fields.ts": 4285, + "5235-inline-union-fields-publish.ts": 2840, + "5236-inline-union-unchecked-reads.ts": 1998, + "5237-inline-union-frame-objects.ts": 2284, + "524-map-cycles.ts": 3272, + "5240-event-target-subclass.ts": 3668, + "5241-event-subclass.ts": 4201, + "5242-event-target-subclass-hierarchy.ts": 2218, + "5243-event-target-subclass-dynamic.ts": 2613, + "5244-event-target-subclass.js": 3715, + "5245-event-target-subclass-signals.ts": 3077, + "5246-event-target-subclass-listener-throw.ts": 2770, + "5247-event-target-subclass-lifetimes.ts": 3603, + "5248-event-target-subclass-warnings.ts": 2743, + "5249-event-target-subclass-unconstructed.ts": 1632, + "525-map-rc-stress.ts": 3853, "5250-cipher-aes-gcm.ts": 5771, "5251-cipher-aes-cbc.ts": 3823, "5252-cipher-aes-ctr.ts": 2580, @@ -1704,45 +1704,45 @@ "5257-cipher-vectors.ts": 3572, "5258-cipher-handles.js": 2980, "5259-cipher-chunked.ts": 2586, - "526-set-basics.ts": 2254, - "5260-record-unknown-identity.ts": 2475, - "5261-optional-field-identity.ts": 3183, - "5262-record-unknown-many.ts": 2600, - "527-set-foreach.ts": 2444, - "5270-url-parse-no-deprecation.cjs": 3324, - "5271-url-parse-throw-deprecation.cjs": 3222, - "5275-http-end-callback-order.ts": 3388, - "5276-style-text-hex-colors.cjs": 2986, - "5277-fs-read-file-buffer-option.cjs": 2730, - "5278-host-null-bytes.cjs": 2802, - "5279-search-params-null-init.cjs": 2749, - "528-set-seeded.ts": 3056, - "5285-blob-construct.ts": 2884, - "5286-blob-readers.ts": 2550, - "5287-blob-inspect.ts": 3329, - "5288-blob-validation.js": 3838, - "5289-blob-read-order.ts": 3430, - "529-map-seeded.ts": 2821, - "5290-blob-dynamic.js": 3167, - "5295-readline-promises-question.ts": 3310, - "5296-readline-lines.ts": 2423, - "5297-readline-callback-events.cjs": 2594, - "5298-readline-abort.cjs": 3296, - "5299-readline-stdin.ts": 3344, - "530-record-arrays.ts": 2381, - "5300-stream-add-abort-signal.ts": 3578, - "5301-stream-add-abort-signal-errors.cjs": 3164, - "5302-stream-promises-options.ts": 2875, - "5303-stream-finished-callback-opts.cjs": 3111, - "5305-json-stringify-typed-arrays.ts": 3510, - "531-record-array-hofs.ts": 3334, - "5315-map-iterate-after-front-deletes.ts": 2670, - "5316-map-lru-eviction.ts": 3171, - "5317-map-iterate-while-mutating.ts": 3109, - "5318-set-iterate-after-deletes.ts": 3338, - "5319-map-iteration-values.ts": 2901, - "532-record-arrays-rc-stress.ts": 2965, - "5320-map-iterate-across-compaction.ts": 2712, + "526-set-basics.ts": 1919, + "5260-record-unknown-identity.ts": 2937, + "5261-optional-field-identity.ts": 2860, + "5262-record-unknown-many.ts": 2984, + "527-set-foreach.ts": 3210, + "5270-url-parse-no-deprecation.cjs": 3158, + "5271-url-parse-throw-deprecation.cjs": 2975, + "5275-http-end-callback-order.ts": 2389, + "5276-style-text-hex-colors.cjs": 2820, + "5277-fs-read-file-buffer-option.cjs": 2710, + "5278-host-null-bytes.cjs": 2114, + "5279-search-params-null-init.cjs": 1781, + "528-set-seeded.ts": 2610, + "5285-blob-construct.ts": 2681, + "5286-blob-readers.ts": 3079, + "5287-blob-inspect.ts": 3817, + "5288-blob-validation.js": 3803, + "5289-blob-read-order.ts": 2829, + "529-map-seeded.ts": 2574, + "5290-blob-dynamic.js": 2354, + "5295-readline-promises-question.ts": 3709, + "5296-readline-lines.ts": 2760, + "5297-readline-callback-events.cjs": 2472, + "5298-readline-abort.cjs": 2757, + "5299-readline-stdin.ts": 3087, + "530-record-arrays.ts": 2787, + "5300-stream-add-abort-signal.ts": 3027, + "5301-stream-add-abort-signal-errors.cjs": 2717, + "5302-stream-promises-options.ts": 3120, + "5303-stream-finished-callback-opts.cjs": 2705, + "5305-json-stringify-typed-arrays.ts": 3153, + "531-record-array-hofs.ts": 2832, + "5315-map-iterate-after-front-deletes.ts": 3911, + "5316-map-lru-eviction.ts": 2782, + "5317-map-iterate-while-mutating.ts": 2769, + "5318-set-iterate-after-deletes.ts": 2291, + "5319-map-iteration-values.ts": 2689, + "532-record-arrays-rc-stress.ts": 2437, + "5320-map-iterate-across-compaction.ts": 3526, "5321-integer-closed-arithmetic-loops.ts": 3349, "5321-json-parse-cycles.ts": 3308, "5322-integer-variable-step-loops.ts": 2801, @@ -1751,29 +1751,29 @@ "5323-int32-nonnegative-slot-facts.ts": 2381, "5324-int32-initializer-locals.ts": 3123, "5324-structured-clone-documents.ts": 3223, - "5325-record-boundary-returns.ts": 1813, - "5326-record-boundary-params.ts": 2295, - "5327-record-boundary-identity.ts": 3016, - "5328-record-boundary-open.ts": 2956, - "5329-record-boundary-recursion.ts": 3001, - "533-array-element-cycles.ts": 2575, - "5330-record-boundary-fields.ts": 2897, - "5331-record-boundary-methods.ts": 2874, + "5325-record-boundary-returns.ts": 1763, + "5326-record-boundary-params.ts": 2634, + "5327-record-boundary-identity.ts": 2323, + "5328-record-boundary-open.ts": 2561, + "5329-record-boundary-recursion.ts": 2680, + "533-array-element-cycles.ts": 2932, + "5330-record-boundary-fields.ts": 1977, + "5331-record-boundary-methods.ts": 3130, "5332-int32-narrowed-slot-facts.ts": 2932, "5333-integer-guarded-while-counters.ts": 2773, - "5333-record-boundary-nullable-argument.ts": 2389, - "5334-fetch-mentions-without-calls.ts": 2822, + "5333-record-boundary-nullable-argument.ts": 3012, + "5334-fetch-mentions-without-calls.ts": 2532, "5335-stream-operators-values.ts": 3448, - "5335-top-level-await-pending-exit-code.ts": 2359, + "5335-top-level-await-pending-exit-code.ts": 1919, "5336-stream-operators-promise-timing.ts": 3509, - "5336-top-level-await-pending-exit-listener.ts": 2649, - "5337-dc-subscriber-throw-next-tick.cjs": 2705, + "5336-top-level-await-pending-exit-listener.ts": 3734, + "5337-dc-subscriber-throw-next-tick.cjs": 2604, "5337-stream-operators-concurrency.ts": 2478, - "5338-js-tdz-function-element.js": 2787, + "5338-js-tdz-function-element.js": 2562, "5338-stream-operators-checks.cjs": 3991, - "5339-array-buffer-constructor.js": 3134, + "5339-array-buffer-constructor.js": 2502, "5339-stream-for-await-hops.ts": 2919, - "534-record-width-subtyping.ts": 3068, + "534-record-width-subtyping.ts": 2615, "5340-readable-from-options.ts": 1980, "5341-compound-any-operand.ts": 3314, "5341-generator-callback-params.ts": 3955, @@ -1789,28 +1789,28 @@ "5343-stream-compose-edges.ts": 3078, "5344-json-parse-undeclared-keys.ts": 4193, "5344-stream-pipeline-timing.ts": 3177, - "5345-object-values-for-of-unknown.ts": 3435, - "5346-object-values-length-dynamic.ts": 3274, - "5347-object-values-loop-control.ts": 3443, - "5348-object-values-for-of-js.js": 2832, - "5349-object-entries-values-optional.ts": 3325, - "535-object-statics.ts": 3232, - "5350-object-values-wide-record.ts": 2628, - "5351-object-values-methods-index.ts": 4093, + "5345-object-values-for-of-unknown.ts": 3008, + "5346-object-values-length-dynamic.ts": 3055, + "5347-object-values-loop-control.ts": 3030, + "5348-object-values-for-of-js.js": 2732, + "5349-object-entries-values-optional.ts": 2083, + "535-object-statics.ts": 2312, + "5350-object-values-wide-record.ts": 2790, + "5351-object-values-methods-index.ts": 3275, "5352-final-field-loop-reads.ts": 2894, "5353-captured-const-values.ts": 3727, "5354-captured-const-tdz.ts": 2243, "5355-captured-function-declarations.ts": 2917, "5356-captured-tdz-ordering.ts": 2726, "5357-init-only-module-bindings.ts": 1956, - "536-map-seed-array.ts": 1912, - "5360-array-sort-comparator-calls.ts": 3363, - "5361-array-sort-inconsistent-comparators.ts": 3560, - "5362-array-sort-comparator-throws.ts": 3410, - "5363-array-sort-comparator-writes.ts": 7945, - "5364-array-sort-union-and-boolean-elements.ts": 10573, - "5365-array-sort-dynamic-values.js": 2528, - "537-map-iter-drains.ts": 3127, + "536-map-seed-array.ts": 2712, + "5360-array-sort-comparator-calls.ts": 3175, + "5361-array-sort-inconsistent-comparators.ts": 3161, + "5362-array-sort-comparator-throws.ts": 2896, + "5363-array-sort-comparator-writes.ts": 6813, + "5364-array-sort-union-and-boolean-elements.ts": 8514, + "5365-array-sort-dynamic-values.js": 2402, + "537-map-iter-drains.ts": 2867, "5370-zlib-stream-roundtrip.ts": 3486, "5371-zlib-stream-chunking.cjs": 4025, "5372-zlib-stream-errors.cjs": 2794, @@ -1821,29 +1821,29 @@ "5377-zlib-stream-backpressure.cjs": 2917, "5378-zlib-sync-options.cjs": 2777, "5379-zlib-callback-options.ts": 2861, - "538-map-set-for-of.ts": 2968, - "5390-interface-loop-element-lifetimes.ts": 3450, - "5391-interface-dispatch-hierarchies.ts": 2856, - "5392-interface-receiver-bindings.ts": 2639, - "5393-interface-array-holes.ts": 3216, - "5394-interface-implementers.ts": 3420, - "5395-locale-compare-ascii.ts": 2643, - "5396-locale-compare-latin.ts": 3373, - "5397-locale-compare-sorting.ts": 2181, - "540-tuples-basics.ts": 3148, - "5400-json-parse-typed-keys.ts": 3311, - "5405-buffer-arraybuffer-window.ts": 2743, - "5406-util-types-keys.ts": 3041, - "5407-http-header-field-limit.ts": 3155, - "5408-http-unread-request-end.ts": 3012, - "5409-http-held-request-body.ts": 3019, - "541-ref-array-json.ts": 2632, - "5410-inspect-class-values.ts": 3232, - "5411-inspect-class-hierarchies.ts": 3027, - "5412-inspect-dynamic-collections.ts": 2914, - "5413-inspect-class-values.cjs": 3313, + "538-map-set-for-of.ts": 2756, + "5390-interface-loop-element-lifetimes.ts": 2999, + "5391-interface-dispatch-hierarchies.ts": 3168, + "5392-interface-receiver-bindings.ts": 2015, + "5393-interface-array-holes.ts": 2530, + "5394-interface-implementers.ts": 2992, + "5395-locale-compare-ascii.ts": 3026, + "5396-locale-compare-latin.ts": 3119, + "5397-locale-compare-sorting.ts": 3179, + "540-tuples-basics.ts": 2776, + "5400-json-parse-typed-keys.ts": 3131, + "5405-buffer-arraybuffer-window.ts": 2729, + "5406-util-types-keys.ts": 2747, + "5407-http-header-field-limit.ts": 2785, + "5408-http-unread-request-end.ts": 3226, + "5409-http-held-request-body.ts": 3218, + "541-ref-array-json.ts": 3099, + "5410-inspect-class-values.ts": 1875, + "5411-inspect-class-hierarchies.ts": 2712, + "5412-inspect-dynamic-collections.ts": 2792, + "5413-inspect-class-values.cjs": 3020, "5415-zlib-dynamic-inputs.cjs": 3606, - "542-union-element-arrays.ts": 3131, + "542-union-element-arrays.ts": 2846, "5420-readable-from-generators.ts": 3459, "5421-readable-from-generators.cjs": 3156, "5422-stream-async-push-wakeup.ts": 3051, @@ -1854,43 +1854,43 @@ "5427-pipeline-generator-backpressure.ts": 3096, "5428-pipeline-generator-stages.cjs": 2057, "5429-pipeline-generator-buffers.ts": 2918, - "5430-dyn-number-string-boxes.ts": 3282, - "5435-crypto-hash-algorithms.ts": 2301, - "5436-crypto-hash-names.js": 2084, - "5437-crypto-hmac-algorithms.ts": 3303, - "5438-crypto-kdf-digests.ts": 2137, - "5439-crypto-kdf-callbacks.js": 3353, - "5440-crypto-hash-encodings.js": 4466, - "5441-crypto-hash-output-length.ts": 3422, - "5442-crypto-random-values.ts": 3350, - "5443-crypto-random-arguments.js": 3269, - "5444-crypto-timing-safe-equal.js": 2816, - "5445-crypto-secret-key-objects.ts": 3209, - "5445-stream-buffer-chunks.ts": 3329, - "5446-crypto-secret-key-errors.js": 2813, - "5446-stream-buffer-chunks-dynamic.js": 2503, - "5447-fs-readdir-order.ts": 2263, - "5448-fs-glob-patterns.ts": 2912, - "5449-fs-glob-options.ts": 3879, - "5450-fs-glob-validation.js": 4118, - "5451-fs-promises-glob.ts": 3698, - "5452-fs-glob-callback.ts": 2619, - "5455-power-of-two-remainder.ts": 2806, - "5456-remainder-large-integer-dividends.ts": 3156, - "5457-lcg-modulus.ts": 2975, - "5458-fractional-remainder.ts": 2938, - "5460-locale-compare-contractions.ts": 2684, - "5461-locale-compare-equivalents.ts": 3166, - "5462-locale-compare-probe-sweep.ts": 4453, - "5463-locale-compare-combining-letters.ts": 2871, - "5464-locale-compare-fractions.ts": 3156, + "5430-dyn-number-string-boxes.ts": 3059, + "5435-crypto-hash-algorithms.ts": 2030, + "5436-crypto-hash-names.js": 2098, + "5437-crypto-hmac-algorithms.ts": 2699, + "5438-crypto-kdf-digests.ts": 2741, + "5439-crypto-kdf-callbacks.js": 2685, + "5440-crypto-hash-encodings.js": 4004, + "5441-crypto-hash-output-length.ts": 3671, + "5442-crypto-random-values.ts": 3947, + "5443-crypto-random-arguments.js": 3548, + "5444-crypto-timing-safe-equal.js": 3213, + "5445-crypto-secret-key-objects.ts": 3869, + "5445-stream-buffer-chunks.ts": 2881, + "5446-crypto-secret-key-errors.js": 3035, + "5446-stream-buffer-chunks-dynamic.js": 2859, + "5447-fs-readdir-order.ts": 2639, + "5448-fs-glob-patterns.ts": 2837, + "5449-fs-glob-options.ts": 3025, + "5450-fs-glob-validation.js": 3327, + "5451-fs-promises-glob.ts": 3059, + "5452-fs-glob-callback.ts": 2936, + "5455-power-of-two-remainder.ts": 2837, + "5456-remainder-large-integer-dividends.ts": 2786, + "5457-lcg-modulus.ts": 1426, + "5458-fractional-remainder.ts": 1394, + "5460-locale-compare-contractions.ts": 2979, + "5461-locale-compare-equivalents.ts": 2661, + "5462-locale-compare-probe-sweep.ts": 3400, + "5463-locale-compare-combining-letters.ts": 2733, + "5464-locale-compare-fractions.ts": 2833, "5465-dyn-index-read-arrays.ts": 3603, "5466-dyn-index-read-special.ts": 2823, - "5470-strip-vt-osc.cjs": 2872, - "5471-strip-vt-csi.cjs": 2359, - "5472-strip-vt-random.cjs": 3265, - "5473-strip-vt-unterminated.cjs": 3751, - "5474-strip-vt-surrogates.ts": 2805, + "5470-strip-vt-osc.cjs": 2497, + "5471-strip-vt-csi.cjs": 2651, + "5472-strip-vt-random.cjs": 2375, + "5473-strip-vt-unterminated.cjs": 3521, + "5474-strip-vt-surrogates.ts": 2534, "5510-assert-error-properties.js": 2744, "5511-assert-error-class.ts": 3998, "5512-assert-error-options.js": 3572, @@ -1911,20 +1911,20 @@ "5530-buffer-pool.ts": 3788, "5531-buffer-pool-first-slab.ts": 5451, "5532-buffer-pool-first-slab-untyped.mjs": 37592, - "5540-fs-callback-forms.cjs": 3863, - "5541-fs-stats-fields.cjs": 4344, - "5542-fs-promises-parity.cjs": 2640, - "5543-fs-promises-typed.ts": 3538, - "5544-fs-opendir.cjs": 3175, - "5545-fs-options-encoding.cjs": 3831, + "5540-fs-callback-forms.cjs": 3233, + "5541-fs-stats-fields.cjs": 3564, + "5542-fs-promises-parity.cjs": 3940, + "5543-fs-promises-typed.ts": 1655, + "5544-fs-opendir.cjs": 3024, + "5545-fs-options-encoding.cjs": 2994, "5546-fs-read-stream.cjs": 3808, "5547-fs-write-stream.cjs": 5798, - "5548-fs-callback-arguments.cjs": 4728, - "5549-fs-callback-option-checks.cjs": 4270, - "5550-locale-compare-ascii-words.ts": 2457, - "5551-array-search-references.ts": 2240, - "5552-string-appends.ts": 3367, - "5553-string-append-char-code.ts": 2628, + "5548-fs-callback-arguments.cjs": 4041, + "5549-fs-callback-option-checks.cjs": 3738, + "5550-locale-compare-ascii-words.ts": 2509, + "5551-array-search-references.ts": 3475, + "5552-string-appends.ts": 2703, + "5553-string-append-char-code.ts": 2870, "5554-fs-streams-typed.ts": 4016, "5555-fs-callback-turns.cjs": 3136, "5555-http-server-close-keep-alive.ts": 6777, @@ -1937,15 +1937,15 @@ "5562-https-verify-errors.ts": 3646, "5563-http-keep-alive-timeout.ts": 11895, "5564-http-request-signal.ts": 4124, - "5565-fs-dirent-untyped.mjs": 2565, - "5566-fs-dirent-dyn-boundaries/main.mjs": 3508, + "5565-fs-dirent-untyped.mjs": 2600, + "5566-fs-dirent-dyn-boundaries/main.mjs": 2607, "5567-fs-cpsync.ts": 3736, "5568-fs-cp-errors.js": 4246, "5569-fs-cp-symlinks.ts": 2136, "5570-fs-cp-async.ts": 3348, "5571-fs-cp-deep.ts": 4817, - "5585-record-results-inlined.ts": 3419, - "5595-net-ref-unref.ts": 3245, + "5585-record-results-inlined.ts": 2922, + "5595-net-ref-unref.ts": 2593, "5600-dyn-cycle-self.ts": 2318, "5601-dyn-cycle-mutual.ts": 2455, "5602-dyn-cycle-arrays.ts": 3115, @@ -1970,19 +1970,19 @@ "5624-timers-promises-unawaited.ts": 2304, "5625-promisify-exec.ts": 7463, "5626-promisify-forms.ts": 2936, - "5627-exec-callback.ts": 2909, + "5627-exec-callback.ts": 1900, "5628-promisify-timers.ts": 3194, "5629-promisify-stream.ts": 2517, "5630-promisify-zlib.ts": 2503, - "5631-promisify-crypto.ts": 4296, - "5632-promisify-dns.ts": 2784, - "5644-net-socket-addresses.ts": 2435, - "5645-net-socket-callbacks.ts": 2678, - "5646-net-server-connections.ts": 3279, - "5647-net-is-ip.ts": 2496, - "5648-dns-lookup-forms.ts": 2735, - "5649-dns-service-servers.ts": 3175, - "5650-dns-lookup-errors-untyped.cjs": 1968, + "5631-promisify-crypto.ts": 2200, + "5632-promisify-dns.ts": 1700, + "5644-net-socket-addresses.ts": 2220, + "5645-net-socket-callbacks.ts": 2442, + "5646-net-server-connections.ts": 2389, + "5647-net-is-ip.ts": 2776, + "5648-dns-lookup-forms.ts": 2992, + "5649-dns-service-servers.ts": 2712, + "5650-dns-lookup-errors-untyped.cjs": 2822, "5651-tls-socket-protocol.ts": 2771, "5652-http-client-trailer-overflow.ts": 3884, "5653-net-socket-read-ahead.ts": 4524, @@ -1995,7 +1995,7 @@ "5664-tls-client-identity.ts": 3727, "5674-union-instanceof-array-arms.ts": 2159, "5680-array-growth-after-copy.ts": 3791, - "5681-array-pop-and-length.ts": 2915, + "5681-array-pop-and-length.ts": 3754, "5682-publish-wide-objects.ts": 3326, "5700-cycle-release-retained.ts": 2156, "5701-cycle-release-old-edges.ts": 2601, @@ -2060,39 +2060,39 @@ "5795-worker-message-port-batches.ts": 1925, "5796-worker-message-channel.cjs": 2678, "5797-worker-message-port-transfer.ts": 3445, - "5800-broadcast-channel.ts": 3609, - "5801-broadcast-channel.cjs": 3080, - "5802-broadcast-channel-workers.ts": 2610, - "5803-worker-environment-data.ts": 3416, - "5804-worker-environment-data.cjs": 2230, - "5805-worker-receive-message-parent-port.ts": 3538, - "5806-worker-resource-limits.ts": 2813, - "5807-worker-error-values.ts": 4237, - "5808-worker-unhandled-rejections.ts": 4239, - "5809-process-exit-and-rejections.cjs": 3639, - "5810-mock-method-records.ts": 3521, - "5811-mock-tracker-restore.ts": 2838, - "5812-dyn-box-async-fields.ts": 3501, - "5813-mock-timers-module.ts": 3107, - "5814-mock-timers-date.ts": 2412, + "5800-broadcast-channel.ts": 2899, + "5801-broadcast-channel.cjs": 2727, + "5802-broadcast-channel-workers.ts": 2809, + "5803-worker-environment-data.ts": 2748, + "5804-worker-environment-data.cjs": 2469, + "5805-worker-receive-message-parent-port.ts": 2839, + "5806-worker-resource-limits.ts": 3153, + "5807-worker-error-values.ts": 3304, + "5808-worker-unhandled-rejections.ts": 3430, + "5809-process-exit-and-rejections.cjs": 3294, + "5810-mock-method-records.ts": 3976, + "5811-mock-tracker-restore.ts": 3698, + "5812-dyn-box-async-fields.ts": 3522, + "5813-mock-timers-module.ts": 3766, + "5814-mock-timers-date.ts": 3760, "5830-timers-promises-signal.ts": 3875, - "5831-util-types-brands.ts": 4018, - "5832-util-types-brands-dynamic.js": 3859, - "5833-url-search-params-iterators.ts": 2320, - "5834-url-search-params-iterators-dynamic.mjs": 3863, - "5835-util-format-integer-specifiers.ts": 2838, - "5836-url-search-params-tuple-pairs.ts": 3097, - "5837-util-format-json-circular.ts": 2711, - "5838-qs-stringify-bigint.ts": 3073, + "5831-util-types-brands.ts": 3347, + "5832-util-types-brands-dynamic.js": 3250, + "5833-url-search-params-iterators.ts": 2678, + "5834-url-search-params-iterators-dynamic.mjs": 2696, + "5835-util-format-integer-specifiers.ts": 2534, + "5836-url-search-params-tuple-pairs.ts": 2118, + "5837-util-format-json-circular.ts": 3117, + "5838-qs-stringify-bigint.ts": 2207, "5839-timers-promises-scheduler.ts": 3195, "5840-promise-with-resolvers-js.js": 2842, - "5841-json-typed-dyn-members.ts": 3759, - "5842-qs-parse-null-prototype.ts": 3419, - "5843-qs-parse-null-prototype-js.mjs": 2453, - "5844-date-unknown-values.ts": 3400, + "5841-json-typed-dyn-members.ts": 5467, + "5842-qs-parse-null-prototype.ts": 1774, + "5843-qs-parse-null-prototype-js.mjs": 1559, + "5844-date-unknown-values.ts": 3969, "5845-groupby-null-prototype.ts": 2868, - "5846-events-esm-default-max.ts": 2670, - "5847-events-cjs-default-max.cjs": 2274, + "5846-events-esm-default-max.ts": 2633, + "5847-events-cjs-default-max.cjs": 2823, "5849-class-view-observations.ts": 3073, "5850-using-disposable-values.ts": 3391, "5851-using-suppressed-error-values.ts": 2932, @@ -2101,45 +2101,45 @@ "5854-array-from-async.ts": 4140, "5855-array-from-async-js.js": 3324, "5856-error-is-error.ts": 2937, - "5857-regexp-unicode-sets.ts": 2520, - "5858-disposable-stack.ts": 4398, - "5859-disposable-stack-js.js": 3669, + "5857-regexp-unicode-sets.ts": 3350, + "5858-disposable-stack.ts": 3050, + "5859-disposable-stack-js.js": 3100, "5860-url-ipv4-hosts.ts": 3101, - "5870-worker-thread-names.ts": 3899, - "5871-worker-untransferable.cjs": 3409, + "5870-worker-thread-names.ts": 3106, + "5871-worker-untransferable.cjs": 2786, "5872-readline-positional-create-interface.mjs": 3151, "5873-readline-promises-namespace.cjs": 2023, - "5874-worker-stdio-streams.ts": 3395, - "5875-worker-stdout-pipe.cjs": 3257, - "5879-worker-stdin.ts": 3922, + "5874-worker-stdio-streams.ts": 2839, + "5875-worker-stdout-pipe.cjs": 2740, + "5879-worker-stdin.ts": 3158, "5880-emitter-leak-warning-delivery.ts": 3418, - "5881-inspect-weak-collections.ts": 2457, - "5882-string-decoder-runtime-encoding.ts": 2823, - "5883-os-set-priority.ts": 2720, - "5884-inspect-layout-options.ts": 3781, + "5881-inspect-weak-collections.ts": 2615, + "5882-string-decoder-runtime-encoding.ts": 2541, + "5883-os-set-priority.ts": 2380, + "5884-inspect-layout-options.ts": 3108, "5885-events-max-listener-helpers.ts": 2992, - "5886-inspect-dates.ts": 3072, - "5887-inspect-typed-arrays.ts": 2960, - "5888-inspect-sorted.ts": 3397, + "5886-inspect-dates.ts": 2559, + "5887-inspect-typed-arrays.ts": 3448, + "5888-inspect-sorted.ts": 2998, "5889-timers-scheduler-signal.ts": 2284, "5890-while-string-length-counters.ts": 2516, "5892-buffer-write-utf16le-runs.ts": 3107, - "5900-float16-array.ts": 3631, - "5901-float16-array-js.js": 3789, - "5904-async-generator-completion.ts": 5745, - "5905-array-from-async-generator.ts": 3532, - "5906-array-from-async-generator-js.js": 3910, - "5907-regex-groups-match-rows.ts": 4071, - "5910-set-prototype-of-primitive-object-kinds.ts": 3248, - "5911-dyn-class-to-primitive.ts": 6701, - "5912-dyn-class-conversion-methods.ts": 4374, - "5913-prototype-type-error-messages.ts": 3102, - "5914-dyn-in-class-prototype-members.ts": 2530, - "5915-dyn-error-string-conversions.ts": 3023, + "5900-float16-array.ts": 3000, + "5901-float16-array-js.js": 2900, + "5904-async-generator-completion.ts": 2950, + "5905-array-from-async-generator.ts": 2750, + "5906-array-from-async-generator-js.js": 2950, + "5907-regex-groups-match-rows.ts": 3150, + "5910-set-prototype-of-primitive-object-kinds.ts": 2719, + "5911-dyn-class-to-primitive.ts": 2850, + "5912-dyn-class-conversion-methods.ts": 3251, + "5913-prototype-type-error-messages.ts": 2484, + "5914-dyn-in-class-prototype-members.ts": 3169, + "5915-dyn-error-string-conversions.ts": 3200, "5920-promise-try-args.ts": 3028, "5921-promise-try-args-js.js": 3179, - "5922-matchall-groups-callbacks.ts": 4418, - "5923-matchall-groups-js.js": 3161, + "5922-matchall-groups-callbacks.ts": 3650, + "5923-matchall-groups-js.js": 3970, "5924-js-literal-identity.js": 2577, "5925-class-view-identity-observers.ts": 2297, "5926-class-view-switch-js.js": 2243, @@ -2155,2564 +2155,2567 @@ "5935-js-subclass-fields-and-element-calls.js": 2484, "5936-checked-js-class-types.js": 3412, "5937-override-narrowed-union-returns.ts": 3036, - "5938-object-literal-computed-keys-keep-methods.ts": 3273, - "5939-js-let-object-reassigned-wider.js": 1819, + "5938-object-literal-computed-keys-keep-methods.ts": 3195, + "5939-js-let-object-reassigned-wider.js": 1945, "5940-callback-helper-specialization.ts": 3109, "5941-callback-specialization-recursion.ts": 3112, "5942-callback-specialization-throws.ts": 3221, - "5945-local-class-observed-methods.ts": 2284, - "5946-nested-record-field-optional-writes.ts": 2987, - "5950-tuple-predicate-methods.ts": 4611, - "5951-result-never-widening.ts": 2943, - "5952-record-missing-keys.ts": 2332, - "5953-nan-coded-method-returns.ts": 2799, - "5955-any-promise-methods.js": 3148, - "5956-erased-generic-members.ts": 4927, - "5958-asserted-union-receiver.ts": 2198, - "5959-date-to-json.ts": 3051, + "5943-fields-read-before-assignment.ts": 6856, + "5944-js-fields-read-before-assignment.js": 4247, + "5945-local-class-observed-methods.ts": 5063, + "5946-nested-record-field-optional-writes.ts": 6045, + "5950-tuple-predicate-methods.ts": 5990, + "5951-result-never-widening.ts": 4710, + "5952-record-missing-keys.ts": 6090, + "5953-nan-coded-method-returns.ts": 4100, + "5955-any-promise-methods.js": 3940, + "5956-erased-generic-members.ts": 6730, + "5958-asserted-union-receiver.ts": 2430, + "5959-date-to-json.ts": 3330, "5960-frame-records-own-references.ts": 3563, - "5960-generic-mapped-types.ts": 2996, + "5960-generic-mapped-types.ts": 2540, "5961-frame-spread-updates.ts": 3260, "5962-frame-tuples.ts": 3208, - "5970-net-connect-host-name.ts": 1747, - "5971-buffer-chunks-to-string.ts": 3079, - "5972-net-set-encoding-listeners.ts": 3253, + "5970-net-connect-host-name.ts": 2400, + "5971-buffer-chunks-to-string.ts": 2700, + "5972-net-set-encoding-listeners.ts": 2550, "5973-large-closure-environment.ts": 4499, - "5974-typeof-module-exports.cjs": 2558, - "5975-zlib-class-values.ts": 2531, - "5990-worker-uncloneable.mjs": 3772, - "5991-worker-async-dispose.mjs": 4075, - "5992-worker-thread-name-lifetime.mjs": 3241, + "5974-typeof-module-exports.cjs": 2000, + "5975-zlib-class-values.ts": 2800, + "5990-worker-uncloneable.mjs": 3283, + "5991-worker-async-dispose.mjs": 5699, + "5992-worker-thread-name-lifetime.mjs": 2687, "5993-array-length-loop-resizing.ts": 3187, "5994-array-length-sparse-loops.ts": 3292, "5995-array-dense-loop-boundaries.ts": 2596, - "600-closures-basic.ts": 2093, - "601-closures-loops.ts": 2964, - "602-closures-identity-recursion.ts": 2859, - "6020-class-extends-function-constructor.js": 3170, - "6021-asserted-literal-union-arm.ts": 3166, - "603-closures-rc-stress.ts": 2756, - "604-closures-for-of.ts": 2963, + "5996-rejections-between-macrotasks.cjs": 3034, + "600-closures-basic.ts": 2349, + "601-closures-loops.ts": 1788, + "602-closures-identity-recursion.ts": 2372, + "6020-class-extends-function-constructor.js": 4300, + "6021-asserted-literal-union-arm.ts": 3400, + "603-closures-rc-stress.ts": 1832, + "604-closures-for-of.ts": 2639, "6041-error-cause-redeclared.ts": 2988, "6042-regex-match-object-destructuring.ts": 3393, "6043-string-index-narrowed-union.ts": 2983, - "605-closures-forward-capture-tdz.ts": 2902, + "605-closures-forward-capture-tdz.ts": 3277, "6140-cjs-require-tdz-throws/main.js": 2731, "6141-cjs-require-tdz-checked/main.js": 2856, "6142-cjs-require-published-early/main.js": 3400, "6143-cjs-require-json/main.js": 3245, "6144-cjs-require-builtin-nested/main.js": 2181, "6145-cjs-require-cycle/main.js": 3507, - "700-classes-basic.ts": 2476, - "701-classes-composition.ts": 2819, - "702-classes-this-capture.ts": 2834, - "703-classes-rc-stress.ts": 2484, - "710-inheritance-basics.ts": 2629, - "711-inheritance-dispatch.ts": 2199, - "712-inheritance-instanceof.ts": 2914, - "713-inheritance-rc-stress.ts": 2307, - "720-accessors-basics.ts": 2496, - "721-accessors-eval-order.ts": 3007, - "722-accessors-inheritance.ts": 2266, - "723-accessors-rc-stress.ts": 2951, - "750-cycle-closure-box.ts": 2797, - "751-cycle-records-mutual.ts": 2867, - "752-cycle-classes.ts": 2668, - "753-cycle-owned-arrays.ts": 2613, - "754-cycle-external-ref.ts": 2566, - "755-cycle-async-promise.ts": 2707, - "756-cycle-inheritance.ts": 2258, - "757-cycle-cross-generation.ts": 3080, - "762-any-boundary.ts": 3283, - "764-any-async.ts": 2876, - "765-any-optional-chain.ts": 3213, - "766-any-union-boundary.ts": 3515, - "767-string-literal-keys.ts": 2750, - "768-any-uninitialized.ts": 2902, - "800-switch-basics.ts": 2776, - "801-switch-lazy-tests.ts": 2159, - "802-switch-loops.ts": 2543, - "803-switch-rc-stress.ts": 3003, - "804-switch-braced-blocks.ts": 2593, - "810-do-while.ts": 2089, - "820-multi-decl.ts": 2503, - "830-let-uninitialized.ts": 2817, - "900-records-basics.ts": 2340, - "901-records-eval-order.ts": 2257, - "902-records-functions-closures.ts": 2757, - "903-records-rc-stress.ts": 2938, - "904-records-optional-fields.ts": 2935, - "905-records-optional-rc-stress.ts": 2626, - "906-records-utility-types.ts": 2717, - "907-records-utility-generics.ts": 2997, - "908-records-index-signatures.ts": 3162, - "909-records-index-json.ts": 3408, - "910-records-index-rc-stress.ts": 2486, - "911-records-index-dot-access.ts": 3533, - "912-unknown-slots.ts": 2761, - "913-records-index-iteration.ts": 3662, - "914-records-from-entries.ts": 3551, - "915-unknown-tostring-eq.ts": 3814, - "916-unknown-bytes.ts": 2926, - "917-record-array-index-dot.ts": 2493, - "950-modules-basic/main.ts": 2549, - "951-modules-diamond/main.ts": 2015, - "952-modules-cross/main.ts": 2203, - "953-modules-default/main.ts": 2058, - "954-modules-reexport/main.ts": 2223, - "957-builtins-namespace.ts": 2583, - "960-generics-basics.ts": 2371, - "961-generics-recursion.ts": 2698, - "962-generics-closures.ts": 2945, - "963-generics-modules/main.ts": 1815, - "964-generics-rc-stress.ts": 3183, - "965-generics-async.ts": 3138, - "965-unions-retag.ts": 2552, - "966-unions-retag-rc-stress.ts": 2838, - "967-record-field-widening.ts": 3366, - "969-unions-arm-matrix.ts": 2362, - "970-unions-basics.ts": 2298, - "971-unions-switch.ts": 2850, - "972-unions-nested.ts": 2374, - "973-unions-rc-stress.ts": 1915, - "974-unions-modules/main.ts": 2639, - "975-unions-undefined.ts": 2297, - "976-unions-null.ts": 1941, - "977-unions-unit-rc-stress.ts": 2513, - "978-unions-nullish.ts": 3070, - "979-unions-optional-chaining.ts": 3263, - "980-exceptions-basics.ts": 2631, - "981-exceptions-values.ts": 2273, - "982-exceptions-rc-stress.ts": 2398, - "983-exceptions-control-flow.ts": 2350, - "984-exceptions-finally.ts": 2928, - "985-exceptions-call-chains.ts": 2642, - "986-exceptions-uncaught.ts": 2072, - "987-exceptions-result-unions.ts": 2255, - "990-process-basics.ts": 2565, - "991-process-exit.ts": 1649, - "992-fs-roundtrip.ts": 2134, - "993-fs-readdir.ts": 2805, - "994-fs-errors.ts": 1790, - "995-fs-uncaught.ts": 2295, - "996-fs-rc-stress.ts": 3230, - "997-fs-modules/main.ts": 2893, - "998-process-env.ts": 1803, - "abstract-property-dispatch.ts": 3619, - "arguments-arrow-capture.mjs": 2943, - "arguments-reexport/main.ts": 2123, - "array-argument-lifetimes-exits.ts": 3367, - "array-argument-lifetimes-mutation.ts": 2372, - "array-argument-lifetimes-strings.ts": 2429, - "array-argument-lifetimes-values.ts": 3148, - "array-buffer-conversions.js": 2274, - "array-buffer-storage.ts": 2433, - "array-checked-callback-results.mjs": 2526, - "array-checked-constructor.js": 3336, - "array-concat-widening.ts": 1977, + "700-classes-basic.ts": 2530, + "701-classes-composition.ts": 2357, + "702-classes-this-capture.ts": 2140, + "703-classes-rc-stress.ts": 2186, + "710-inheritance-basics.ts": 2728, + "711-inheritance-dispatch.ts": 2360, + "712-inheritance-instanceof.ts": 2715, + "713-inheritance-rc-stress.ts": 2448, + "720-accessors-basics.ts": 2562, + "721-accessors-eval-order.ts": 2406, + "722-accessors-inheritance.ts": 2543, + "723-accessors-rc-stress.ts": 2054, + "750-cycle-closure-box.ts": 2227, + "751-cycle-records-mutual.ts": 2118, + "752-cycle-classes.ts": 2207, + "753-cycle-owned-arrays.ts": 2148, + "754-cycle-external-ref.ts": 2118, + "755-cycle-async-promise.ts": 2303, + "756-cycle-inheritance.ts": 2162, + "757-cycle-cross-generation.ts": 2893, + "762-any-boundary.ts": 2310, + "764-any-async.ts": 2553, + "765-any-optional-chain.ts": 2593, + "766-any-union-boundary.ts": 3292, + "767-string-literal-keys.ts": 2238, + "768-any-uninitialized.ts": 2264, + "800-switch-basics.ts": 2244, + "801-switch-lazy-tests.ts": 2610, + "802-switch-loops.ts": 2329, + "803-switch-rc-stress.ts": 2314, + "804-switch-braced-blocks.ts": 2594, + "810-do-while.ts": 2658, + "820-multi-decl.ts": 2315, + "830-let-uninitialized.ts": 2519, + "900-records-basics.ts": 2736, + "901-records-eval-order.ts": 2544, + "902-records-functions-closures.ts": 2645, + "903-records-rc-stress.ts": 2871, + "904-records-optional-fields.ts": 1801, + "905-records-optional-rc-stress.ts": 2425, + "906-records-utility-types.ts": 2878, + "907-records-utility-generics.ts": 2738, + "908-records-index-signatures.ts": 2545, + "909-records-index-json.ts": 2019, + "910-records-index-rc-stress.ts": 1878, + "911-records-index-dot-access.ts": 3510, + "912-unknown-slots.ts": 2427, + "913-records-index-iteration.ts": 3462, + "914-records-from-entries.ts": 3129, + "915-unknown-tostring-eq.ts": 3072, + "916-unknown-bytes.ts": 2767, + "917-record-array-index-dot.ts": 2445, + "950-modules-basic/main.ts": 2473, + "951-modules-diamond/main.ts": 1969, + "952-modules-cross/main.ts": 2427, + "953-modules-default/main.ts": 2409, + "954-modules-reexport/main.ts": 2586, + "957-builtins-namespace.ts": 2102, + "960-generics-basics.ts": 2487, + "961-generics-recursion.ts": 2589, + "962-generics-closures.ts": 2098, + "963-generics-modules/main.ts": 2726, + "964-generics-rc-stress.ts": 2825, + "965-generics-async.ts": 2802, + "965-unions-retag.ts": 2772, + "966-unions-retag-rc-stress.ts": 2336, + "967-record-field-widening.ts": 2097, + "969-unions-arm-matrix.ts": 2419, + "970-unions-basics.ts": 2692, + "971-unions-switch.ts": 2491, + "972-unions-nested.ts": 3069, + "973-unions-rc-stress.ts": 2478, + "974-unions-modules/main.ts": 2052, + "975-unions-undefined.ts": 2811, + "976-unions-null.ts": 2344, + "977-unions-unit-rc-stress.ts": 2013, + "978-unions-nullish.ts": 2330, + "979-unions-optional-chaining.ts": 2341, + "980-exceptions-basics.ts": 1988, + "981-exceptions-values.ts": 2615, + "982-exceptions-rc-stress.ts": 2259, + "983-exceptions-control-flow.ts": 2004, + "984-exceptions-finally.ts": 2140, + "985-exceptions-call-chains.ts": 2787, + "986-exceptions-uncaught.ts": 2529, + "987-exceptions-result-unions.ts": 2390, + "990-process-basics.ts": 2623, + "991-process-exit.ts": 2155, + "992-fs-roundtrip.ts": 2680, + "993-fs-readdir.ts": 2781, + "994-fs-errors.ts": 2322, + "995-fs-uncaught.ts": 2134, + "996-fs-rc-stress.ts": 2214, + "997-fs-modules/main.ts": 2230, + "998-process-env.ts": 2196, + "abstract-property-dispatch.ts": 2956, + "arguments-arrow-capture.mjs": 2802, + "arguments-reexport/main.ts": 2655, + "array-argument-lifetimes-exits.ts": 2164, + "array-argument-lifetimes-mutation.ts": 2547, + "array-argument-lifetimes-strings.ts": 2738, + "array-argument-lifetimes-values.ts": 3081, + "array-buffer-conversions.js": 1978, + "array-buffer-storage.ts": 3147, + "array-checked-callback-results.mjs": 3053, + "array-checked-constructor.js": 3001, + "array-concat-widening.ts": 2947, "array-deque-unshift.ts": 3233, - "array-element-compound-updates.ts": 3547, - "array-fill-unit-values.ts": 2929, - "array-from-checked.js": 3397, - "array-from-value.mjs": 3059, - "array-isarray-value/main.js": 2918, - "array-numeric-own-keys.ts": 2790, - "array-optional-number-write-index.ts": 2704, - "array-primitive-ordering.ts": 4576, + "array-element-compound-updates.ts": 3325, + "array-fill-unit-values.ts": 2281, + "array-from-checked.js": 3228, + "array-from-value.mjs": 2658, + "array-isarray-value/main.js": 2180, + "array-numeric-own-keys.ts": 2770, + "array-optional-number-write-index.ts": 2584, + "array-primitive-ordering.ts": 3806, "array-queue-head-room.ts": 2847, - "array-read-helper-effects.ts": 3311, - "array-refined-storage.ts": 2961, - "array-sort-dense-effects.ts": 4064, - "array-sort-dense-values.ts": 4011, - "array-sort-holes-published.ts": 7513, - "array-sort-runs.ts": 5700, - "array-sort-runtime-comparator.ts": 4830, - "array-sort-unknown-comparator.ts": 3102, - "array-storage-transitions.ts": 3965, - "array-truncate-reuse.ts": 3475, - "async-backend-factory.mjs": 2766, - "async-local-typed-results.ts": 3471, - "atomics-integer-operations.ts": 3518, - "bigint-checked-casts.ts": 3182, - "bigint-checked-storage.js": 3679, - "bigint-union-conversion.ts": 2403, - "boxed-error-rethrows.mjs": 2704, - "buffer-codec-boundaries.ts": 3023, - "buffer-primitive-predicate.ts": 2153, - "builtin-prototype-method-values.mjs": 2713, - "byte-loop-bounds.ts": 3126, - "byte-number-pipeline.ts": 3555, - "byte-record-windows.ts": 3164, - "call-lifetimes-argument-order.ts": 3386, - "call-lifetimes-control-flow.ts": 2774, - "call-lifetimes-owned-boundaries.ts": 2902, - "call-lifetimes-projections.ts": 2603, - "call-lifetimes-union-values.ts": 3045, - "call-lifetimes-virtual-optionals.ts": 2344, - "callable-module-members.mjs": 2928, - "callable-properties.mjs": 2765, - "callable-property-cycles.js": 1847, - "callable-reexport/main.ts": 2222, - "captured-class-refinement.ts": 3000, - "catch-capture.ts": 3112, - "caught-class-identity.ts": 3640, - "caught-standalone-class.ts": 3171, - "caught-system-error-fields.ts": 3152, - "checked-addition.js": 2684, - "checked-any-addition.ts": 2642, - "checked-array-assignment.ts": 2697, - "checked-array-flat/main.ts": 2840, - "checked-bitwise/main.js": 2581, - "checked-builder-cycles.js": 2948, - "checked-byte-storage/main.ts": 2611, - "checked-callback-options.ts": 1643, - "checked-class-descriptors.mjs": 3640, - "checked-class-factory.mjs": 2778, - "checked-collection-iterators.ts": 3241, - "checked-collection-symbol-methods.ts": 2293, - "checked-dispatch-input-lifetimes.js": 2742, - "checked-increment/main.js": 2072, - "checked-inherited-fields.ts": 3028, - "checked-iterator-consumption.js": 3107, - "checked-numeric-arithmetic.js": 2378, - "checked-object-module-alias.js": 2947, - "checked-optional-calls.mjs": 3142, - "checked-promise-recovery.ts": 2855, - "checked-proxy-callback/main.ts": 1847, - "checked-record-constructor.ts": 2481, - "checked-renderer-defaults.js": 2013, - "checked-rest-function-adapters.js": 3046, - "checked-storage-transitions.js": 2689, - "checked-symbol-array.ts": 2459, - "checked-value-input-lifetimes.ts": 3335, - "class-accessor-returned-function.js": 2629, - "class-array-optional-return.ts": 2795, - "class-bracket-method-calls.js": 3486, - "class-brand-overload.js": 2784, - "class-callback-replacement.js": 2660, - "class-callback-storage.ts": 3042, - "class-checked-composites.ts": 3335, - "class-checked-upcast.ts": 3076, - "class-collection-insertion.ts": 2281, - "class-computed-presence.ts": 3266, - "class-computed-symbols.js": 2803, - "class-covariant-returns.ts": 3398, - "class-curried-factory.mjs": 3626, - "class-data-descriptors.js": 3529, - "class-factory-inherited-statics.mjs": 3667, - "class-factory-parameter-base.mjs": 2767, - "class-factory-record-base.mjs": 3407, - "class-factory-recursive-statics.mjs": 3184, - "class-factory-static-members.mjs": 3515, - "class-function-base/main.js": 3746, - "class-instance-constructor.js": 3651, - "class-interface-protocols.ts": 5020, - "class-interface-refinements.ts": 2194, - "class-json-checked.ts": 1821, - "class-local-function-base.mjs": 3398, - "class-method-spreads.ts": 3880, - "class-narrowed-views.ts": 3116, - "class-property-call-values.mjs": 3490, - "class-prototype-data.js": 3512, - "class-prototype-descriptor-copy.mjs": 4571, - "class-specialized-computed-base.mjs": 3883, - "class-static-data.js": 2886, - "class-subclass-assertions.ts": 3020, - "class-super-surplus-spread.mjs": 2209, - "class-symbol-accessors.ts": 2490, - "class-symbol-cache.mjs": 2911, - "class-value-constructor-exceptions.ts": 2697, + "array-read-helper-effects.ts": 3223, + "array-refined-storage.ts": 3132, + "array-sort-dense-effects.ts": 2813, + "array-sort-dense-values.ts": 3705, + "array-sort-holes-published.ts": 6604, + "array-sort-runs.ts": 5713, + "array-sort-runtime-comparator.ts": 5050, + "array-sort-unknown-comparator.ts": 1888, + "array-storage-transitions.ts": 3122, + "array-truncate-reuse.ts": 2475, + "async-backend-factory.mjs": 2638, + "async-local-typed-results.ts": 2579, + "atomics-integer-operations.ts": 3320, + "bigint-checked-casts.ts": 2572, + "bigint-checked-storage.js": 3519, + "bigint-union-conversion.ts": 2774, + "boxed-error-rethrows.mjs": 2034, + "buffer-codec-boundaries.ts": 3206, + "buffer-primitive-predicate.ts": 2712, + "builtin-prototype-method-values.mjs": 3158, + "byte-loop-bounds.ts": 2922, + "byte-number-pipeline.ts": 2738, + "byte-record-windows.ts": 2668, + "call-lifetimes-argument-order.ts": 1933, + "call-lifetimes-control-flow.ts": 2653, + "call-lifetimes-owned-boundaries.ts": 2979, + "call-lifetimes-projections.ts": 3011, + "call-lifetimes-union-values.ts": 2366, + "call-lifetimes-virtual-optionals.ts": 2747, + "callable-module-members.mjs": 2647, + "callable-properties.mjs": 3266, + "callable-property-cycles.js": 2241, + "callable-reexport/main.ts": 2809, + "captured-class-refinement.ts": 2580, + "catch-capture.ts": 2050, + "caught-class-identity.ts": 3173, + "caught-standalone-class.ts": 2858, + "caught-system-error-fields.ts": 2612, + "checked-addition.js": 2460, + "checked-any-addition.ts": 2551, + "checked-array-assignment.ts": 2273, + "checked-array-flat/main.ts": 2256, + "checked-bitwise/main.js": 2560, + "checked-builder-cycles.js": 3055, + "checked-byte-storage/main.ts": 3171, + "checked-callback-options.ts": 2385, + "checked-class-descriptors.mjs": 3021, + "checked-class-factory.mjs": 2266, + "checked-collection-iterators.ts": 2906, + "checked-collection-symbol-methods.ts": 2575, + "checked-dispatch-input-lifetimes.js": 3038, + "checked-increment/main.js": 2332, + "checked-inherited-fields.ts": 2382, + "checked-iterator-consumption.js": 3603, + "checked-numeric-arithmetic.js": 2783, + "checked-object-module-alias.js": 2898, + "checked-optional-calls.mjs": 2763, + "checked-promise-recovery.ts": 2689, + "checked-proxy-callback/main.ts": 2754, + "checked-record-constructor.ts": 2506, + "checked-renderer-defaults.js": 2308, + "checked-rest-function-adapters.js": 2312, + "checked-storage-transitions.js": 2557, + "checked-symbol-array.ts": 1859, + "checked-value-input-lifetimes.ts": 2728, + "class-accessor-returned-function.js": 2068, + "class-array-optional-return.ts": 2589, + "class-bracket-method-calls.js": 2833, + "class-brand-overload.js": 2700, + "class-callback-replacement.js": 3640, + "class-callback-storage.ts": 3803, + "class-checked-composites.ts": 2846, + "class-checked-upcast.ts": 2625, + "class-collection-insertion.ts": 3901, + "class-computed-presence.ts": 3018, + "class-computed-symbols.js": 3495, + "class-covariant-returns.ts": 3069, + "class-curried-factory.mjs": 3062, + "class-data-descriptors.js": 3732, + "class-factory-inherited-statics.mjs": 2710, + "class-factory-parameter-base.mjs": 2492, + "class-factory-record-base.mjs": 4680, + "class-factory-recursive-statics.mjs": 2820, + "class-factory-static-members.mjs": 2990, + "class-function-base/main.js": 2706, + "class-instance-constructor.js": 2628, + "class-interface-protocols.ts": 3911, + "class-interface-refinements.ts": 2967, + "class-json-checked.ts": 2638, + "class-local-function-base.mjs": 2970, + "class-method-spreads.ts": 3142, + "class-narrowed-views.ts": 2862, + "class-property-call-values.mjs": 3343, + "class-prototype-data.js": 3393, + "class-prototype-descriptor-copy.mjs": 3870, + "class-specialized-computed-base.mjs": 3439, + "class-static-data.js": 2153, + "class-subclass-assertions.ts": 2814, + "class-super-surplus-spread.mjs": 2024, + "class-symbol-accessors.ts": 2458, + "class-symbol-cache.mjs": 2883, + "class-value-constructor-exceptions.ts": 2222, "closed-virtual-dispatch-modules/main.ts": 2682, "closed-virtual-dispatch.ts": 3944, - "closure-nullable-union-return.ts": 3308, - "closure-union-locals.ts": 3570, - "collection-array-cycles.ts": 2714, - "collection-array-maps.ts": 3451, - "collection-array-missing.ts": 3109, - "collection-array-sets.ts": 2862, - "collection-copy-identities.ts": 3119, - "collection-data-unions.ts": 3087, - "collection-ingestion-mappers.ts": 3823, - "collection-ingestion-protocol/main.ts": 2461, - "collection-ingestion-references.ts": 3913, - "collection-ingestion.ts": 3524, - "collection-storage-copies.ts": 3595, - "collection-value-keys.ts": 2425, - "compound-field-receivers.ts": 2962, - "compound-presence-guards.ts": 3337, - "conditional-tuple-destructuring.ts": 2631, - "console-imports.cjs": 2257, - "console-native-value.js": 2531, - "const-enum-module-cycle/main.ts": 2437, - "constant-callback-dispatch.ts": 2800, - "constant-module-globals/main.ts": 3036, - "constant-number-remainders.ts": 2724, - "constructed-class-dispatch.ts": 3005, - "contextual-array-union-write.ts": 6554, - "contextual-return-layouts.ts": 2859, - "counted-loop-numbers.ts": 2703, - "counted-loop-storage.ts": 2473, - "crypto-hash-optional-input.ts": 3036, - "cycle-generations-long-lived.ts": 2902, - "cycle-growth-yield.ts": 3252, - "date-checked-native.js": 2177, - "declared-index-spread.ts": 3543, - "deep-reference-teardown.ts": 2409, - "default-undefined-parameters.ts": 3171, - "deferred-field-updates.ts": 2290, - "deferred-registry-many.ts": 3267, - "derived-numeric-updates.ts": 2762, - "destructure-call-assignment.js": 2259, - "destructure-inferred-row-defaults.js": 2953, - "destructure-union-arrays.ts": 3202, - "dynamic-function-descriptors.js": 2214, - "error-cause-writes.js": 3441, - "error-inherited-message.mjs": 3449, - "error-inherited-name.mjs": 2955, - "error-property-writes.mjs": 2326, - "error-prototype-tostring.js": 2596, - "error-stack-frames.ts": 2880, - "error-stack-limit.ts": 2871, - "error-tostring-overrides.ts": 2481, - "error-values-inspect.ts": 2856, - "exact-index-round-trip.ts": 3660, - "expression-runtime-values.ts": 2159, - "fiber-switch-stress.ts": 2800, - "fiberless-async-ordering.ts": 3075, - "fiberless-async-unhandled.ts": 2437, - "field-assignment-values.ts": 2878, - "file-handle-values.ts": 2035, - "file-read-storage.ts": 2737, - "file-url-percent-decoding.ts": 2029, - "final-field-borrows.ts": 3105, - "for-multiple-bindings.ts": 2994, - "for-multiple-lexical-bindings.ts": 2863, - "for-of-checked-iterator.js": 3515, - "for-of-subclass-elements.ts": 2469, - "forward-generic-signatures.ts": 3287, - "fresh-array-union-layout.js": 2961, - "frozen-checked-dictionaries.mjs": 3021, - "fs-native-realpath.ts": 3263, + "closure-nullable-union-return.ts": 2472, + "closure-union-locals.ts": 2465, + "collection-array-cycles.ts": 2552, + "collection-array-maps.ts": 3481, + "collection-array-missing.ts": 2873, + "collection-array-sets.ts": 3383, + "collection-copy-identities.ts": 2585, + "collection-data-unions.ts": 2565, + "collection-ingestion-mappers.ts": 3262, + "collection-ingestion-protocol/main.ts": 3814, + "collection-ingestion-references.ts": 3375, + "collection-ingestion.ts": 3053, + "collection-storage-copies.ts": 3096, + "collection-value-keys.ts": 3176, + "compound-field-receivers.ts": 2272, + "compound-presence-guards.ts": 3094, + "conditional-tuple-destructuring.ts": 2487, + "console-imports.cjs": 2314, + "console-native-value.js": 2165, + "const-enum-module-cycle/main.ts": 2618, + "constant-callback-dispatch.ts": 2539, + "constant-module-globals/main.ts": 2455, + "constant-number-remainders.ts": 2350, + "constructed-class-dispatch.ts": 3014, + "contextual-array-union-write.ts": 5379, + "contextual-return-layouts.ts": 2919, + "counted-loop-numbers.ts": 2515, + "counted-loop-storage.ts": 2556, + "crypto-hash-optional-input.ts": 2860, + "cycle-generations-long-lived.ts": 2691, + "cycle-growth-yield.ts": 2929, + "date-checked-native.js": 2323, + "declared-index-spread.ts": 2660, + "deep-reference-teardown.ts": 3136, + "default-undefined-parameters.ts": 2589, + "deferred-field-updates.ts": 2347, + "deferred-registry-many.ts": 2661, + "derived-numeric-updates.ts": 1907, + "destructure-call-assignment.js": 2267, + "destructure-inferred-row-defaults.js": 2538, + "destructure-union-arrays.ts": 2379, + "dynamic-function-descriptors.js": 2763, + "error-cause-writes.js": 2954, + "error-inherited-message.mjs": 2631, + "error-inherited-name.mjs": 2285, + "error-property-writes.mjs": 2636, + "error-prototype-tostring.js": 3155, + "error-stack-frames.ts": 2206, + "error-stack-limit.ts": 2510, + "error-tostring-overrides.ts": 2305, + "error-values-inspect.ts": 2398, + "exact-index-round-trip.ts": 2801, + "expression-runtime-values.ts": 2027, + "fiber-switch-stress.ts": 2898, + "fiberless-async-ordering.ts": 2908, + "fiberless-async-unhandled.ts": 2133, + "field-assignment-values.ts": 2107, + "file-handle-values.ts": 2357, + "file-read-storage.ts": 2439, + "file-url-percent-decoding.ts": 2222, + "final-field-borrows.ts": 2890, + "for-multiple-bindings.ts": 2286, + "for-multiple-lexical-bindings.ts": 2283, + "for-of-checked-iterator.js": 3511, + "for-of-subclass-elements.ts": 2219, + "forward-generic-signatures.ts": 2294, + "fresh-array-union-layout.js": 2480, + "frozen-checked-dictionaries.mjs": 2629, + "fs-native-realpath.ts": 2351, "fs-null-byte-paths-js.cjs": 2762, "fs-null-byte-paths.ts": 3411, - "fs-read-encodings.ts": 3220, + "fs-read-encodings.ts": 2505, "fs-read-utf8-edges.ts": 3246, "fs-read-utf8-handle-forms.ts": 3163, - "fs-remove-readonly.ts": 2468, - "fs-write-string-bytes-union.ts": 2571, - "function-apply-value.mjs": 2118, - "function-constructor-global.mjs": 2459, - "function-constructor-kinds/main.js": 2510, - "function-custom-prototype.js": 3445, - "function-custom-to-string.mjs": 3088, - "function-object-assign.js": 2894, - "function-own-prototype/main.js": 2937, - "generator-checked-protocol.ts": 3202, - "generator-checked-return.js": 2917, - "generator-custom-delegation/main.ts": 5180, - "generator-default-return-pattern.ts": 2163, - "generator-delegation-values.ts": 2121, - "generator-inferred-date.js": 1700, - "generator-mixed-checked-channels.ts": 3203, - "generator-untyped-consumer/main.ts": 3571, - "generic-base-specializations.ts": 2610, - "generic-binding-ownership.ts": 3653, - "generic-class-js-functions/main.ts": 2631, - "generic-class-recovery.ts": 3190, - "generic-namespace-factories/main.ts": 2712, - "generic-nullable-collections.ts": 2692, - "generic-pattern-bindings.ts": 2004, - "generic-record-index.ts": 2705, - "generic-visitor-void.ts": 2865, + "fs-remove-readonly.ts": 2354, + "fs-write-string-bytes-union.ts": 2286, + "function-apply-value.mjs": 2558, + "function-constructor-global.mjs": 1848, + "function-constructor-kinds/main.js": 2532, + "function-custom-prototype.js": 2604, + "function-custom-to-string.mjs": 2607, + "function-object-assign.js": 2509, + "function-own-prototype/main.js": 2423, + "generator-checked-protocol.ts": 2631, + "generator-checked-return.js": 2326, + "generator-custom-delegation/main.ts": 3343, + "generator-default-return-pattern.ts": 2653, + "generator-delegation-values.ts": 2368, + "generator-inferred-date.js": 2465, + "generator-mixed-checked-channels.ts": 2662, + "generator-untyped-consumer/main.ts": 2958, + "generic-base-specializations.ts": 2073, + "generic-binding-ownership.ts": 2817, + "generic-class-js-functions/main.ts": 2051, + "generic-class-recovery.ts": 2415, + "generic-namespace-factories/main.ts": 2073, + "generic-nullable-collections.ts": 2677, + "generic-pattern-bindings.ts": 2698, + "generic-record-index.ts": 2753, + "generic-visitor-void.ts": 2405, "global-accumulator-loops.ts": 3053, - "global-error-subclasses.ts": 2690, - "global-runtime-probes.js": 1976, - "global-stored-probes.js": 2924, - "global-string-cache/main.js": 2572, - "global-symbol-cache/main.js": 2380, - "guarded-native-iterables.ts": 2466, - "heap-input-aliases.ts": 2784, - "heap-input-collections.ts": 3100, - "in-array-runtime-index.ts": 3210, - "indexed-assignment-values.js": 3521, - "indexed-assignment-values.ts": 2224, - "indexed-element-field-reads.ts": 2611, - "inferred-array-assignment-values.mjs": 2976, - "inferred-class-default.mjs": 2564, - "inferred-compound-values.mjs": 2110, - "inferred-conditional-class.mjs": 2584, - "inferred-error-fields.js": 2163, - "inferred-map-patterns.mjs": 2233, - "inferred-method-override.js": 2516, - "inferred-partial-destructuring.mjs": 2158, - "inferred-primitive-properties.mjs": 2508, - "inferred-record-return.mjs": 2099, - "inferred-recursive-record.mjs": 2183, - "inferred-undefined-field.mjs": 3012, - "input-lifetime-intervals.ts": 3244, - "input-lifetimes-modules/main.ts": 2793, - "instanceof-class-record-union.ts": 2242, - "integer-flow-arithmetic.ts": 3060, - "integer-loop-forms.ts": 2872, - "integer-view-control.ts": 2400, - "integer-view-numbers.ts": 2753, - "integer-view-storage.ts": 2545, - "intl-grapheme-conformance/main.ts": 4747, - "intl-grapheme.ts": 2345, - "iterator-typed-returns.ts": 3833, - "js-abort-portable.js": 2996, - "js-array-constructor.js": 3177, - "js-array-default-buffer.js": 2796, - "js-array-iterators.js": 3414, - "js-arrow-bind.cjs": 4772, - "js-buffer-callback-brand.cjs": 2001, + "global-error-subclasses.ts": 1773, + "global-runtime-probes.js": 2288, + "global-stored-probes.js": 2726, + "global-string-cache/main.js": 1889, + "global-symbol-cache/main.js": 3399, + "guarded-native-iterables.ts": 2496, + "heap-input-aliases.ts": 2746, + "heap-input-collections.ts": 2558, + "in-array-runtime-index.ts": 2579, + "indexed-assignment-values.js": 2971, + "indexed-assignment-values.ts": 1852, + "indexed-element-field-reads.ts": 2452, + "inferred-array-assignment-values.mjs": 2352, + "inferred-class-default.mjs": 2460, + "inferred-compound-values.mjs": 2473, + "inferred-conditional-class.mjs": 2635, + "inferred-error-fields.js": 2509, + "inferred-map-patterns.mjs": 2353, + "inferred-method-override.js": 2137, + "inferred-partial-destructuring.mjs": 2205, + "inferred-primitive-properties.mjs": 2135, + "inferred-record-return.mjs": 1793, + "inferred-recursive-record.mjs": 1833, + "inferred-undefined-field.mjs": 1777, + "input-lifetime-intervals.ts": 2714, + "input-lifetimes-modules/main.ts": 3258, + "instanceof-class-record-union.ts": 2400, + "integer-flow-arithmetic.ts": 3652, + "integer-loop-forms.ts": 2368, + "integer-view-control.ts": 1809, + "integer-view-numbers.ts": 2394, + "integer-view-storage.ts": 2439, + "intl-grapheme-conformance/main.ts": 3718, + "intl-grapheme.ts": 2449, + "iterator-typed-returns.ts": 3400, + "js-abort-portable.js": 2829, + "js-array-constructor.js": 3163, + "js-array-default-buffer.js": 2537, + "js-array-iterators.js": 2559, + "js-arrow-bind.cjs": 3343, + "js-buffer-callback-brand.cjs": 2262, "js-builder-string-method-names/main.ts": 4550, "js-callable-builder.js": 4500, - "js-callable-proxy.js": 3739, - "js-chained-native-results.mjs": 2683, - "js-checked-array-iterator.js": 2865, - "js-checked-array-reference.js": 3607, - "js-checked-number-negation.mjs": 2731, - "js-checked-sort-result.js": 2328, - "js-child-error-listener.cjs": 2751, - "js-cjs-callable-snapshots/main.cjs": 2946, - "js-class-added-parameters.js": 2228, - "js-class-checked-overrides.js": 2130, - "js-class-computed-fields.js": 2657, + "js-callable-proxy.js": 3516, + "js-chained-native-results.mjs": 2641, + "js-checked-array-iterator.js": 2670, + "js-checked-array-reference.js": 2270, + "js-checked-number-negation.mjs": 1915, + "js-checked-sort-result.js": 2373, + "js-child-error-listener.cjs": 2357, + "js-cjs-callable-snapshots/main.cjs": 1981, + "js-class-added-parameters.js": 2472, + "js-class-checked-overrides.js": 2571, + "js-class-computed-fields.js": 1830, "js-class-constructor-returns/main.ts": 4350, - "js-class-enumeration.js": 2642, - "js-class-field-accessor-override.js": 2687, - "js-class-fluent-overrides.js": 2370, - "js-class-late-method-values.js": 3690, - "js-class-member-dispatch.js": 3108, - "js-class-return-shapes.js": 3149, - "js-class-shadowed-methods.js": 3491, - "js-class-stored-method-receiver.js": 2218, - "js-class-subclass-properties.js": 4610, - "js-class-symbol-spread.cjs": 2295, - "js-computed-prototype-additions.js": 3232, - "js-constructor-returned-callable.js": 2404, - "js-constructor-spread.js": 3538, - "js-dataview-dispatch.js": 3187, - "js-declared-fields.cjs": 4825, - "js-default-listener-arguments.cjs": 1767, - "js-default-options/main.ts": 3097, - "js-deferred-field-initializers.js": 1977, - "js-deferred-registry-effects.js": 2772, - "js-derived-constructor-hoisting.js": 2288, - "js-dormant-array-write.js": 2420, - "js-dormant-overrides.js": 2890, - "js-expando-records.js": 2867, + "js-class-enumeration.js": 3296, + "js-class-field-accessor-override.js": 2567, + "js-class-fluent-overrides.js": 2822, + "js-class-late-method-values.js": 2309, + "js-class-member-dispatch.js": 3016, + "js-class-return-shapes.js": 2231, + "js-class-shadowed-methods.js": 2942, + "js-class-stored-method-receiver.js": 2382, + "js-class-subclass-properties.js": 3695, + "js-class-symbol-spread.cjs": 2704, + "js-computed-prototype-additions.js": 3142, + "js-constructor-returned-callable.js": 2605, + "js-constructor-spread.js": 2289, + "js-dataview-dispatch.js": 2273, + "js-declared-fields.cjs": 3263, + "js-default-listener-arguments.cjs": 2549, + "js-default-options/main.ts": 3044, + "js-deferred-field-initializers.js": 2121, + "js-deferred-registry-effects.js": 2381, + "js-derived-constructor-hoisting.js": 1805, + "js-dormant-array-write.js": 1888, + "js-dormant-overrides.js": 2569, + "js-expando-records.js": 2454, "js-function-prototype-value.js": 3650, - "js-implicit-call-results.js": 2946, - "js-inferred-callback-exports/main.js": 4147, - "js-inferred-class-array-return.js": 3209, - "js-inferred-object-values.js": 2234, - "js-inherited-field-storage.js": 2161, - "js-inherited-parameter-abi.js": 2457, - "js-iterable-spread.js": 3088, - "js-loose-dynamic-primitives.js": 2797, - "js-map-object-seeds.js": 3253, - "js-member-increment.js": 3027, - "js-module-function-values.js": 3358, - "js-mutable-null-members.js": 2588, - "js-nested-native-descriptors.js": 2862, - "js-normalize-dispatch.js": 3006, - "js-nullish-inherited-fields.mjs": 2812, + "js-implicit-call-results.js": 3064, + "js-inferred-callback-exports/main.js": 3830, + "js-inferred-class-array-return.js": 2570, + "js-inferred-object-values.js": 2380, + "js-inherited-field-storage.js": 3121, + "js-inherited-parameter-abi.js": 2210, + "js-iterable-spread.js": 2950, + "js-loose-dynamic-primitives.js": 1960, + "js-map-object-seeds.js": 2610, + "js-member-increment.js": 2926, + "js-module-function-values.js": 2014, + "js-mutable-null-members.js": 2370, + "js-nested-native-descriptors.js": 2412, + "js-normalize-dispatch.js": 2793, + "js-nullish-inherited-fields.mjs": 2710, "js-number-parse-dynamic.js": 2700, - "js-object-receiver-storage.js": 2500, - "js-object-returning-constructors.mjs": 2542, - "js-object-shared-arrays.js": 2369, - "js-omitted-typed-arguments.js": 2596, - "js-open-binding-writes.js": 2909, - "js-optional-class-fields.js": 3469, - "js-optional-member-call.js": 3126, - "js-primitive-union-addition.js": 2730, + "js-object-receiver-storage.js": 2613, + "js-object-returning-constructors.mjs": 2186, + "js-object-shared-arrays.js": 2465, + "js-omitted-typed-arguments.js": 2236, + "js-open-binding-writes.js": 1787, + "js-optional-class-fields.js": 2266, + "js-optional-member-call.js": 1883, + "js-primitive-union-addition.js": 2256, "js-process-destructure.mjs": 4750, - "js-promise-all-values.js": 3561, - "js-promise-catch-handler.js": 2902, - "js-promise-finally-order.js": 2511, - "js-promise-pending-reactions.js": 2712, - "js-prototype-host-boundary.js": 2617, - "js-reflect-receivers.js": 3341, - "js-regex-record-captures.js": 3157, + "js-promise-all-values.js": 3079, + "js-promise-catch-handler.js": 1749, + "js-promise-finally-order.js": 1913, + "js-promise-pending-reactions.js": 2644, + "js-prototype-host-boundary.js": 2224, + "js-reflect-receivers.js": 3119, + "js-regex-record-captures.js": 2010, "js-reshaped-object-literal.js": 5700, - "js-scalar-iterables.js": 3299, - "js-shared-method-dispatch.js": 3057, - "js-specialized-field-method.js": 2254, - "js-static-accessors.js": 3374, - "js-static-method-values.js": 3629, - "js-static-registries.cjs": 3164, - "js-super-accessor-initialization.js": 2332, - "js-uninitialized-native-fields.js": 2069, - "json-guarded-map-values.ts": 3048, - "json-output-bulk.ts": 1978, - "json-runtime-options.mjs": 3034, - "json-stringify-value.js": 2308, - "json-typed-parse-direct.ts": 2696, + "js-scalar-iterables.js": 2477, + "js-shared-method-dispatch.js": 2033, + "js-specialized-field-method.js": 2335, + "js-static-accessors.js": 2520, + "js-static-method-values.js": 2194, + "js-static-registries.cjs": 2703, + "js-super-accessor-initialization.js": 2100, + "js-uninitialized-native-fields.js": 2180, + "json-guarded-map-values.ts": 2374, + "json-output-bulk.ts": 2827, + "json-runtime-options.mjs": 1997, + "json-stringify-value.js": 2563, + "json-typed-parse-direct.ts": 2355, "json-typed-parse-index-signatures.ts": 3686, "json-typed-parse-optional-members.ts": 3044, "json-typed-parse-union-members.ts": 3090, - "literal-switch-dispatch.ts": 2612, - "live-reference-shared-converters.ts": 3144, - "llvm-read-receiver-lifetime.ts": 1978, - "local-class-call-spreads.js": 1989, - "local-class-declaration.ts": 1927, - "local-class-evaluation.ts": 2816, - "local-class-inheritance.ts": 2647, - "local-class-lifetimes.ts": 3188, - "local-class-namespace/main.js": 3542, - "local-class-prototype-data.js": 2714, - "local-class-specialization.js": 2650, - "local-class-unknown.ts": 2915, - "local-class-values.ts": 2331, - "local-union-storage.ts": 2638, - "locale-compare-root-order.ts": 3001, - "logical-assignment-dynamic.js": 3172, - "logical-assignment-values.ts": 2043, - "logical-runtime-optional-record.ts": 2200, - "loop-reference-lifetimes.ts": 2559, - "map-checked-boundary/main.ts": 2442, - "map-checked-seed.js": 2756, + "literal-switch-dispatch.ts": 2500, + "live-reference-shared-converters.ts": 2552, + "llvm-read-receiver-lifetime.ts": 2343, + "local-class-call-spreads.js": 3208, + "local-class-declaration.ts": 2486, + "local-class-evaluation.ts": 2605, + "local-class-inheritance.ts": 2327, + "local-class-lifetimes.ts": 2376, + "local-class-namespace/main.js": 2940, + "local-class-prototype-data.js": 2781, + "local-class-specialization.js": 2399, + "local-class-unknown.ts": 2443, + "local-class-values.ts": 1784, + "local-union-storage.ts": 2967, + "locale-compare-root-order.ts": 2518, + "logical-assignment-dynamic.js": 2592, + "logical-assignment-values.ts": 2497, + "logical-runtime-optional-record.ts": 2944, + "loop-reference-lifetimes.ts": 2542, + "map-checked-boundary/main.ts": 2629, + "map-checked-seed.js": 3013, "map-get-set-fusion.ts": 3284, - "map-number-keys-dense.ts": 2972, - "map-read-lifetimes-exits.ts": 2860, - "map-read-lifetimes.ts": 2905, - "map-seeds-and-spreads.ts": 2984, - "map-typed-array-values.ts": 2649, - "math-function-values.js": 2638, - "missing-read-lambda-results.ts": 2850, - "missing-read-narrowed-storage.ts": 3077, - "missing-read-number-conversions.ts": 3015, - "module-byte-loops.ts": 2315, - "module-fallback-functions/main.js": 2716, - "narrowed-nullish-values.ts": 2405, - "native-any-timer-callback.ts": 2380, - "native-array-borrowed-find-last.js": 2591, - "native-array-borrowed-slice.js": 2966, - "native-array-copying-methods.js": 2605, - "native-array-fill-copywithin.js": 2662, - "native-array-frozen-noops.js": 2568, - "native-array-index-boundaries.js": 2581, - "native-array-integrity.js": 3066, - "native-array-length.js": 3005, - "native-array-named-properties.js": 2812, - "native-array-prototype/main.js": 3103, - "native-array-read-lifetimes.ts": 2912, - "native-array-reduce-find-last.js": 2732, - "native-array-search-from-index.js": 2720, - "native-array-splice-coercion.js": 1769, - "native-array-splice-flat.js": 2701, - "native-buffer-coercion.js": 2837, - "native-callback-dispatch.ts": 3750, - "native-class-array-boundaries.ts": 3033, - "native-class-cache.js": 3922, - "native-class-properties.cjs": 5335, - "native-class-property-cycles.cjs": 2421, - "native-class-property-order.cjs": 2798, - "native-class-type-predicates.ts": 2523, - "native-factory-records.js": 2515, - "native-method-values.js": 4031, - "native-method-values.ts": 2347, - "native-npm-imports/main.ts": 3454, - "native-object-descriptors.js": 1755, - "native-object-for-in-minimal.js": 2603, - "native-object-property-attributes.js": 3035, - "native-object-prototype.js": 2445, - "native-property-names.ts": 2425, - "native-proxy-env.js": 3704, - "native-worker-arena-reuse.ts": 6858, - "native-worker-bounded-errors.ts": 2058, - "native-worker-buffer-consumers.ts": 3068, - "native-worker-cancel-hot.ts": 2722, - "native-worker-class-fields.ts": 2782, - "native-worker-clone-errors.ts": 2690, - "native-worker-commonjs.cjs": 3412, - "native-worker-delayed-messages.ts": 2375, - "native-worker-discarded-heaps.ts": 5717, - "native-worker-environment.ts": 2804, - "native-worker-error.ts": 2211, - "native-worker-exception-state.ts": 4167, - "native-worker-exit-listeners.ts": 2523, - "native-worker-io.ts": 3345, - "native-worker-loop-cancellation.ts": 2510, - "native-worker-message-graphs.ts": 2419, - "native-worker-messages.ts": 2757, - "native-worker-poll-exceptions.ts": 3061, - "native-worker-port-lifetime.ts": 2699, - "native-worker-process-exit.ts": 2130, - "native-worker-publish-classes.ts": 3636, - "native-worker-publish-refusals.ts": 2020, - "native-worker-published-graphs.ts": 2461, - "native-worker-references.ts": 2598, - "native-worker-roots/main.ts": 3212, - "native-worker-shared-views.ts": 2802, - "native-worker-stack-overflow.ts": 2946, - "native-worker-terminate-exception-state.ts": 3847, - "native-worker-terminate-loop.ts": 2735, - "native-worker-terminate-recursion.ts": 4636, - "native-worker-terminate-suspended.ts": 2692, - "native-worker-terminate-tested-loops.ts": 3271, - "native-worker-terminate-wait.ts": 2775, - "native-worker-typed-arrays.ts": 3254, - "nested-map-cycles.ts": 2753, - "nested-map-values.ts": 4785, - "never-returning-calls.ts": 2228, - "next-tick-commonjs-entry.cjs": 1929, - "node24-buffer-encoding-errors.ts": 2283, - "node24-buffer-encoding.ts": 2691, - "node24-crypto-kdf-errors.ts": 3129, - "node24-crypto-kdf-options.ts": 3852, - "node24-crypto-kdf.ts": 3936, - "node24-crypto-sha2.ts": 1860, - "node24-deep-equality-properties.js": 2441, - "node24-deep-equality.cjs": 2912, - "node24-deep-equality.ts": 3378, - "node24-env-files-errors.ts": 2760, - "node24-env-files.ts": 2643, - "node24-env-imports.cjs": 1749, - "node24-env-parse-errors.ts": 2987, - "node24-env-parse.ts": 1797, - "node24-esm-metadata/main.mjs": 2385, - "node24-file-url-buffer.ts": 2665, - "node24-file-url-errors.js": 3394, - "node24-file-url-options.ts": 3117, - "node24-fs-links-callbacks.cjs": 2182, - "node24-fs-links-errors.cjs": 2221, - "node24-fs-links-options.cjs": 3438, - "node24-fs-links-promise-errors.cjs": 1752, - "node24-fs-links-promises.ts": 2960, - "node24-fs-links.ts": 3132, - "node24-fs-statfs-callbacks.cjs": 2404, - "node24-fs-statfs-errors.cjs": 3053, - "node24-fs-statfs-options.cjs": 3275, - "node24-fs-statfs.ts": 2771, - "node24-fs-timestamps-callbacks.cjs": 3442, - "node24-fs-timestamps-errors.cjs": 2214, - "node24-fs-timestamps-promises.ts": 2905, - "node24-fs-timestamps-symlinks.ts": 2911, - "node24-fs-timestamps.ts": 2652, - "node24-no-error-assertions-coercion.js": 3450, - "node24-no-error-assertions.cjs": 2131, - "node24-no-error-assertions.ts": 3704, - "node24-parseargs.js": 3975, - "node24-string-decoder.ts": 1840, - "node24-style-text-environment.js": 1777, - "node24-style-text-validation.js": 2850, - "node24-style-text.cjs": 2428, - "node24-style-text.ts": 2934, - "node24-system-error-validation.js": 2301, - "node24-system-errors.cjs": 2559, - "node24-system-errors.ts": 2989, - "node24-text-codec-properties.ts": 3210, - "node24-text-encode-into.ts": 2657, - "node24-text-utilities-coercion.js": 2506, - "node24-text-utilities-validation.js": 3129, - "node24-text-utilities.cjs": 2550, - "node24-text-utilities.ts": 2610, - "node24-url-authority-coercion.js": 3075, - "node24-url-authority.ts": 2397, - "node24-url-factories.ts": 3132, - "node24-url-factory-errors.ts": 2346, - "node24-url-mutation-coercion.js": 2926, - "node24-url-mutation.ts": 2845, - "node24-util-types.cjs": 2459, - "node24-util-types.js": 2601, - "node24-util-types.ts": 3126, - "non-null-class-iteration.ts": 1674, - "nonnull-element-arguments.ts": 2593, - "nonnull-forwarded-class-values.ts": 1775, - "nullable-object-extension.mjs": 1502, - "nullish-asserted-class-arms.ts": 2652, - "nullish-assignment-values.ts": 2755, - "nullish-long-chain.ts": 3588, - "number-parse-statics.ts": 2229, - "number-predicates-unknown.ts": 2605, - "numeric-call-specialization.ts": 1690, - "object-enumeration-array-reads.ts": 3043, - "object-from-checked-entries.js": 3900, - "object-inherited-to-string.js": 1733, - "object-key-indexes.js": 3227, - "object-prototype-identity.mjs": 2689, - "object-reexport/main.js": 2801, - "object-spread-computed.ts": 2239, - "opentui-byte-queue.js": 3379, - "optional-callback-arity.ts": 1977, - "optional-class-flows.ts": 2120, - "optional-element-defaults.ts": 2378, - "optional-flag-comparisons.ts": 2194, - "optional-native-callables.js": 2420, - "optional-node-list-iteration.ts": 2425, - "optional-string-index/main.ts": 2629, - "path-to-file-url-options.ts": 1964, - "performance-presence.ts": 2369, - "primitive-and-function-descriptors.js": 2715, - "primitive-union-string.ts": 2231, - "process-builtin-values.js": 3831, - "process-constrained-memory.ts": 2154, - "process-env-computed-keys.js": 2619, - "process-hrtime.js": 2376, - "process-named-signals.cjs": 2024, - "process-uncaught-handler-throws.cjs": 2023, - "process-uncaught-loop.cjs": 1789, - "process-uncaught-module.mjs": 1660, - "process-uncaught-monitor.cjs": 2359, - "process-uncaught-rejection.cjs": 2287, - "process-uncaught-sync.cjs": 2104, - "process-version-pin.ts": 2000, - "process-versions-storage.ts": 2763, - "projected-collection-lifetimes.ts": 2478, - "promise-checked-rejections.ts": 2584, - "promise-resolve-void.ts": 1939, - "prototype-method-overrides.mjs": 5633, - "prototype-named-data-records.ts": 2571, + "map-number-keys-dense.ts": 2562, + "map-read-lifetimes-exits.ts": 2227, + "map-read-lifetimes.ts": 2725, + "map-seeds-and-spreads.ts": 2719, + "map-typed-array-values.ts": 2850, + "math-function-values.js": 2367, + "missing-read-lambda-results.ts": 2379, + "missing-read-narrowed-storage.ts": 2498, + "missing-read-number-conversions.ts": 2181, + "module-byte-loops.ts": 2636, + "module-fallback-functions/main.js": 2148, + "narrowed-nullish-values.ts": 2410, + "native-any-timer-callback.ts": 1834, + "native-array-borrowed-find-last.js": 2515, + "native-array-borrowed-slice.js": 2404, + "native-array-copying-methods.js": 2076, + "native-array-fill-copywithin.js": 2636, + "native-array-frozen-noops.js": 2476, + "native-array-index-boundaries.js": 1913, + "native-array-integrity.js": 2429, + "native-array-length.js": 2568, + "native-array-named-properties.js": 2390, + "native-array-prototype/main.js": 2161, + "native-array-read-lifetimes.ts": 2771, + "native-array-reduce-find-last.js": 2375, + "native-array-search-from-index.js": 1823, + "native-array-splice-coercion.js": 2296, + "native-array-splice-flat.js": 1933, + "native-buffer-coercion.js": 2389, + "native-callback-dispatch.ts": 3007, + "native-class-array-boundaries.ts": 2676, + "native-class-cache.js": 3391, + "native-class-properties.cjs": 3541, + "native-class-property-cycles.cjs": 2291, + "native-class-property-order.cjs": 1867, + "native-class-type-predicates.ts": 2386, + "native-factory-records.js": 2851, + "native-method-values.js": 2903, + "native-method-values.ts": 2495, + "native-npm-imports/main.ts": 2716, + "native-object-descriptors.js": 2717, + "native-object-for-in-minimal.js": 2536, + "native-object-property-attributes.js": 3149, + "native-object-prototype.js": 3180, + "native-property-names.ts": 1827, + "native-proxy-env.js": 3519, + "native-worker-arena-reuse.ts": 4699, + "native-worker-bounded-errors.ts": 2268, + "native-worker-buffer-consumers.ts": 2531, + "native-worker-cancel-hot.ts": 2446, + "native-worker-class-fields.ts": 2650, + "native-worker-clone-errors.ts": 2347, + "native-worker-commonjs.cjs": 2188, + "native-worker-delayed-messages.ts": 3114, + "native-worker-discarded-heaps.ts": 4430, + "native-worker-environment.ts": 3538, + "native-worker-error.ts": 2810, + "native-worker-exception-state.ts": 3938, + "native-worker-exit-listeners.ts": 2965, + "native-worker-io.ts": 3018, + "native-worker-loop-cancellation.ts": 2773, + "native-worker-message-graphs.ts": 2440, + "native-worker-messages.ts": 2911, + "native-worker-poll-exceptions.ts": 2706, + "native-worker-port-lifetime.ts": 3175, + "native-worker-process-exit.ts": 2168, + "native-worker-publish-classes.ts": 2797, + "native-worker-publish-refusals.ts": 2330, + "native-worker-published-graphs.ts": 3411, + "native-worker-references.ts": 2156, + "native-worker-roots/main.ts": 2962, + "native-worker-shared-views.ts": 2377, + "native-worker-stack-overflow.ts": 2443, + "native-worker-terminate-exception-state.ts": 3368, + "native-worker-terminate-loop.ts": 1929, + "native-worker-terminate-recursion.ts": 2935, + "native-worker-terminate-suspended.ts": 2843, + "native-worker-terminate-tested-loops.ts": 3082, + "native-worker-terminate-wait.ts": 2267, + "native-worker-typed-arrays.ts": 2361, + "nested-map-cycles.ts": 2306, + "nested-map-values.ts": 2038, + "never-returning-calls.ts": 2680, + "next-tick-commonjs-entry.cjs": 1924, + "node24-buffer-encoding-errors.ts": 2742, + "node24-buffer-encoding.ts": 2822, + "node24-crypto-kdf-errors.ts": 2607, + "node24-crypto-kdf-options.ts": 1925, + "node24-crypto-kdf.ts": 3401, + "node24-crypto-sha2.ts": 2336, + "node24-deep-equality-properties.js": 2551, + "node24-deep-equality.cjs": 2373, + "node24-deep-equality.ts": 3193, + "node24-env-files-errors.ts": 2555, + "node24-env-files.ts": 2556, + "node24-env-imports.cjs": 2518, + "node24-env-parse-errors.ts": 2083, + "node24-env-parse.ts": 2189, + "node24-esm-metadata/main.mjs": 2257, + "node24-file-url-buffer.ts": 1904, + "node24-file-url-errors.js": 2838, + "node24-file-url-options.ts": 2563, + "node24-fs-links-callbacks.cjs": 2964, + "node24-fs-links-errors.cjs": 2795, + "node24-fs-links-options.cjs": 3096, + "node24-fs-links-promise-errors.cjs": 2481, + "node24-fs-links-promises.ts": 2014, + "node24-fs-links.ts": 3060, + "node24-fs-statfs-callbacks.cjs": 2761, + "node24-fs-statfs-errors.cjs": 3068, + "node24-fs-statfs-options.cjs": 2927, + "node24-fs-statfs.ts": 2192, + "node24-fs-timestamps-callbacks.cjs": 2865, + "node24-fs-timestamps-errors.cjs": 2733, + "node24-fs-timestamps-promises.ts": 2476, + "node24-fs-timestamps-symlinks.ts": 2406, + "node24-fs-timestamps.ts": 2758, + "node24-no-error-assertions-coercion.js": 2950, + "node24-no-error-assertions.cjs": 2361, + "node24-no-error-assertions.ts": 2895, + "node24-parseargs.js": 3512, + "node24-string-decoder.ts": 2569, + "node24-style-text-environment.js": 2370, + "node24-style-text-validation.js": 2999, + "node24-style-text.cjs": 1883, + "node24-style-text.ts": 2102, + "node24-system-error-validation.js": 2003, + "node24-system-errors.cjs": 2247, + "node24-system-errors.ts": 2302, + "node24-text-codec-properties.ts": 2178, + "node24-text-encode-into.ts": 2427, + "node24-text-utilities-coercion.js": 2867, + "node24-text-utilities-validation.js": 1874, + "node24-text-utilities.cjs": 2132, + "node24-text-utilities.ts": 2215, + "node24-url-authority-coercion.js": 2529, + "node24-url-authority.ts": 2720, + "node24-url-factories.ts": 2586, + "node24-url-factory-errors.ts": 1931, + "node24-url-mutation-coercion.js": 2518, + "node24-url-mutation.ts": 2194, + "node24-util-types.cjs": 3057, + "node24-util-types.js": 1900, + "node24-util-types.ts": 2935, + "non-null-class-iteration.ts": 2350, + "nonnull-element-arguments.ts": 2545, + "nonnull-forwarded-class-values.ts": 2532, + "nullable-object-extension.mjs": 1922, + "nullish-asserted-class-arms.ts": 2485, + "nullish-assignment-values.ts": 1745, + "nullish-long-chain.ts": 2326, + "number-parse-statics.ts": 2443, + "number-predicates-unknown.ts": 2375, + "numeric-call-specialization.ts": 2588, + "object-enumeration-array-reads.ts": 1967, + "object-from-checked-entries.js": 2542, + "object-inherited-to-string.js": 2670, + "object-key-indexes.js": 2753, + "object-prototype-identity.mjs": 2064, + "object-reexport/main.js": 2482, + "object-spread-computed.ts": 2578, + "opentui-byte-queue.js": 2802, + "optional-callback-arity.ts": 2348, + "optional-class-flows.ts": 2247, + "optional-element-defaults.ts": 2052, + "optional-flag-comparisons.ts": 2527, + "optional-native-callables.js": 2309, + "optional-node-list-iteration.ts": 2316, + "optional-string-index/main.ts": 2950, + "path-to-file-url-options.ts": 2299, + "performance-presence.ts": 2043, + "primitive-and-function-descriptors.js": 2222, + "primitive-union-string.ts": 2856, + "process-builtin-values.js": 2616, + "process-constrained-memory.ts": 2105, + "process-env-computed-keys.js": 2252, + "process-hrtime.js": 2596, + "process-named-signals.cjs": 2604, + "process-uncaught-handler-throws.cjs": 2306, + "process-uncaught-loop.cjs": 2320, + "process-uncaught-module.mjs": 1832, + "process-uncaught-monitor.cjs": 2077, + "process-uncaught-rejection.cjs": 2431, + "process-uncaught-sync.cjs": 2425, + "process-version-pin.ts": 2418, + "process-versions-storage.ts": 2051, + "projected-collection-lifetimes.ts": 2409, + "promise-checked-rejections.ts": 1985, + "promise-resolve-void.ts": 2341, + "prototype-method-overrides.mjs": 4870, + "prototype-named-data-records.ts": 2513, "rc-last-use-moves.ts": 2854, "rc-private-array-writes.ts": 3076, - "record-field-presence.ts": 3566, - "record-key-order.ts": 2682, - "record-optional-json-presence.ts": 2822, - "record-presence-copies.ts": 3201, - "record-presence-delete-json.ts": 3074, - "record-unchecked-read-presence.ts": 2374, - "record-unknown-values.ts": 3234, - "reflect-own-keys.mjs": 1796, - "reflect-record-union-keys.mjs": 2278, - "reflect-typed-record-keys.ts": 2418, - "regex-callback-replacements.ts": 2839, - "regex-callback-values.js": 2887, - "regex-checked-casts.ts": 1808, - "regex-checked-storage.js": 2999, - "regex-exec-long-subject.ts": 2794, + "record-field-presence.ts": 3025, + "record-key-order.ts": 2807, + "record-optional-json-presence.ts": 2623, + "record-presence-copies.ts": 2693, + "record-presence-delete-json.ts": 2748, + "record-unchecked-read-presence.ts": 2103, + "record-unknown-values.ts": 3450, + "reflect-own-keys.mjs": 2583, + "reflect-record-union-keys.mjs": 2454, + "reflect-typed-record-keys.ts": 1855, + "regex-callback-replacements.ts": 2492, + "regex-callback-values.js": 2733, + "regex-checked-casts.ts": 2350, + "regex-checked-storage.js": 2669, + "regex-exec-long-subject.ts": 4533, "regex-exec-result-arrays.ts": 3204, "regex-fs-text-surfaces.ts": 3720, - "regex-input-lifetimes.ts": 2060, - "regex-native-matcher.ts": 4292, - "regex-optional-captures.ts": 2856, - "regex-optional-templates.ts": 2387, - "regex-split-captures.ts": 2496, - "regex-text-paths.ts": 3201, - "regexp-constructor-repeat.ts": 2842, - "regexp-optional-constructor.ts": 2495, - "regexp-string-coercion.js": 1920, - "renderer-export-dictionaries.js": 2828, - "renderer-null-state.js": 2692, - "renderer-specializations.js": 2881, - "repeat-and-typed-read-errors.ts": 2395, - "rest-optional-array-arguments.ts": 2478, - "rest-optional-elements.ts": 2534, - "return-void-through-finally.ts": 2913, - "runtime-optional-string-flows.ts": 2188, - "scalar-string-slices.ts": 2172, - "set-checked-methods.js": 3226, - "set-checked-storage.ts": 1974, - "set-iterator-seed-references.ts": 2018, - "set-iterator-seeds.ts": 3264, - "set-optional-seeds.ts": 2769, - "small-collection-transitions.ts": 3115, + "regex-input-lifetimes.ts": 2535, + "regex-native-matcher.ts": 3683, + "regex-optional-captures.ts": 2606, + "regex-optional-templates.ts": 2338, + "regex-split-captures.ts": 2583, + "regex-text-paths.ts": 2889, + "regexp-constructor-repeat.ts": 2351, + "regexp-optional-constructor.ts": 2315, + "regexp-string-coercion.js": 1897, + "renderer-export-dictionaries.js": 2582, + "renderer-null-state.js": 2185, + "renderer-specializations.js": 2653, + "repeat-and-typed-read-errors.ts": 2751, + "rest-optional-array-arguments.ts": 2671, + "rest-optional-elements.ts": 2289, + "return-void-through-finally.ts": 2486, + "runtime-optional-string-flows.ts": 2406, + "scalar-string-slices.ts": 2175, + "set-checked-methods.js": 2631, + "set-checked-storage.ts": 2064, + "set-iterator-seed-references.ts": 2863, + "set-iterator-seeds.ts": 2896, + "set-optional-seeds.ts": 2121, + "small-collection-transitions.ts": 2645, "speculative-integer-globals.ts": 2544, "speculative-integer-loops.ts": 2308, "speculative-integer-reads.ts": 3059, - "stack-depth-async-bodies.ts": 2625, - "stack-overflow-async.ts": 1714, - "stack-overflow-caught.ts": 2878, - "stack-overflow-finally.ts": 2668, - "stack-overflow-shapes.ts": 3524, - "stack-overflow-uncaught.ts": 2587, + "stack-depth-async-bodies.ts": 1910, + "stack-overflow-async.ts": 2447, + "stack-overflow-caught.ts": 2424, + "stack-overflow-finally.ts": 2613, + "stack-overflow-shapes.ts": 2534, + "stack-overflow-uncaught.ts": 2317, "stackless-async-concurrency.ts": 3322, "stackless-async-context.ts": 1853, "stackless-async-exceptions.ts": 3251, "stackless-async-ordering.ts": 3551, "stackless-async-unhandled.ts": 1779, - "static-field-updates/main.ts": 2473, - "static-method-receivers.ts": 2567, - "stdio-values.mjs": 2963, - "stdio-write-errors.mjs": 2760, - "stdio-write-overrides.mjs": 2090, - "stored-native-builtins.js": 2900, - "stored-object-helpers.js": 2328, + "static-field-updates/main.ts": 2050, + "static-method-receivers.ts": 2243, + "stdio-values.mjs": 2578, + "stdio-write-errors.mjs": 1977, + "stdio-write-overrides.mjs": 2495, + "stored-native-builtins.js": 2831, + "stored-object-helpers.js": 2747, "stream-dynamic-entry-kinds.cjs": 2778, "stream-dynamic-entry-kinds.ts": 2624, "stream-encoded-from-entries.cjs": 2924, "stream-encoded-from-entries.ts": 3274, - "string-char-code-integer-loops.ts": 1819, - "string-code-points.ts": 1858, - "string-concat-number-parts.ts": 1705, - "string-construction-order.ts": 2928, + "string-char-code-integer-loops.ts": 2495, + "string-code-points.ts": 1970, + "string-concat-number-parts.ts": 2044, + "string-construction-order.ts": 2502, "string-field-append.ts": 2926, - "string-lifetimes-boundaries.ts": 1843, - "string-lifetimes-evaluation.ts": 2718, - "string-lifetimes-iteration.ts": 2668, - "string-lifetimes-operations.ts": 2866, - "string-normalize.ts": 2507, - "string-pattern-replacement.ts": 3053, - "string-scan-fast-paths.ts": 2942, - "string-split-checked-separator.mjs": 2465, - "string-split-traversal.ts": 3686, - "structural-class-properties.ts": 2071, - "structured-text-boundaries.js": 2038, - "structured-text-storage.ts": 2083, - "switch-integer-dispatch.ts": 2561, - "symbol-checked-boundary/main.ts": 3073, - "symbol-class-fields.ts": 1839, - "symbol-class-fields/main.cjs": 2716, - "symbol-class-methods/main.ts": 1920, - "symbol-fields-deferred-factory.ts": 2270, - "symbol-fields-inferred.js": 1610, - "symbol-object-properties/main.js": 2842, - "synchronous-callback-lifetimes.ts": 3460, - "terminal-stream-properties.ts": 2151, - "text-codec-values/main.ts": 2261, - "text-codec-var.ts": 2601, - "text-encode-into-boundaries.ts": 2554, - "timers-clear-many.ts": 2390, + "string-lifetimes-boundaries.ts": 2481, + "string-lifetimes-evaluation.ts": 2486, + "string-lifetimes-iteration.ts": 2043, + "string-lifetimes-operations.ts": 2490, + "string-normalize.ts": 2391, + "string-pattern-replacement.ts": 3527, + "string-scan-fast-paths.ts": 2272, + "string-split-checked-separator.mjs": 2144, + "string-split-traversal.ts": 3038, + "structural-class-properties.ts": 2610, + "structured-text-boundaries.js": 2792, + "structured-text-storage.ts": 2942, + "switch-integer-dispatch.ts": 2290, + "symbol-checked-boundary/main.ts": 2273, + "symbol-class-fields.ts": 2065, + "symbol-class-fields/main.cjs": 2595, + "symbol-class-methods/main.ts": 1855, + "symbol-fields-deferred-factory.ts": 2253, + "symbol-fields-inferred.js": 2329, + "symbol-object-properties/main.js": 2835, + "synchronous-callback-lifetimes.ts": 2768, + "terminal-stream-properties.ts": 2586, + "text-codec-values/main.ts": 2158, + "text-codec-var.ts": 2182, + "text-encode-into-boundaries.ts": 1971, + "timers-clear-many.ts": 2704, "truthy-object-logical.ts": 5950, - "tuple-and-string-search.ts": 2238, - "tuple-array-union.ts": 2290, - "tuple-callback-visitation.ts": 3777, - "tuple-forof-visitation.ts": 2917, - "typed-array-bulk-conversion.mjs": 4510, - "typed-array-byte-io.js": 2794, - "typed-array-checked-index.js": 1963, - "typed-array-constructor-alias.ts": 2203, - "typed-array-constructor-identity.js": 2030, - "typed-array-constructor-union.ts": 2632, - "typed-array-constructor-values.mjs": 3162, - "typed-array-dynamic-methods.js": 2468, - "typed-array-integer-widths.ts": 2823, - "typed-array-nan-coded-reads.ts": 3658, - "typed-array-numeric-import.ts": 2758, - "typed-array-present-reads.ts": 2812, - "typed-array-reversed-storage.ts": 2702, - "typed-array-unknown.ts": 2767, - "typed-collection-iterator-references.ts": 3694, - "typed-collection-iterators.ts": 3044, - "typed-collection-views/main.ts": 3027, - "typed-index-arguments.ts": 2801, - "typed-prototype-methods.ts": 2702, - "typed-rest-callables.ts": 2066, - "typed-rest-filtered-return.ts": 1741, - "typedarray-native-inputs.js": 3278, - "typeof-checked-comparison.js": 2471, - "uint8array-sort-domains.ts": 2675, - "unicode-case-paths.ts": 2617, - "unicode-process-argv.ts": 2688, - "union-discriminant-width.ts": 3120, - "union-literal-scalar-discriminants.ts": 3160, - "union-literal-slot-conversion.ts": 2002, - "union-nested-layout-discriminant.ts": 2160, - "union-optional-semantic-identity.ts": 3319, - "union-record-clone.ts": 3245, - "union-record-structural-copy.ts": 3278, - "union-reference-comparison.ts": 2689, - "unknown-array-holes.ts": 1863, - "unknown-collections.ts": 2098, - "unknown-object-enumeration.ts": 4264, - "unknown-record-views.ts": 2126, - "url-runtime-base.ts": 2747, - "utf8-span-decoding.ts": 2143, - "util-parseargs-wrapped/main.ts": 3020, - "virtual-runtime-optional-returns.ts": 3408, - "weak-map-array-buffer.ts": 2113, - "weak-map-fresh-array.js": 2822, - "weak-map-native.js": 2623, - "weak-native-class-identity.ts": 1967, - "weak-set-native.js": 2320, - "worker-class-instance-clone.ts": 3408 + "tuple-and-string-search.ts": 2663, + "tuple-array-union.ts": 2706, + "tuple-callback-visitation.ts": 3464, + "tuple-forof-visitation.ts": 2357, + "typed-array-bulk-conversion.mjs": 3837, + "typed-array-byte-io.js": 2552, + "typed-array-checked-index.js": 2420, + "typed-array-constructor-alias.ts": 2507, + "typed-array-constructor-identity.js": 2453, + "typed-array-constructor-union.ts": 2428, + "typed-array-constructor-values.mjs": 2571, + "typed-array-dynamic-methods.js": 2604, + "typed-array-integer-widths.ts": 2747, + "typed-array-nan-coded-reads.ts": 2921, + "typed-array-numeric-import.ts": 2450, + "typed-array-present-reads.ts": 2582, + "typed-array-reversed-storage.ts": 2168, + "typed-array-unknown.ts": 2500, + "typed-collection-iterator-references.ts": 3186, + "typed-collection-iterators.ts": 2946, + "typed-collection-views/main.ts": 2523, + "typed-index-arguments.ts": 2494, + "typed-prototype-methods.ts": 2527, + "typed-rest-callables.ts": 2391, + "typed-rest-filtered-return.ts": 2578, + "typedarray-native-inputs.js": 3104, + "typeof-checked-comparison.js": 2116, + "uint8array-sort-domains.ts": 2494, + "unicode-case-paths.ts": 2356, + "unicode-process-argv.ts": 2569, + "union-discriminant-width.ts": 2670, + "union-literal-scalar-discriminants.ts": 2869, + "union-literal-slot-conversion.ts": 2792, + "union-nested-layout-discriminant.ts": 2120, + "union-optional-semantic-identity.ts": 2455, + "union-record-clone.ts": 2790, + "union-record-structural-copy.ts": 2905, + "union-reference-comparison.ts": 2401, + "unknown-array-holes.ts": 1853, + "unknown-collections.ts": 3166, + "unknown-object-enumeration.ts": 3783, + "unknown-record-views.ts": 3243, + "url-runtime-base.ts": 2584, + "utf8-span-decoding.ts": 2564, + "util-parseargs-wrapped/main.ts": 2257, + "virtual-runtime-optional-returns.ts": 2981, + "weak-map-array-buffer.ts": 2435, + "weak-map-fresh-array.js": 2341, + "weak-map-native.js": 3068, + "weak-native-class-identity.ts": 2403, + "weak-set-native.js": 2924, + "worker-class-instance-clone.ts": 3052 }, "san": { - "001-hello.ts": 48584, - "002-log-args.ts": 53231, - "100-number-format.ts": 36832, - "1000-json-stringify-basics.ts": 52367, - "1001-json-escapes-unicode.ts": 4807, - "1002-json-parse-cast.ts": 5113, - "1003-json-parse-unions.ts": 7293, - "1004-json-parse-errors.ts": 49116, - "1005-json-nested.ts": 41496, - "1006-json-fs-config.ts": 48813, - "1007-json-rc-stress.ts": 4968, - "1008-json-null-arms.ts": 49375, - "1009-json-optional-fields.ts": 52902, - "101-arithmetic.ts": 4596, - "1010-json-stringify-space.ts": 7197, - "1011-json-unknown-typeof.ts": 38530, - "102-comparisons.ts": 45324, - "1020-async-basics.ts": 5928, - "1021-async-ordering.ts": 3518, - "1022-async-exceptions.ts": 4562, - "1023-async-rc-stress.ts": 49059, - "1024-async-pending-exit.ts": 4366, - "1025-async-promise-capture.ts": 4983, - "1026-throw-promise.ts": 47886, - "1027-async-return-promise.ts": 3187, - "1028-async-return-record-literals.ts": 53064, - "1029-async-eager-chains.ts": 5109, - "103-ternary.ts": 4538, - "104-ternary-empty-arrays.ts": 50460, - "1050-comptime-tables.ts": 7149, - "1051-comptime-strings.ts": 4737, - "1052-comptime-records.ts": 37872, - "1053-comptime-json.ts": 4779, - "1054-comptime-modules/main.ts": 7660, - "110-number-radix.ts": 4935, - "111-record-entries.ts": 7207, - "1110-math-members.ts": 4805, - "1111-math-random.ts": 5313, - "1113-string-methods.ts": 39688, - "1114-string-unicode-island.ts": 61280, - "1115-parse-globals.ts": 4273, - "1116-island-static-mix.ts": 58945, - "1117-typeof-static-union.ts": 4726, - "1118-object-spread-conditional.ts": 5790, - "1119-switch-union.ts": 3967, - "112-class-descriptor-key.js": 6359, - "1121-infinity-number-tostring.ts": 6448, - "1122-any-captures.ts": 5744, - "1124-union-narrowed-retag.ts": 48623, - "113-promise-checked-exits.ts": 5906, - "114-live-record-delete.ts": 5041, - "115-array-compound.js": 45694, - "116-text-decoder-runtime.js": 42554, - "117-weak-cache-cycle.js": 4096, - "118-fs-stored-callbacks.cjs": 67405, - "119-native-patterns.js": 6976, - "1200-regex-test-basics.ts": 59964, - "1201-regex-replace.ts": 59629, - "1202-regex-substitutions.ts": 64765, - "1203-regex-split.ts": 40181, - "1204-regex-empty-unicode.ts": 4019, - "1205-regex-rc-stress.ts": 6786, - "1300-errors-basics.ts": 4602, - "1301-errors-subclass.ts": 4547, - "1302-errors-typed-catch.ts": 5456, - "1303-errors-rc-stress.ts": 3915, - "1304-errors-uncaught.ts": 4301, - "1305-errors-async-rejections.ts": 25668, - "1306-errors-runtime-instances.ts": 56774, - "1350-path-normalize-join.ts": 4099, - "1351-path-parts.ts": 3517, - "1352-path-resolve-relative.ts": 4602, - "1353-os-basics.ts": 4075, - "1354-builtin-bare-specifiers.ts": 4565, - "1355-url-parse.ts": 3650, - "1356-url-file-bridge.ts": 5481, - "1357-fsp-roundtrip.ts": 4525, - "1358-crypto-random.ts": 3809, - "1359-json-module/main.ts": 4642, - "1360-spawn-sync.ts": 14534, - "1361-spawn-events.ts": 3384, - "1362-spawn-timers.ts": 9556, - "1363-spawn-unhandled-error.ts": 3577, - "1364-union-truthiness.ts": 4455, - "1365-union-logical.ts": 5263, - "1366-union-equality.ts": 5404, - "1367-destructuring.ts": 6097, - "1368-constructor-functions.ts": 4502, - "1369-promise-union.ts": 5171, - "1370-spread.ts": 5455, - "1371-union-template-tostring.ts": 5704, - "1372-loose-null-tests.ts": 4863, - "1373-union-array-arms.ts": 6061, - "140-bitwise-operators.ts": 5704, - "1400-typedarray-basics.ts": 4417, - "1401-typedarray-slice-set.ts": 6150, - "1402-buffer-encodings.ts": 6652, - "1403-buffer-fs.ts": 4712, - "1404-zlib-crypto-bytes.ts": 8302, - "1405-bytes-unions-arrays.ts": 4908, - "1406-dataview-mp4.ts": 4190, - "1407-dataview-bounds.ts": 5248, - "1408-string-indexing.ts": 6549, - "1409-typedarray-integer-loops.ts": 5748, - "1420-number-statics.ts": 4080, - "1421-number-parse-strings.ts": 3030, - "1422-date-iso.ts": 4656, - "1423-text-codec.ts": 42827, - "1424-fs-options.ts": 4763, - "1425-stdin-tty.ts": 3515, - "1426-stdin-read.ts": 4428, - "1427-fromcharcode-lastindexof.ts": 4393, - "1428-settled-await-order.ts": 3638, - "1429-promise-catch-finally.ts": 6438, - "1430-promise-race.ts": 5872, - "1431-caught-tostring.ts": 4401, - "1432-destructured-params.ts": 3887, - "1433-filter-narrow.ts": 5268, - "1434-async-never.ts": 3971, - "1435-math-spread.ts": 5075, - "1436-default-undef-param.ts": 4896, - "1437-pad-default.ts": 5306, - "1438-promise-all.ts": 8026, - "1440-interval-basics.ts": 3886, - "1441-interval-clear-cross.ts": 8806, - "1442-interval-throw.ts": 3908, - "1443-signal-handlers.ts": 10098, - "1444-exit-listeners.ts": 6271, - "1445-exit-process-exit.ts": 6288, - "1446-exit-uncaught.ts": 4829, - "1447-stdin-closed-events.ts": 5308, - "1448-stream-columns.ts": 3842, - "1450-incdec-expression.ts": 4062, - "1451-instanceof-uint8array-unknown.ts": 4913, - "1452-return-through-finally.ts": 3940, - "1453-pmap-settled.ts": 5769, - "1454-nonnull-narrow-and-fcc-bytes.ts": 5066, - "1455-lambda-union-return-adoption.ts": 4687, - "1460-console-error-warn.ts": 4173, - "1461-process-pid-getuid-kill.ts": 3798, - "1462-exec-sync.ts": 4955, - "1463-timeout-unref.ts": 3605, - "1464-env-writes.ts": 3898, - "1465-env-value.ts": 5166, - "1466-child-containers.ts": 4567, - "1467-string-match.ts": 31065, - "1468-exec-path.ts": 3971, - "1469-remove-listener.ts": 5771, - "1470-child-lifecycle.ts": 4259, - "1471-child-unref.ts": 8596, - "1472-errno-code.ts": 3697, - "1473-promisify-execfile.ts": 5268, - "1474-string-decoder.ts": 4402, - "1475-readline-closed-stdin.ts": 7198, - "1476-assign-expression.ts": 4160, - "1477-in-expressions.ts": 3377, - "1478-promise-reject.ts": 4766, - "1479-destructuring-assign.ts": 3620, - "1480-os-network-interfaces.ts": 5191, - "1481-string-case-static.ts": 47079, - "1482-spawnsync-error.ts": 4222, - "1483-array-slice.ts": 37812, - "1520-fs-wider-surface.ts": 4505, - "1520-string-split-static.ts": 5103, - "1521-fs-lstat-lock.ts": 4862, - "1521-string-trim-pad-static.ts": 4149, - "1522-parseint-static.ts": 3342, - "1522-spawnsync-options.ts": 6589, - "1523-isnan-floor-static.ts": 4386, - "1523-spawn-options.ts": 4864, - "1524-atomics-sleep-static.ts": 5554, - "1524-catch-narrowing.ts": 4776, - "1525-child-exit-signal.ts": 3419, - "1525-unknown-typeof-validation.ts": 4171, - "1526-set-spread.ts": 6387, - "1527-logical-mixed-operands.ts": 56825, - "1528-delete-records-env.ts": 3989, - "1529-class-with-statics.ts": 4851, - "1530-array-push-variadic.ts": 4575, - "1530-spread-override-completion.ts": 4651, - "1531-delete-optional-fields.ts": 5027, - "1531-process-arch-versions.ts": 4345, - "1532-array-splice-shift.ts": 5472, - "1532-union-shared-field-read.ts": 4768, - "1533-bool-equality.ts": 4449, - "1533-path-platform-namespaces.ts": 3877, - "1534-crypto-hash-chain.ts": 4113, - "1534-union-as-arm-cast.ts": 3510, - "1535-spawn-fd-stdio.ts": 3466, - "1535-union-param-defaults.ts": 3648, - "1536-destructuring-defaults.ts": 3985, - "1536-string-array-sweep.ts": 4779, - "1537-chalk-hybrid/main.ts": 4311, - "1537-os-release-spawnsync-stdio.ts": 3803, - "1538-await-promiselike-return.ts": 4183, - "1538-math-static-scalar.ts": 4776, - "1539-readonly-set-map.ts": 4240, - "1539-unknown-truthiness.ts": 3925, - "1540-os-userinfo.ts": 3976, - "1540-void-statement.ts": 3920, - "1541-fs-readdir-dirent.ts": 6148, - "1541-union-keyed-reads.ts": 5049, - "1542-map-promise-values.ts": 4830, - "1542-record-literal-into-union.ts": 4691, - "1543-rest-destructuring.ts": 4682, - "1543-set-server-handles.ts": 11403, - "1544-dyn-json-reads.ts": 5540, - "1544-string-matchall.ts": 4621, - "1545-spread-order-and-optional.ts": 4810, - "1546-union-element-reads.ts": 4735, - "1547-computed-key-fold.ts": 4346, - "1548-boolean-condition-forms.ts": 4311, - "1549-array-isarray-unions.ts": 4783, - "1550-param-defaults-func-set.ts": 4654, - "1551-dyn-receiver-methods.ts": 47581, - "1552-exec-options-record.ts": 4931, - "1553-truthy-hof-predicates.ts": 3759, - "1554-caught-into-unknown.ts": 4792, - "1555-index-spread-into-declared.ts": 5295, - "1556-union-retag-width-arms.ts": 4339, - "1557-url-host.ts": 4062, - "1558-any-joins-and-dyn-validation.ts": 4201, - "1559-conditional-spread-index-merge.ts": 4811, - "1560-forof-homogeneous-tuples.ts": 3801, - "1561-forof-strings.ts": 4569, - "1561-promise-then.ts": 5688, - "1562-optional-chain-tails.ts": 4544, - "1562-spawn-conditional-spread.ts": 5015, - "1563-forof-iterator-projections.ts": 3931, - "1563-string-raw-fold.ts": 2934, - "1564-fs-watch.ts": 4633, - "1564-string-raw.ts": 4462, - "1565-spawn-pipe-streams.ts": 4825, - "1565-union-element-join.ts": 4303, - "1566-child-duck-interface.ts": 3784, - "1567-server-close-override.ts": 8452, - "1568-x509-fingerprint.ts": 4642, - "1569-fsp-mkdir-unlink-chmod.ts": 4604, - "1570-child-unref-kill-reffed.ts": 10519, - "1571-optional-call-tostring-tail.ts": 4149, - "1571-stdin-set-raw-mode-non-tty.ts": 3975, - "1572-promise-reject-all-tuple.ts": 4421, - "1572-x509-validity-date-gettime.ts": 3928, - "1573-promisify-execfile-env-spread.ts": 4371, - "1573-tdz-scalar-forward-capture.ts": 3510, - "1574-dyn-optional-method-number-keys.ts": 5406, - "1574-promise-all-tuple-literal.ts": 4446, - "1575-unknown-assert-into-record.ts": 4160, - "1576-width-coercions.ts": 4905, - "1577-url-hostname.ts": 3830, - "1578-exec-input-optional.ts": 4111, - "1579-matchall-index.ts": 3935, - "1580-exec-env-conditional-spread.ts": 4157, - "1581-declare-const-read.ts": 4532, - "1582-timer-sleep-resolve.ts": 5668, - "1583-loops-and-stream-captures.ts": 4447, - "1584-union-field-unassigned.ts": 4778, - "1585-union-field-conditional-ctor.ts": 4205, - "1586-derived-field-before-super-init.ts": 4167, - "1590-js-unannotated.js": 4511, - "1591-js-closures.js": 4889, - "1592-js-classes.js": 7239, - "1593-js-jsdoc-records.js": 5280, - "1594-js-async.js": 3437, - "1595-js-island-gap/main.js": 3858, - "1596-cjs-modules/main.js": 3826, - "1597-mjs-graph/main.mjs": 4207, - "1598-cjs-builtin-require/main.js": 4782, - "1599-js-uncaught-throw.js": 3029, - "1600-assert-passing.ts": 4584, - "1601-assert-fail-exit.ts": 5710, - "1602-assert-caught-error.ts": 5606, - "1603-assert-scalar-messages.ts": 6055, - "1604-assert-deep-structures.ts": 4164, - "1605-assert-import-forms.ts": 4744, - "1606-assert-strict-module.ts": 3846, - "1607-assert-throws-match.ts": 3634, - "1608-cjs-assert/main.js": 22902, - "1609-assert-async.ts": 5276, - "1610-path-win32-full.ts": 4297, - "1611-url-file-bridge-neutral.ts": 4511, - "1612-cjs-module-globals.cjs": 4120, - "1613-cjs-esm-proxy-named/main.mjs": 4168, - "1614-js-fence-dodges.cjs": 5147, - "1615-cjs-export-shapes/main.cjs": 5790, - "1616-cjs-esm-lexer-invisible/main.mjs": 3074, - "1617-cjs-esm-lexer-visible/main.mjs": 4703, - "1618-cjs-esm-poisoned-tail/main.mjs": 4175, - "1619-cjs-esm-reexport-invisible/main.mjs": 3250, - "1620-cjs-require-effects-order/main.js": 4047, - "1621-cjs-require-cache-hit/main.js": 3190, - "1622-cjs-require-conditional/main.js": 4002, - "1623-cjs-require-diamond/main.js": 3383, - "1624-cjs-require-dir-mid-file/main.js": 4621, - "1625-cjs-require-lazy-fn/main.js": 4138, - "1626-cjs-require-mjs/main.js": 3518, - "1627-mjs-import-cjs-requires/main.mjs": 4705, - "1628-checked-dynamic-builtin-args.cjs": 4815, - "1629-require-main-filename.cjs": 3830, - "1630-inspect-scalars.ts": 3402, - "1630-rmsync-retry-options.cjs": 4168, - "1631-inspect-arrays.ts": 5636, - "1632-inspect-records.ts": 5322, - "1633-inspect-map-set.ts": 4905, - "1634-inspect-classes.ts": 50857, - "1635-inspect-buffer.ts": 3662, - "1636-util-format.ts": 3856, - "1637-inspect-dyn.ts": 4713, - "1638-inspect-cjs.cjs": 4782, - "1639-versions-openssl-probe.ts": 3624, - "1640-fd-read-decode.ts": 4777, - "1641-string-search.ts": 42621, - "1642-object-fromentries-rows.ts": 3842, - "1643-metadata-dyn-return.cjs": 6131, - "1644-ee-basics.ts": 4824, - "1645-ee-extends.ts": 4269, - "1646-ee-once-remove.ts": 5597, - "1647-ee-meta-events.ts": 4609, - "1648-ee-error-event.ts": 3894, - "1649-ee-names-counts.ts": 3445, - "1650-ee-prepend.ts": 5882, - "1651-ee-max-listeners.ts": 3513, - "1652-ee-snapshot.ts": 3828, - "1653-ee-cjs.cjs": 5160, - "1654-ee-namespace.ts": 4086, - "1655-spawnsync-neutral.ts": 5575, - "1656-execsync-neutral.ts": 5201, - "1657-spawn-async-neutral.ts": 4183, - "1660-buffer-read-write-num.ts": 4602, - "1661-buffer-encodings-full.ts": 4532, - "1662-string-decoder-encodings.ts": 4447, - "1663-buffer-compare-search-fill.ts": 6507, - "1664-dyn-fn-boundary.cjs": 3753, - "1665-dyn-fn-mustcall/main.cjs": 3637, - "1666-dyn-fn-identity.ts": 4113, - "1667-dyn-fn-not-callable.cjs": 5226, - "1668-dyn-fn-throws.cjs": 3927, - "1669-symbol-identity.ts": 5374, - "1670-symbol-registry.ts": 5422, - "1671-symbol-typeof.ts": 5011, - "1672-symbol-containers.ts": 6131, - "1673-symbol-cjs.cjs": 3807, - "1674-symbol-inspect.ts": 4101, - "1676-func-array-surface.ts": 3917, - "1677-emitter-listeners.ts": 5384, - "1678-emitter-dyn-listeners.cjs": 6837, - "1679-console-dyn.js": 5132, - "1680-assert-bytes.ts": 5780, - "1681-assert-funcs.ts": 4542, - "1685-stream-readable-basics.ts": 6799, - "1686-stream-readable-paused.ts": 7460, - "1687-stream-readable-flow-control.ts": 6103, - "1688-stream-writable-basics.ts": 8189, - "1689-stream-writable-async-drain.ts": 6061, - "1690-stream-duplex.ts": 8154, - "1691-stream-transform.ts": 8459, - "1692-stream-pipe.ts": 8943, - "1693-stream-pipe-backpressure.ts": 7445, - "1694-stream-destroy.ts": 4337, - "1695-stream-props.ts": 4409, - "1696-stream-read-inside-read.ts": 4780, - "1697-stream-tick-vs-timer.ts": 4369, - "1698-stream-uncaught-error.ts": 9453, - "1699-stream-callback-shapes.ts": 6489, - "1700-mustcall-common/main.cjs": 5513, - "1701-mustcall-exit-report/main.cjs": 5169, - "1702-dyn-proto-dispatch.cjs": 3843, - "1703-arguments-rest-props.cjs": 5139, - "1710-cjs-export-class/main.js": 4603, - "1711-cjs-export-single-values/main.js": 4271, - "1712-field-incdec.ts": 4369, - "1713-js-dyn-fields.js": 3948, - "1720-assert-throws-shape.ts": 4422, - "1721-assert-throws-regex-class.ts": 3508, - "1722-assert-rejects.ts": 4110, - "1723-assert-does-not-reject.ts": 4852, - "1724-assert-iferror.ts": 5098, - "1725-assert-symbols.ts": 4520, - "1726-promise-with-resolvers.ts": 4144, - "1727-assert-throws-shape-exit.ts": 4544, - "1730-countdown-symbol-keys/main.js": 4981, - "1731-symbol-field-shapes.cjs": 4983, - "1732-symbol-field-cross-module/main.js": 6365, - "1740-stream-extends-readable.ts": 4706, - "1741-stream-extends-writable.ts": 8537, - "1742-stream-extends-duplex-transform.ts": 8628, - "1743-stream-extends-vt-dispatch.ts": 7490, - "1744-stream-set-encoding.ts": 3923, - "1745-stream-encoding-js.cjs": 3912, - "1746-stream-for-await.ts": 5266, - "1747-stream-for-await-js.cjs": 9157, - "1750-http-agent-options.ts": 4824, - "1751-options-record-stance.ts": 4860, - "1760-surplus-args-drop.cjs": 3596, - "1761-emitter-special-event-names.cjs": 5408, - "1770-assert-dyn-strict.ts": 4549, - "1771-assert-dyn-deep.ts": 4653, - "1772-assert-dyn-js.cjs": 4842, - "1773-assert-dyn-exit.ts": 3322, - "1780-http-res-surface.ts": 7900, - "1781-http-server-shapes.cjs": 5025, - "1790-computed-key-folds.ts": 4472, - "1791-searchparams-core.ts": 3100, - "1792-searchparams-encoding.ts": 4024, - "1793-searchparams-iteration.ts": 2933, - "1794-searchparams-url-live.ts": 2969, - "1795-dyn-handle-request.cjs": 8538, - "1796-dyn-handle-body.cjs": 8773, - "1797-dyn-handle-socket.cjs": 5230, - "1798-dyn-handle-typed-box.ts": 9154, - "1800-immediate-basics.ts": 3918, - "1801-immediate-handle.ts": 3182, - "1802-immediate-unref-exit.ts": 3903, - "1803-timeout-refresh.ts": 3243, - "1804-timers-module.ts": 3435, - "1805-timer-callback-args.ts": 3958, - "1806-timer-delay-trunc.ts": 4233, - "1810-stream-options-const-record.ts": 3952, - "1811-stream-option-value-callbacks.cjs": 4066, - "1812-stream-super-options-forwarding.cjs": 8532, - "1813-stream-finished.ts": 3971, - "1814-stream-pipeline.cjs": 4413, - "1815-stream-state-reads.cjs": 4085, - "1820-static-block-basics.ts": 3479, - "1821-static-block-order.ts": 4110, - "1822-static-block-js.js": 3095, - "1823-static-instance-method-names.ts": 3531, - "1824-for-of-destructuring-defaults.ts": 3925, - "1825-exhaustive-typeof-switch.ts": 3439, - "1826-settimeout-arguments-callback.js": 3758, - "1830-enum-numeric-basics.ts": 3846, - "1831-enum-string-const-reverse.ts": 3347, - "1832-enum-modules/main.ts": 3603, - "1835-var-basics.ts": 3009, - "1836-var-loop-capture.ts": 4162, - "1837-var-undefined-hoisting.ts": 3457, - "1838-var-modules/main.ts": 4306, - "1839-var-js/main.cjs": 4870, - "1840-jsdoc-import-type-only/main.js": 3497, - "1850-overload-basics.ts": 4398, - "1851-overload-return-narrowing.ts": 3452, - "1852-overload-class-members.ts": 3733, - "1853-overload-modules/main.ts": 3524, - "1854-ambient-declare-fn.ts": 4169, - "1855-ambient-declare-fn-uncaught.ts": 2640, - "1870-unit-type-values.ts": 4848, - "1871-empty-array-never.ts": 3051, - "1872-template-tostring-composite.ts": 3835, - "1880-json-declared-field-order.ts": 5173, - "1881-default-anon/main.ts": 3809, - "1882-default-cjs-interop/main.ts": 3893, - "1883-default-exports/main.ts": 4076, - "1890-ns-imports/main.ts": 3441, - "1891-ns-reexport/main.ts": 3946, - "1940-class-values-basics.ts": 3823, - "1941-class-values-registry.ts": 3834, - "1942-class-expressions.ts": 3250, - "1943-class-statics-expanded.ts": 3491, - "1944-class-values-modules/main.ts": 3807, - "1950-generic-fn-values.ts": 4479, - "1951-generic-classes-basics.ts": 4288, - "1952-generic-class-statics-values.ts": 4461, - "1953-generic-class-hierarchy.ts": 2769, - "1954-generic-modules/main.ts": 4012, - "1960-namespace-basics.ts": 4063, - "1961-namespace-nested.ts": 4436, - "1962-namespace-classes.ts": 3835, - "1963-namespace-aliases.ts": 4480, - "1964-namespace-type-only.ts": 4245, - "1965-namespace-ambient.ts": 3646, - "1966-namespace-modules/main.ts": 3158, - "1967-namespace-alias-typeonly.ts": 2894, - "1968-namespace-import-eq-snapshot.ts": 4133, - "1970-decorators-basics.ts": 5269, - "1971-decorators-rebinding.ts": 4674, - "1972-decorators-throwing.ts": 3103, - "1973-decorators-ambient.ts": 3465, - "1980-primitive-proto-statics.ts": 4370, - "1981-date-utc.ts": 3865, - "1982-freeze-resolve-passthrough.ts": 4409, - "1983-array-tuple-surfaces.ts": 4749, - "1990-labels-basics.ts": 3921, - "1991-for-in-loops.ts": 4875, - "1992-small-syntax.ts": 4940, - "200-strings.ts": 2950, - "2000-generic-methods-basic.ts": 19968, - "2001-generic-methods-generic-class.ts": 3103, - "2002-generic-methods-inheritance.ts": 4643, - "2003-generic-methods-object-literal.ts": 4397, - "2004-generic-methods-statics.ts": 2813, - "201-templates.ts": 3364, - "2010-generators-basics.ts": 4186, - "2011-generators-forof.ts": 4950, - "2012-generators-return-throw.ts": 4210, - "2013-generators-sent-values.ts": 4475, - "2014-generators-values.ts": 4791, - "2015-generators-yieldstar.ts": 3849, - "2016-generators-rc-stress.ts": 4017, - "2017-generators-async.ts": 4735, - "2018-generators-uncaught.ts": 4005, - "2019-generators-loops.ts": 2646, - "2020-generic-value-bindings.ts": 4401, - "2021-generic-value-binding-modules/main.ts": 3358, - "2022-width-index-capture.ts": 3719, - "2023-width-readonly.ts": 3719, - "2024-width-array-elems.ts": 3231, - "2025-width-union-compose.ts": 3698, - "2026-width-spread.ts": 3241, - "2030-width-nested.ts": 4055, - "2031-width-tuples.ts": 3342, - "2032-cjs-export-assigned-class-expression/main.cjs": 3882, - "2033-property-assigned-class-extends.cjs": 3781, - "2035-ternary-array-retag.cjs": 3818, - "2036-evolving-array-decl.cjs": 4090, - "2037-fn-decl-hoisting.cjs": 3678, - "2038-evolving-array-js.cjs": 5045, - "2040-any-bindings.ts": 3791, - "2040-mixin-heritage.ts": 4699, - "2041-any-params-returns.ts": 3681, - "2041-mixin-values.ts": 4051, - "2042-any-flow-loops.ts": 3594, - "2042-mixin-modules/main.ts": 4173, - "2043-any-dom-values.ts": 2471, - "2043-mixin-rc-stress.ts": 4344, - "2044-vtable-sibling-slots.ts": 3559, - "2045-objlit-accessors-basic.ts": 3871, - "2045-parameter-properties.ts": 4491, - "2046-abstract-classes.ts": 5595, - "2046-objlit-accessors-effects.ts": 2807, - "2047-objlit-accessors-shapes.ts": 3455, - "2047-optional-class-fields.ts": 5630, - "2050-dynamic-import-own-module/main.ts": 3193, - "2051-dynamic-import-then/main.ts": 4043, - "2052-dynamic-import-self.ts": 4058, - "2053-typeof-static-fold.ts": 3537, - "2054-destructuring-island-source.ts": 3138, - "2060-empty-tuple.ts": 3805, - "2070-computed-key-folds.ts": 4750, - "2071-integer-key-enumeration-order.ts": 3546, - "2072-expando-function-members.ts": 4747, - "2073-destructuring-assignment.ts": 3553, - "2074-island-destructuring.ts": 4229, - "2075-index-signature-runtime-keys.ts": 5005, - "2080-destructuring-defaults.ts": 4463, - "2081-destructuring-rest.ts": 3264, - "2082-destructuring-assignment.ts": 4012, - "2085-destructuring-heads-rest-params.ts": 3930, - "2087-destructuring-for-heads.ts": 3872, - "2090-index-signature-number-keys.ts": 4103, - "2091-index-signature-string-intersection.ts": 3918, - "2092-package-imports/main.ts": 3799, - "2093-timers-promises.ts": 3870, - "2094-diagnostics-channel.ts": 4547, - "2095-js-catch-unknown.js": 4236, - "2096-os-type.ts": 3673, - "2097-js-evolving-globals.js": 3604, - "210-string-methods.ts": 3491, - "2100-stream-default-hwm.ts": 6786, - "2101-dyn-param-defaults.ts": 2902, - "2102-empty-pattern-decls.ts": 2680, - "2105-computed-key-static-folds.ts": 4156, - "2106-comma-expressions.ts": 4616, - "211-string-unicode.ts": 3897, - "2110-top-object-types.ts": 3870, - "2111-json-stringify-unknown.ts": 4435, - "2112-array-at-findlast.ts": 4707, - "2113-string-index-methods.js": 3454, - "212-string-aliasing-append.ts": 3894, - "2120-package-self-import/main.ts": 2683, - "2121-esm-cycle-inert-backedge/main.ts": 2391, - "2123-ambient-import-crash/main.ts": 3826, - "2124-imports-field-wildcard/main.ts": 4011, - "2140-uri-component-codecs.ts": 4495, - "2160-dc-tracing-channel.cjs": 5323, - "2161-js-object-literal-identity.cjs": 4357, - "2162-js-dyn-destructure.cjs": 3222, - "2163-js-selfref-const.cjs": 3731, - "2164-js-then-dyn-handler.cjs": 3928, - "2165-js-throw-dyn.cjs": 3594, - "2166-cjs-getter-this/main.cjs": 2580, - "2170-island-array-exits.ts": 5872, - "2171-island-json-stringify.ts": 3235, - "2172-island-regexp-boundary.ts": 4811, - "2190-new-object-and-string-wrappers.ts": 3881, - "2191-uri-encoders.ts": 2785, - "2192-object-default-tostring.ts": 3767, - "2193-discarded-stdlib-reads.ts": 2753, - "2194-ambient-undef-chains.ts": 3966, - "2195-require-missing-package/main.mjs": 3949, - "2196-island-computed-key-chain.ts": 3859, - "2210-dyn-promise-crossing.cjs": 5056, - "2211-dc-trace-promise.cjs": 4674, - "2212-unhandled-rejection-listener.cjs": 3832, - "2213-async-local-storage.cjs": 4800, - "2214-dc-bind-store.cjs": 4857, - "2215-process-emit-warning-exit.cjs": 4319, - "2240-width-class-into-record.ts": 4526, - "2241-width-record-into-class.ts": 3828, - "2242-width-statics-into-record.ts": 3590, - "2243-width-assert-satisfies-shapes.ts": 4657, - "2250-tagged-templates.ts": 3291, - "2252-class-iterators.ts": 4007, - "2253-union-coercions.ts": 2990, - "2260-http2-constants.cjs": 3422, - "2280-builtin-namespace-destructure.cjs": 3322, - "2281-domexception-atob-btoa.cjs": 3717, - "2282-queue-microtask.cjs": 4471, - "2283-structured-clone.cjs": 6184, - "2284-regexp-constructor.cjs": 3737, - "2285-iferror-dyn.cjs": 3898, - "2286-dyn-object-walks.cjs": 3663, - "2300-dyn-record-spread-and-keyed-access.cjs": 3720, - "2301-cjs-export-table-dom-attach.cjs": 3384, - "2310-process-next-tick.ts": 5910, - "2311-next-tick-js-callbacks.js": 2877, - "2312-stream-underscore-assign.ts": 8104, - "2313-stream-underscore-assign-js.cjs": 4045, - "2314-process-introspection.ts": 4555, - "2320-await-unit.ts": 3726, - "2321-emitter-static-setmax.cjs": 4139, - "2322-dyn-array-sort.cjs": 3726, - "2323-timer-callback-returns.ts": 3622, - "2330-tls-server-runtime-options.cjs": 27710, - "2331-tls-server-options-typed.ts": 27128, - "2350-nan-global.ts": 4123, - "2351-async-methods.ts": 4008, - "2352-void-coercions.ts": 4044, - "2353-decorators-member-ambient.ts": 3507, - "2354-decorators-expression-ambient.ts": 3756, - "2360-tuple-to-array.ts": 3301, - "2361-assign-index-record.ts": 4658, - "2362-execsync-inherit.ts": 3671, - "2363-nullish-retag.ts": 4322, - "2364-in-runtime-key.ts": 3872, - "2365-dyn-into-island.ts": 4202, - "2366-string-well-formed.ts": 4097, - "2367-regexp-escape.ts": 2500, - "2368-set-methods.ts": 4362, - "2369-promise-try.ts": 4105, - "2370-group-by.ts": 5234, - "2371-iterator-helpers.ts": 3705, - "2380-buffer-module-named-import.ts": 3866, - "2381-builtin-default-imports.js": 3690, - "2382-cycle-two-decl/main.ts": 3053, - "2383-cycle-assertdoc/main.js": 3424, - "2384-cycle-mixed-bindings/main.ts": 3805, - "2385-builtin-reexport-facade/main.ts": 3157, - "2386-string-to-chars.ts": 3939, - "2387-tonumber-argv.ts": 2788, - "2388-tonumber-grammar-zoo.ts": 3308, - "2389-tonumber-unary-plus.ts": 4585, - "2390-dot-requires/main.cjs": 3582, - "2391-default-builtin-imports/main.ts": 3597, - "2392-block-guard-alias-scope.ts": 3540, - "2393-loop-exit-guard-narrow.ts": 4327, - "2394-loop-narrow-containment.ts": 3359, - "2395-while-cond-guard.ts": 3736, - "2396-born-narrowed-decl.ts": 3669, - "2397-branch-kill-merge.ts": 3852, - "2398-switch-arm-kill.ts": 3957, - "2399-reassign-kill-polarity.ts": 3597, - "240-stdout-write.ts": 2582, - "2400-kill-return-edge.ts": 3990, - "2401-kill-break-staging.ts": 3661, - "2402-labeled-break-kill.ts": 3719, - "2403-kill-continue-backedge.ts": 3491, - "2404-kill-throw-catch.ts": 3664, - "2405-sibling-arm-narrow.ts": 3896, - "2406-switch-clause-sibling-narrow.ts": 3538, - "2407-infinite-loop-seal.ts": 3968, - "2408-loop-terminality-reopen.ts": 3262, - "2409-loop-body-return-not-terminal.ts": 3183, - "2410-stacked-cases-terminality.ts": 4213, - "2411-exhaustive-switch-terminality.ts": 4119, - "2412-dowhile-guard-trailing-test.ts": 2693, - "2413-dowhile-kill-renarrow.ts": 3480, - "2414-dowhile-continue-kill.ts": 3748, - "2415-dowhile-break-trailing-test.ts": 3696, - "2416-spread-ternary-positions.ts": 3541, - "2417-ternary-local-inference.ts": 4012, - "2418-wrapped-ternary-arms.ts": 3646, - "2419-selector-ternary-union.ts": 4650, - "2420-nullish-null-identity.ts": 4115, - "2421-float-lane-inference.ts": 3944, - "2422-ieee-div-rem-corners.ts": 4159, - "2423-param-null-reassign.ts": 2605, - "2424-ternary-miss-first-narrowing.ts": 4261, - "2425-elseif-head-exit-narrow.ts": 2714, - "2426-default-snapshot-mutable/main.ts": 3509, - "2427-perf-hooks-now.ts": 3643, - "2428-field-redeclare-inherited.ts": 3729, - "2429-destructure-class-instance.ts": 3764, - "2430-empty-literal-unknown-field.js": 3619, - "2431-primitive-ctor-values.ts": 2975, - "2432-generic-member-fields-async.ts": 3894, - "2433-as-const-command-tables.ts": 4279, - "2434-deferred-init-fields.ts": 3904, - "2435-loose-same-kind-equality.ts": 2449, - "2440-console-inspect-args.ts": 4983, - "2441-console-process-argv.ts": 3366, - "2442-union-literal-arm-widening.ts": 3510, - "2443-union-literal-shadow-narrowing.ts": 4296, - "2444-union-literal-reducer-spread.ts": 4322, - "2445-math-minmax-nary.ts": 4287, - "2446-performance-global.ts": 2765, - "2447-island-boundary-slots/main.ts": 30163, - "2448-entries-null-arms-regex-arrays.ts": 5050, - "2450-private-instance-methods.ts": 3745, - "2451-private-fields.ts": 4055, - "2452-private-statics.ts": 4122, - "2453-private-accessors.ts": 3729, - "2454-private-generator-methods.ts": 4591, - "2455-private-brand-checks.ts": 3790, - "2456-private-async-methods.ts": 4068, - "2457-private-members.js": 3733, - "2460-qs-parse-grammar.ts": 4511, - "2461-qs-parse-options.ts": 5074, - "2462-qs-stringify.ts": 5146, - "2463-qs-escape-unescape.ts": 4740, - "2464-qs-require-forms.cjs": 3706, - "2470-mockable-module-shape.js": 4001, - "2471-record-keyed-write-hasown.js": 4306, - "2472-string-regexp-union.ts": 4333, - "2473-option-table-widths.js": 4080, - "2474-island-literal-forms.ts": 3640, - "2475-variadic-wrapper-island.js": 3607, - "2476-map-regex-values.ts": 3840, - "2480-recursive-record-tree.ts": 3961, - "2481-mutual-recursive-records.ts": 3629, - "2482-recursive-union-tree.ts": 3442, - "2483-recursive-record-cycles.ts": 3728, - "2484-json-stringify-circular.ts": 3926, - "2485-inspect-circular-refs.ts": 4207, - "2486-recursive-record-boundaries.ts": 3631, - "2487-recursive-deep-equal.ts": 4488, - "2488-ast-walker.ts": 3489, - "2490-find-miss-null-compare.ts": 3128, - "2491-strict-unit-compare-no-arm.ts": 3378, - "2492-loose-null-compare-unions.ts": 3406, - "2493-switch-unit-cases.ts": 4046, - "2494-no-arm-compare-effects.ts": 3576, - "2500-net-autosel-timeout.ts": 6361, - "2510-dyn-evolving-array-map.ts": 4082, - "2511-dyn-evolving-array-filter-foreach.ts": 4487, - "2512-dyn-evolving-array-mixed-push.ts": 3602, - "2520-private-statics-class-name-calls.ts": 3443, - "2521-private-statics-class-expression.ts": 4261, - "2522-private-statics-decorated.ts": 3872, - "2523-private-statics-aliased-class.ts": 3793, - "2530-object-destructuring-decl.ts": 3717, - "2531-array-tuple-destructuring-decl.ts": 4697, - "2532-param-destructuring-options.ts": 4524, - "2533-forof-destructuring.ts": 4725, - "2534-object-rest-decl.ts": 4160, - "2535-destructuring-assign-basics.ts": 3008, - "2536-destructuring-assign-nested.ts": 3971, - "2537-destructuring-assign-member-targets.ts": 4117, - "2538-destructuring-assign-class-source.ts": 3926, - "2539-class-instance-rest.ts": 3983, - "2540-accessor-destructuring-defaults.ts": 2587, - "2541-destructuring-eval-order.ts": 4204, - "2550-generics-keyof-pick.ts": 4104, - "2551-generics-value-aliases.ts": 3651, - "2552-generics-iface-methods.ts": 3134, - "2553-generics-signature-bindings.ts": 4036, - "2554-generics-frontier-mix.ts": 4173, - "2555-generics-keyof-writes.ts": 3734, - "2556-crypto-introspection.ts": 3814, - "2556-width-hybrid-shapes.ts": 4554, - "2557-tls-ca-store.ts": 4247, - "2557-width-field-lifts.ts": 3310, - "2558-index-signature-func-values.ts": 3316, - "2558-rejection-events.cjs": 3816, - "2559-index-signature-container-values.ts": 4363, - "2560-arraybuffer-dataview-set.ts": 4259, - "2561-object-is.ts": 3615, - "2562-intl-numberformat-en-us.ts": 4400, - "2563-stream-promises-pipeline.ts": 3735, - "2564-stream-promises-finished.ts": 8470, - "2565-stream-promises-js.cjs": 4670, - "2566-promise-reject-dyn-reason.js": 3862, - "2567-rest-spread-forward.js": 4241, - "2568-rest-spread-forward-dynamic.js": 3805, - "2569-upcast-identity.ts": 2741, - "2570-buffer-arg-validation.cjs": 5723, - "2571-searchparams-arg-validation.cjs": 4325, - "2572-readable-emitted-readable-flag.cjs": 3665, - "2573-fs-url-arg-ladders.cjs": 3433, - "2574-emitter-max-listeners-ladders.cjs": 4082, - "2575-string-destructuring-decl.ts": 4618, - "2576-string-destructuring-assign.ts": 4254, - "2577-builtin-global-destructuring.js": 3582, - "2578-jsval-into-unknown-rows.ts": 4068, - "2579-jsval-object-param-crossing.js": 4185, - "2580-jsval-routed-keyed-ops.js": 4278, - "2581-jsval-routed-calls.js": 4541, - "2582-jsval-object-statics.js": 4272, - "2582-jsval-routed-keyed-ops.js": 3765, - "2583-dyn-nullish-coalesce.js": 3622, - "2583-jsval-routed-calls.js": 4186, - "2584-jsval-object-statics.js": 3517, - "2584-union-dyn-collapse.ts": 5179, - "2585-dyn-nullish-coalesce.js": 4450, - "2585-unknown-array.ts": 4082, - "2586-object-assign-spread.js": 3285, - "2587-array-entries-forof.ts": 4350, - "2588-array-entries-chains.ts": 4523, - "2589-object-create-null.cjs": 4020, - "2590-object-create-dynamic.js": 3068, - "2591-ambient-generic-traps.ts": 4200, - "2592-ambient-trap-uncaught.ts": 3460, - "2593-generic-inert-bindings.ts": 3588, - "2594-nullish-generic-bindings.ts": 3726, - "2595-fs-arg-ladders.cjs": 6740, - "2596-net-arg-ladders.cjs": 6682, - "2597-dgram-send-ladders.cjs": 5257, - "2598-tls-arg-ladders.cjs": 28958, - "2599-stream-arg-ladders.cjs": 4068, - "2600-dyn-keyed-write-harness.js": 4122, - "2601-dyn-keyed-write-ops.js": 3049, - "2602-dyn-array-destructure.js": 3757, - "2603-island-keyed-write-dyn.js": 3437, - "2604-cycle-classes-mutual/main.ts": 3996, - "2605-cycle-three-module/main.ts": 3537, - "2606-dynamic-import-cycle/main.ts": 3810, - "2608-regex-named-groups.ts": 4091, - "2609-regex-named-replace.ts": 2758, - "2610-regex-named-matchall.ts": 4465, - "2611-regex-named-groups-js.cjs": 6008, - "2613-for-init-uninitialized-let.ts": 3817, - "2614-trap-binding-later-writes.ts": 4020, - "2615-nullish-field-record-binding.ts": 3220, - "2616-js-collect-probe-defers.js": 3633, - "2617-enum-static-field-import/main.ts": 3698, - "2618-ee-emit-override.ts": 2900, - "2619-ee-override-chain.ts": 3741, - "2620-ee-override-once-order.ts": 3799, - "2621-ee-override-error-throw.ts": 3035, - "2622-ee-override-filter.ts": 3418, - "2623-ee-job-queue.ts": 3306, - "2624-ee-override-js.cjs": 4196, - "2625-bytes-views.ts": 4141, - "2626-stream-event-names.ts": 5209, - "2627-stream-ticks-are-nextticks.ts": 3902, - "2628-stream-push-encodings.cjs": 3828, - "2629-stream-consumers.ts": 5554, - "2630-stream-consumers-errors.ts": 4330, - "2631-create-require/main.ts": 4336, - "2632-dyn-jsval-iterate.js": 4764, - "2633-island-promise-crossing.js": 5106, - "2634-stream-pipeline-arg-ladders.cjs": 3877, - "2635-trap-binding-unmappable-written.ts": 3449, - "2636-trap-binding-ambient-rooted-rewrite.ts": 4109, - "2637-create-require-bare/main.ts": 3645, - "2638-http-dyn-res-compat.cjs": 7173, - "2639-http-dyn-req-pause.cjs": 7147, - "2640-net-dyn-socket-compat.cjs": 5745, - "2641-http-agent-surface.cjs": 7414, - "2642-http-agent-maxsockets.cjs": 4580, - "2643-or-default-retag.ts": 4099, - "2644-http-client-url-argument.ts": 4758, - "2645-https-client-url-argument.ts": 45938, - "2646-top-level-await.ts": 3701, - "2647-top-level-await-modules/main.ts": 4075, - "2648-top-level-await-rejection.ts": 3331, - "2649-top-level-await-pending.ts": 3587, - "2650-top-level-await-self-import.ts": 3982, - "2651-top-level-await-pending-unhandled.ts": 3896, - "2652-top-level-await-dynamic/main.ts": 3670, - "2653-top-level-await-rejection-stops-loop.ts": 3674, - "2654-top-level-await-unrelated-rejection.ts": 4358, - "2655-top-level-await-cycle/main.ts": 3663, - "2656-top-level-await-cycle-order/main.ts": 3641, - "2657-top-level-await-cycle-dynamic/main.ts": 3605, - "2658-top-level-await-sync-completion/main.ts": 3738, - "2659-top-level-await-dynamic-cycle/main.ts": 3937, - "2660-top-level-await-cycle-rejection/main.ts": 3839, - "2661-top-level-await-dynamic-runtime-root/main.ts": 4277, - "2662-top-level-await-cycle-external-wait/main.ts": 3840, - "2663-top-level-await-dependency-errors/main.ts": 4026, - "2664-top-level-await-same-checkpoint-rejection.ts": 3900, - "2665-top-level-await-unhandled-listener-liveness.ts": 3124, - "2666-array-to-sorted.ts": 7343, - "2668-stored-number-array-iterator.ts": 4155, - "2669-array-copying-methods.ts": 4893, - "2670-uint8array-copy-iterate.ts": 4534, - "2671-array-copying-js.cjs": 4071, - "2672-http-request-response-callback.ts": 25478, - "2673-top-level-await-implicit-module.ts": 3661, - "2674-top-level-for-await-implicit-module.ts": 4714, - "2675-create-require-nested-esm.js": 3731, - "2675-process-self-reexec.ts": 3793, - "2676-indexed-read-strict-equality.ts": 3177, - "2676-record-clone-overrides.ts": 3884, - "2676-top-level-await-ambiguous/main.ts": 3335, - "2677-runtime-optional-closure.ts": 4747, - "2677-top-level-await-module-scope/main.ts": 2879, - "2678-date-instances.ts": 3537, - "2678-large-string-sparse-index.ts": 3659, - "2678-util-parseargs.ts": 8501, - "2679-util-parseargs-cjs.cjs": 5362, - "2680-util-parseargs-default.ts": 3698, - "2681-util-parseargs-dynamic.js": 5047, - "2682-fs-rename.ts": 4318, - "2683-filter-truthy-predicate.ts": 4083, - "2683-fs-rename-js.cjs": 4168, - "2684-filter-no-predicate-dyn.cjs": 3139, - "2684-fs-rename-abort.ts": 3244, - "2685-array-unshift-reverse.ts": 3752, - "2685-fs-write-sync.ts": 3562, - "2686-fs-file-handle.ts": 5916, - "2687-fsp-write-file-options.ts": 4133, - "2687-process-write-args.ts": 3739, - "2688-fs-stats-disk-fields.ts": 4196, - "2689-http-server-timeout-properties.ts": 9510, - "2690-https-server-timeout-option.ts": 26255, - "2691-retained-lowering-record-order.ts": 5714, - "2692-inline-record-assert-index.ts": 4256, - "2692-string-accumulation.ts": 4000, - "2693-math-constants.ts": 3814, - "2700-array-sort-complexity.ts": 4128, - "2700-http-static-trailers.ts": 3673, - "2700-wasi-core.ts": 3941, - "2701-array-sort-snapshot.ts": 5063, - "2701-http-static-trailer-wire.ts": 4002, - "2701-import-meta/main.mjs": 4298, - "2702-http-static-trailer-end.ts": 4488, - "2702-type-import-link-static/main.ts": 3632, - "2702-uint8array-to-sorted.ts": 4201, - "2703-array-sparse-sort.ts": 7778, - "2703-type-import-link-static-reexport/main.ts": 3591, - "2704-array-sparse-to-sorted.ts": 8196, - "2704-type-import-link-static-success/main.ts": 3547, - "2705-array-sparse-sort-append.ts": 6478, - "2705-type-import-link-dynamic/main.ts": 3402, - "2706-array-search-missing-needle.ts": 4264, - "2706-type-import-link-dynamic-success/main.ts": 3801, - "2707-array-search-huge-sparse.ts": 45112, - "2707-type-import-link-static-default-reexport/main.ts": 3162, - "2708-type-import-link-dynamic/main.ts": 2849, - "2720-array-read-parity.ts": 4418, - "2721-array-nested-missing-receiver.ts": 4224, - "2750-array-sparse-foundation.ts": 3486, - "2751-buffer-concat-sparse-list.ts": 3809, - "2752-array-optional-stores.ts": 3893, - "2753-array-optional-method-values.ts": 4447, - "2754-array-property-undefined.ts": 3437, - "2755-array-optional-literal-forwarding.ts": 3309, - "2780-array-parity-composition.ts": 11152, - "2781-array-missing-value-escape.ts": 3766, - "2782-array-sparse-callbacks.ts": 4827, - "2783-array-defaults-rest.ts": 3752, - "2784-array-reduce-missing-result.ts": 3900, - "2785-array-missing-destructuring.ts": 4350, - "2786-array-sparse-serialization.ts": 4399, - "2787-array-missing-string-arithmetic.ts": 3532, - "2788-array-missing-builtin-conversions.ts": 2629, - "2789-array-missing-optional-tostring.ts": 4012, - "2790-dynamic-import-self-name/main.ts": 3567, - "2791-record-optional-keys.ts": 4180, - "2792-record-optional-spread-entries.ts": 3957, - "2793-union-conversion-identity-capture.ts": 4016, - "2794-array-generic-callback-values.ts": 3192, - "2795-array-optional-typedarray-source.ts": 39238, - "2796-array-sparse-class-value-instanceof.ts": 3057, - "2800-array-expression-consumers.ts": 3984, - "2801-array-switch-consumers.ts": 3844, - "2820-array-missing-method-receivers.ts": 4015, - "2821-array-optional-numeric-comparisons.ts": 3715, - "2830-cjs-require-self-name/main.cjs": 3843, - "2840-finally-completions.ts": 3843, - "2841-using-sync.ts": 3805, - "2842-await-using.ts": 3336, - "2843-using-suppressed-error.ts": 3417, - "2844-node-disposable-resources.ts": 4668, - "2845-for-using-of.ts": 3487, - "2846-generator-using.ts": 4293, - "2850-async-generators-protocol.ts": 4610, - "2851-async-generators-values.ts": 4267, - "2852-timers-promises-interval.ts": 3195, - "2854-leading-bom-literals.ts": 3717, - "2855-searchparams-sort-complexity.ts": 3679, - "2856-dynamic-any-local-operators.ts": 3601, - "2857-branded-primitives.ts": 3846, - "2858-import-meta-resolve/main.mjs": 3869, - "2859-import-meta-resolve-dynamic/main.mjs": 3441, - "2860-require-resolve/main.cjs": 3856, - "2861-readable-iterator-close.ts": 8658, - "2862-web-readable-async-iteration.ts": 60491, - "2863-class-async-iterator.ts": 3807, - "2864-array-class-method-receivers.ts": 3808, - "2865-cjs-process-alias.cjs": 3058, - "2866-dyn-switch.ts": 4091, - "2867-array-shift-length.js": 3560, - "2868-empty-record-promise-presence.js": 3622, - "2869-nullish-mixed-lazy.ts": 3214, - "2870-and-dropped-truthy-arm.ts": 3668, - "2871-optional-promise-to-unknown.ts": 3151, - "2872-unobserved-dynamic-event.ts": 3479, - "2873-optional-receiver-loop-lifetime.js": 3838, - "2874-nullable-callback-field-cycle.js": 3416, - "2875-evolving-let-read-before-write.js": 3393, - "2876-class-unknown-roundtrip.ts": 3172, - "2877-child-unknown-roundtrip.ts": 3088, - "2878-class-private-unknown.cjs": 3951, - "2880-cjs-module-graph/main.cjs": 4546, - "2890-crypto-static-utility.ts": 4147, - "2891-json-record-key-escapes.ts": 4489, - "2892-windows-console-unicode.ts": 3631, - "2893-child-stdin-duplex.ts": 4001, - "2894-child-stdin-backpressure.ts": 3911, - "2895-child-stdin-write-after-end.ts": 4040, - "2896-child-stdin-write-after-finish.ts": 4046, - "2897-child-stdin-destroy.ts": 4182, - "2898-child-stdin-spawn-failure.ts": 3819, - "2899-nested-mutual-recursion.ts": 3391, - "2900-float64array-static.ts": 4170, - "2900-void-conditional-arrow.ts": 2973, - "2901-bigint-core.ts": 3785, - "2902-bigint-bytes.ts": 3878, - "2903-bigint-storage.ts": 4174, - "2904-bigint-errors.ts": 3154, - "2905-bigint-edges.ts": 3535, - "2906-bigint-wasi-width.ts": 3636, - "2910-overloaded-callable-alias.ts": 3507, - "2911-execfile-callback.ts": 3775, - "2912-execfile-callback-options.ts": 3546, - "2912-promisify-fs-readfile.ts": 3527, - "2913-builtin-callable-alias.ts": 5224, - "2914-fixed-tuple-call-spread.ts": 4266, - "2915-path-function-values.ts": 4335, - "2916-path-function-values-cjs.ts": 3661, - "2917-builtin-callable-widths.ts": 4692, - "2918-builtin-callable-widths-cjs.ts": 3911, - "2919-fs-function-values.ts": 3993, - "2920-fs-promises-function-values.ts": 3700, - "2921-zlib-callbacks.ts": 4702, - "2922-dyn-bitwise-not.cjs": 3792, - "2923-cjs-factory-export/main.cjs": 3686, - "2930-union-receiver-calls.ts": 4496, - "2931-union-dynamic-field-call.js": 3249, - "2932-create-require-program/main.ts": 4121, - "2933-static-dynamic-import/main.ts": 3790, - "2934-static-import-stored.ts": 2637, - "2935-module-namespace-values/main.ts": 4033, - "2936-static-loose-equality.ts": 4807, - "2937-bitwise-hot-loop.ts": 3730, - "2938-fs-sync-overloads.cjs": 2978, - "2939-child-shell-text.ts": 4396, - "2940-date-parse.ts": 3909, - "2940-fsp-realpath.ts": 3670, - "2941-fsp-lstat-identity.ts": 4973, - "2941-process-exit-code.ts": 2597, - "2942-fsp-readdir-dirent.ts": 3959, - "2942-process-exit-code-override.ts": 3773, - "2943-process-exit-code-invalid.ts": 3459, - "2944-process-exit-code-wrap.ts": 4312, - "2945-url-origin-username.ts": 2754, - "2946-child-fork-ipc/main.ts": 4571, - "2946-url-port-hash.ts": 3017, - "2947-set-readonly-seeds.ts": 3976, - "2948-child-fork-eof-callback/main.ts": 4009, - "2948-stdio-callback-record.ts": 2902, - "2949-child-fork-default/main.mjs": 3935, - "2949-url-password.ts": 3040, - "2950-fs-descriptor-publication.ts": 2555, - "2951-math-static-analytic.ts": 4273, - "2952-math-static-remaining.ts": 3480, - "2953-http-header-validation.ts": 6668, - "2954-http-outgoing-headers.ts": 4292, - "2955-http-static-state.ts": 3942, - "2956-http-static-informational.ts": 8174, - "2957-http-static-response-controls.ts": 4254, - "2961-emitter-computed-names.cjs": 2876, - "2962-emitter-computed-optional.ts": 3963, - "2963-child-fork-dispatch/main.ts": 3170, - "2964-indexed-compound.ts": 4621, - "2966-numeric-array-read-fusion.ts": 3495, - "2967-numeric-array-read-lifetime.ts": 3370, - "2968-numeric-array-borrow.ts": 4623, - "2969-scalar-record-results.ts": 3919, - "2970-constant-numeric-tables.ts": 2953, - "2971-constant-table-modules/main.ts": 2780, - "2972-http-static-distinct-snapshots.ts": 7024, - "2972-math-receiver-borrow.ts": 4560, - "2973-http-static-agent.ts": 8993, - "2973-integer-bitwise-arithmetic.ts": 3843, - "2974-array-search-from-index.ts": 102834, - "2974-http-static-module-values.ts": 6368, - "2974-numeric-remainder.ts": 4108, - "2975-bigint-default-radix.ts": 3498, - "2975-http-static-client-controls.ts": 3623, - "2976-http-static-incoming-state.ts": 2971, - "2976-json-stringify-no-arguments.js": 3696, - "2977-http-static-incoming-timeout.ts": 4074, - "2977-nested-array-binding-defaults.js": 4142, - "2978-http-static-client-timeout.ts": 9714, - "2978-regexp-optional-subject.js": 49628, - "2979-array-search-mixed-needles.js": 4303, - "2979-http-static-server-timeout.ts": 6006, - "2980-http-static-server-timeout-default.ts": 7270, - "2980-string-position-arguments.js": 3086, - "2981-http-static-events.ts": 3123, - "2981-string-optional-positions.ts": 3368, - "2982-http-static-close-all.ts": 3822, - "2982-string-position-coercion-order.js": 3928, - "2983-http-static-close-idle.ts": 3614, - "2984-http-static-close-upgrade.ts": 3907, - "2985-http-static-message-destroy.ts": 3388, - "2986-http-static-client-socket-finish.ts": 3798, - "2987-http-static-timeout-errors.ts": 4096, - "2988-http-static-client-abort.ts": 2850, - "2989-http-static-response-timeout-handled.ts": 3345, - "2990-http-static-request-timeout-handled.ts": 4813, - "2991-array-indexed-equality.ts": 4275, - "2992-stream-rows.ts": 3533, - "2993-fiber-stack-lifetimes.ts": 4327, - "2994-fromcharcode-scalar.ts": 4187, - "2995-math-hyperbolic.ts": 4005, - "2996-math-near-one.ts": 4413, - "2997-math-integer-float.ts": 3945, - "300-if-else.ts": 4350, - "3001-caught-typeof-object.js": 3508, - "3002-promise-then-two.ts": 4636, - "301-while.ts": 3775, - "302-for.ts": 3729, - "3020-string-last-index-position.ts": 2972, - "3021-buffer-union-narrow-callback.ts": 3784, - "3022-string-affix-positions.ts": 3752, - "3023-string-affix-position-coercion.js": 3717, - "3024-string-number-narrow-for-in.ts": 4025, - "3025-string-search-position-coercion.js": 2818, - "3026-array-last-index-of.js": 4346, - "3027-array-last-index-of-records.ts": 2717, - "3028-string-search-dynamic-needle.js": 3694, - "3029-string-search-union-needle.js": 3379, - "303-break-continue.ts": 3648, - "3030-array-search-no-arg.js": 3591, - "3031-array-relative-index-coercion.js": 3587, - "3031-string-last-index-search-value.js": 4017, - "3032-string-search-value.js": 3564, - "3033-string-search-needle-coercion.js": 3378, - "3034-arguments-with-parameters.js": 3967, - "3035-string-positioned-search-value.js": 3417, - "3036-string-object-search-value.js": 3926, - "3037-number-nullish-conversion.js": 4703, - "3038-number-scalar-unions.ts": 3646, - "3039-string-repeat-count.js": 3646, - "304-compound-incdec.ts": 3722, - "3040-string-prototype-call.js": 4670, - "3041-string-prototype-object-call.js": 3431, - "3042-string-padding-coercion.js": 3284, - "3043-string-split-arguments.js": 3505, - "3044-array-slice-splice-positions.js": 3592, - "3045-array-indexed-mutation.js": 3564, - "3046-array-indexed-ref-identity.ts": 4051, - "3047-object-prototype-tag.js": 4202, - "3048-object-own-prototype.ts": 4672, - "3049-array-flat-depth.ts": 3327, - "305-truthiness.ts": 3686, - "3050-array-splice-insert.ts": 4238, - "3051-array-join-default.ts": 3649, - "3052-array-construction.ts": 5275, - "3053-array-construction-js.js": 4051, - "3054-dynamic-abort-record.ts": 31946, - "3055-default-builtin-nodenext/main.ts": 3742, - "3056-default-builtin-bundler/main.ts": 3900, - "3057-default-builtin-nodenext-dynamic/main.ts": 3548, - "3058-optional-array-chain-join.ts": 4351, - "3059-arguments-property-names.ts": 3823, - "3061-concurrent-fiber-stacks.ts": 4696, - "3062-runtime-optional-record-guards.ts": 4448, - "3063-runtime-optional-class-guards.ts": 4574, - "3064-installed-entry-imports/main.ts": 3681, - "3065-installed-entry-js/main.js": 3134, - "3066-source-debugging/main.ts": 3285, - "3067-cjs-function-export-require/main.cjs": 3758, - "3068-debug-variables/main.ts": 3691, - "3068-url-checked-identity.ts": 3668, - "3069-set-checked-seed.js": 3693, - "3069-tuple-spread.ts": 4624, - "3070-checked-object-accessors.js": 4486, - "3070-collection-views.ts": 3364, - "3071-checked-specialization-narrowing.js": 3480, - "3071-map-contextual-record-seeds.ts": 3949, - "3072-optional-union-receivers.ts": 5187, - "3072-weak-process-streams.js": 3596, - "3073-optional-callable-module.js": 2912, - "3073-union-keyed-reads.ts": 4086, - "3074-discriminated-intersections.ts": 3579, - "3075-recursive-contextual-literals.ts": 4053, - "3076-nullish-record-defaults.ts": 4277, - "3077-optional-union-array-reads.ts": 3951, - "3078-forward-mutable-captures.ts": 4480, - "3079-forward-mutable-tdz.ts": 4237, - "3080-exhaustive-never-bindings.ts": 3901, - "3081-recursive-array-destinations.ts": 4116, - "3082-forward-write-unwind.ts": 3019, - "3083-set-string-seed.ts": 4323, - "3084-record-own-membership.ts": 4601, - "3085-conditional-record-construction.ts": 4376, - "3086-error-constructor-options.ts": 4642, - "3087-error-options-lifetime.ts": 3925, - "3088-array-wide-callbacks.ts": 4497, - "3089-array-find-narrowing.ts": 4974, - "3090-json-discriminated-records.ts": 4438, - "3091-json-recursive-discriminants.ts": 5400, - "3092-number-union-predicates.ts": 3730, - "3093-error-option-data.ts": 2865, - "3094-json-replacer-traversal.ts": 4373, - "3095-json-reviver-traversal.ts": 4032, - "3096-json-callback-nonfinite.ts": 3197, - "3097-json-callback-reentrancy.ts": 3379, - "3098-json-callback-space.ts": 3597, - "3099-json-callback-functions.ts": 4206, - "3100-json-callback-holder.js": 4588, - "3101-json-callback-bytes.ts": 4349, - "3102-json-unknown-fields.ts": 3200, - "3103-scalar-record-nested-control-flow.ts": 4214, - "3104-native-analysis-tables-loops.ts": 2623, - "3105-nullable-collections.ts": 4138, - "3106-mixed-insertion-spreads.ts": 3715, - "3107-nullable-collection-lifetimes.ts": 4148, - "3108-for-await-sync-arrays.js": 6166, - "3108-identity-map-keys.ts": 4867, - "3109-destructuring-unknown-defaults.js": 4021, - "3109-identity-union-collections.ts": 5097, - "3110-builtin-error-families.ts": 3559, - "3110-identity-collection-mutation.ts": 3934, - "3111-identity-collection-cycles.ts": 3848, - "3112-union-switch-control-flow.ts": 3478, - "3113-union-array-removal.ts": 4714, - "3114-union-record-field-write.ts": 3240, - "3115-zlib-static-compression-levels.ts": 4206, - "3116-sequence-expression-lifetimes.ts": 4356, - "3117-unknown-switch-control-flow.ts": 3816, - "3118-recursive-union-spread.ts": 4372, - "3119-runtime-optional-spread.ts": 4825, - "3120-dynamic-property-descriptors.js": 3522, - "3120-generator-method-loop-bindings.ts": 4192, - "3120-ir-nonfinite-numbers.ts": 4200, - "3121-compound-assignment-values.js": 3684, - "3121-dynamic-accessor-descriptors.js": 4951, - "3122-dynamic-delete-descriptors.cjs": 4063, - "3122-dynamic-delete-descriptors.js": 3650, - "3122-js-async-class-methods.js": 4320, - "3123-destructured-global-tdz.js": 3748, - "3124-array-prototype-borrow.js": 4580, - "3125-regex-global-match.ts": 2619, - "3126-js-number-radix/main.ts": 4047, - "3127-spawn-runtime-options.ts": 4379, - "3128-regex-last-index.ts": 4682, - "3129-js-token-union/main.ts": 4567, - "3130-child-generic-streams.ts": 4888, - "3131-child-rest-listeners.js": 2682, - "3132-child-generic-stream-completion.ts": 9689, - "3133-text-decoder-streaming.ts": 21112, - "3134-fs-vectors.ts": 3917, - "3135-fs-file-handle-controls.ts": 5050, - "3136-fs-file-handle-options.ts": 5320, - "3137-fs-vector-callbacks.cjs": 5540, - "3138-array-large-storage.ts": 6344, - "3139-regex-native-deep-alternatives.ts": 31598, - "3140-array-dense-access.ts": 6506, - "3141-map-string-key-hash.ts": 4564, - "3150-integer-remainder.ts": 4200, - "3151-array-push-writes.ts": 4614, - "3170-number-conversion-fast-paths.ts": 4996, - "3171-method-census-data-writes.ts": 4891, - "400-fib.ts": 4470, - "401-mutual-recursion.ts": 3443, - "402-string-functions.ts": 3554, - "403-void-and-params.ts": 2749, - "4030-runtime-object-truthiness.ts": 2971, - "4031-event-emitter-long-tuples.ts": 3712, - "4032-inline-rc-fast-paths.ts": 6866, - "404-rc-stress.ts": 3585, - "4040-adapted-function-identity.ts": 3063, - "4041-adapted-function-properties.ts": 4165, - "4042-object-is-union-subclass.ts": 3846, - "4043-nonnull-missing-element.ts": 3736, - "4044-adapted-callback-modules/main.ts": 4121, - "4045-optional-element-projections.ts": 4159, - "4046-captured-parameter-values.ts": 3178, - "4047-captured-parameter-rebinding.ts": 4100, - "405-params-optional.ts": 3985, - "406-params-defaults.ts": 3592, - "4060-cycle-shared-instance/main.ts": 3695, - "4060-stack-union-reads.ts": 5003, - "4061-cycle-evaluation-order/main.ts": 3985, - "4061-nullable-ref-fields.ts": 7201, - "4062-cycle-tdz-read/main.ts": 3866, - "4063-cycle-hoisted-calls/main.ts": 3773, - "4064-cycle-classes-after-init/main.ts": 3673, - "4065-cycle-init-throws/main.ts": 3693, - "4066-cycle-top-level-tdz/main.ts": 3937, - "4067-dynamic-import-cycle-tdz/main.ts": 4237, - "407-params-rest.ts": 4125, - "408-params-ctors-inheritance.ts": 3692, - "4080-optional-read-presence-tests.ts": 3038, - "4080-string-index-bounds.ts": 3844, - "4081-hoisted-function-tdz.ts": 3262, - "4081-string-index-unproven.ts": 4125, - "4082-hoisted-function-tdz-uncaught.ts": 2818, - "4083-dynamic-import-failure/main.ts": 3160, - "4084-record-optional-field-copies.ts": 5146, - "4085-generator-loop-close.ts": 4113, - "4086-optional-capture-defaults.ts": 3684, - "4088-class-static-tdz.ts": 3477, - "4089-class-wrapper-tdz.js": 2771, - "409-params-async-generics.ts": 4030, - "4090-computed-key-tdz.js": 3578, - "4091-class-evaluation-deferred.ts": 4329, - "410-params-rc-stress.ts": 4376, - "4140-array-callback-split-visit.ts": 7471, - "4141-array-callback-ambient-receiver/main.ts": 3909, - "4142-array-callback-factories.ts": 3472, - "4143-union-refinement-intersection-arms.ts": 3347, - "420-dead-strip-modules/main.ts": 3742, - "4290-acyclic-immutable-trees.ts": 4974, - "4291-acyclic-constructor-escapes.ts": 4252, - "4292-acyclic-readonly-bypass.ts": 4530, - "4293-acyclic-dynamic-writes.ts": 4090, - "4294-console-line-sizes.ts": 7343, - "4295-console-template-parts.ts": 3542, - "4296-console-glued-long-parts.ts": 5181, - "4410-inline-object-allocation.ts": 4560, - "4411-nullable-ref-values.ts": 6207, - "4412-nullable-record-values.ts": 5237, - "4413-cycle-old-late-death.ts": 5172, - "4413-nullable-null-and-undefined.ts": 4068, - "4414-cycle-old-weak-keys.ts": 4401, - "4414-nullable-string-values.ts": 7453, - "4415-identity-borrowed-operands.ts": 3629, - "4415-nullable-container-values.ts": 5776, - "4431-exception-pending-contexts.ts": 4992, - "4432-checked-downcast-failures.ts": 4520, - "4451-int32-field-storage.ts": 4554, - "4452-int32-field-dynamic-writes.ts": 4987, - "4453-int32-closed-locals.ts": 4516, + "001-hello.ts": 38244, + "002-log-args.ts": 31270, + "100-number-format.ts": 45195, + "1000-json-stringify-basics.ts": 46332, + "1001-json-escapes-unicode.ts": 4513, + "1002-json-parse-cast.ts": 35521, + "1003-json-parse-unions.ts": 3512, + "1004-json-parse-errors.ts": 3903, + "1005-json-nested.ts": 3425, + "1006-json-fs-config.ts": 3347, + "1007-json-rc-stress.ts": 34305, + "1008-json-null-arms.ts": 3422, + "1009-json-optional-fields.ts": 4004, + "101-arithmetic.ts": 4655, + "1010-json-stringify-space.ts": 45417, + "1011-json-unknown-typeof.ts": 4001, + "102-comparisons.ts": 3774, + "1020-async-basics.ts": 3697, + "1021-async-ordering.ts": 3078, + "1022-async-exceptions.ts": 3780, + "1023-async-rc-stress.ts": 3889, + "1024-async-pending-exit.ts": 3389, + "1025-async-promise-capture.ts": 42296, + "1026-throw-promise.ts": 4482, + "1027-async-return-promise.ts": 3534, + "1028-async-return-record-literals.ts": 3843, + "1029-async-eager-chains.ts": 4890, + "103-ternary.ts": 3470, + "104-ternary-empty-arrays.ts": 7056, + "1050-comptime-tables.ts": 4643, + "1051-comptime-strings.ts": 42895, + "1052-comptime-records.ts": 44375, + "1053-comptime-json.ts": 4497, + "1054-comptime-modules/main.ts": 4326, + "110-number-radix.ts": 3100, + "111-record-entries.ts": 7961, + "1110-math-members.ts": 3457, + "1111-math-random.ts": 4321, + "1113-string-methods.ts": 23286, + "1114-string-unicode-island.ts": 45718, + "1115-parse-globals.ts": 3277, + "1116-island-static-mix.ts": 3738, + "1117-typeof-static-union.ts": 4351, + "1118-object-spread-conditional.ts": 3602, + "1119-switch-union.ts": 4833, + "112-class-descriptor-key.js": 4674, + "1121-infinity-number-tostring.ts": 4470, + "1122-any-captures.ts": 7125, + "1124-union-narrowed-retag.ts": 3484, + "113-promise-checked-exits.ts": 4562, + "114-live-record-delete.ts": 3572, + "115-array-compound.js": 6457, + "116-text-decoder-runtime.js": 33483, + "117-weak-cache-cycle.js": 5789, + "118-fs-stored-callbacks.cjs": 52946, + "119-native-patterns.js": 6101, + "1200-regex-test-basics.ts": 47554, + "1201-regex-replace.ts": 3959, + "1202-regex-substitutions.ts": 3855, + "1203-regex-split.ts": 31517, + "1204-regex-empty-unicode.ts": 4662, + "1205-regex-rc-stress.ts": 36658, + "1300-errors-basics.ts": 4354, + "1301-errors-subclass.ts": 4687, + "1302-errors-typed-catch.ts": 4229, + "1303-errors-rc-stress.ts": 3431, + "1304-errors-uncaught.ts": 3763, + "1305-errors-async-rejections.ts": 4254, + "1306-errors-runtime-instances.ts": 4140, + "1350-path-normalize-join.ts": 4224, + "1351-path-parts.ts": 4167, + "1352-path-resolve-relative.ts": 4382, + "1353-os-basics.ts": 4007, + "1354-builtin-bare-specifiers.ts": 3999, + "1355-url-parse.ts": 3346, + "1356-url-file-bridge.ts": 3553, + "1357-fsp-roundtrip.ts": 4325, + "1358-crypto-random.ts": 3398, + "1359-json-module/main.ts": 4414, + "1360-spawn-sync.ts": 4387, + "1361-spawn-events.ts": 4260, + "1362-spawn-timers.ts": 9971, + "1363-spawn-unhandled-error.ts": 3744, + "1364-union-truthiness.ts": 3907, + "1365-union-logical.ts": 4258, + "1366-union-equality.ts": 3058, + "1367-destructuring.ts": 5461, + "1368-constructor-functions.ts": 3781, + "1369-promise-union.ts": 3864, + "1370-spread.ts": 3429, + "1371-union-template-tostring.ts": 3265, + "1372-loose-null-tests.ts": 3885, + "1373-union-array-arms.ts": 3435, + "140-bitwise-operators.ts": 4527, + "1400-typedarray-basics.ts": 5395, + "1401-typedarray-slice-set.ts": 3626, + "1402-buffer-encodings.ts": 4871, + "1403-buffer-fs.ts": 4268, + "1404-zlib-crypto-bytes.ts": 5331, + "1405-bytes-unions-arrays.ts": 3838, + "1406-dataview-mp4.ts": 3661, + "1407-dataview-bounds.ts": 5553, + "1408-string-indexing.ts": 5392, + "1409-typedarray-integer-loops.ts": 4558, + "1420-number-statics.ts": 3886, + "1421-number-parse-strings.ts": 4644, + "1422-date-iso.ts": 4015, + "1423-text-codec.ts": 38476, + "1424-fs-options.ts": 3473, + "1425-stdin-tty.ts": 4093, + "1426-stdin-read.ts": 3982, + "1427-fromcharcode-lastindexof.ts": 2946, + "1428-settled-await-order.ts": 3794, + "1429-promise-catch-finally.ts": 4465, + "1430-promise-race.ts": 4414, + "1431-caught-tostring.ts": 2971, + "1432-destructured-params.ts": 3941, + "1433-filter-narrow.ts": 3907, + "1434-async-never.ts": 3465, + "1435-math-spread.ts": 3652, + "1436-default-undef-param.ts": 3877, + "1437-pad-default.ts": 3475, + "1438-promise-all.ts": 7297, + "1440-interval-basics.ts": 4144, + "1441-interval-clear-cross.ts": 7176, + "1442-interval-throw.ts": 3609, + "1443-signal-handlers.ts": 7600, + "1444-exit-listeners.ts": 4768, + "1445-exit-process-exit.ts": 5403, + "1446-exit-uncaught.ts": 4319, + "1447-stdin-closed-events.ts": 4894, + "1448-stream-columns.ts": 4014, + "1450-incdec-expression.ts": 3639, + "1451-instanceof-uint8array-unknown.ts": 3654, + "1452-return-through-finally.ts": 4057, + "1453-pmap-settled.ts": 4531, + "1454-nonnull-narrow-and-fcc-bytes.ts": 3459, + "1455-lambda-union-return-adoption.ts": 3583, + "1460-console-error-warn.ts": 3484, + "1461-process-pid-getuid-kill.ts": 3345, + "1462-exec-sync.ts": 5307, + "1463-timeout-unref.ts": 3316, + "1464-env-writes.ts": 3946, + "1465-env-value.ts": 3554, + "1466-child-containers.ts": 4064, + "1467-string-match.ts": 3329, + "1468-exec-path.ts": 3588, + "1469-remove-listener.ts": 5747, + "1470-child-lifecycle.ts": 2972, + "1471-child-unref.ts": 8472, + "1472-errno-code.ts": 3388, + "1473-promisify-execfile.ts": 5200, + "1474-string-decoder.ts": 3868, + "1475-readline-closed-stdin.ts": 3587, + "1476-assign-expression.ts": 4319, + "1477-in-expressions.ts": 3951, + "1478-promise-reject.ts": 4331, + "1479-destructuring-assign.ts": 3821, + "1480-os-network-interfaces.ts": 4186, + "1481-string-case-static.ts": 2782, + "1482-spawnsync-error.ts": 2721, + "1483-array-slice.ts": 52661, + "1520-fs-wider-surface.ts": 3691, + "1520-string-split-static.ts": 3432, + "1521-fs-lstat-lock.ts": 3409, + "1521-string-trim-pad-static.ts": 4078, + "1522-parseint-static.ts": 3461, + "1522-spawnsync-options.ts": 5773, + "1523-isnan-floor-static.ts": 3552, + "1523-spawn-options.ts": 5294, + "1524-atomics-sleep-static.ts": 4028, + "1524-catch-narrowing.ts": 2626, + "1525-child-exit-signal.ts": 3477, + "1525-unknown-typeof-validation.ts": 2889, + "1526-set-spread.ts": 3802, + "1527-logical-mixed-operands.ts": 4773, + "1528-delete-records-env.ts": 3621, + "1529-class-with-statics.ts": 3381, + "1530-array-push-variadic.ts": 2970, + "1530-spread-override-completion.ts": 2499, + "1531-delete-optional-fields.ts": 3623, + "1531-process-arch-versions.ts": 2740, + "1532-array-splice-shift.ts": 4204, + "1532-union-shared-field-read.ts": 2834, + "1533-bool-equality.ts": 4076, + "1533-path-platform-namespaces.ts": 3406, + "1534-crypto-hash-chain.ts": 4097, + "1534-union-as-arm-cast.ts": 45787, + "1535-spawn-fd-stdio.ts": 3840, + "1535-union-param-defaults.ts": 4358, + "1536-destructuring-defaults.ts": 3812, + "1536-string-array-sweep.ts": 3859, + "1537-chalk-hybrid/main.ts": 4683, + "1537-os-release-spawnsync-stdio.ts": 2674, + "1538-await-promiselike-return.ts": 2642, + "1538-math-static-scalar.ts": 3735, + "1539-readonly-set-map.ts": 3299, + "1539-unknown-truthiness.ts": 3045, + "1540-os-userinfo.ts": 4119, + "1540-void-statement.ts": 2941, + "1541-fs-readdir-dirent.ts": 5432, + "1541-union-keyed-reads.ts": 4646, + "1542-map-promise-values.ts": 33000, + "1542-record-literal-into-union.ts": 2885, + "1543-rest-destructuring.ts": 3500, + "1543-set-server-handles.ts": 6770, + "1544-dyn-json-reads.ts": 4863, + "1544-string-matchall.ts": 4770, + "1545-spread-order-and-optional.ts": 4536, + "1546-union-element-reads.ts": 4536, + "1547-computed-key-fold.ts": 3960, + "1548-boolean-condition-forms.ts": 4649, + "1549-array-isarray-unions.ts": 4084, + "1550-param-defaults-func-set.ts": 3020, + "1551-dyn-receiver-methods.ts": 3403, + "1552-exec-options-record.ts": 2877, + "1553-truthy-hof-predicates.ts": 3895, + "1554-caught-into-unknown.ts": 3417, + "1555-index-spread-into-declared.ts": 4534, + "1556-union-retag-width-arms.ts": 3587, + "1557-url-host.ts": 2566, + "1558-any-joins-and-dyn-validation.ts": 33883, + "1559-conditional-spread-index-merge.ts": 3282, + "1560-forof-homogeneous-tuples.ts": 3680, + "1561-forof-strings.ts": 2878, + "1561-promise-then.ts": 3851, + "1562-optional-chain-tails.ts": 4618, + "1562-spawn-conditional-spread.ts": 4043, + "1563-forof-iterator-projections.ts": 3930, + "1563-string-raw-fold.ts": 3100, + "1564-fs-watch.ts": 4051, + "1564-string-raw.ts": 3075, + "1565-spawn-pipe-streams.ts": 3895, + "1565-union-element-join.ts": 4167, + "1566-child-duck-interface.ts": 3875, + "1567-server-close-override.ts": 3304, + "1568-x509-fingerprint.ts": 2839, + "1569-fsp-mkdir-unlink-chmod.ts": 3012, + "1570-child-unref-kill-reffed.ts": 9046, + "1571-optional-call-tostring-tail.ts": 26380, + "1571-stdin-set-raw-mode-non-tty.ts": 4151, + "1572-promise-reject-all-tuple.ts": 4201, + "1572-x509-validity-date-gettime.ts": 3944, + "1573-promisify-execfile-env-spread.ts": 4480, + "1573-tdz-scalar-forward-capture.ts": 2862, + "1574-dyn-optional-method-number-keys.ts": 3192, + "1574-promise-all-tuple-literal.ts": 4410, + "1575-unknown-assert-into-record.ts": 3424, + "1576-width-coercions.ts": 4144, + "1577-url-hostname.ts": 4030, + "1578-exec-input-optional.ts": 4028, + "1579-matchall-index.ts": 4108, + "1580-exec-env-conditional-spread.ts": 3516, + "1581-declare-const-read.ts": 3997, + "1582-timer-sleep-resolve.ts": 4177, + "1583-loops-and-stream-captures.ts": 4450, + "1584-union-field-unassigned.ts": 3964, + "1585-union-field-conditional-ctor.ts": 3070, + "1586-derived-field-before-super-init.ts": 4073, + "1590-js-unannotated.js": 4738, + "1591-js-closures.js": 3535, + "1592-js-classes.js": 7400, + "1593-js-jsdoc-records.js": 4695, + "1594-js-async.js": 3836, + "1595-js-island-gap/main.js": 3139, + "1596-cjs-modules/main.js": 3283, + "1597-mjs-graph/main.mjs": 3605, + "1598-cjs-builtin-require/main.js": 2977, + "1599-js-uncaught-throw.js": 3196, + "1600-assert-passing.ts": 4333, + "1601-assert-fail-exit.ts": 3725, + "1602-assert-caught-error.ts": 3373, + "1603-assert-scalar-messages.ts": 5128, + "1604-assert-deep-structures.ts": 4364, + "1605-assert-import-forms.ts": 4371, + "1606-assert-strict-module.ts": 2984, + "1607-assert-throws-match.ts": 4301, + "1608-cjs-assert/main.js": 3820, + "1609-assert-async.ts": 2695, + "1610-path-win32-full.ts": 2757, + "1611-url-file-bridge-neutral.ts": 4375, + "1612-cjs-module-globals.cjs": 3706, + "1613-cjs-esm-proxy-named/main.mjs": 3290, + "1614-js-fence-dodges.cjs": 2861, + "1615-cjs-export-shapes/main.cjs": 4723, + "1616-cjs-esm-lexer-invisible/main.mjs": 2991, + "1617-cjs-esm-lexer-visible/main.mjs": 3860, + "1618-cjs-esm-poisoned-tail/main.mjs": 3236, + "1619-cjs-esm-reexport-invisible/main.mjs": 3244, + "1620-cjs-require-effects-order/main.js": 2604, + "1621-cjs-require-cache-hit/main.js": 3531, + "1622-cjs-require-conditional/main.js": 3501, + "1623-cjs-require-diamond/main.js": 4051, + "1624-cjs-require-dir-mid-file/main.js": 2658, + "1625-cjs-require-lazy-fn/main.js": 3635, + "1626-cjs-require-mjs/main.js": 2942, + "1627-mjs-import-cjs-requires/main.mjs": 3236, + "1628-checked-dynamic-builtin-args.cjs": 2968, + "1629-require-main-filename.cjs": 2826, + "1630-inspect-scalars.ts": 3908, + "1630-rmsync-retry-options.cjs": 3797, + "1631-inspect-arrays.ts": 4065, + "1632-inspect-records.ts": 4843, + "1633-inspect-map-set.ts": 3133, + "1634-inspect-classes.ts": 3805, + "1635-inspect-buffer.ts": 3530, + "1636-util-format.ts": 2945, + "1637-inspect-dyn.ts": 3297, + "1638-inspect-cjs.cjs": 3549, + "1639-versions-openssl-probe.ts": 3544, + "1640-fd-read-decode.ts": 2932, + "1641-string-search.ts": 3476, + "1642-object-fromentries-rows.ts": 3699, + "1643-metadata-dyn-return.cjs": 4074, + "1644-ee-basics.ts": 4205, + "1645-ee-extends.ts": 3512, + "1646-ee-once-remove.ts": 3828, + "1647-ee-meta-events.ts": 3673, + "1648-ee-error-event.ts": 3271, + "1649-ee-names-counts.ts": 3057, + "1650-ee-prepend.ts": 3927, + "1651-ee-max-listeners.ts": 4648, + "1652-ee-snapshot.ts": 4220, + "1653-ee-cjs.cjs": 3230, + "1654-ee-namespace.ts": 3631, + "1655-spawnsync-neutral.ts": 5393, + "1656-execsync-neutral.ts": 3546, + "1657-spawn-async-neutral.ts": 3320, + "1660-buffer-read-write-num.ts": 4303, + "1661-buffer-encodings-full.ts": 3877, + "1662-string-decoder-encodings.ts": 3423, + "1663-buffer-compare-search-fill.ts": 4770, + "1664-dyn-fn-boundary.cjs": 3405, + "1665-dyn-fn-mustcall/main.cjs": 2819, + "1666-dyn-fn-identity.ts": 2740, + "1667-dyn-fn-not-callable.cjs": 3303, + "1668-dyn-fn-throws.cjs": 3745, + "1669-symbol-identity.ts": 3617, + "1670-symbol-registry.ts": 4207, + "1671-symbol-typeof.ts": 3400, + "1672-symbol-containers.ts": 3581, + "1673-symbol-cjs.cjs": 3624, + "1674-symbol-inspect.ts": 2758, + "1676-func-array-surface.ts": 2900, + "1677-emitter-listeners.ts": 4932, + "1678-emitter-dyn-listeners.cjs": 3287, + "1679-console-dyn.js": 3576, + "1680-assert-bytes.ts": 3903, + "1681-assert-funcs.ts": 3918, + "1685-stream-readable-basics.ts": 6503, + "1686-stream-readable-paused.ts": 6965, + "1687-stream-readable-flow-control.ts": 3669, + "1688-stream-writable-basics.ts": 3711, + "1689-stream-writable-async-drain.ts": 6004, + "1690-stream-duplex.ts": 6220, + "1691-stream-transform.ts": 6193, + "1692-stream-pipe.ts": 6662, + "1693-stream-pipe-backpressure.ts": 3700, + "1694-stream-destroy.ts": 3259, + "1695-stream-props.ts": 4843, + "1696-stream-read-inside-read.ts": 3524, + "1697-stream-tick-vs-timer.ts": 3256, + "1698-stream-uncaught-error.ts": 4826, + "1699-stream-callback-shapes.ts": 3791, + "1700-mustcall-common/main.cjs": 4329, + "1701-mustcall-exit-report/main.cjs": 3995, + "1702-dyn-proto-dispatch.cjs": 4694, + "1703-arguments-rest-props.cjs": 3485, + "1710-cjs-export-class/main.js": 2945, + "1711-cjs-export-single-values/main.js": 3527, + "1712-field-incdec.ts": 3301, + "1713-js-dyn-fields.js": 3702, + "1720-assert-throws-shape.ts": 3665, + "1721-assert-throws-regex-class.ts": 3205, + "1722-assert-rejects.ts": 3941, + "1723-assert-does-not-reject.ts": 3991, + "1724-assert-iferror.ts": 2922, + "1725-assert-symbols.ts": 4117, + "1726-promise-with-resolvers.ts": 3773, + "1727-assert-throws-shape-exit.ts": 4180, + "1730-countdown-symbol-keys/main.js": 3717, + "1731-symbol-field-shapes.cjs": 4041, + "1732-symbol-field-cross-module/main.js": 3671, + "1740-stream-extends-readable.ts": 5413, + "1741-stream-extends-writable.ts": 6469, + "1742-stream-extends-duplex-transform.ts": 6437, + "1743-stream-extends-vt-dispatch.ts": 7212, + "1744-stream-set-encoding.ts": 3635, + "1745-stream-encoding-js.cjs": 2973, + "1746-stream-for-await.ts": 4707, + "1747-stream-for-await-js.cjs": 4902, + "1750-http-agent-options.ts": 7371, + "1751-options-record-stance.ts": 4112, + "1760-surplus-args-drop.cjs": 3672, + "1761-emitter-special-event-names.cjs": 5508, + "1770-assert-dyn-strict.ts": 4072, + "1771-assert-dyn-deep.ts": 3521, + "1772-assert-dyn-js.cjs": 3744, + "1773-assert-dyn-exit.ts": 3156, + "1780-http-res-surface.ts": 7173, + "1781-http-server-shapes.cjs": 3500, + "1790-computed-key-folds.ts": 3641, + "1791-searchparams-core.ts": 3206, + "1792-searchparams-encoding.ts": 3500, + "1793-searchparams-iteration.ts": 3620, + "1794-searchparams-url-live.ts": 3114, + "1795-dyn-handle-request.cjs": 6764, + "1796-dyn-handle-body.cjs": 6226, + "1797-dyn-handle-socket.cjs": 3886, + "1798-dyn-handle-typed-box.ts": 6248, + "1800-immediate-basics.ts": 3211, + "1801-immediate-handle.ts": 3455, + "1802-immediate-unref-exit.ts": 3001, + "1803-timeout-refresh.ts": 3714, + "1804-timers-module.ts": 3580, + "1805-timer-callback-args.ts": 3293, + "1806-timer-delay-trunc.ts": 3354, + "1810-stream-options-const-record.ts": 4095, + "1811-stream-option-value-callbacks.cjs": 3113, + "1812-stream-super-options-forwarding.cjs": 3239, + "1813-stream-finished.ts": 3753, + "1814-stream-pipeline.cjs": 3633, + "1815-stream-state-reads.cjs": 3723, + "1820-static-block-basics.ts": 3496, + "1821-static-block-order.ts": 3121, + "1822-static-block-js.js": 2926, + "1823-static-instance-method-names.ts": 2971, + "1824-for-of-destructuring-defaults.ts": 3389, + "1825-exhaustive-typeof-switch.ts": 2558, + "1826-settimeout-arguments-callback.js": 3292, + "1830-enum-numeric-basics.ts": 3721, + "1831-enum-string-const-reverse.ts": 3386, + "1832-enum-modules/main.ts": 3491, + "1835-var-basics.ts": 3090, + "1836-var-loop-capture.ts": 4227, + "1837-var-undefined-hoisting.ts": 3129, + "1838-var-modules/main.ts": 3442, + "1839-var-js/main.cjs": 2943, + "1840-jsdoc-import-type-only/main.js": 3153, + "1850-overload-basics.ts": 3527, + "1851-overload-return-narrowing.ts": 3485, + "1852-overload-class-members.ts": 3165, + "1853-overload-modules/main.ts": 3369, + "1854-ambient-declare-fn.ts": 3339, + "1855-ambient-declare-fn-uncaught.ts": 2825, + "1870-unit-type-values.ts": 3760, + "1871-empty-array-never.ts": 2995, + "1872-template-tostring-composite.ts": 3281, + "1880-json-declared-field-order.ts": 3669, + "1881-default-anon/main.ts": 3229, + "1882-default-cjs-interop/main.ts": 3282, + "1883-default-exports/main.ts": 3775, + "1890-ns-imports/main.ts": 3324, + "1891-ns-reexport/main.ts": 3059, + "1940-class-values-basics.ts": 3481, + "1941-class-values-registry.ts": 3018, + "1942-class-expressions.ts": 2837, + "1943-class-statics-expanded.ts": 3294, + "1944-class-values-modules/main.ts": 3634, + "1950-generic-fn-values.ts": 3713, + "1951-generic-classes-basics.ts": 3449, + "1952-generic-class-statics-values.ts": 3863, + "1953-generic-class-hierarchy.ts": 3771, + "1954-generic-modules/main.ts": 3506, + "1960-namespace-basics.ts": 3039, + "1961-namespace-nested.ts": 2879, + "1962-namespace-classes.ts": 3820, + "1963-namespace-aliases.ts": 2943, + "1964-namespace-type-only.ts": 3637, + "1965-namespace-ambient.ts": 3549, + "1966-namespace-modules/main.ts": 3116, + "1967-namespace-alias-typeonly.ts": 2879, + "1968-namespace-import-eq-snapshot.ts": 3284, + "1970-decorators-basics.ts": 3029, + "1971-decorators-rebinding.ts": 3079, + "1972-decorators-throwing.ts": 2634, + "1973-decorators-ambient.ts": 3508, + "1980-primitive-proto-statics.ts": 3768, + "1981-date-utc.ts": 3681, + "1982-freeze-resolve-passthrough.ts": 3352, + "1983-array-tuple-surfaces.ts": 3130, + "1990-labels-basics.ts": 3662, + "1991-for-in-loops.ts": 4312, + "1992-small-syntax.ts": 3036, + "200-strings.ts": 3188, + "2000-generic-methods-basic.ts": 3233, + "2001-generic-methods-generic-class.ts": 3654, + "2002-generic-methods-inheritance.ts": 3883, + "2003-generic-methods-object-literal.ts": 4002, + "2004-generic-methods-statics.ts": 2781, + "201-templates.ts": 3259, + "2010-generators-basics.ts": 2930, + "2011-generators-forof.ts": 3439, + "2012-generators-return-throw.ts": 3077, + "2013-generators-sent-values.ts": 3157, + "2014-generators-values.ts": 3230, + "2015-generators-yieldstar.ts": 2691, + "2016-generators-rc-stress.ts": 3408, + "2017-generators-async.ts": 3645, + "2018-generators-uncaught.ts": 3372, + "2019-generators-loops.ts": 3684, + "2020-generic-value-bindings.ts": 4814, + "2021-generic-value-binding-modules/main.ts": 2613, + "2022-width-index-capture.ts": 4066, + "2023-width-readonly.ts": 3988, + "2024-width-array-elems.ts": 3088, + "2025-width-union-compose.ts": 3148, + "2026-width-spread.ts": 3721, + "2030-width-nested.ts": 3956, + "2031-width-tuples.ts": 3454, + "2032-cjs-export-assigned-class-expression/main.cjs": 3771, + "2033-property-assigned-class-extends.cjs": 2857, + "2035-ternary-array-retag.cjs": 3742, + "2036-evolving-array-decl.cjs": 3733, + "2037-fn-decl-hoisting.cjs": 3504, + "2038-evolving-array-js.cjs": 4258, + "2040-any-bindings.ts": 3664, + "2040-mixin-heritage.ts": 3192, + "2041-any-params-returns.ts": 3362, + "2041-mixin-values.ts": 3893, + "2042-any-flow-loops.ts": 3770, + "2042-mixin-modules/main.ts": 3144, + "2043-any-dom-values.ts": 3779, + "2043-mixin-rc-stress.ts": 4190, + "2044-vtable-sibling-slots.ts": 4054, + "2045-objlit-accessors-basic.ts": 3443, + "2045-parameter-properties.ts": 3049, + "2046-abstract-classes.ts": 4183, + "2046-objlit-accessors-effects.ts": 3215, + "2047-objlit-accessors-shapes.ts": 3091, + "2047-optional-class-fields.ts": 4146, + "2050-dynamic-import-own-module/main.ts": 3451, + "2051-dynamic-import-then/main.ts": 3601, + "2052-dynamic-import-self.ts": 3591, + "2053-typeof-static-fold.ts": 3479, + "2054-destructuring-island-source.ts": 3225, + "2060-empty-tuple.ts": 3198, + "2070-computed-key-folds.ts": 3432, + "2071-integer-key-enumeration-order.ts": 3897, + "2072-expando-function-members.ts": 3830, + "2073-destructuring-assignment.ts": 3540, + "2074-island-destructuring.ts": 3784, + "2075-index-signature-runtime-keys.ts": 2791, + "2080-destructuring-defaults.ts": 3781, + "2081-destructuring-rest.ts": 3728, + "2082-destructuring-assignment.ts": 3505, + "2085-destructuring-heads-rest-params.ts": 3490, + "2087-destructuring-for-heads.ts": 3190, + "2090-index-signature-number-keys.ts": 2803, + "2091-index-signature-string-intersection.ts": 2723, + "2092-package-imports/main.ts": 2857, + "2093-timers-promises.ts": 4034, + "2094-diagnostics-channel.ts": 3375, + "2095-js-catch-unknown.js": 3448, + "2096-os-type.ts": 3784, + "2097-js-evolving-globals.js": 3531, + "210-string-methods.ts": 3602, + "2100-stream-default-hwm.ts": 3572, + "2101-dyn-param-defaults.ts": 2799, + "2102-empty-pattern-decls.ts": 3305, + "2105-computed-key-static-folds.ts": 3458, + "2106-comma-expressions.ts": 3662, + "211-string-unicode.ts": 2722, + "2110-top-object-types.ts": 2930, + "2111-json-stringify-unknown.ts": 2894, + "2112-array-at-findlast.ts": 3347, + "2113-string-index-methods.js": 2954, + "212-string-aliasing-append.ts": 2936, + "2120-package-self-import/main.ts": 2637, + "2121-esm-cycle-inert-backedge/main.ts": 2688, + "2123-ambient-import-crash/main.ts": 2830, + "2124-imports-field-wildcard/main.ts": 2779, + "2140-uri-component-codecs.ts": 3028, + "2160-dc-tracing-channel.cjs": 3125, + "2161-js-object-literal-identity.cjs": 3710, + "2162-js-dyn-destructure.cjs": 2745, + "2163-js-selfref-const.cjs": 4243, + "2164-js-then-dyn-handler.cjs": 4454, + "2165-js-throw-dyn.cjs": 3859, + "2166-cjs-getter-this/main.cjs": 3481, + "2170-island-array-exits.ts": 5249, + "2171-island-json-stringify.ts": 3408, + "2172-island-regexp-boundary.ts": 4656, + "2190-new-object-and-string-wrappers.ts": 2892, + "2191-uri-encoders.ts": 2460, + "2192-object-default-tostring.ts": 3152, + "2193-discarded-stdlib-reads.ts": 3436, + "2194-ambient-undef-chains.ts": 3329, + "2195-require-missing-package/main.mjs": 3396, + "2196-island-computed-key-chain.ts": 4364, + "2210-dyn-promise-crossing.cjs": 3412, + "2211-dc-trace-promise.cjs": 4496, + "2212-unhandled-rejection-listener.cjs": 3503, + "2213-async-local-storage.cjs": 3304, + "2214-dc-bind-store.cjs": 4372, + "2215-process-emit-warning-exit.cjs": 4385, + "2240-width-class-into-record.ts": 3816, + "2241-width-record-into-class.ts": 3107, + "2242-width-statics-into-record.ts": 3187, + "2243-width-assert-satisfies-shapes.ts": 3725, + "2250-tagged-templates.ts": 2802, + "2252-class-iterators.ts": 4024, + "2253-union-coercions.ts": 2969, + "2260-http2-constants.cjs": 2611, + "2280-builtin-namespace-destructure.cjs": 2964, + "2281-domexception-atob-btoa.cjs": 3116, + "2282-queue-microtask.cjs": 3672, + "2283-structured-clone.cjs": 3661, + "2284-regexp-constructor.cjs": 2921, + "2285-iferror-dyn.cjs": 2815, + "2286-dyn-object-walks.cjs": 2814, + "2300-dyn-record-spread-and-keyed-access.cjs": 3340, + "2301-cjs-export-table-dom-attach.cjs": 2994, + "2310-process-next-tick.ts": 3462, + "2311-next-tick-js-callbacks.js": 3541, + "2312-stream-underscore-assign.ts": 4210, + "2313-stream-underscore-assign-js.cjs": 3281, + "2314-process-introspection.ts": 4007, + "2320-await-unit.ts": 2773, + "2321-emitter-static-setmax.cjs": 3576, + "2322-dyn-array-sort.cjs": 2683, + "2323-timer-callback-returns.ts": 3611, + "2330-tls-server-runtime-options.cjs": 22007, + "2331-tls-server-options-typed.ts": 22550, + "2350-nan-global.ts": 3586, + "2351-async-methods.ts": 3496, + "2352-void-coercions.ts": 2875, + "2353-decorators-member-ambient.ts": 2855, + "2354-decorators-expression-ambient.ts": 2445, + "2360-tuple-to-array.ts": 3725, + "2361-assign-index-record.ts": 3918, + "2362-execsync-inherit.ts": 3204, + "2363-nullish-retag.ts": 3277, + "2364-in-runtime-key.ts": 3653, + "2365-dyn-into-island.ts": 2967, + "2366-string-well-formed.ts": 3530, + "2367-regexp-escape.ts": 3537, + "2368-set-methods.ts": 3321, + "2369-promise-try.ts": 3477, + "2370-group-by.ts": 3834, + "2371-iterator-helpers.ts": 3503, + "2380-buffer-module-named-import.ts": 3337, + "2381-builtin-default-imports.js": 3386, + "2382-cycle-two-decl/main.ts": 2540, + "2383-cycle-assertdoc/main.js": 3635, + "2384-cycle-mixed-bindings/main.ts": 2680, + "2385-builtin-reexport-facade/main.ts": 2415, + "2386-string-to-chars.ts": 3358, + "2387-tonumber-argv.ts": 3189, + "2388-tonumber-grammar-zoo.ts": 2478, + "2389-tonumber-unary-plus.ts": 3505, + "2390-dot-requires/main.cjs": 3502, + "2391-default-builtin-imports/main.ts": 3560, + "2392-block-guard-alias-scope.ts": 2811, + "2393-loop-exit-guard-narrow.ts": 3396, + "2394-loop-narrow-containment.ts": 3368, + "2395-while-cond-guard.ts": 2736, + "2396-born-narrowed-decl.ts": 3324, + "2397-branch-kill-merge.ts": 2593, + "2398-switch-arm-kill.ts": 3348, + "2399-reassign-kill-polarity.ts": 3637, + "240-stdout-write.ts": 3882, + "2400-kill-return-edge.ts": 3195, + "2401-kill-break-staging.ts": 3449, + "2402-labeled-break-kill.ts": 2813, + "2403-kill-continue-backedge.ts": 3428, + "2404-kill-throw-catch.ts": 2824, + "2405-sibling-arm-narrow.ts": 2442, + "2406-switch-clause-sibling-narrow.ts": 2665, + "2407-infinite-loop-seal.ts": 3312, + "2408-loop-terminality-reopen.ts": 3281, + "2409-loop-body-return-not-terminal.ts": 3145, + "2410-stacked-cases-terminality.ts": 3627, + "2411-exhaustive-switch-terminality.ts": 3158, + "2412-dowhile-guard-trailing-test.ts": 3265, + "2413-dowhile-kill-renarrow.ts": 2701, + "2414-dowhile-continue-kill.ts": 3317, + "2415-dowhile-break-trailing-test.ts": 3362, + "2416-spread-ternary-positions.ts": 3467, + "2417-ternary-local-inference.ts": 3368, + "2418-wrapped-ternary-arms.ts": 3310, + "2419-selector-ternary-union.ts": 3702, + "2420-nullish-null-identity.ts": 2553, + "2421-float-lane-inference.ts": 3344, + "2422-ieee-div-rem-corners.ts": 3186, + "2423-param-null-reassign.ts": 3025, + "2424-ternary-miss-first-narrowing.ts": 3552, + "2425-elseif-head-exit-narrow.ts": 3257, + "2426-default-snapshot-mutable/main.ts": 3423, + "2427-perf-hooks-now.ts": 3049, + "2428-field-redeclare-inherited.ts": 3585, + "2429-destructure-class-instance.ts": 2694, + "2430-empty-literal-unknown-field.js": 3401, + "2431-primitive-ctor-values.ts": 2884, + "2432-generic-member-fields-async.ts": 5845, + "2433-as-const-command-tables.ts": 3180, + "2434-deferred-init-fields.ts": 3249, + "2435-loose-same-kind-equality.ts": 3363, + "2440-console-inspect-args.ts": 5418, + "2441-console-process-argv.ts": 3041, + "2442-union-literal-arm-widening.ts": 2555, + "2443-union-literal-shadow-narrowing.ts": 3302, + "2444-union-literal-reducer-spread.ts": 3618, + "2445-math-minmax-nary.ts": 2645, + "2446-performance-global.ts": 3980, + "2447-island-boundary-slots/main.ts": 6217, + "2448-entries-null-arms-regex-arrays.ts": 3545, + "2450-private-instance-methods.ts": 2931, + "2451-private-fields.ts": 3694, + "2452-private-statics.ts": 2965, + "2453-private-accessors.ts": 3478, + "2454-private-generator-methods.ts": 3697, + "2455-private-brand-checks.ts": 3515, + "2456-private-async-methods.ts": 3535, + "2457-private-members.js": 2780, + "2460-qs-parse-grammar.ts": 4534, + "2461-qs-parse-options.ts": 4115, + "2462-qs-stringify.ts": 3434, + "2463-qs-escape-unescape.ts": 3311, + "2464-qs-require-forms.cjs": 2821, + "2470-mockable-module-shape.js": 2978, + "2471-record-keyed-write-hasown.js": 2970, + "2472-string-regexp-union.ts": 3393, + "2473-option-table-widths.js": 3653, + "2474-island-literal-forms.ts": 3643, + "2475-variadic-wrapper-island.js": 3606, + "2476-map-regex-values.ts": 3711, + "2480-recursive-record-tree.ts": 3376, + "2481-mutual-recursive-records.ts": 3699, + "2482-recursive-union-tree.ts": 3347, + "2483-recursive-record-cycles.ts": 2764, + "2484-json-stringify-circular.ts": 3845, + "2485-inspect-circular-refs.ts": 3694, + "2486-recursive-record-boundaries.ts": 3988, + "2487-recursive-deep-equal.ts": 3416, + "2488-ast-walker.ts": 3100, + "2490-find-miss-null-compare.ts": 3107, + "2491-strict-unit-compare-no-arm.ts": 2820, + "2492-loose-null-compare-unions.ts": 3683, + "2493-switch-unit-cases.ts": 3703, + "2494-no-arm-compare-effects.ts": 3089, + "2500-net-autosel-timeout.ts": 3775, + "2510-dyn-evolving-array-map.ts": 3265, + "2511-dyn-evolving-array-filter-foreach.ts": 2885, + "2512-dyn-evolving-array-mixed-push.ts": 3639, + "2520-private-statics-class-name-calls.ts": 3155, + "2521-private-statics-class-expression.ts": 3520, + "2522-private-statics-decorated.ts": 3673, + "2523-private-statics-aliased-class.ts": 3795, + "2530-object-destructuring-decl.ts": 2869, + "2531-array-tuple-destructuring-decl.ts": 3168, + "2532-param-destructuring-options.ts": 2906, + "2533-forof-destructuring.ts": 2840, + "2534-object-rest-decl.ts": 3199, + "2535-destructuring-assign-basics.ts": 3816, + "2536-destructuring-assign-nested.ts": 3047, + "2537-destructuring-assign-member-targets.ts": 3590, + "2538-destructuring-assign-class-source.ts": 3544, + "2539-class-instance-rest.ts": 3764, + "2540-accessor-destructuring-defaults.ts": 3201, + "2541-destructuring-eval-order.ts": 2670, + "2550-generics-keyof-pick.ts": 3947, + "2551-generics-value-aliases.ts": 3227, + "2552-generics-iface-methods.ts": 3318, + "2553-generics-signature-bindings.ts": 3442, + "2554-generics-frontier-mix.ts": 3344, + "2555-generics-keyof-writes.ts": 3448, + "2556-crypto-introspection.ts": 3351, + "2556-width-hybrid-shapes.ts": 3462, + "2557-tls-ca-store.ts": 4438, + "2557-width-field-lifts.ts": 4453, + "2558-index-signature-func-values.ts": 3590, + "2558-rejection-events.cjs": 3641, + "2559-index-signature-container-values.ts": 4066, + "2560-arraybuffer-dataview-set.ts": 3614, + "2561-object-is.ts": 3391, + "2562-intl-numberformat-en-us.ts": 3241, + "2563-stream-promises-pipeline.ts": 3490, + "2564-stream-promises-finished.ts": 2994, + "2565-stream-promises-js.cjs": 2616, + "2566-promise-reject-dyn-reason.js": 3548, + "2567-rest-spread-forward.js": 3292, + "2568-rest-spread-forward-dynamic.js": 3367, + "2569-upcast-identity.ts": 2553, + "2570-buffer-arg-validation.cjs": 5779, + "2571-searchparams-arg-validation.cjs": 3913, + "2572-readable-emitted-readable-flag.cjs": 3556, + "2573-fs-url-arg-ladders.cjs": 3502, + "2574-emitter-max-listeners-ladders.cjs": 2895, + "2575-string-destructuring-decl.ts": 3433, + "2576-string-destructuring-assign.ts": 2984, + "2577-builtin-global-destructuring.js": 3466, + "2578-jsval-into-unknown-rows.ts": 3398, + "2579-jsval-object-param-crossing.js": 3294, + "2580-jsval-routed-keyed-ops.js": 3298, + "2581-jsval-routed-calls.js": 3542, + "2582-jsval-object-statics.js": 3509, + "2582-jsval-routed-keyed-ops.js": 3136, + "2583-dyn-nullish-coalesce.js": 2976, + "2583-jsval-routed-calls.js": 2950, + "2584-jsval-object-statics.js": 3305, + "2584-union-dyn-collapse.ts": 2970, + "2585-dyn-nullish-coalesce.js": 3632, + "2585-unknown-array.ts": 3809, + "2586-object-assign-spread.js": 4084, + "2587-array-entries-forof.ts": 2633, + "2588-array-entries-chains.ts": 4097, + "2589-object-create-null.cjs": 3112, + "2590-object-create-dynamic.js": 4279, + "2591-ambient-generic-traps.ts": 3216, + "2592-ambient-trap-uncaught.ts": 3198, + "2593-generic-inert-bindings.ts": 3007, + "2594-nullish-generic-bindings.ts": 3321, + "2595-fs-arg-ladders.cjs": 3930, + "2596-net-arg-ladders.cjs": 3528, + "2597-dgram-send-ladders.cjs": 4536, + "2598-tls-arg-ladders.cjs": 4142, + "2599-stream-arg-ladders.cjs": 5465, + "2600-dyn-keyed-write-harness.js": 2800, + "2601-dyn-keyed-write-ops.js": 3269, + "2602-dyn-array-destructure.js": 3207, + "2603-island-keyed-write-dyn.js": 3608, + "2604-cycle-classes-mutual/main.ts": 3410, + "2605-cycle-three-module/main.ts": 2592, + "2606-dynamic-import-cycle/main.ts": 2445, + "2608-regex-named-groups.ts": 3896, + "2609-regex-named-replace.ts": 3215, + "2610-regex-named-matchall.ts": 3887, + "2611-regex-named-groups-js.cjs": 3523, + "2613-for-init-uninitialized-let.ts": 3167, + "2614-trap-binding-later-writes.ts": 3345, + "2615-nullish-field-record-binding.ts": 2720, + "2616-js-collect-probe-defers.js": 3534, + "2617-enum-static-field-import/main.ts": 3068, + "2618-ee-emit-override.ts": 3915, + "2619-ee-override-chain.ts": 2567, + "2620-ee-override-once-order.ts": 3439, + "2621-ee-override-error-throw.ts": 3265, + "2622-ee-override-filter.ts": 3339, + "2623-ee-job-queue.ts": 3586, + "2624-ee-override-js.cjs": 2637, + "2625-bytes-views.ts": 2847, + "2626-stream-event-names.ts": 3436, + "2627-stream-ticks-are-nextticks.ts": 4048, + "2628-stream-push-encodings.cjs": 3219, + "2629-stream-consumers.ts": 4523, + "2630-stream-consumers-errors.ts": 3353, + "2631-create-require/main.ts": 2869, + "2632-dyn-jsval-iterate.js": 3938, + "2633-island-promise-crossing.js": 3898, + "2634-stream-pipeline-arg-ladders.cjs": 2829, + "2635-trap-binding-unmappable-written.ts": 3493, + "2636-trap-binding-ambient-rooted-rewrite.ts": 3155, + "2637-create-require-bare/main.ts": 3093, + "2638-http-dyn-res-compat.cjs": 7897, + "2639-http-dyn-req-pause.cjs": 4028, + "2640-net-dyn-socket-compat.cjs": 3877, + "2641-http-agent-surface.cjs": 6286, + "2642-http-agent-maxsockets.cjs": 4681, + "2643-or-default-retag.ts": 3292, + "2644-http-client-url-argument.ts": 3256, + "2645-https-client-url-argument.ts": 24258, + "2646-top-level-await.ts": 3392, + "2647-top-level-await-modules/main.ts": 3047, + "2648-top-level-await-rejection.ts": 3150, + "2649-top-level-await-pending.ts": 3160, + "2650-top-level-await-self-import.ts": 2440, + "2651-top-level-await-pending-unhandled.ts": 2762, + "2652-top-level-await-dynamic/main.ts": 3760, + "2653-top-level-await-rejection-stops-loop.ts": 2631, + "2654-top-level-await-unrelated-rejection.ts": 2643, + "2655-top-level-await-cycle/main.ts": 3098, + "2656-top-level-await-cycle-order/main.ts": 3167, + "2657-top-level-await-cycle-dynamic/main.ts": 2957, + "2658-top-level-await-sync-completion/main.ts": 3318, + "2659-top-level-await-dynamic-cycle/main.ts": 2585, + "2660-top-level-await-cycle-rejection/main.ts": 3210, + "2661-top-level-await-dynamic-runtime-root/main.ts": 3366, + "2662-top-level-await-cycle-external-wait/main.ts": 3005, + "2663-top-level-await-dependency-errors/main.ts": 2847, + "2664-top-level-await-same-checkpoint-rejection.ts": 3116, + "2665-top-level-await-unhandled-listener-liveness.ts": 2875, + "2666-array-to-sorted.ts": 7633, + "2668-stored-number-array-iterator.ts": 3253, + "2669-array-copying-methods.ts": 3549, + "2670-uint8array-copy-iterate.ts": 3853, + "2671-array-copying-js.cjs": 3682, + "2672-http-request-response-callback.ts": 4143, + "2673-top-level-await-implicit-module.ts": 3247, + "2674-top-level-for-await-implicit-module.ts": 3134, + "2675-create-require-nested-esm.js": 2364, + "2675-process-self-reexec.ts": 2727, + "2676-indexed-read-strict-equality.ts": 2731, + "2676-record-clone-overrides.ts": 2957, + "2676-top-level-await-ambiguous/main.ts": 2732, + "2677-runtime-optional-closure.ts": 4013, + "2677-top-level-await-module-scope/main.ts": 3413, + "2678-date-instances.ts": 2682, + "2678-large-string-sparse-index.ts": 3695, + "2678-util-parseargs.ts": 6509, + "2679-util-parseargs-cjs.cjs": 4674, + "2680-util-parseargs-default.ts": 2968, + "2681-util-parseargs-dynamic.js": 4805, + "2682-fs-rename.ts": 3870, + "2683-filter-truthy-predicate.ts": 3057, + "2683-fs-rename-js.cjs": 3194, + "2684-filter-no-predicate-dyn.cjs": 2886, + "2684-fs-rename-abort.ts": 4187, + "2685-array-unshift-reverse.ts": 3336, + "2685-fs-write-sync.ts": 3018, + "2686-fs-file-handle.ts": 4533, + "2687-fsp-write-file-options.ts": 3468, + "2687-process-write-args.ts": 4056, + "2688-fs-stats-disk-fields.ts": 3885, + "2689-http-server-timeout-properties.ts": 3928, + "2690-https-server-timeout-option.ts": 21635, + "2691-retained-lowering-record-order.ts": 4394, + "2692-inline-record-assert-index.ts": 4260, + "2692-string-accumulation.ts": 2769, + "2693-math-constants.ts": 2825, + "2700-array-sort-complexity.ts": 3067, + "2700-http-static-trailers.ts": 3428, + "2700-wasi-core.ts": 3839, + "2701-array-sort-snapshot.ts": 3995, + "2701-http-static-trailer-wire.ts": 3237, + "2701-import-meta/main.mjs": 2794, + "2702-http-static-trailer-end.ts": 3525, + "2702-type-import-link-static/main.ts": 3217, + "2702-uint8array-to-sorted.ts": 3838, + "2703-array-sparse-sort.ts": 7138, + "2703-type-import-link-static-reexport/main.ts": 2989, + "2704-array-sparse-to-sorted.ts": 7251, + "2704-type-import-link-static-success/main.ts": 3249, + "2705-array-sparse-sort-append.ts": 6240, + "2705-type-import-link-dynamic/main.ts": 2760, + "2706-array-search-missing-needle.ts": 3091, + "2706-type-import-link-dynamic-success/main.ts": 3330, + "2707-array-search-huge-sparse.ts": 45179, + "2707-type-import-link-static-default-reexport/main.ts": 2758, + "2708-type-import-link-dynamic/main.ts": 4132, + "2720-array-read-parity.ts": 3456, + "2721-array-nested-missing-receiver.ts": 3322, + "2750-array-sparse-foundation.ts": 3816, + "2751-buffer-concat-sparse-list.ts": 3043, + "2752-array-optional-stores.ts": 3548, + "2753-array-optional-method-values.ts": 3422, + "2754-array-property-undefined.ts": 3456, + "2755-array-optional-literal-forwarding.ts": 3507, + "2780-array-parity-composition.ts": 9748, + "2781-array-missing-value-escape.ts": 2984, + "2782-array-sparse-callbacks.ts": 3368, + "2783-array-defaults-rest.ts": 3426, + "2784-array-reduce-missing-result.ts": 2920, + "2785-array-missing-destructuring.ts": 4220, + "2786-array-sparse-serialization.ts": 3688, + "2787-array-missing-string-arithmetic.ts": 2565, + "2788-array-missing-builtin-conversions.ts": 2767, + "2789-array-missing-optional-tostring.ts": 3009, + "2790-dynamic-import-self-name/main.ts": 3621, + "2791-record-optional-keys.ts": 3660, + "2792-record-optional-spread-entries.ts": 3741, + "2793-union-conversion-identity-capture.ts": 3519, + "2794-array-generic-callback-values.ts": 2842, + "2795-array-optional-typedarray-source.ts": 29642, + "2796-array-sparse-class-value-instanceof.ts": 4014, + "2800-array-expression-consumers.ts": 2964, + "2801-array-switch-consumers.ts": 3634, + "2820-array-missing-method-receivers.ts": 3219, + "2821-array-optional-numeric-comparisons.ts": 3648, + "2830-cjs-require-self-name/main.cjs": 2817, + "2840-finally-completions.ts": 2484, + "2841-using-sync.ts": 3654, + "2842-await-using.ts": 3139, + "2843-using-suppressed-error.ts": 3369, + "2844-node-disposable-resources.ts": 3909, + "2845-for-using-of.ts": 3562, + "2846-generator-using.ts": 3676, + "2850-async-generators-protocol.ts": 4224, + "2851-async-generators-values.ts": 3418, + "2852-timers-promises-interval.ts": 3999, + "2854-leading-bom-literals.ts": 3644, + "2855-searchparams-sort-complexity.ts": 2896, + "2856-dynamic-any-local-operators.ts": 3122, + "2857-branded-primitives.ts": 2535, + "2858-import-meta-resolve/main.mjs": 2803, + "2859-import-meta-resolve-dynamic/main.mjs": 2791, + "2860-require-resolve/main.cjs": 3416, + "2861-readable-iterator-close.ts": 3965, + "2862-web-readable-async-iteration.ts": 48807, + "2863-class-async-iterator.ts": 3227, + "2864-array-class-method-receivers.ts": 2404, + "2865-cjs-process-alias.cjs": 3403, + "2866-dyn-switch.ts": 2311, + "2867-array-shift-length.js": 3507, + "2868-empty-record-promise-presence.js": 2925, + "2869-nullish-mixed-lazy.ts": 2958, + "2870-and-dropped-truthy-arm.ts": 2834, + "2871-optional-promise-to-unknown.ts": 3267, + "2872-unobserved-dynamic-event.ts": 3355, + "2873-optional-receiver-loop-lifetime.js": 3047, + "2874-nullable-callback-field-cycle.js": 3534, + "2875-evolving-let-read-before-write.js": 2810, + "2876-class-unknown-roundtrip.ts": 3764, + "2877-child-unknown-roundtrip.ts": 2785, + "2878-class-private-unknown.cjs": 3352, + "2880-cjs-module-graph/main.cjs": 3782, + "2890-crypto-static-utility.ts": 2826, + "2891-json-record-key-escapes.ts": 3816, + "2892-windows-console-unicode.ts": 3563, + "2893-child-stdin-duplex.ts": 3578, + "2894-child-stdin-backpressure.ts": 3536, + "2895-child-stdin-write-after-end.ts": 3038, + "2896-child-stdin-write-after-finish.ts": 3391, + "2897-child-stdin-destroy.ts": 3563, + "2898-child-stdin-spawn-failure.ts": 3036, + "2899-nested-mutual-recursion.ts": 3350, + "2900-float64array-static.ts": 3865, + "2900-void-conditional-arrow.ts": 2828, + "2901-bigint-core.ts": 3440, + "2902-bigint-bytes.ts": 2684, + "2903-bigint-storage.ts": 3029, + "2904-bigint-errors.ts": 3660, + "2905-bigint-edges.ts": 3424, + "2906-bigint-wasi-width.ts": 3017, + "2910-overloaded-callable-alias.ts": 3175, + "2911-execfile-callback.ts": 3152, + "2912-execfile-callback-options.ts": 3514, + "2912-promisify-fs-readfile.ts": 3307, + "2913-builtin-callable-alias.ts": 4333, + "2914-fixed-tuple-call-spread.ts": 3657, + "2915-path-function-values.ts": 2684, + "2916-path-function-values-cjs.ts": 3544, + "2917-builtin-callable-widths.ts": 3312, + "2918-builtin-callable-widths-cjs.ts": 4040, + "2919-fs-function-values.ts": 4214, + "2920-fs-promises-function-values.ts": 2447, + "2921-zlib-callbacks.ts": 4192, + "2922-dyn-bitwise-not.cjs": 2704, + "2923-cjs-factory-export/main.cjs": 3106, + "2930-union-receiver-calls.ts": 3700, + "2931-union-dynamic-field-call.js": 3466, + "2932-create-require-program/main.ts": 3686, + "2933-static-dynamic-import/main.ts": 3405, + "2934-static-import-stored.ts": 2381, + "2935-module-namespace-values/main.ts": 3289, + "2936-static-loose-equality.ts": 3642, + "2937-bitwise-hot-loop.ts": 3298, + "2938-fs-sync-overloads.cjs": 2598, + "2939-child-shell-text.ts": 2919, + "2940-date-parse.ts": 3171, + "2940-fsp-realpath.ts": 3497, + "2941-fsp-lstat-identity.ts": 3608, + "2941-process-exit-code.ts": 3007, + "2942-fsp-readdir-dirent.ts": 3744, + "2942-process-exit-code-override.ts": 2479, + "2943-process-exit-code-invalid.ts": 3225, + "2944-process-exit-code-wrap.ts": 3249, + "2945-url-origin-username.ts": 2371, + "2946-child-fork-ipc/main.ts": 4191, + "2946-url-port-hash.ts": 2720, + "2947-set-readonly-seeds.ts": 3363, + "2948-child-fork-eof-callback/main.ts": 3691, + "2948-stdio-callback-record.ts": 3021, + "2949-child-fork-default/main.mjs": 3752, + "2949-url-password.ts": 3268, + "2950-fs-descriptor-publication.ts": 3039, + "2951-math-static-analytic.ts": 2897, + "2952-math-static-remaining.ts": 3708, + "2953-http-header-validation.ts": 2926, + "2954-http-outgoing-headers.ts": 3568, + "2955-http-static-state.ts": 3392, + "2956-http-static-informational.ts": 3156, + "2957-http-static-response-controls.ts": 3011, + "2961-emitter-computed-names.cjs": 3061, + "2962-emitter-computed-optional.ts": 3117, + "2963-child-fork-dispatch/main.ts": 3069, + "2964-indexed-compound.ts": 4283, + "2966-numeric-array-read-fusion.ts": 2881, + "2967-numeric-array-read-lifetime.ts": 3327, + "2968-numeric-array-borrow.ts": 3624, + "2969-scalar-record-results.ts": 3705, + "2970-constant-numeric-tables.ts": 3396, + "2971-constant-table-modules/main.ts": 2786, + "2972-http-static-distinct-snapshots.ts": 3464, + "2972-math-receiver-borrow.ts": 4257, + "2973-http-static-agent.ts": 3844, + "2973-integer-bitwise-arithmetic.ts": 3703, + "2974-array-search-from-index.ts": 120829, + "2974-http-static-module-values.ts": 5733, + "2974-numeric-remainder.ts": 3749, + "2975-bigint-default-radix.ts": 2671, + "2975-http-static-client-controls.ts": 3229, + "2976-http-static-incoming-state.ts": 3560, + "2976-json-stringify-no-arguments.js": 3221, + "2977-http-static-incoming-timeout.ts": 3554, + "2977-nested-array-binding-defaults.js": 3145, + "2978-http-static-client-timeout.ts": 3607, + "2978-regexp-optional-subject.js": 3504, + "2979-array-search-mixed-needles.js": 2692, + "2979-http-static-server-timeout.ts": 3769, + "2980-http-static-server-timeout-default.ts": 3050, + "2980-string-position-arguments.js": 3269, + "2981-http-static-events.ts": 2644, + "2981-string-optional-positions.ts": 2494, + "2982-http-static-close-all.ts": 2737, + "2982-string-position-coercion-order.js": 3410, + "2983-http-static-close-idle.ts": 3031, + "2984-http-static-close-upgrade.ts": 3101, + "2985-http-static-message-destroy.ts": 3632, + "2986-http-static-client-socket-finish.ts": 2911, + "2987-http-static-timeout-errors.ts": 3301, + "2988-http-static-client-abort.ts": 2940, + "2989-http-static-response-timeout-handled.ts": 3640, + "2990-http-static-request-timeout-handled.ts": 3597, + "2991-array-indexed-equality.ts": 3696, + "2992-stream-rows.ts": 3357, + "2993-fiber-stack-lifetimes.ts": 3545, + "2994-fromcharcode-scalar.ts": 3381, + "2995-math-hyperbolic.ts": 3225, + "2996-math-near-one.ts": 2714, + "2997-math-integer-float.ts": 3635, + "300-if-else.ts": 2510, + "3001-caught-typeof-object.js": 3444, + "3002-promise-then-two.ts": 3645, + "301-while.ts": 3200, + "302-for.ts": 2865, + "3020-string-last-index-position.ts": 3627, + "3021-buffer-union-narrow-callback.ts": 3829, + "3022-string-affix-positions.ts": 3463, + "3023-string-affix-position-coercion.js": 3644, + "3024-string-number-narrow-for-in.ts": 3394, + "3025-string-search-position-coercion.js": 3367, + "3026-array-last-index-of.js": 2868, + "3027-array-last-index-of-records.ts": 3472, + "3028-string-search-dynamic-needle.js": 2934, + "3029-string-search-union-needle.js": 3701, + "303-break-continue.ts": 2701, + "3030-array-search-no-arg.js": 3806, + "3031-array-relative-index-coercion.js": 3498, + "3031-string-last-index-search-value.js": 2610, + "3032-string-search-value.js": 3067, + "3033-string-search-needle-coercion.js": 3292, + "3034-arguments-with-parameters.js": 2687, + "3035-string-positioned-search-value.js": 3575, + "3036-string-object-search-value.js": 2688, + "3037-number-nullish-conversion.js": 3018, + "3038-number-scalar-unions.ts": 2381, + "3039-string-repeat-count.js": 2336, + "304-compound-incdec.ts": 3307, + "3040-string-prototype-call.js": 3584, + "3041-string-prototype-object-call.js": 3163, + "3042-string-padding-coercion.js": 3486, + "3043-string-split-arguments.js": 3038, + "3044-array-slice-splice-positions.js": 3582, + "3045-array-indexed-mutation.js": 4003, + "3046-array-indexed-ref-identity.ts": 2594, + "3047-object-prototype-tag.js": 5012, + "3048-object-own-prototype.ts": 4080, + "3049-array-flat-depth.ts": 3414, + "305-truthiness.ts": 2664, + "3050-array-splice-insert.ts": 2966, + "3051-array-join-default.ts": 3468, + "3052-array-construction.ts": 4201, + "3053-array-construction-js.js": 2937, + "3054-dynamic-abort-record.ts": 25141, + "3055-default-builtin-nodenext/main.ts": 2702, + "3056-default-builtin-bundler/main.ts": 3487, + "3057-default-builtin-nodenext-dynamic/main.ts": 2447, + "3058-optional-array-chain-join.ts": 3991, + "3059-arguments-property-names.ts": 2550, + "3061-concurrent-fiber-stacks.ts": 3788, + "3062-runtime-optional-record-guards.ts": 3181, + "3063-runtime-optional-class-guards.ts": 3568, + "3064-installed-entry-imports/main.ts": 2606, + "3065-installed-entry-js/main.js": 3045, + "3066-source-debugging/main.ts": 3383, + "3067-cjs-function-export-require/main.cjs": 2939, + "3068-debug-variables/main.ts": 2618, + "3068-url-checked-identity.ts": 3006, + "3069-set-checked-seed.js": 3140, + "3069-tuple-spread.ts": 3376, + "3070-checked-object-accessors.js": 3573, + "3070-collection-views.ts": 3175, + "3071-checked-specialization-narrowing.js": 3321, + "3071-map-contextual-record-seeds.ts": 4329, + "3072-optional-union-receivers.ts": 3610, + "3072-weak-process-streams.js": 2918, + "3073-optional-callable-module.js": 3300, + "3073-union-keyed-reads.ts": 3869, + "3074-discriminated-intersections.ts": 3384, + "3075-recursive-contextual-literals.ts": 4502, + "3076-nullish-record-defaults.ts": 3009, + "3077-optional-union-array-reads.ts": 3992, + "3078-forward-mutable-captures.ts": 3466, + "3079-forward-mutable-tdz.ts": 3489, + "3080-exhaustive-never-bindings.ts": 3664, + "3081-recursive-array-destinations.ts": 3893, + "3082-forward-write-unwind.ts": 3471, + "3083-set-string-seed.ts": 3139, + "3084-record-own-membership.ts": 2971, + "3085-conditional-record-construction.ts": 3822, + "3086-error-constructor-options.ts": 3660, + "3087-error-options-lifetime.ts": 2905, + "3088-array-wide-callbacks.ts": 3195, + "3089-array-find-narrowing.ts": 4220, + "3090-json-discriminated-records.ts": 3463, + "3091-json-recursive-discriminants.ts": 3555, + "3092-number-union-predicates.ts": 2884, + "3093-error-option-data.ts": 2574, + "3094-json-replacer-traversal.ts": 3823, + "3095-json-reviver-traversal.ts": 3825, + "3096-json-callback-nonfinite.ts": 3620, + "3097-json-callback-reentrancy.ts": 2760, + "3098-json-callback-space.ts": 3696, + "3099-json-callback-functions.ts": 4108, + "3100-json-callback-holder.js": 3675, + "3101-json-callback-bytes.ts": 3250, + "3102-json-unknown-fields.ts": 2925, + "3103-scalar-record-nested-control-flow.ts": 3592, + "3104-native-analysis-tables-loops.ts": 3494, + "3105-nullable-collections.ts": 3244, + "3106-mixed-insertion-spreads.ts": 4146, + "3107-nullable-collection-lifetimes.ts": 3486, + "3108-for-await-sync-arrays.js": 4312, + "3108-identity-map-keys.ts": 3894, + "3109-destructuring-unknown-defaults.js": 3234, + "3109-identity-union-collections.ts": 3977, + "3110-builtin-error-families.ts": 3250, + "3110-identity-collection-mutation.ts": 3825, + "3111-identity-collection-cycles.ts": 3640, + "3112-union-switch-control-flow.ts": 2681, + "3113-union-array-removal.ts": 3778, + "3114-union-record-field-write.ts": 3884, + "3115-zlib-static-compression-levels.ts": 4085, + "3116-sequence-expression-lifetimes.ts": 3245, + "3117-unknown-switch-control-flow.ts": 3706, + "3118-recursive-union-spread.ts": 3476, + "3119-runtime-optional-spread.ts": 4508, + "3120-dynamic-property-descriptors.js": 3228, + "3120-generator-method-loop-bindings.ts": 3222, + "3120-ir-nonfinite-numbers.ts": 3251, + "3121-compound-assignment-values.js": 3525, + "3121-dynamic-accessor-descriptors.js": 4470, + "3122-dynamic-delete-descriptors.cjs": 3353, + "3122-dynamic-delete-descriptors.js": 3300, + "3122-js-async-class-methods.js": 3524, + "3123-destructured-global-tdz.js": 3896, + "3124-array-prototype-borrow.js": 4000, + "3125-regex-global-match.ts": 2889, + "3126-js-number-radix/main.ts": 3491, + "3127-spawn-runtime-options.ts": 3338, + "3128-regex-last-index.ts": 3768, + "3129-js-token-union/main.ts": 3461, + "3130-child-generic-streams.ts": 3435, + "3131-child-rest-listeners.js": 3280, + "3132-child-generic-stream-completion.ts": 6821, + "3133-text-decoder-streaming.ts": 32031, + "3134-fs-vectors.ts": 3621, + "3135-fs-file-handle-controls.ts": 3152, + "3136-fs-file-handle-options.ts": 4992, + "3137-fs-vector-callbacks.cjs": 3636, + "3138-array-large-storage.ts": 5104, + "3139-regex-native-deep-alternatives.ts": 38096, + "3140-array-dense-access.ts": 4712, + "3141-map-string-key-hash.ts": 3358, + "3150-integer-remainder.ts": 3568, + "3151-array-push-writes.ts": 3892, + "3170-number-conversion-fast-paths.ts": 2663, + "3171-method-census-data-writes.ts": 4253, + "400-fib.ts": 3919, + "401-mutual-recursion.ts": 2844, + "402-string-functions.ts": 3081, + "403-void-and-params.ts": 3112, + "4030-runtime-object-truthiness.ts": 3275, + "4031-event-emitter-long-tuples.ts": 3646, + "4032-inline-rc-fast-paths.ts": 4866, + "404-rc-stress.ts": 2781, + "4040-adapted-function-identity.ts": 3610, + "4041-adapted-function-properties.ts": 3413, + "4042-object-is-union-subclass.ts": 2746, + "4043-nonnull-missing-element.ts": 3815, + "4044-adapted-callback-modules/main.ts": 2918, + "4045-optional-element-projections.ts": 4182, + "4046-captured-parameter-values.ts": 4191, + "4047-captured-parameter-rebinding.ts": 2867, + "405-params-optional.ts": 2408, + "406-params-defaults.ts": 2614, + "4060-cycle-shared-instance/main.ts": 2758, + "4060-stack-union-reads.ts": 4386, + "4061-cycle-evaluation-order/main.ts": 3229, + "4061-nullable-ref-fields.ts": 6151, + "4062-cycle-tdz-read/main.ts": 3056, + "4063-cycle-hoisted-calls/main.ts": 3238, + "4064-cycle-classes-after-init/main.ts": 2548, + "4065-cycle-init-throws/main.ts": 2955, + "4066-cycle-top-level-tdz/main.ts": 3040, + "4067-dynamic-import-cycle-tdz/main.ts": 3004, + "407-params-rest.ts": 3335, + "408-params-ctors-inheritance.ts": 3021, + "4080-optional-read-presence-tests.ts": 3095, + "4080-string-index-bounds.ts": 3083, + "4081-hoisted-function-tdz.ts": 3193, + "4081-string-index-unproven.ts": 3273, + "4082-hoisted-function-tdz-uncaught.ts": 2845, + "4083-dynamic-import-failure/main.ts": 3748, + "4084-record-optional-field-copies.ts": 4118, + "4085-generator-loop-close.ts": 3638, + "4086-optional-capture-defaults.ts": 3227, + "4088-class-static-tdz.ts": 3234, + "4089-class-wrapper-tdz.js": 3393, + "409-params-async-generics.ts": 2742, + "4090-computed-key-tdz.js": 2796, + "4091-class-evaluation-deferred.ts": 3464, + "410-params-rc-stress.ts": 3461, + "4140-array-callback-split-visit.ts": 7289, + "4141-array-callback-ambient-receiver/main.ts": 3100, + "4142-array-callback-factories.ts": 4541, + "4143-union-refinement-intersection-arms.ts": 3822, + "420-dead-strip-modules/main.ts": 3118, + "4290-acyclic-immutable-trees.ts": 3580, + "4291-acyclic-constructor-escapes.ts": 3039, + "4292-acyclic-readonly-bypass.ts": 4316, + "4293-acyclic-dynamic-writes.ts": 3268, + "4294-console-line-sizes.ts": 6986, + "4295-console-template-parts.ts": 3358, + "4296-console-glued-long-parts.ts": 3290, + "4410-inline-object-allocation.ts": 3305, + "4411-nullable-ref-values.ts": 5301, + "4412-nullable-record-values.ts": 5088, + "4413-cycle-old-late-death.ts": 4012, + "4413-nullable-null-and-undefined.ts": 4328, + "4414-cycle-old-weak-keys.ts": 4005, + "4414-nullable-string-values.ts": 5044, + "4415-identity-borrowed-operands.ts": 3101, + "4415-nullable-container-values.ts": 4932, + "4431-exception-pending-contexts.ts": 3487, + "4432-checked-downcast-failures.ts": 3971, + "4451-int32-field-storage.ts": 3668, + "4452-int32-field-dynamic-writes.ts": 4531, + "4453-int32-closed-locals.ts": 2786, "4454-int32-field-reflection-reads.ts": 3494, "4455-live-view-reads-without-stores.ts": 4871, - "4471-unassigned-field-reads.ts": 3438, - "4476-string-ascii-header-fact.ts": 4141, - "4477-buffer-write-ascii-runs.ts": 4249, - "4478-string-large-index-reads.ts": 4215, - "4481-array-optional-push.ts": 3757, - "4482-instanceof-static-class-optional.ts": 3228, - "4483-array-splice-statement.ts": 4359, - "4484-array-length-reset.ts": 3824, - "4485-array-splice-optional-item.ts": 4447, - "4486-array-field-element-borrows.ts": 4170, - "4487-array-literal-optional-values.ts": 3597, - "4520-optional-guard-narrowing.ts": 4519, - "4521-array-callback-element-presence.ts": 6504, - "4522-captured-parameter-lifetimes.ts": 3501, - "4523-array-pop-removal.ts": 4310, - "4524-array-callback-supertype-params.ts": 4795, - "4541-nullable-wrap-borrows.ts": 4219, - "4542-preserving-call-borrows.ts": 4390, - "4543-walk-borrowed-locals.ts": 4424, - "4544-checked-cast-aliases.ts": 4017, - "4545-borrowed-returns.ts": 5010, - "4546-rebound-borrowed-params.ts": 4038, - "4560-field-store-borrowed-receivers.ts": 4292, - "4561-virtual-borrowed-parameters.ts": 3188, - "4562-string-self-concat-move.ts": 3258, - "4563-array-read-projection-receivers.ts": 4193, - "4564-literal-choice-strings.ts": 4376, - "4568-for-of-hole-elements.ts": 4040, - "4569-shorthand-missing-elements.ts": 5489, - "4570-map-lookup-default-record.ts": 4379, - "4591-weak-keys-union-records.ts": 3376, - "4592-cycle-const-from-import/main.ts": 3235, - "4593-weak-keys-empty-objects.ts": 4125, - "4594-union-class-field-mixed-types.ts": 6642, - "4595-union-class-field-optional-receiver.ts": 3958, - "4596-error-subclass-int-fields.ts": 3809, - "4596-tdz-nullable-forward-capture.ts": 5432, - "4597-callback-field-method-name.ts": 4265, - "4598-live-array-ref-element-access.ts": 9798, - "4598-map-set-clear-reuse.ts": 5772, - "4598-os-available-parallelism.ts": 3841, - "4598-publish-constructor-stores.ts": 4373, - "4599-construction-only-field-borrows.ts": 4185, - "4600-construction-only-fields-dynamic-writes.ts": 3870, - "4601-cycle-holders.ts": 3436, - "4602-constructor-escape-order.ts": 4107, - "4610-array-ext-dyn-refresh.ts": 4200, - "4620-optional-chain-borrowed-receivers.ts": 3633, - "4621-edge-preserving-callees/main.ts": 4459, - "4630-contract-int32.ts": 3693, - "4630-reference-write-call-arguments.ts": 3005, - "4631-contract-nothrow.ts": 3977, - "4631-reference-write-aliases.ts": 4000, - "4632-contract-immutable.ts": 4206, - "4632-reference-write-loops-and-walks.ts": 3622, - "4633-contract-program-lifetime.ts": 4928, - "4633-reference-write-callbacks-returns.ts": 4472, - "4634-contract-program-lifetime-publish.ts": 58146, - "4634-optional-element-borrowed-returns.ts": 3892, - "4640-bitwise-identity-ranges.ts": 3488, - "4641-nothrow-try-catch.ts": 3941, - "4642-acyclic-contract.ts": 4488, - "4650-stale-property-narrowing.ts": 5393, - "4651-map-string-get-entry.ts": 4850, - "4652-stale-closure-binding-narrowing.ts": 4646, - "4660-typed-rest-spread-forwarding.ts": 3964, - "4671-scoped-array-read-borrows.ts": 4659, - "4690-cycle-bypass-long-lived.ts": 6611, - "4691-publish-constructor-self-alias.ts": 32098, - "4692-borrowed-result-mutating-callees.ts": 4121, - "4720-cold-throw-paths.ts": 3462, - "4721-integer-induction-numbers.ts": 4315, - "4730-touint32-large-magnitudes.ts": 4331, - "4731-string-mixed-ascii-slices.ts": 4955, - "4732-buffer-write-utf16le-runs.ts": 4567, - "4733-typed-array-read-compares.ts": 4680, - "4750-map-string-absent-filter.ts": 3842, - "4751-string-search-multibyte-needles.ts": 4006, - "4795-published-untyped-member-reads.ts": 3280, - "4806-uint32-loop-accumulators.ts": 4561, - "4810-union-identity-retags.ts": 35042, - "4811-union-retag-checked-cast.ts": 4067, - "4812-int32-wrapping-sums.ts": 5061, - "4813-typed-array-read-equality-bindings.ts": 6041, - "4820-sort-comparator-lent-arguments.ts": 5459, - "4821-callback-lent-arguments.ts": 5557, - "4822-stable-capture-reads.ts": 4662, - "4823-array-store-receivers.ts": 3343, - "4830-typed-teardown-chains.ts": 4609, - "4831-cycle-bypass-probe-windows.ts": 6532, - "4840-array-hole-free-prefix.ts": 5275, - "4860-int32-local-storage.ts": 4493, - "4870-array-pipeline-fusion.ts": 9864, - "4871-array-pipeline-analytics.ts": 5983, - "4872-array-pipeline-temporaries.ts": 10585, - "4875-stream-consumers-array-buffer.ts": 5489, - "4876-array-buffer-inspect.ts": 4454, - "4880-await-call-turn-order.ts": 4340, - "4881-await-call-exceptions.ts": 3334, - "4882-await-call-request-chain.ts": 4240, - "4883-await-values-and-hops.ts": 3792, - "4884-await-call-unhandled-sibling.ts": 4171, - "4885-await-call-checkpoints.ts": 4125, - "4890-regex-literal-sites.ts": 3489, - "4891-regex-plain-text-patterns.ts": 3217, - "4892-regex-exec-read-captures.ts": 3864, - "4900-bigint-division-cross-check.ts": 4497, - "4900-console-instances.ts": 4959, - "4901-bigint-radix-text.ts": 4256, - "4901-console-instance-errors.ts": 2879, - "4902-bigint-compound-assign.ts": 3676, - "4903-bigint-fixed-width.ts": 3178, - "4904-bigint-large-products.ts": 3926, - "4905-bigint-fixed-width-fusion.ts": 5267, - "4906-bigint-small-value-trees.ts": 5678, - "4907-bigint-random-trees.ts": 7288, - "4910-hole-free-prefix-upkeep.ts": 4535, - "4920-string-literal-switch.ts": 4267, - "4930-typed-record-reflection.ts": 5782, - "4931-typed-data-generic-walks.ts": 6195, - "4932-typed-json-unknown.ts": 4431, - "4940-async-return-adoption.ts": 4857, - "4941-async-return-adoption-try.ts": 4613, - "4942-async-return-adoption-values.ts": 6005, - "4943-async-return-adoption-interleaved.ts": 3930, - "4950-regex-compiled-captures.ts": 5282, - "4951-regex-compiled-last-index.ts": 4338, - "4952-regex-compiled-anchors-classes.ts": 4435, - "4953-regex-compiled-backtracking.ts": 5380, - "4954-regex-log-report.ts": 5479, - "4955-regex-compiled-differential.ts": 20554, - "4970-int32-call-abi.ts": 4776, - "4980-generator-early-exit-finally.ts": 4365, - "4981-generator-delegation-iterables.ts": 5570, - "4982-generator-sent-values.ts": 4472, - "4983-generator-reuse-iterables.ts": 2952, - "4984-generator-exceptions.ts": 4164, - "4985-generator-lazy-pipeline.ts": 5491, - "4986-generator-default-channels.ts": 3496, - "4987-generator-closures-methods.ts": 4260, - "4988-generator-async-interplay.ts": 4288, - "4989-generator-step-drives.ts": 4530, - "4990-lone-surrogates.ts": 4508, - "4991-lone-surrogate-halves.ts": 4237, - "4992-lone-surrogate-search.ts": 4305, - "4993-lone-surrogate-json.ts": 4527, - "4994-lone-surrogate-uri.ts": 4891, - "4995-lone-surrogate-regex.ts": 4198, - "4996-lone-surrogate-stdio.ts": 3963, - "4997-lone-surrogate-stdout-patch.js": 4611, - "4998-lone-surrogate-buffers.ts": 4299, - "4999-lone-surrogate-io.ts": 4020, - "500-array-basics.ts": 4115, - "501-array-push-pop.ts": 4134, - "5010-lifetime-region-generations.ts": 4583, - "5011-lifetime-region-outside-references.ts": 3728, - "5012-lifetime-region-shapes.ts": 4853, - "5013-lifetime-region-async.ts": 5075, - "5014-lifetime-region-nesting.ts": 4021, - "5015-lifetime-region-publish.ts": 41998, - "5016-lifetime-region-weak-keys.ts": 3440, - "5017-lifetime-region-cycles.ts": 3981, - "5018-lifetime-region-hierarchies.ts": 5065, - "5019-lifetime-region-values.ts": 4354, - "502-array-for-of.ts": 3573, - "5020-lifetime-region-large.ts": 6813, - "5021-lifetime-region-opaque-holders.ts": 3165, - "5022-lifetime-region-workers.ts": 44993, + "4471-unassigned-field-reads.ts": 3896, + "4476-string-ascii-header-fact.ts": 3522, + "4477-buffer-write-ascii-runs.ts": 3321, + "4478-string-large-index-reads.ts": 4146, + "4481-array-optional-push.ts": 3259, + "4482-instanceof-static-class-optional.ts": 3786, + "4483-array-splice-statement.ts": 4036, + "4484-array-length-reset.ts": 2849, + "4485-array-splice-optional-item.ts": 3817, + "4486-array-field-element-borrows.ts": 2903, + "4487-array-literal-optional-values.ts": 3145, + "4520-optional-guard-narrowing.ts": 2774, + "4521-array-callback-element-presence.ts": 5601, + "4522-captured-parameter-lifetimes.ts": 3907, + "4523-array-pop-removal.ts": 3769, + "4524-array-callback-supertype-params.ts": 4594, + "4541-nullable-wrap-borrows.ts": 3939, + "4542-preserving-call-borrows.ts": 3361, + "4543-walk-borrowed-locals.ts": 3633, + "4544-checked-cast-aliases.ts": 3723, + "4545-borrowed-returns.ts": 4116, + "4546-rebound-borrowed-params.ts": 2930, + "4560-field-store-borrowed-receivers.ts": 4438, + "4561-virtual-borrowed-parameters.ts": 3634, + "4562-string-self-concat-move.ts": 2703, + "4563-array-read-projection-receivers.ts": 3601, + "4564-literal-choice-strings.ts": 3137, + "4568-for-of-hole-elements.ts": 3387, + "4569-shorthand-missing-elements.ts": 3958, + "4570-map-lookup-default-record.ts": 3112, + "4591-weak-keys-union-records.ts": 3556, + "4592-cycle-const-from-import/main.ts": 3467, + "4593-weak-keys-empty-objects.ts": 2938, + "4594-union-class-field-mixed-types.ts": 4040, + "4595-union-class-field-optional-receiver.ts": 3379, + "4596-error-subclass-int-fields.ts": 3559, + "4596-tdz-nullable-forward-capture.ts": 4676, + "4597-callback-field-method-name.ts": 4014, + "4598-live-array-ref-element-access.ts": 8384, + "4598-map-set-clear-reuse.ts": 4224, + "4598-os-available-parallelism.ts": 3815, + "4598-publish-constructor-stores.ts": 3618, + "4599-construction-only-field-borrows.ts": 3619, + "4600-construction-only-fields-dynamic-writes.ts": 3184, + "4601-cycle-holders.ts": 3348, + "4602-constructor-escape-order.ts": 3674, + "4610-array-ext-dyn-refresh.ts": 4598, + "4620-optional-chain-borrowed-receivers.ts": 3411, + "4621-edge-preserving-callees/main.ts": 3288, + "4630-contract-int32.ts": 2810, + "4630-reference-write-call-arguments.ts": 3333, + "4631-contract-nothrow.ts": 3196, + "4631-reference-write-aliases.ts": 4264, + "4632-contract-immutable.ts": 3449, + "4632-reference-write-loops-and-walks.ts": 3791, + "4633-contract-program-lifetime.ts": 4644, + "4633-reference-write-callbacks-returns.ts": 4024, + "4634-contract-program-lifetime-publish.ts": 42618, + "4634-optional-element-borrowed-returns.ts": 3411, + "4640-bitwise-identity-ranges.ts": 3713, + "4641-nothrow-try-catch.ts": 3056, + "4642-acyclic-contract.ts": 4040, + "4650-stale-property-narrowing.ts": 3665, + "4651-map-string-get-entry.ts": 3369, + "4652-stale-closure-binding-narrowing.ts": 3504, + "4660-typed-rest-spread-forwarding.ts": 3148, + "4671-scoped-array-read-borrows.ts": 3020, + "4690-cycle-bypass-long-lived.ts": 5374, + "4691-publish-constructor-self-alias.ts": 38620, + "4692-borrowed-result-mutating-callees.ts": 3592, + "4720-cold-throw-paths.ts": 4339, + "4721-integer-induction-numbers.ts": 3854, + "4730-touint32-large-magnitudes.ts": 3431, + "4731-string-mixed-ascii-slices.ts": 4436, + "4732-buffer-write-utf16le-runs.ts": 4084, + "4733-typed-array-read-compares.ts": 3240, + "4750-map-string-absent-filter.ts": 3584, + "4751-string-search-multibyte-needles.ts": 3227, + "4795-published-untyped-member-reads.ts": 3450, + "4806-uint32-loop-accumulators.ts": 3543, + "4810-union-identity-retags.ts": 34911, + "4811-union-retag-checked-cast.ts": 3044, + "4812-int32-wrapping-sums.ts": 3457, + "4813-typed-array-read-equality-bindings.ts": 4853, + "4820-sort-comparator-lent-arguments.ts": 3579, + "4821-callback-lent-arguments.ts": 4210, + "4822-stable-capture-reads.ts": 3094, + "4823-array-store-receivers.ts": 3774, + "4830-typed-teardown-chains.ts": 3908, + "4831-cycle-bypass-probe-windows.ts": 6157, + "4840-array-hole-free-prefix.ts": 3932, + "4860-int32-local-storage.ts": 5136, + "4870-array-pipeline-fusion.ts": 6645, + "4871-array-pipeline-analytics.ts": 4575, + "4872-array-pipeline-temporaries.ts": 10635, + "4875-stream-consumers-array-buffer.ts": 4120, + "4876-array-buffer-inspect.ts": 2819, + "4880-await-call-turn-order.ts": 3872, + "4881-await-call-exceptions.ts": 3027, + "4882-await-call-request-chain.ts": 2730, + "4883-await-values-and-hops.ts": 3412, + "4884-await-call-unhandled-sibling.ts": 3410, + "4885-await-call-checkpoints.ts": 2703, + "4890-regex-literal-sites.ts": 3712, + "4891-regex-plain-text-patterns.ts": 3018, + "4892-regex-exec-read-captures.ts": 4130, + "4900-bigint-division-cross-check.ts": 3763, + "4900-console-instances.ts": 4286, + "4901-bigint-radix-text.ts": 3099, + "4901-console-instance-errors.ts": 3171, + "4902-bigint-compound-assign.ts": 3431, + "4903-bigint-fixed-width.ts": 3707, + "4904-bigint-large-products.ts": 3972, + "4905-bigint-fixed-width-fusion.ts": 3443, + "4906-bigint-small-value-trees.ts": 4875, + "4907-bigint-random-trees.ts": 5277, + "4910-hole-free-prefix-upkeep.ts": 4073, + "4920-string-literal-switch.ts": 3607, + "4930-typed-record-reflection.ts": 4869, + "4931-typed-data-generic-walks.ts": 5228, + "4932-typed-json-unknown.ts": 3250, + "4940-async-return-adoption.ts": 4405, + "4941-async-return-adoption-try.ts": 3533, + "4942-async-return-adoption-values.ts": 4824, + "4943-async-return-adoption-interleaved.ts": 3851, + "4950-regex-compiled-captures.ts": 5146, + "4951-regex-compiled-last-index.ts": 4316, + "4952-regex-compiled-anchors-classes.ts": 3149, + "4953-regex-compiled-backtracking.ts": 3822, + "4954-regex-log-report.ts": 4449, + "4955-regex-compiled-differential.ts": 20102, + "4970-int32-call-abi.ts": 3029, + "4980-generator-early-exit-finally.ts": 3262, + "4981-generator-delegation-iterables.ts": 5306, + "4982-generator-sent-values.ts": 3649, + "4983-generator-reuse-iterables.ts": 4023, + "4984-generator-exceptions.ts": 4220, + "4985-generator-lazy-pipeline.ts": 3164, + "4986-generator-default-channels.ts": 3434, + "4987-generator-closures-methods.ts": 3505, + "4988-generator-async-interplay.ts": 2790, + "4989-generator-step-drives.ts": 3509, + "4990-lone-surrogates.ts": 3213, + "4991-lone-surrogate-halves.ts": 4020, + "4992-lone-surrogate-search.ts": 3375, + "4993-lone-surrogate-json.ts": 3473, + "4994-lone-surrogate-uri.ts": 3848, + "4995-lone-surrogate-regex.ts": 4302, + "4996-lone-surrogate-stdio.ts": 2592, + "4997-lone-surrogate-stdout-patch.js": 3072, + "4998-lone-surrogate-buffers.ts": 3134, + "4999-lone-surrogate-io.ts": 3225, + "500-array-basics.ts": 2886, + "501-array-push-pop.ts": 2682, + "5010-lifetime-region-generations.ts": 4147, + "5011-lifetime-region-outside-references.ts": 3407, + "5012-lifetime-region-shapes.ts": 4861, + "5013-lifetime-region-async.ts": 3124, + "5014-lifetime-region-nesting.ts": 3259, + "5015-lifetime-region-publish.ts": 27669, + "5016-lifetime-region-weak-keys.ts": 2554, + "5017-lifetime-region-cycles.ts": 3105, + "5018-lifetime-region-hierarchies.ts": 4007, + "5019-lifetime-region-values.ts": 2888, + "502-array-for-of.ts": 3621, + "5020-lifetime-region-large.ts": 4812, + "5021-lifetime-region-opaque-holders.ts": 3957, + "5022-lifetime-region-workers.ts": 38841, "5023-lifetime-region-await.ts": 5986, "5024-lifetime-region-await-forms.ts": 5123, - "503-array-functions.ts": 4084, - "504-array-rc-stress.ts": 3791, - "5040-promise-all-race-turns.ts": 5348, - "5041-promise-all-turns.js": 4084, - "5042-async-generator-return-promise.ts": 4929, - "5043-async-generator-return-forms.ts": 3900, - "5045-generator-delegation-typed-next.ts": 4863, - "5046-generator-delegation-return-throw.ts": 4938, - "5047-generator-delegation-iterables-typed.ts": 4203, - "5048-generator-delegation-async.ts": 4733, - "5049-generator-delegation-edges.ts": 5078, - "5050-inherited-in-membership.ts": 4630, - "5051-typed-record-prototypes.ts": 4286, - "5052-class-for-in-unknown.ts": 4449, - "5053-json-replacer-arrays.ts": 4672, - "5054-required-field-delete.ts": 3969, - "5055-object-create-record-literal.ts": 3612, - "5056-generator-in-unknown.ts": 3544, - "5060-child-fork-exit-after-messages/main.ts": 3945, - "5061-child-fork-local-disconnect/main.ts": 3909, - "5062-child-fork-message-before-eof/main.ts": 4129, - "5065-global-increment-initializers.ts": 3769, - "5066-global-compound-updates.ts": 4136, - "5067-global-updates-in-functions.ts": 3795, - "5068-global-var-let-const-updates.ts": 3571, - "5069-global-update-modules/main.ts": 3587, - "5070-optional-read-bindings.ts": 3671, - "5071-optional-chain-scalars.ts": 4013, - "5072-optional-nullish-ternary.ts": 4374, - "5073-optional-results.ts": 4392, - "5074-optional-pop-shift.ts": 3500, - "5075-optional-reads-unchecked/main.ts": 3399, - "5076-optional-escapes.ts": 4284, - "5080-boolean-array-storage.ts": 10145, - "5081-boolean-array-dynamic-views.ts": 5152, - "5085-promise-allsettled-turns.ts": 5572, - "5086-promise-any-turns.ts": 4418, - "5087-promise-allsettled-any-dyn.js": 6479, - "5088-promise-combinator-thenables.js": 3786, - "5089-promise-settled-records.ts": 4701, - "5090-generator-finished-result-value.ts": 4294, - "5091-generator-delegation-arrays-strings.ts": 4885, - "5092-generator-delegation-sets-maps.ts": 3752, - "5095-console-count-group.ts": 4618, - "5096-console-assert-dir.ts": 5191, - "5097-console-table.ts": 3751, - "5098-console-time-warnings.ts": 9353, - "5099-console-methods-dynamic.cjs": 4255, - "510-array-map-filter-foreach.ts": 4191, - "511-array-indexof-includes.ts": 3499, - "5110-var-hoisting-early-reads.ts": 3823, - "5111-var-hoisting-closures-classes.ts": 4157, - "5112-var-hoisting-function-scope.ts": 3874, - "5113-tdz-let-const-class.ts": 3814, - "5114-var-hoisting-js.js": 3818, - "5115-regex-replace-compiled.ts": 3620, - "5116-regex-capture-reads.ts": 2873, - "5117-regex-log-report-spans.ts": 4784, - "5118-regex-replace-char-chains.ts": 3663, - "512-array-join-chains.ts": 2771, - "5120-frame-records.ts": 3939, - "5121-frame-objects.ts": 2783, - "5122-frame-result-slots.ts": 3197, - "5123-frame-reassigned.ts": 3173, - "5124-frame-objects-control.ts": 3904, - "5125-frame-mutating-methods.ts": 3799, - "5126-frame-returned-params.ts": 3813, - "5127-frame-loop-bindings.ts": 4488, - "513-array-methods-rc-stress.ts": 3775, - "5130-event-target-dispatch.js": 6111, - "5131-event-target-listener-errors.js": 4456, - "5132-event-target-typed.ts": 7166, - "5133-abort-signal-event-target.ts": 23098, - "5134-events-error-monitor.ts": 4010, - "5135-event-target-warnings.js": 31124, - "5136-events-error-monitor-string-name.ts": 4008, - "5137-events-error-monitor-computed-name.js": 4468, - "5138-events-error-monitor-shared-listener.ts": 3052, - "5139-event-target-listener-throw.ts": 4657, - "514-array-find-some-every.ts": 3980, - "5140-os-host-facts.ts": 3296, - "5141-os-constants.ts": 4894, - "5142-path-parse-format.ts": 4155, - "5145-path-matches-glob-basics.ts": 3777, - "5146-path-matches-glob-braces.ts": 5827, - "5147-path-matches-glob-extglob.ts": 4341, - "5148-path-matches-glob-classes.ts": 2888, - "5149-path-matches-glob-win32.ts": 4096, - "515-array-flatmap.ts": 4332, - "5150-small-array-inline-slots.ts": 3637, - "5155-cycle-header-types.ts": 43009, - "516-array-reduce.ts": 4514, - "5160-field-callback-receiver.ts": 4758, - "5161-field-callback-receiver-escape.ts": 3837, - "5162-field-method-reference-receiver.ts": 4262, - "5163-field-callback-receiver.cjs": 5679, - "5164-worker-field-callback-receiver.ts": 38682, - "5165-interface-method-dispatch.ts": 4568, - "5166-interface-method-values.ts": 5588, - "5167-interface-method-order.ts": 5287, - "5168-interface-method-hierarchy.ts": 6196, - "5169-interface-method-chains.ts": 4139, - "517-array-hof-index-args.ts": 4188, - "5170-string-scan-eviction.ts": 3592, - "5171-lone-surrogate-replace-seams.ts": 3960, - "5175-forin-typed-as-unknown.ts": 4247, - "5176-object-keys-typed-as-unknown.ts": 3688, - "5177-forin-dynamic-objects.ts": 4079, - "5178-forin-keys-js.js": 3608, - "5179-forin-typed-shapes.ts": 4197, - "518-array-sort.ts": 4624, - "518-promise-void-union-callbacks.ts": 4051, - "5180-interface-arrays.ts": 3814, - "5181-interface-array-methods.ts": 11031, - "5182-interface-array-boundaries.ts": 3743, - "5183-interface-property-reads.ts": 4427, - "5184-interface-property-objects.ts": 3309, - "5185-util-inherits.cjs": 5164, - "5186-util-inherits.ts": 4876, - "5187-util-deprecate.cjs": 4074, - "5188-util-deprecate-flags.cjs": 4955, - "5189-util-deprecate.ts": 5071, - "519-array-from-length.ts": 4423, - "519-promise-union-await-values.ts": 3904, - "5190-util-callbackify.cjs": 7841, - "5191-util-callbackify.ts": 6629, - "5192-util-debuglog.cjs": 6718, - "5193-util-debuglog.ts": 4689, - "5194-process-emit-warning-tick.cjs": 3727, - "5195-object-entries-typed-as-unknown.ts": 5084, - "5196-object-values-typed-as-unknown.ts": 3864, - "5197-object-entries-dynamic-objects.ts": 4955, - "5198-object-entries-values-js.js": 4220, - "5199-object-entries-identity.ts": 3999, - "520-map-basics.ts": 3545, - "5200-array-sort-keyed-numbers.ts": 5325, - "5201-array-sort-keyed-records.ts": 7394, - "5202-array-sort-keyed-lookalikes.ts": 5009, - "5203-typed-array-sort-default.ts": 8431, - "5204-typed-array-sort-comparators.ts": 5119, - "521-map-number-keys.ts": 3823, - "5210-process-memory-usage.ts": 4235, - "5211-process-identity.ts": 3797, - "5212-perf-marks-measures.ts": 5056, - "5213-perf-timing-errors.ts": 4031, - "5214-perf-entry-inspect.ts": 4809, - "5215-perf-timing-validation.js": 6147, - "5216-perf-spread-arguments.js": 4892, - "5217-perf-spread-typed.ts": 4228, - "522-map-foreach.ts": 4028, - "5220-url-parse-warnings.ts": 3469, - "5221-url-parse-shapes.ts": 6083, - "5222-url-parse-hosts.ts": 5268, - "5223-url-parse-query.ts": 5608, - "5224-url-format-objects.ts": 5477, - "5225-url-format-whatwg.ts": 3013, - "5226-url-resolve.ts": 6250, - "5227-url-legacy-dependency/main.ts": 6988, - "5228-url-domain-conversion.ts": 4749, - "5229-url-legacy-errors.cjs": 6936, - "523-map-ref-values.ts": 4339, - "5230-inline-union-fields.ts": 4733, - "5231-inline-union-field-kinds.ts": 5128, - "5232-inline-union-fields-dynamic.ts": 4858, - "5233-inline-union-fields-shapes.ts": 3241, - "5234-inline-union-class-fields.ts": 3221, - "5235-inline-union-fields-publish.ts": 3389, - "5236-inline-union-unchecked-reads.ts": 4250, - "5237-inline-union-frame-objects.ts": 4148, - "524-map-cycles.ts": 2484, - "5240-event-target-subclass.ts": 7308, - "5241-event-subclass.ts": 5029, - "5242-event-target-subclass-hierarchy.ts": 4680, - "5243-event-target-subclass-dynamic.ts": 6118, - "5244-event-target-subclass.js": 4898, - "5245-event-target-subclass-signals.ts": 8806, - "5246-event-target-subclass-listener-throw.ts": 3474, - "5247-event-target-subclass-lifetimes.ts": 5918, - "5248-event-target-subclass-warnings.ts": 4004, - "5249-event-target-subclass-unconstructed.ts": 3498, - "525-map-rc-stress.ts": 3774, + "503-array-functions.ts": 2982, + "504-array-rc-stress.ts": 3289, + "5040-promise-all-race-turns.ts": 4439, + "5041-promise-all-turns.js": 3708, + "5042-async-generator-return-promise.ts": 3292, + "5043-async-generator-return-forms.ts": 3922, + "5045-generator-delegation-typed-next.ts": 4740, + "5046-generator-delegation-return-throw.ts": 3192, + "5047-generator-delegation-iterables-typed.ts": 4558, + "5048-generator-delegation-async.ts": 3457, + "5049-generator-delegation-edges.ts": 3057, + "5050-inherited-in-membership.ts": 4297, + "5051-typed-record-prototypes.ts": 3534, + "5052-class-for-in-unknown.ts": 3663, + "5053-json-replacer-arrays.ts": 4093, + "5054-required-field-delete.ts": 3619, + "5055-object-create-record-literal.ts": 3237, + "5056-generator-in-unknown.ts": 3060, + "5060-child-fork-exit-after-messages/main.ts": 3584, + "5061-child-fork-local-disconnect/main.ts": 4277, + "5062-child-fork-message-before-eof/main.ts": 3570, + "5065-global-increment-initializers.ts": 2946, + "5066-global-compound-updates.ts": 3425, + "5067-global-updates-in-functions.ts": 3465, + "5068-global-var-let-const-updates.ts": 3395, + "5069-global-update-modules/main.ts": 3167, + "5070-optional-read-bindings.ts": 3316, + "5071-optional-chain-scalars.ts": 3214, + "5072-optional-nullish-ternary.ts": 2900, + "5073-optional-results.ts": 3751, + "5074-optional-pop-shift.ts": 3099, + "5075-optional-reads-unchecked/main.ts": 3754, + "5076-optional-escapes.ts": 3593, + "5080-boolean-array-storage.ts": 7564, + "5081-boolean-array-dynamic-views.ts": 3915, + "5085-promise-allsettled-turns.ts": 4557, + "5086-promise-any-turns.ts": 3994, + "5087-promise-allsettled-any-dyn.js": 5205, + "5088-promise-combinator-thenables.js": 5007, + "5089-promise-settled-records.ts": 4859, + "5090-generator-finished-result-value.ts": 3648, + "5091-generator-delegation-arrays-strings.ts": 3362, + "5092-generator-delegation-sets-maps.ts": 4496, + "5095-console-count-group.ts": 3356, + "5096-console-assert-dir.ts": 3645, + "5097-console-table.ts": 3255, + "5098-console-time-warnings.ts": 7324, + "5099-console-methods-dynamic.cjs": 3314, + "510-array-map-filter-foreach.ts": 3232, + "511-array-indexof-includes.ts": 3286, + "5110-var-hoisting-early-reads.ts": 4048, + "5111-var-hoisting-closures-classes.ts": 2474, + "5112-var-hoisting-function-scope.ts": 3383, + "5113-tdz-let-const-class.ts": 3628, + "5114-var-hoisting-js.js": 3550, + "5115-regex-replace-compiled.ts": 3344, + "5116-regex-capture-reads.ts": 3874, + "5117-regex-log-report-spans.ts": 3719, + "5118-regex-replace-char-chains.ts": 3632, + "512-array-join-chains.ts": 3268, + "5120-frame-records.ts": 3221, + "5121-frame-objects.ts": 3861, + "5122-frame-result-slots.ts": 3008, + "5123-frame-reassigned.ts": 3589, + "5124-frame-objects-control.ts": 3184, + "5125-frame-mutating-methods.ts": 3607, + "5126-frame-returned-params.ts": 3362, + "5127-frame-loop-bindings.ts": 4392, + "513-array-methods-rc-stress.ts": 3208, + "5130-event-target-dispatch.js": 4958, + "5131-event-target-listener-errors.js": 4558, + "5132-event-target-typed.ts": 5171, + "5133-abort-signal-event-target.ts": 22917, + "5134-events-error-monitor.ts": 3499, + "5135-event-target-warnings.js": 9058, + "5136-events-error-monitor-string-name.ts": 3057, + "5137-events-error-monitor-computed-name.js": 4052, + "5138-events-error-monitor-shared-listener.ts": 2466, + "5139-event-target-listener-throw.ts": 2925, + "514-array-find-some-every.ts": 3925, + "5140-os-host-facts.ts": 3438, + "5141-os-constants.ts": 2815, + "5142-path-parse-format.ts": 3808, + "5145-path-matches-glob-basics.ts": 3287, + "5146-path-matches-glob-braces.ts": 4987, + "5147-path-matches-glob-extglob.ts": 3938, + "5148-path-matches-glob-classes.ts": 3973, + "5149-path-matches-glob-win32.ts": 3835, + "515-array-flatmap.ts": 3688, + "5150-small-array-inline-slots.ts": 4419, + "5155-cycle-header-types.ts": 38708, + "516-array-reduce.ts": 4017, + "5160-field-callback-receiver.ts": 3678, + "5161-field-callback-receiver-escape.ts": 2857, + "5162-field-method-reference-receiver.ts": 2944, + "5163-field-callback-receiver.cjs": 3655, + "5164-worker-field-callback-receiver.ts": 30046, + "5165-interface-method-dispatch.ts": 2969, + "5166-interface-method-values.ts": 4129, + "5167-interface-method-order.ts": 3988, + "5168-interface-method-hierarchy.ts": 4483, + "5169-interface-method-chains.ts": 3336, + "517-array-hof-index-args.ts": 3024, + "5170-string-scan-eviction.ts": 3285, + "5171-lone-surrogate-replace-seams.ts": 3558, + "5175-forin-typed-as-unknown.ts": 4230, + "5176-object-keys-typed-as-unknown.ts": 3721, + "5177-forin-dynamic-objects.ts": 2893, + "5178-forin-keys-js.js": 2555, + "5179-forin-typed-shapes.ts": 4446, + "518-array-sort.ts": 3134, + "518-promise-void-union-callbacks.ts": 2401, + "5180-interface-arrays.ts": 3230, + "5181-interface-array-methods.ts": 11973, + "5182-interface-array-boundaries.ts": 3847, + "5183-interface-property-reads.ts": 3799, + "5184-interface-property-objects.ts": 3828, + "5185-util-inherits.cjs": 5041, + "5186-util-inherits.ts": 4542, + "5187-util-deprecate.cjs": 5818, + "5188-util-deprecate-flags.cjs": 4078, + "5189-util-deprecate.ts": 3798, + "519-array-from-length.ts": 2988, + "519-promise-union-await-values.ts": 3664, + "5190-util-callbackify.cjs": 5115, + "5191-util-callbackify.ts": 4367, + "5192-util-debuglog.cjs": 5096, + "5193-util-debuglog.ts": 4056, + "5194-process-emit-warning-tick.cjs": 2761, + "5195-object-entries-typed-as-unknown.ts": 3177, + "5196-object-values-typed-as-unknown.ts": 4077, + "5197-object-entries-dynamic-objects.ts": 4742, + "5198-object-entries-values-js.js": 3089, + "5199-object-entries-identity.ts": 3679, + "520-map-basics.ts": 3767, + "5200-array-sort-keyed-numbers.ts": 4618, + "5201-array-sort-keyed-records.ts": 5422, + "5202-array-sort-keyed-lookalikes.ts": 4034, + "5203-typed-array-sort-default.ts": 7941, + "5204-typed-array-sort-comparators.ts": 4085, + "521-map-number-keys.ts": 3317, + "5210-process-memory-usage.ts": 3262, + "5211-process-identity.ts": 3448, + "5212-perf-marks-measures.ts": 4026, + "5213-perf-timing-errors.ts": 4151, + "5214-perf-entry-inspect.ts": 4315, + "5215-perf-timing-validation.js": 2982, + "5216-perf-spread-arguments.js": 3745, + "5217-perf-spread-typed.ts": 4057, + "522-map-foreach.ts": 2964, + "5220-url-parse-warnings.ts": 4859, + "5221-url-parse-shapes.ts": 3814, + "5222-url-parse-hosts.ts": 3398, + "5223-url-parse-query.ts": 2653, + "5224-url-format-objects.ts": 5550, + "5225-url-format-whatwg.ts": 5213, + "5226-url-resolve.ts": 2600, + "5227-url-legacy-dependency/main.ts": 5803, + "5228-url-domain-conversion.ts": 4876, + "5229-url-legacy-errors.cjs": 5195, + "523-map-ref-values.ts": 4321, + "5230-inline-union-fields.ts": 3644, + "5231-inline-union-field-kinds.ts": 4871, + "5232-inline-union-fields-dynamic.ts": 3887, + "5233-inline-union-fields-shapes.ts": 4145, + "5234-inline-union-class-fields.ts": 3244, + "5235-inline-union-fields-publish.ts": 3360, + "5236-inline-union-unchecked-reads.ts": 3108, + "5237-inline-union-frame-objects.ts": 2533, + "524-map-cycles.ts": 3943, + "5240-event-target-subclass.ts": 5571, + "5241-event-subclass.ts": 4311, + "5242-event-target-subclass-hierarchy.ts": 4079, + "5243-event-target-subclass-dynamic.ts": 3528, + "5244-event-target-subclass.js": 4645, + "5245-event-target-subclass-signals.ts": 9410, + "5246-event-target-subclass-listener-throw.ts": 3995, + "5247-event-target-subclass-lifetimes.ts": 5991, + "5248-event-target-subclass-warnings.ts": 4513, + "5249-event-target-subclass-unconstructed.ts": 2679, + "525-map-rc-stress.ts": 2764, "5250-cipher-aes-gcm.ts": 8740, "5251-cipher-aes-cbc.ts": 42449, "5252-cipher-aes-ctr.ts": 26060, @@ -4723,45 +4726,45 @@ "5257-cipher-vectors.ts": 7138, "5258-cipher-handles.js": 24870, "5259-cipher-chunked.ts": 7052, - "526-set-basics.ts": 3756, - "5260-record-unknown-identity.ts": 4341, - "5261-optional-field-identity.ts": 3817, - "5262-record-unknown-many.ts": 3331, - "527-set-foreach.ts": 4129, - "5270-url-parse-no-deprecation.cjs": 5103, - "5271-url-parse-throw-deprecation.cjs": 6761, - "5275-http-end-callback-order.ts": 4622, - "5276-style-text-hex-colors.cjs": 4317, - "5277-fs-read-file-buffer-option.cjs": 3338, - "5278-host-null-bytes.cjs": 64320, - "5279-search-params-null-init.cjs": 2979, - "528-set-seeded.ts": 2529, - "5285-blob-construct.ts": 4818, - "5286-blob-readers.ts": 3080, - "5287-blob-inspect.ts": 3383, - "5288-blob-validation.js": 4818, - "5289-blob-read-order.ts": 4674, - "529-map-seeded.ts": 3233, - "5290-blob-dynamic.js": 4041, - "5295-readline-promises-question.ts": 3501, - "5296-readline-lines.ts": 5784, - "5297-readline-callback-events.cjs": 3985, - "5298-readline-abort.cjs": 10936, - "5299-readline-stdin.ts": 5881, - "530-record-arrays.ts": 4186, - "5300-stream-add-abort-signal.ts": 25846, - "5301-stream-add-abort-signal-errors.cjs": 8721, - "5302-stream-promises-options.ts": 13350, - "5303-stream-finished-callback-opts.cjs": 5087, - "5305-json-stringify-typed-arrays.ts": 6867, - "531-record-array-hofs.ts": 4059, - "5315-map-iterate-after-front-deletes.ts": 3530, - "5316-map-lru-eviction.ts": 3884, - "5317-map-iterate-while-mutating.ts": 4053, - "5318-set-iterate-after-deletes.ts": 4066, - "5319-map-iteration-values.ts": 4477, - "532-record-arrays-rc-stress.ts": 3905, - "5320-map-iterate-across-compaction.ts": 4243, + "526-set-basics.ts": 2480, + "5260-record-unknown-identity.ts": 3505, + "5261-optional-field-identity.ts": 3914, + "5262-record-unknown-many.ts": 3839, + "527-set-foreach.ts": 3683, + "5270-url-parse-no-deprecation.cjs": 4076, + "5271-url-parse-throw-deprecation.cjs": 3487, + "5275-http-end-callback-order.ts": 3028, + "5276-style-text-hex-colors.cjs": 4502, + "5277-fs-read-file-buffer-option.cjs": 2635, + "5278-host-null-bytes.cjs": 16385, + "5279-search-params-null-init.cjs": 2915, + "528-set-seeded.ts": 3643, + "5285-blob-construct.ts": 3124, + "5286-blob-readers.ts": 3309, + "5287-blob-inspect.ts": 2504, + "5288-blob-validation.js": 3775, + "5289-blob-read-order.ts": 3614, + "529-map-seeded.ts": 3331, + "5290-blob-dynamic.js": 2674, + "5295-readline-promises-question.ts": 2401, + "5296-readline-lines.ts": 3088, + "5297-readline-callback-events.cjs": 2975, + "5298-readline-abort.cjs": 6980, + "5299-readline-stdin.ts": 3836, + "530-record-arrays.ts": 3125, + "5300-stream-add-abort-signal.ts": 7154, + "5301-stream-add-abort-signal-errors.cjs": 7763, + "5302-stream-promises-options.ts": 8927, + "5303-stream-finished-callback-opts.cjs": 7119, + "5305-json-stringify-typed-arrays.ts": 4254, + "531-record-array-hofs.ts": 3609, + "5315-map-iterate-after-front-deletes.ts": 2759, + "5316-map-lru-eviction.ts": 3688, + "5317-map-iterate-while-mutating.ts": 3035, + "5318-set-iterate-after-deletes.ts": 2543, + "5319-map-iteration-values.ts": 4062, + "532-record-arrays-rc-stress.ts": 2708, + "5320-map-iterate-across-compaction.ts": 2736, "5321-integer-closed-arithmetic-loops.ts": 3710, "5321-json-parse-cycles.ts": 3383, "5322-integer-variable-step-loops.ts": 3384, @@ -4770,29 +4773,29 @@ "5323-int32-nonnegative-slot-facts.ts": 3774, "5324-int32-initializer-locals.ts": 2663, "5324-structured-clone-documents.ts": 4264, - "5325-record-boundary-returns.ts": 4089, - "5326-record-boundary-params.ts": 3793, - "5327-record-boundary-identity.ts": 3464, - "5328-record-boundary-open.ts": 4146, - "5329-record-boundary-recursion.ts": 3748, - "533-array-element-cycles.ts": 3379, - "5330-record-boundary-fields.ts": 2753, - "5331-record-boundary-methods.ts": 3914, + "5325-record-boundary-returns.ts": 3046, + "5326-record-boundary-params.ts": 2989, + "5327-record-boundary-identity.ts": 3529, + "5328-record-boundary-open.ts": 3718, + "5329-record-boundary-recursion.ts": 3361, + "533-array-element-cycles.ts": 3118, + "5330-record-boundary-fields.ts": 3048, + "5331-record-boundary-methods.ts": 2560, "5332-int32-narrowed-slot-facts.ts": 3588, "5333-integer-guarded-while-counters.ts": 3896, - "5333-record-boundary-nullable-argument.ts": 3869, - "5334-fetch-mentions-without-calls.ts": 3676, + "5333-record-boundary-nullable-argument.ts": 3100, + "5334-fetch-mentions-without-calls.ts": 4032, "5335-stream-operators-values.ts": 6378, - "5335-top-level-await-pending-exit-code.ts": 3377, + "5335-top-level-await-pending-exit-code.ts": 2383, "5336-stream-operators-promise-timing.ts": 4282, - "5336-top-level-await-pending-exit-listener.ts": 3680, - "5337-dc-subscriber-throw-next-tick.cjs": 3947, + "5336-top-level-await-pending-exit-listener.ts": 2814, + "5337-dc-subscriber-throw-next-tick.cjs": 3273, "5337-stream-operators-concurrency.ts": 8858, - "5338-js-tdz-function-element.js": 3181, + "5338-js-tdz-function-element.js": 3733, "5338-stream-operators-checks.cjs": 5284, - "5339-array-buffer-constructor.js": 4102, + "5339-array-buffer-constructor.js": 2884, "5339-stream-for-await-hops.ts": 5704, - "534-record-width-subtyping.ts": 3856, + "534-record-width-subtyping.ts": 3530, "5340-readable-from-options.ts": 4031, "5341-compound-any-operand.ts": 3905, "5341-generator-callback-params.ts": 4564, @@ -4808,28 +4811,28 @@ "5343-stream-compose-edges.ts": 10326, "5344-json-parse-undeclared-keys.ts": 5823, "5344-stream-pipeline-timing.ts": 4092, - "5345-object-values-for-of-unknown.ts": 4269, - "5346-object-values-length-dynamic.ts": 3585, - "5347-object-values-loop-control.ts": 4004, - "5348-object-values-for-of-js.js": 4048, - "5349-object-entries-values-optional.ts": 3374, - "535-object-statics.ts": 4653, - "5350-object-values-wide-record.ts": 3999, - "5351-object-values-methods-index.ts": 3750, + "5345-object-values-for-of-unknown.ts": 4013, + "5346-object-values-length-dynamic.ts": 3930, + "5347-object-values-loop-control.ts": 3598, + "5348-object-values-for-of-js.js": 2760, + "5349-object-entries-values-optional.ts": 3370, + "535-object-statics.ts": 2862, + "5350-object-values-wide-record.ts": 3272, + "5351-object-values-methods-index.ts": 3637, "5352-final-field-loop-reads.ts": 4118, "5353-captured-const-values.ts": 3887, "5354-captured-const-tdz.ts": 3465, "5355-captured-function-declarations.ts": 4030, "5356-captured-tdz-ordering.ts": 4031, "5357-init-only-module-bindings.ts": 3717, - "536-map-seed-array.ts": 3444, - "5360-array-sort-comparator-calls.ts": 3618, - "5361-array-sort-inconsistent-comparators.ts": 4844, - "5362-array-sort-comparator-throws.ts": 4204, - "5363-array-sort-comparator-writes.ts": 13543, - "5364-array-sort-union-and-boolean-elements.ts": 21219, - "5365-array-sort-dynamic-values.js": 3456, - "537-map-iter-drains.ts": 3991, + "536-map-seed-array.ts": 3237, + "5360-array-sort-comparator-calls.ts": 4265, + "5361-array-sort-inconsistent-comparators.ts": 4181, + "5362-array-sort-comparator-throws.ts": 2826, + "5363-array-sort-comparator-writes.ts": 10362, + "5364-array-sort-union-and-boolean-elements.ts": 14300, + "5365-array-sort-dynamic-values.js": 2919, + "537-map-iter-drains.ts": 3050, "5370-zlib-stream-roundtrip.ts": 4546, "5371-zlib-stream-chunking.cjs": 6071, "5372-zlib-stream-errors.cjs": 6496, @@ -4840,29 +4843,29 @@ "5377-zlib-stream-backpressure.cjs": 4992, "5378-zlib-sync-options.cjs": 4120, "5379-zlib-callback-options.ts": 4524, - "538-map-set-for-of.ts": 3571, - "5390-interface-loop-element-lifetimes.ts": 3555, - "5391-interface-dispatch-hierarchies.ts": 5018, - "5392-interface-receiver-bindings.ts": 2922, - "5393-interface-array-holes.ts": 4247, - "5394-interface-implementers.ts": 4974, - "5395-locale-compare-ascii.ts": 3055, - "5396-locale-compare-latin.ts": 5056, - "5397-locale-compare-sorting.ts": 5049, - "540-tuples-basics.ts": 4222, - "5400-json-parse-typed-keys.ts": 5019, - "5405-buffer-arraybuffer-window.ts": 3206, - "5406-util-types-keys.ts": 3783, - "5407-http-header-field-limit.ts": 3678, - "5408-http-unread-request-end.ts": 4813, - "5409-http-held-request-body.ts": 4829, - "541-ref-array-json.ts": 4046, - "5410-inspect-class-values.ts": 3502, - "5411-inspect-class-hierarchies.ts": 3285, - "5412-inspect-dynamic-collections.ts": 3541, - "5413-inspect-class-values.cjs": 4035, + "538-map-set-for-of.ts": 3029, + "5390-interface-loop-element-lifetimes.ts": 3566, + "5391-interface-dispatch-hierarchies.ts": 3731, + "5392-interface-receiver-bindings.ts": 3061, + "5393-interface-array-holes.ts": 2702, + "5394-interface-implementers.ts": 3603, + "5395-locale-compare-ascii.ts": 3587, + "5396-locale-compare-latin.ts": 4291, + "5397-locale-compare-sorting.ts": 3576, + "540-tuples-basics.ts": 3420, + "5400-json-parse-typed-keys.ts": 3141, + "5405-buffer-arraybuffer-window.ts": 3036, + "5406-util-types-keys.ts": 2954, + "5407-http-header-field-limit.ts": 3052, + "5408-http-unread-request-end.ts": 3992, + "5409-http-held-request-body.ts": 3771, + "541-ref-array-json.ts": 3761, + "5410-inspect-class-values.ts": 3124, + "5411-inspect-class-hierarchies.ts": 2423, + "5412-inspect-dynamic-collections.ts": 3042, + "5413-inspect-class-values.cjs": 3217, "5415-zlib-dynamic-inputs.cjs": 4054, - "542-union-element-arrays.ts": 4182, + "542-union-element-arrays.ts": 2812, "5420-readable-from-generators.ts": 5843, "5421-readable-from-generators.cjs": 3752, "5422-stream-async-push-wakeup.ts": 3679, @@ -4873,43 +4876,43 @@ "5427-pipeline-generator-backpressure.ts": 4175, "5428-pipeline-generator-stages.cjs": 9702, "5429-pipeline-generator-buffers.ts": 6406, - "5430-dyn-number-string-boxes.ts": 3692, - "5435-crypto-hash-algorithms.ts": 4078, - "5436-crypto-hash-names.js": 3345, - "5437-crypto-hmac-algorithms.ts": 3794, - "5438-crypto-kdf-digests.ts": 3694, - "5439-crypto-kdf-callbacks.js": 3780, - "5440-crypto-hash-encodings.js": 4405, - "5441-crypto-hash-output-length.ts": 4754, - "5442-crypto-random-values.ts": 5239, - "5443-crypto-random-arguments.js": 4330, - "5444-crypto-timing-safe-equal.js": 2751, - "5445-crypto-secret-key-objects.ts": 4863, - "5445-stream-buffer-chunks.ts": 4296, - "5446-crypto-secret-key-errors.js": 4577, - "5446-stream-buffer-chunks-dynamic.js": 8609, - "5447-fs-readdir-order.ts": 3829, - "5448-fs-glob-patterns.ts": 3945, - "5449-fs-glob-options.ts": 5046, - "5450-fs-glob-validation.js": 3911, - "5451-fs-promises-glob.ts": 5150, - "5452-fs-glob-callback.ts": 4895, - "5455-power-of-two-remainder.ts": 3875, - "5456-remainder-large-integer-dividends.ts": 3066, - "5457-lcg-modulus.ts": 3468, - "5458-fractional-remainder.ts": 3767, - "5460-locale-compare-contractions.ts": 3556, - "5461-locale-compare-equivalents.ts": 4015, - "5462-locale-compare-probe-sweep.ts": 5293, - "5463-locale-compare-combining-letters.ts": 4084, - "5464-locale-compare-fractions.ts": 3409, + "5430-dyn-number-string-boxes.ts": 3930, + "5435-crypto-hash-algorithms.ts": 3451, + "5436-crypto-hash-names.js": 3185, + "5437-crypto-hmac-algorithms.ts": 3269, + "5438-crypto-kdf-digests.ts": 3099, + "5439-crypto-kdf-callbacks.js": 4398, + "5440-crypto-hash-encodings.js": 4908, + "5441-crypto-hash-output-length.ts": 3959, + "5442-crypto-random-values.ts": 4791, + "5443-crypto-random-arguments.js": 3724, + "5444-crypto-timing-safe-equal.js": 4074, + "5445-crypto-secret-key-objects.ts": 4784, + "5445-stream-buffer-chunks.ts": 5661, + "5446-crypto-secret-key-errors.js": 3275, + "5446-stream-buffer-chunks-dynamic.js": 5780, + "5447-fs-readdir-order.ts": 3355, + "5448-fs-glob-patterns.ts": 3298, + "5449-fs-glob-options.ts": 3827, + "5450-fs-glob-validation.js": 4321, + "5451-fs-promises-glob.ts": 3074, + "5452-fs-glob-callback.ts": 3887, + "5455-power-of-two-remainder.ts": 4228, + "5456-remainder-large-integer-dividends.ts": 3551, + "5457-lcg-modulus.ts": 2909, + "5458-fractional-remainder.ts": 2650, + "5460-locale-compare-contractions.ts": 3201, + "5461-locale-compare-equivalents.ts": 3410, + "5462-locale-compare-probe-sweep.ts": 4164, + "5463-locale-compare-combining-letters.ts": 3755, + "5464-locale-compare-fractions.ts": 3312, "5465-dyn-index-read-arrays.ts": 3798, "5466-dyn-index-read-special.ts": 4384, - "5470-strip-vt-osc.cjs": 3494, - "5471-strip-vt-csi.cjs": 3770, - "5472-strip-vt-random.cjs": 3968, - "5473-strip-vt-unterminated.cjs": 4621, - "5474-strip-vt-surrogates.ts": 3567, + "5470-strip-vt-osc.cjs": 2708, + "5471-strip-vt-csi.cjs": 3038, + "5472-strip-vt-random.cjs": 2850, + "5473-strip-vt-unterminated.cjs": 4462, + "5474-strip-vt-surrogates.ts": 3554, "5510-assert-error-properties.js": 5349, "5511-assert-error-class.ts": 4329, "5512-assert-error-options.js": 3469, @@ -4930,20 +4933,20 @@ "5530-buffer-pool.ts": 4413, "5531-buffer-pool-first-slab.ts": 5557, "5532-buffer-pool-first-slab-untyped.mjs": 220640, - "5540-fs-callback-forms.cjs": 4591, - "5541-fs-stats-fields.cjs": 6904, - "5542-fs-promises-parity.cjs": 4673, - "5543-fs-promises-typed.ts": 5025, - "5544-fs-opendir.cjs": 4673, - "5545-fs-options-encoding.cjs": 5256, + "5540-fs-callback-forms.cjs": 3079, + "5541-fs-stats-fields.cjs": 4039, + "5542-fs-promises-parity.cjs": 3312, + "5543-fs-promises-typed.ts": 2944, + "5544-fs-opendir.cjs": 3622, + "5545-fs-options-encoding.cjs": 3497, "5546-fs-read-stream.cjs": 5295, "5547-fs-write-stream.cjs": 6075, - "5548-fs-callback-arguments.cjs": 4982, - "5549-fs-callback-option-checks.cjs": 4309, - "5550-locale-compare-ascii-words.ts": 3614, - "5551-array-search-references.ts": 4656, - "5552-string-appends.ts": 3810, - "5553-string-append-char-code.ts": 4013, + "5548-fs-callback-arguments.cjs": 3905, + "5549-fs-callback-option-checks.cjs": 3471, + "5550-locale-compare-ascii-words.ts": 2824, + "5551-array-search-references.ts": 3964, + "5552-string-appends.ts": 3653, + "5553-string-append-char-code.ts": 3292, "5554-fs-streams-typed.ts": 4873, "5555-fs-callback-turns.cjs": 3708, "5555-http-server-close-keep-alive.ts": 15618, @@ -4956,15 +4959,15 @@ "5562-https-verify-errors.ts": 4777, "5563-http-keep-alive-timeout.ts": 17783, "5564-http-request-signal.ts": 10735, - "5565-fs-dirent-untyped.mjs": 4337, - "5566-fs-dirent-dyn-boundaries/main.mjs": 4371, + "5565-fs-dirent-untyped.mjs": 2898, + "5566-fs-dirent-dyn-boundaries/main.mjs": 3333, "5567-fs-cpsync.ts": 4945, "5568-fs-cp-errors.js": 4099, "5569-fs-cp-symlinks.ts": 3686, "5570-fs-cp-async.ts": 4176, "5571-fs-cp-deep.ts": 5306, - "5585-record-results-inlined.ts": 3957, - "5595-net-ref-unref.ts": 5321, + "5585-record-results-inlined.ts": 3681, + "5595-net-ref-unref.ts": 3036, "5600-dyn-cycle-self.ts": 3365, "5601-dyn-cycle-mutual.ts": 4239, "5602-dyn-cycle-arrays.ts": 3453, @@ -4989,19 +4992,19 @@ "5624-timers-promises-unawaited.ts": 4420, "5625-promisify-exec.ts": 8488, "5626-promisify-forms.ts": 3100, - "5627-exec-callback.ts": 3311, + "5627-exec-callback.ts": 2500, "5628-promisify-timers.ts": 3913, "5629-promisify-stream.ts": 3357, "5630-promisify-zlib.ts": 3392, - "5631-promisify-crypto.ts": 3727, - "5632-promisify-dns.ts": 5476, - "5644-net-socket-addresses.ts": 3677, - "5645-net-socket-callbacks.ts": 4544, - "5646-net-server-connections.ts": 3663, - "5647-net-is-ip.ts": 3569, - "5648-dns-lookup-forms.ts": 5746, - "5649-dns-service-servers.ts": 4846, - "5650-dns-lookup-errors-untyped.cjs": 4466, + "5631-promisify-crypto.ts": 2600, + "5632-promisify-dns.ts": 2000, + "5644-net-socket-addresses.ts": 2393, + "5645-net-socket-callbacks.ts": 2060, + "5646-net-server-connections.ts": 2755, + "5647-net-is-ip.ts": 2560, + "5648-dns-lookup-forms.ts": 3416, + "5649-dns-service-servers.ts": 4916, + "5650-dns-lookup-errors-untyped.cjs": 3889, "5651-tls-socket-protocol.ts": 30873, "5652-http-client-trailer-overflow.ts": 3512, "5653-net-socket-read-ahead.ts": 6212, @@ -5014,7 +5017,7 @@ "5664-tls-client-identity.ts": 6340, "5674-union-instanceof-array-arms.ts": 3943, "5680-array-growth-after-copy.ts": 4581, - "5681-array-pop-and-length.ts": 4279, + "5681-array-pop-and-length.ts": 3216, "5682-publish-wide-objects.ts": 3376, "5700-cycle-release-retained.ts": 3414, "5701-cycle-release-old-edges.ts": 4210, @@ -5079,39 +5082,39 @@ "5795-worker-message-port-batches.ts": 2995, "5796-worker-message-channel.cjs": 3812, "5797-worker-message-port-transfer.ts": 3633, - "5800-broadcast-channel.ts": 40203, - "5801-broadcast-channel.cjs": 5126, - "5802-broadcast-channel-workers.ts": 4593, - "5803-worker-environment-data.ts": 5183, - "5804-worker-environment-data.cjs": 3173, - "5805-worker-receive-message-parent-port.ts": 2696, - "5806-worker-resource-limits.ts": 3922, - "5807-worker-error-values.ts": 6807, - "5808-worker-unhandled-rejections.ts": 7138, - "5809-process-exit-and-rejections.cjs": 33202, - "5810-mock-method-records.ts": 6251, - "5811-mock-tracker-restore.ts": 6093, - "5812-dyn-box-async-fields.ts": 3948, - "5813-mock-timers-module.ts": 5361, - "5814-mock-timers-date.ts": 7472, + "5800-broadcast-channel.ts": 28374, + "5801-broadcast-channel.cjs": 27251, + "5802-broadcast-channel-workers.ts": 27251, + "5803-worker-environment-data.ts": 29298, + "5804-worker-environment-data.cjs": 26404, + "5805-worker-receive-message-parent-port.ts": 30268, + "5806-worker-resource-limits.ts": 29711, + "5807-worker-error-values.ts": 35248, + "5808-worker-unhandled-rejections.ts": 33209, + "5809-process-exit-and-rejections.cjs": 30261, + "5810-mock-method-records.ts": 6363, + "5811-mock-tracker-restore.ts": 4503, + "5812-dyn-box-async-fields.ts": 5278, + "5813-mock-timers-module.ts": 4227, + "5814-mock-timers-date.ts": 17708, "5830-timers-promises-signal.ts": 4170, - "5831-util-types-brands.ts": 3902, - "5832-util-types-brands-dynamic.js": 4287, - "5833-url-search-params-iterators.ts": 3492, - "5834-url-search-params-iterators-dynamic.mjs": 3994, - "5835-util-format-integer-specifiers.ts": 3659, - "5836-url-search-params-tuple-pairs.ts": 3814, - "5837-util-format-json-circular.ts": 4225, - "5838-qs-stringify-bigint.ts": 5010, + "5831-util-types-brands.ts": 4380, + "5832-util-types-brands-dynamic.js": 3658, + "5833-url-search-params-iterators.ts": 5339, + "5834-url-search-params-iterators-dynamic.mjs": 3797, + "5835-util-format-integer-specifiers.ts": 2768, + "5836-url-search-params-tuple-pairs.ts": 3193, + "5837-util-format-json-circular.ts": 3408, + "5838-qs-stringify-bigint.ts": 3519, "5839-timers-promises-scheduler.ts": 3897, "5840-promise-with-resolvers-js.js": 3596, - "5841-json-typed-dyn-members.ts": 5082, - "5842-qs-parse-null-prototype.ts": 3325, - "5843-qs-parse-null-prototype-js.mjs": 3033, - "5844-date-unknown-values.ts": 4145, + "5841-json-typed-dyn-members.ts": 3238, + "5842-qs-parse-null-prototype.ts": 7077, + "5843-qs-parse-null-prototype-js.mjs": 5395, + "5844-date-unknown-values.ts": 4543, "5845-groupby-null-prototype.ts": 4290, - "5846-events-esm-default-max.ts": 2759, - "5847-events-cjs-default-max.cjs": 3509, + "5846-events-esm-default-max.ts": 3102, + "5847-events-cjs-default-max.cjs": 3039, "5849-class-view-observations.ts": 4659, "5850-using-disposable-values.ts": 3072, "5851-using-suppressed-error-values.ts": 3950, @@ -5120,45 +5123,45 @@ "5854-array-from-async.ts": 5635, "5855-array-from-async-js.js": 3433, "5856-error-is-error.ts": 3928, - "5857-regexp-unicode-sets.ts": 3859, - "5858-disposable-stack.ts": 5135, - "5859-disposable-stack-js.js": 3801, + "5857-regexp-unicode-sets.ts": 3900, + "5858-disposable-stack.ts": 3750, + "5859-disposable-stack-js.js": 3600, "5860-url-ipv4-hosts.ts": 4018, - "5870-worker-thread-names.ts": 7328, - "5871-worker-untransferable.cjs": 43661, + "5870-worker-thread-names.ts": 31697, + "5871-worker-untransferable.cjs": 27481, "5872-readline-positional-create-interface.mjs": 6166, "5873-readline-promises-namespace.cjs": 3811, - "5874-worker-stdio-streams.ts": 50741, - "5875-worker-stdout-pipe.cjs": 50279, - "5879-worker-stdin.ts": 57033, + "5874-worker-stdio-streams.ts": 27801, + "5875-worker-stdout-pipe.cjs": 31391, + "5879-worker-stdin.ts": 33232, "5880-emitter-leak-warning-delivery.ts": 4319, - "5881-inspect-weak-collections.ts": 3631, - "5882-string-decoder-runtime-encoding.ts": 3362, - "5883-os-set-priority.ts": 3308, - "5884-inspect-layout-options.ts": 4849, + "5881-inspect-weak-collections.ts": 2915, + "5882-string-decoder-runtime-encoding.ts": 3854, + "5883-os-set-priority.ts": 3417, + "5884-inspect-layout-options.ts": 3596, "5885-events-max-listener-helpers.ts": 3588, - "5886-inspect-dates.ts": 2966, - "5887-inspect-typed-arrays.ts": 3325, - "5888-inspect-sorted.ts": 3559, + "5886-inspect-dates.ts": 2736, + "5887-inspect-typed-arrays.ts": 2997, + "5888-inspect-sorted.ts": 2861, "5889-timers-scheduler-signal.ts": 8928, "5890-while-string-length-counters.ts": 3822, "5892-buffer-write-utf16le-runs.ts": 3465, - "5900-float16-array.ts": 3954, - "5901-float16-array-js.js": 3925, - "5904-async-generator-completion.ts": 6639, - "5905-array-from-async-generator.ts": 4467, - "5906-array-from-async-generator-js.js": 4458, - "5907-regex-groups-match-rows.ts": 4698, - "5910-set-prototype-of-primitive-object-kinds.ts": 4445, - "5911-dyn-class-to-primitive.ts": 5410, - "5912-dyn-class-conversion-methods.ts": 4298, - "5913-prototype-type-error-messages.ts": 3454, - "5914-dyn-in-class-prototype-members.ts": 3792, - "5915-dyn-error-string-conversions.ts": 3851, + "5900-float16-array.ts": 3750, + "5901-float16-array-js.js": 3700, + "5904-async-generator-completion.ts": 3800, + "5905-array-from-async-generator.ts": 3500, + "5906-array-from-async-generator-js.js": 3750, + "5907-regex-groups-match-rows.ts": 3750, + "5910-set-prototype-of-primitive-object-kinds.ts": 5033, + "5911-dyn-class-to-primitive.ts": 4732, + "5912-dyn-class-conversion-methods.ts": 4424, + "5913-prototype-type-error-messages.ts": 4068, + "5914-dyn-in-class-prototype-members.ts": 4327, + "5915-dyn-error-string-conversions.ts": 4247, "5920-promise-try-args.ts": 3195, "5921-promise-try-args-js.js": 3082, - "5922-matchall-groups-callbacks.ts": 5275, - "5923-matchall-groups-js.js": 4883, + "5922-matchall-groups-callbacks.ts": 5960, + "5923-matchall-groups-js.js": 6650, "5924-js-literal-identity.js": 3065, "5925-class-view-identity-observers.ts": 2685, "5926-class-view-switch-js.js": 3057, @@ -5174,868 +5177,871 @@ "5935-js-subclass-fields-and-element-calls.js": 4470, "5936-checked-js-class-types.js": 4183, "5937-override-narrowed-union-returns.ts": 3827, - "5938-object-literal-computed-keys-keep-methods.ts": 4019, - "5939-js-let-object-reassigned-wider.js": 4037, + "5938-object-literal-computed-keys-keep-methods.ts": 7194, + "5939-js-let-object-reassigned-wider.js": 4436, "5940-callback-helper-specialization.ts": 4548, "5941-callback-specialization-recursion.ts": 4448, "5942-callback-specialization-throws.ts": 3443, - "5945-local-class-observed-methods.ts": 4458, - "5946-nested-record-field-optional-writes.ts": 3537, - "5950-tuple-predicate-methods.ts": 4018, - "5951-result-never-widening.ts": 3970, - "5952-record-missing-keys.ts": 5020, - "5953-nan-coded-method-returns.ts": 2689, - "5955-any-promise-methods.js": 3182, - "5956-erased-generic-members.ts": 5824, - "5958-asserted-union-receiver.ts": 3206, - "5959-date-to-json.ts": 3819, + "5943-fields-read-before-assignment.ts": 72293, + "5944-js-fields-read-before-assignment.js": 40310, + "5945-local-class-observed-methods.ts": 6212, + "5946-nested-record-field-optional-writes.ts": 68117, + "5950-tuple-predicate-methods.ts": 7790, + "5951-result-never-widening.ts": 6120, + "5952-record-missing-keys.ts": 20400, + "5953-nan-coded-method-returns.ts": 15600, + "5955-any-promise-methods.js": 5120, + "5956-erased-generic-members.ts": 8750, + "5958-asserted-union-receiver.ts": 3160, + "5959-date-to-json.ts": 4330, "5960-frame-records-own-references.ts": 3535, - "5960-generic-mapped-types.ts": 3052, + "5960-generic-mapped-types.ts": 3300, "5961-frame-spread-updates.ts": 3732, "5962-frame-tuples.ts": 3372, - "5970-net-connect-host-name.ts": 3461, - "5971-buffer-chunks-to-string.ts": 4886, - "5972-net-set-encoding-listeners.ts": 4672, + "5970-net-connect-host-name.ts": 2800, + "5971-buffer-chunks-to-string.ts": 3100, + "5972-net-set-encoding-listeners.ts": 3000, "5973-large-closure-environment.ts": 5145, - "5974-typeof-module-exports.cjs": 3216, - "5975-zlib-class-values.ts": 4063, - "5990-worker-uncloneable.mjs": 4117, - "5991-worker-async-dispose.mjs": 40350, - "5992-worker-thread-name-lifetime.mjs": 47859, + "5974-typeof-module-exports.cjs": 2500, + "5975-zlib-class-values.ts": 4200, + "5990-worker-uncloneable.mjs": 22432, + "5991-worker-async-dispose.mjs": 25768, + "5992-worker-thread-name-lifetime.mjs": 28932, "5993-array-length-loop-resizing.ts": 4127, "5994-array-length-sparse-loops.ts": 2815, "5995-array-dense-loop-boundaries.ts": 4171, - "600-closures-basic.ts": 3688, - "601-closures-loops.ts": 2905, - "602-closures-identity-recursion.ts": 3340, - "6020-class-extends-function-constructor.js": 3739, - "6021-asserted-literal-union-arm.ts": 3498, - "603-closures-rc-stress.ts": 2788, - "604-closures-for-of.ts": 3472, + "5996-rejections-between-macrotasks.cjs": 22172, + "600-closures-basic.ts": 2534, + "601-closures-loops.ts": 2297, + "602-closures-identity-recursion.ts": 2427, + "6020-class-extends-function-constructor.js": 7500, + "6021-asserted-literal-union-arm.ts": 7200, + "603-closures-rc-stress.ts": 2589, + "604-closures-for-of.ts": 3514, "6041-error-cause-redeclared.ts": 4631, "6042-regex-match-object-destructuring.ts": 3091, "6043-string-index-narrowed-union.ts": 3627, - "605-closures-forward-capture-tdz.ts": 4043, + "605-closures-forward-capture-tdz.ts": 4638, "6140-cjs-require-tdz-throws/main.js": 2989, "6141-cjs-require-tdz-checked/main.js": 4062, "6142-cjs-require-published-early/main.js": 5156, "6143-cjs-require-json/main.js": 3050, "6144-cjs-require-builtin-nested/main.js": 3329, "6145-cjs-require-cycle/main.js": 4761, - "700-classes-basic.ts": 2717, - "701-classes-composition.ts": 3694, - "702-classes-this-capture.ts": 3151, - "703-classes-rc-stress.ts": 3285, - "710-inheritance-basics.ts": 2592, - "711-inheritance-dispatch.ts": 3301, - "712-inheritance-instanceof.ts": 3603, - "713-inheritance-rc-stress.ts": 2631, - "720-accessors-basics.ts": 2515, - "721-accessors-eval-order.ts": 3454, - "722-accessors-inheritance.ts": 3466, - "723-accessors-rc-stress.ts": 3570, - "750-cycle-closure-box.ts": 3720, - "751-cycle-records-mutual.ts": 2782, - "752-cycle-classes.ts": 3168, - "753-cycle-owned-arrays.ts": 3490, - "754-cycle-external-ref.ts": 3578, - "755-cycle-async-promise.ts": 3053, - "756-cycle-inheritance.ts": 2275, - "757-cycle-cross-generation.ts": 3630, - "762-any-boundary.ts": 3627, - "764-any-async.ts": 3271, - "765-any-optional-chain.ts": 2987, - "766-any-union-boundary.ts": 3659, - "767-string-literal-keys.ts": 3306, - "768-any-uninitialized.ts": 3041, - "800-switch-basics.ts": 3127, - "801-switch-lazy-tests.ts": 3237, - "802-switch-loops.ts": 3396, - "803-switch-rc-stress.ts": 3243, - "804-switch-braced-blocks.ts": 3060, - "810-do-while.ts": 3366, - "820-multi-decl.ts": 3412, - "830-let-uninitialized.ts": 2806, - "900-records-basics.ts": 2799, - "901-records-eval-order.ts": 3424, - "902-records-functions-closures.ts": 2868, - "903-records-rc-stress.ts": 3996, - "904-records-optional-fields.ts": 3692, - "905-records-optional-rc-stress.ts": 3288, - "906-records-utility-types.ts": 2706, - "907-records-utility-generics.ts": 2748, - "908-records-index-signatures.ts": 3143, - "909-records-index-json.ts": 3697, - "910-records-index-rc-stress.ts": 4050, - "911-records-index-dot-access.ts": 3683, - "912-unknown-slots.ts": 2923, - "913-records-index-iteration.ts": 4112, - "914-records-from-entries.ts": 3768, - "915-unknown-tostring-eq.ts": 3915, - "916-unknown-bytes.ts": 3466, - "917-record-array-index-dot.ts": 3287, - "950-modules-basic/main.ts": 3531, - "951-modules-diamond/main.ts": 3176, - "952-modules-cross/main.ts": 2507, - "953-modules-default/main.ts": 2473, - "954-modules-reexport/main.ts": 2897, - "957-builtins-namespace.ts": 3213, - "960-generics-basics.ts": 2743, - "961-generics-recursion.ts": 3759, - "962-generics-closures.ts": 3551, - "963-generics-modules/main.ts": 3745, - "964-generics-rc-stress.ts": 3697, - "965-generics-async.ts": 3911, - "965-unions-retag.ts": 2955, - "966-unions-retag-rc-stress.ts": 3416, - "967-record-field-widening.ts": 3252, - "969-unions-arm-matrix.ts": 3502, - "970-unions-basics.ts": 3588, - "971-unions-switch.ts": 3755, - "972-unions-nested.ts": 2659, - "973-unions-rc-stress.ts": 3021, - "974-unions-modules/main.ts": 3329, - "975-unions-undefined.ts": 3414, - "976-unions-null.ts": 3240, - "977-unions-unit-rc-stress.ts": 3807, - "978-unions-nullish.ts": 3471, - "979-unions-optional-chaining.ts": 2680, - "980-exceptions-basics.ts": 3823, - "981-exceptions-values.ts": 3366, - "982-exceptions-rc-stress.ts": 3526, - "983-exceptions-control-flow.ts": 3306, - "984-exceptions-finally.ts": 3693, - "985-exceptions-call-chains.ts": 3523, - "986-exceptions-uncaught.ts": 3377, - "987-exceptions-result-unions.ts": 3446, - "990-process-basics.ts": 3175, - "991-process-exit.ts": 3461, - "992-fs-roundtrip.ts": 3411, - "993-fs-readdir.ts": 3612, - "994-fs-errors.ts": 3748, - "995-fs-uncaught.ts": 3089, - "996-fs-rc-stress.ts": 3714, - "997-fs-modules/main.ts": 3327, - "998-process-env.ts": 2498, - "abstract-property-dispatch.ts": 4365, - "arguments-arrow-capture.mjs": 3544, - "arguments-reexport/main.ts": 3373, - "array-argument-lifetimes-exits.ts": 2870, - "array-argument-lifetimes-mutation.ts": 3721, - "array-argument-lifetimes-strings.ts": 3794, - "array-argument-lifetimes-values.ts": 4076, - "array-buffer-conversions.js": 3267, - "array-buffer-storage.ts": 3982, - "array-checked-callback-results.mjs": 3822, - "array-checked-constructor.js": 3361, - "array-concat-widening.ts": 3515, + "700-classes-basic.ts": 2674, + "701-classes-composition.ts": 2606, + "702-classes-this-capture.ts": 2403, + "703-classes-rc-stress.ts": 3477, + "710-inheritance-basics.ts": 2972, + "711-inheritance-dispatch.ts": 2507, + "712-inheritance-instanceof.ts": 2847, + "713-inheritance-rc-stress.ts": 3484, + "720-accessors-basics.ts": 3144, + "721-accessors-eval-order.ts": 3241, + "722-accessors-inheritance.ts": 3694, + "723-accessors-rc-stress.ts": 2838, + "750-cycle-closure-box.ts": 3262, + "751-cycle-records-mutual.ts": 3163, + "752-cycle-classes.ts": 2239, + "753-cycle-owned-arrays.ts": 2204, + "754-cycle-external-ref.ts": 2593, + "755-cycle-async-promise.ts": 3154, + "756-cycle-inheritance.ts": 2213, + "757-cycle-cross-generation.ts": 3118, + "762-any-boundary.ts": 3063, + "764-any-async.ts": 3129, + "765-any-optional-chain.ts": 3899, + "766-any-union-boundary.ts": 3346, + "767-string-literal-keys.ts": 2340, + "768-any-uninitialized.ts": 2983, + "800-switch-basics.ts": 3128, + "801-switch-lazy-tests.ts": 2842, + "802-switch-loops.ts": 3486, + "803-switch-rc-stress.ts": 2321, + "804-switch-braced-blocks.ts": 3234, + "810-do-while.ts": 3326, + "820-multi-decl.ts": 2338, + "830-let-uninitialized.ts": 2579, + "900-records-basics.ts": 3473, + "901-records-eval-order.ts": 2890, + "902-records-functions-closures.ts": 3085, + "903-records-rc-stress.ts": 3146, + "904-records-optional-fields.ts": 2930, + "905-records-optional-rc-stress.ts": 2986, + "906-records-utility-types.ts": 2822, + "907-records-utility-generics.ts": 3048, + "908-records-index-signatures.ts": 2695, + "909-records-index-json.ts": 3037, + "910-records-index-rc-stress.ts": 2958, + "911-records-index-dot-access.ts": 4686, + "912-unknown-slots.ts": 3359, + "913-records-index-iteration.ts": 3265, + "914-records-from-entries.ts": 3414, + "915-unknown-tostring-eq.ts": 3349, + "916-unknown-bytes.ts": 3729, + "917-record-array-index-dot.ts": 3331, + "950-modules-basic/main.ts": 2717, + "951-modules-diamond/main.ts": 2315, + "952-modules-cross/main.ts": 2751, + "953-modules-default/main.ts": 3300, + "954-modules-reexport/main.ts": 2770, + "957-builtins-namespace.ts": 2759, + "960-generics-basics.ts": 3631, + "961-generics-recursion.ts": 3262, + "962-generics-closures.ts": 2245, + "963-generics-modules/main.ts": 2769, + "964-generics-rc-stress.ts": 3123, + "965-generics-async.ts": 3925, + "965-unions-retag.ts": 3882, + "966-unions-retag-rc-stress.ts": 3167, + "967-record-field-widening.ts": 2827, + "969-unions-arm-matrix.ts": 3297, + "970-unions-basics.ts": 3439, + "971-unions-switch.ts": 3593, + "972-unions-nested.ts": 2812, + "973-unions-rc-stress.ts": 2567, + "974-unions-modules/main.ts": 2485, + "975-unions-undefined.ts": 2505, + "976-unions-null.ts": 3528, + "977-unions-unit-rc-stress.ts": 2503, + "978-unions-nullish.ts": 2591, + "979-unions-optional-chaining.ts": 2499, + "980-exceptions-basics.ts": 2297, + "981-exceptions-values.ts": 3503, + "982-exceptions-rc-stress.ts": 3146, + "983-exceptions-control-flow.ts": 2518, + "984-exceptions-finally.ts": 2504, + "985-exceptions-call-chains.ts": 3540, + "986-exceptions-uncaught.ts": 3473, + "987-exceptions-result-unions.ts": 3527, + "990-process-basics.ts": 3510, + "991-process-exit.ts": 2297, + "992-fs-roundtrip.ts": 2694, + "993-fs-readdir.ts": 3781, + "994-fs-errors.ts": 2370, + "995-fs-uncaught.ts": 2239, + "996-fs-rc-stress.ts": 2822, + "997-fs-modules/main.ts": 2578, + "998-process-env.ts": 2181, + "abstract-property-dispatch.ts": 2739, + "arguments-arrow-capture.mjs": 3039, + "arguments-reexport/main.ts": 2635, + "array-argument-lifetimes-exits.ts": 3136, + "array-argument-lifetimes-mutation.ts": 3333, + "array-argument-lifetimes-strings.ts": 3015, + "array-argument-lifetimes-values.ts": 3223, + "array-buffer-conversions.js": 2594, + "array-buffer-storage.ts": 3699, + "array-checked-callback-results.mjs": 3402, + "array-checked-constructor.js": 3477, + "array-concat-widening.ts": 3858, "array-deque-unshift.ts": 4273, - "array-element-compound-updates.ts": 5390, - "array-fill-unit-values.ts": 3744, - "array-from-checked.js": 4644, - "array-from-value.mjs": 3261, - "array-isarray-value/main.js": 3569, - "array-numeric-own-keys.ts": 3719, - "array-optional-number-write-index.ts": 3067, - "array-primitive-ordering.ts": 4670, + "array-element-compound-updates.ts": 3591, + "array-fill-unit-values.ts": 2572, + "array-from-checked.js": 3097, + "array-from-value.mjs": 3428, + "array-isarray-value/main.js": 3143, + "array-numeric-own-keys.ts": 3632, + "array-optional-number-write-index.ts": 3380, + "array-primitive-ordering.ts": 3925, "array-queue-head-room.ts": 5069, - "array-read-helper-effects.ts": 3808, - "array-refined-storage.ts": 3910, - "array-sort-dense-effects.ts": 4754, - "array-sort-dense-values.ts": 4991, - "array-sort-holes-published.ts": 12914, - "array-sort-runs.ts": 11006, - "array-sort-runtime-comparator.ts": 7044, - "array-sort-unknown-comparator.ts": 2921, - "array-storage-transitions.ts": 4555, - "array-truncate-reuse.ts": 3342, - "async-backend-factory.mjs": 3685, - "async-local-typed-results.ts": 4110, - "atomics-integer-operations.ts": 4324, - "bigint-checked-casts.ts": 3538, - "bigint-checked-storage.js": 3582, - "bigint-union-conversion.ts": 3627, - "boxed-error-rethrows.mjs": 3074, - "buffer-codec-boundaries.ts": 2997, - "buffer-primitive-predicate.ts": 3212, - "builtin-prototype-method-values.mjs": 4169, - "byte-loop-bounds.ts": 3289, - "byte-number-pipeline.ts": 3830, - "byte-record-windows.ts": 4084, - "call-lifetimes-argument-order.ts": 2814, - "call-lifetimes-control-flow.ts": 3242, - "call-lifetimes-owned-boundaries.ts": 3884, - "call-lifetimes-projections.ts": 3960, - "call-lifetimes-union-values.ts": 3288, - "call-lifetimes-virtual-optionals.ts": 4204, - "callable-module-members.mjs": 3631, - "callable-properties.mjs": 3358, - "callable-property-cycles.js": 2892, - "callable-reexport/main.ts": 3566, - "captured-class-refinement.ts": 3716, - "catch-capture.ts": 3398, - "caught-class-identity.ts": 4607, - "caught-standalone-class.ts": 3366, - "caught-system-error-fields.ts": 3842, - "checked-addition.js": 3129, - "checked-any-addition.ts": 3239, - "checked-array-assignment.ts": 3271, - "checked-array-flat/main.ts": 3753, - "checked-bitwise/main.js": 3435, - "checked-builder-cycles.js": 2781, - "checked-byte-storage/main.ts": 3695, - "checked-callback-options.ts": 3641, - "checked-class-descriptors.mjs": 4373, - "checked-class-factory.mjs": 3282, - "checked-collection-iterators.ts": 3261, - "checked-collection-symbol-methods.ts": 2592, - "checked-dispatch-input-lifetimes.js": 2966, - "checked-increment/main.js": 3466, - "checked-inherited-fields.ts": 3091, - "checked-iterator-consumption.js": 4432, - "checked-numeric-arithmetic.js": 3676, - "checked-object-module-alias.js": 3750, - "checked-optional-calls.mjs": 2819, - "checked-promise-recovery.ts": 3546, - "checked-proxy-callback/main.ts": 3548, - "checked-record-constructor.ts": 3491, - "checked-renderer-defaults.js": 2925, - "checked-rest-function-adapters.js": 3233, - "checked-storage-transitions.js": 2999, - "checked-symbol-array.ts": 3209, - "checked-value-input-lifetimes.ts": 2736, - "class-accessor-returned-function.js": 3222, - "class-array-optional-return.ts": 3320, - "class-bracket-method-calls.js": 3856, - "class-brand-overload.js": 3204, - "class-callback-replacement.js": 4854, - "class-callback-storage.ts": 4827, - "class-checked-composites.ts": 3368, - "class-checked-upcast.ts": 3815, - "class-collection-insertion.ts": 5133, - "class-computed-presence.ts": 4064, - "class-computed-symbols.js": 4475, - "class-covariant-returns.ts": 3062, - "class-curried-factory.mjs": 3903, - "class-data-descriptors.js": 4613, - "class-factory-inherited-statics.mjs": 3165, - "class-factory-parameter-base.mjs": 4404, - "class-factory-record-base.mjs": 5117, - "class-factory-recursive-statics.mjs": 3656, - "class-factory-static-members.mjs": 3238, - "class-function-base/main.js": 3349, - "class-instance-constructor.js": 4347, - "class-interface-protocols.ts": 5479, - "class-interface-refinements.ts": 4411, - "class-json-checked.ts": 3478, - "class-local-function-base.mjs": 2889, - "class-method-spreads.ts": 5065, - "class-narrowed-views.ts": 2591, - "class-property-call-values.mjs": 3049, - "class-prototype-data.js": 3914, - "class-prototype-descriptor-copy.mjs": 3673, - "class-specialized-computed-base.mjs": 4340, - "class-static-data.js": 3321, - "class-subclass-assertions.ts": 3532, - "class-super-surplus-spread.mjs": 3433, - "class-symbol-accessors.ts": 3674, - "class-symbol-cache.mjs": 4312, - "class-value-constructor-exceptions.ts": 2729, + "array-read-helper-effects.ts": 3425, + "array-refined-storage.ts": 3909, + "array-sort-dense-effects.ts": 2917, + "array-sort-dense-values.ts": 5261, + "array-sort-holes-published.ts": 13040, + "array-sort-runs.ts": 10059, + "array-sort-runtime-comparator.ts": 5498, + "array-sort-unknown-comparator.ts": 2858, + "array-storage-transitions.ts": 2799, + "array-truncate-reuse.ts": 2407, + "async-backend-factory.mjs": 3609, + "async-local-typed-results.ts": 2487, + "atomics-integer-operations.ts": 3832, + "bigint-checked-casts.ts": 3603, + "bigint-checked-storage.js": 3992, + "bigint-union-conversion.ts": 3125, + "boxed-error-rethrows.mjs": 2646, + "buffer-codec-boundaries.ts": 3139, + "buffer-primitive-predicate.ts": 3495, + "builtin-prototype-method-values.mjs": 4297, + "byte-loop-bounds.ts": 3001, + "byte-number-pipeline.ts": 3966, + "byte-record-windows.ts": 3749, + "call-lifetimes-argument-order.ts": 2794, + "call-lifetimes-control-flow.ts": 3894, + "call-lifetimes-owned-boundaries.ts": 3881, + "call-lifetimes-projections.ts": 3082, + "call-lifetimes-union-values.ts": 3090, + "call-lifetimes-virtual-optionals.ts": 3774, + "callable-module-members.mjs": 2996, + "callable-properties.mjs": 3737, + "callable-property-cycles.js": 2394, + "callable-reexport/main.ts": 2995, + "captured-class-refinement.ts": 3815, + "catch-capture.ts": 2295, + "caught-class-identity.ts": 3893, + "caught-standalone-class.ts": 3591, + "caught-system-error-fields.ts": 3373, + "checked-addition.js": 3059, + "checked-any-addition.ts": 2638, + "checked-array-assignment.ts": 2861, + "checked-array-flat/main.ts": 2441, + "checked-bitwise/main.js": 3177, + "checked-builder-cycles.js": 3284, + "checked-byte-storage/main.ts": 3985, + "checked-callback-options.ts": 3034, + "checked-class-descriptors.mjs": 2786, + "checked-class-factory.mjs": 2348, + "checked-collection-iterators.ts": 3731, + "checked-collection-symbol-methods.ts": 3019, + "checked-dispatch-input-lifetimes.js": 3481, + "checked-increment/main.js": 2884, + "checked-inherited-fields.ts": 2756, + "checked-iterator-consumption.js": 4074, + "checked-numeric-arithmetic.js": 2874, + "checked-object-module-alias.js": 3204, + "checked-optional-calls.mjs": 2897, + "checked-promise-recovery.ts": 2819, + "checked-proxy-callback/main.ts": 3009, + "checked-record-constructor.ts": 3034, + "checked-renderer-defaults.js": 2935, + "checked-rest-function-adapters.js": 2965, + "checked-storage-transitions.js": 2510, + "checked-symbol-array.ts": 2504, + "checked-value-input-lifetimes.ts": 3033, + "class-accessor-returned-function.js": 2287, + "class-array-optional-return.ts": 3498, + "class-bracket-method-calls.js": 3071, + "class-brand-overload.js": 3526, + "class-callback-replacement.js": 3460, + "class-callback-storage.ts": 4585, + "class-checked-composites.ts": 3187, + "class-checked-upcast.ts": 3072, + "class-collection-insertion.ts": 4235, + "class-computed-presence.ts": 2974, + "class-computed-symbols.js": 3740, + "class-covariant-returns.ts": 3957, + "class-curried-factory.mjs": 4128, + "class-data-descriptors.js": 3270, + "class-factory-inherited-statics.mjs": 2538, + "class-factory-parameter-base.mjs": 2587, + "class-factory-record-base.mjs": 5836, + "class-factory-recursive-statics.mjs": 3651, + "class-factory-static-members.mjs": 3672, + "class-function-base/main.js": 2657, + "class-instance-constructor.js": 2942, + "class-interface-protocols.ts": 3713, + "class-interface-refinements.ts": 4567, + "class-json-checked.ts": 2571, + "class-local-function-base.mjs": 3643, + "class-method-spreads.ts": 3220, + "class-narrowed-views.ts": 3766, + "class-property-call-values.mjs": 3125, + "class-prototype-data.js": 4251, + "class-prototype-descriptor-copy.mjs": 3998, + "class-specialized-computed-base.mjs": 3397, + "class-static-data.js": 2157, + "class-subclass-assertions.ts": 3733, + "class-super-surplus-spread.mjs": 2301, + "class-symbol-accessors.ts": 2479, + "class-symbol-cache.mjs": 3721, + "class-value-constructor-exceptions.ts": 3210, "closed-virtual-dispatch-modules/main.ts": 3375, "closed-virtual-dispatch.ts": 4025, - "closure-nullable-union-return.ts": 4235, - "closure-union-locals.ts": 3743, - "collection-array-cycles.ts": 3119, - "collection-array-maps.ts": 3580, - "collection-array-missing.ts": 3529, - "collection-array-sets.ts": 3755, - "collection-copy-identities.ts": 3108, - "collection-data-unions.ts": 3651, - "collection-ingestion-mappers.ts": 3521, - "collection-ingestion-protocol/main.ts": 4669, - "collection-ingestion-references.ts": 4710, - "collection-ingestion.ts": 3512, - "collection-storage-copies.ts": 3878, - "collection-value-keys.ts": 3854, - "compound-field-receivers.ts": 3456, - "compound-presence-guards.ts": 3018, - "conditional-tuple-destructuring.ts": 3519, - "console-imports.cjs": 3565, - "console-native-value.js": 2620, - "const-enum-module-cycle/main.ts": 2768, - "constant-callback-dispatch.ts": 3226, - "constant-module-globals/main.ts": 3076, - "constant-number-remainders.ts": 3457, - "constructed-class-dispatch.ts": 3935, - "contextual-array-union-write.ts": 5322, - "contextual-return-layouts.ts": 4143, - "counted-loop-numbers.ts": 3668, - "counted-loop-storage.ts": 2925, - "crypto-hash-optional-input.ts": 3821, - "cycle-generations-long-lived.ts": 2954, - "cycle-growth-yield.ts": 4304, - "date-checked-native.js": 3239, - "declared-index-spread.ts": 4205, - "deep-reference-teardown.ts": 3431, - "default-undefined-parameters.ts": 4155, - "deferred-field-updates.ts": 2817, - "deferred-registry-many.ts": 4413, - "derived-numeric-updates.ts": 3113, - "destructure-call-assignment.js": 2699, - "destructure-inferred-row-defaults.js": 3698, - "destructure-union-arrays.ts": 3868, - "dynamic-function-descriptors.js": 3825, - "error-cause-writes.js": 3664, - "error-inherited-message.mjs": 4115, - "error-inherited-name.mjs": 4088, - "error-property-writes.mjs": 3831, - "error-prototype-tostring.js": 3723, - "error-stack-frames.ts": 3316, - "error-stack-limit.ts": 3521, - "error-tostring-overrides.ts": 2788, - "error-values-inspect.ts": 2913, - "exact-index-round-trip.ts": 3953, - "expression-runtime-values.ts": 3293, - "fiber-switch-stress.ts": 4327, - "fiberless-async-ordering.ts": 4160, - "fiberless-async-unhandled.ts": 2861, - "field-assignment-values.ts": 3670, - "file-handle-values.ts": 3758, - "file-read-storage.ts": 5381, - "file-url-percent-decoding.ts": 3379, - "final-field-borrows.ts": 3428, - "for-multiple-bindings.ts": 2948, - "for-multiple-lexical-bindings.ts": 3036, - "for-of-checked-iterator.js": 3188, - "for-of-subclass-elements.ts": 3369, - "forward-generic-signatures.ts": 3512, - "fresh-array-union-layout.js": 3601, - "frozen-checked-dictionaries.mjs": 2948, - "fs-native-realpath.ts": 3654, + "closure-nullable-union-return.ts": 2727, + "closure-union-locals.ts": 2878, + "collection-array-cycles.ts": 3240, + "collection-array-maps.ts": 4497, + "collection-array-missing.ts": 3865, + "collection-array-sets.ts": 3087, + "collection-copy-identities.ts": 2655, + "collection-data-unions.ts": 2993, + "collection-ingestion-mappers.ts": 3305, + "collection-ingestion-protocol/main.ts": 5059, + "collection-ingestion-references.ts": 4238, + "collection-ingestion.ts": 3626, + "collection-storage-copies.ts": 4163, + "collection-value-keys.ts": 4167, + "compound-field-receivers.ts": 2877, + "compound-presence-guards.ts": 3145, + "conditional-tuple-destructuring.ts": 3213, + "console-imports.cjs": 2893, + "console-native-value.js": 2516, + "const-enum-module-cycle/main.ts": 3456, + "constant-callback-dispatch.ts": 2916, + "constant-module-globals/main.ts": 2911, + "constant-number-remainders.ts": 2372, + "constructed-class-dispatch.ts": 3382, + "contextual-array-union-write.ts": 6417, + "contextual-return-layouts.ts": 3746, + "counted-loop-numbers.ts": 2724, + "counted-loop-storage.ts": 2302, + "crypto-hash-optional-input.ts": 3311, + "cycle-generations-long-lived.ts": 3514, + "cycle-growth-yield.ts": 3352, + "date-checked-native.js": 2676, + "declared-index-spread.ts": 2941, + "deep-reference-teardown.ts": 4427, + "default-undefined-parameters.ts": 3232, + "deferred-field-updates.ts": 3345, + "deferred-registry-many.ts": 3072, + "derived-numeric-updates.ts": 2702, + "destructure-call-assignment.js": 2978, + "destructure-inferred-row-defaults.js": 3175, + "destructure-union-arrays.ts": 3248, + "dynamic-function-descriptors.js": 2750, + "error-cause-writes.js": 3104, + "error-inherited-message.mjs": 3024, + "error-inherited-name.mjs": 2500, + "error-property-writes.mjs": 3373, + "error-prototype-tostring.js": 3874, + "error-stack-frames.ts": 2418, + "error-stack-limit.ts": 2675, + "error-tostring-overrides.ts": 3246, + "error-values-inspect.ts": 3043, + "exact-index-round-trip.ts": 3701, + "expression-runtime-values.ts": 2154, + "fiber-switch-stress.ts": 5012, + "fiberless-async-ordering.ts": 3413, + "fiberless-async-unhandled.ts": 2739, + "field-assignment-values.ts": 2662, + "file-handle-values.ts": 3133, + "file-read-storage.ts": 3685, + "file-url-percent-decoding.ts": 2659, + "final-field-borrows.ts": 3350, + "for-multiple-bindings.ts": 3223, + "for-multiple-lexical-bindings.ts": 3021, + "for-of-checked-iterator.js": 3541, + "for-of-subclass-elements.ts": 3037, + "forward-generic-signatures.ts": 2999, + "fresh-array-union-layout.js": 2679, + "frozen-checked-dictionaries.mjs": 3220, + "fs-native-realpath.ts": 2477, "fs-null-byte-paths-js.cjs": 3914, "fs-null-byte-paths.ts": 5084, - "fs-read-encodings.ts": 3336, + "fs-read-encodings.ts": 3111, "fs-read-utf8-edges.ts": 4161, "fs-read-utf8-handle-forms.ts": 3562, - "fs-remove-readonly.ts": 3293, - "fs-write-string-bytes-union.ts": 2935, - "function-apply-value.mjs": 3607, - "function-constructor-global.mjs": 3295, - "function-constructor-kinds/main.js": 2837, - "function-custom-prototype.js": 3522, - "function-custom-to-string.mjs": 3399, - "function-object-assign.js": 3758, - "function-own-prototype/main.js": 2807, - "generator-checked-protocol.ts": 3503, - "generator-checked-return.js": 3369, - "generator-custom-delegation/main.ts": 5410, - "generator-default-return-pattern.ts": 2666, - "generator-delegation-values.ts": 3515, - "generator-inferred-date.js": 3280, - "generator-mixed-checked-channels.ts": 3467, - "generator-untyped-consumer/main.ts": 2805, - "generic-base-specializations.ts": 3523, - "generic-binding-ownership.ts": 4463, - "generic-class-js-functions/main.ts": 2699, - "generic-class-recovery.ts": 4031, - "generic-namespace-factories/main.ts": 3082, - "generic-nullable-collections.ts": 3376, - "generic-pattern-bindings.ts": 3388, - "generic-record-index.ts": 3789, - "generic-visitor-void.ts": 3751, + "fs-remove-readonly.ts": 2708, + "fs-write-string-bytes-union.ts": 2772, + "function-apply-value.mjs": 2976, + "function-constructor-global.mjs": 2229, + "function-constructor-kinds/main.js": 3064, + "function-custom-prototype.js": 3165, + "function-custom-to-string.mjs": 3379, + "function-object-assign.js": 3235, + "function-own-prototype/main.js": 2539, + "generator-checked-protocol.ts": 3197, + "generator-checked-return.js": 3544, + "generator-custom-delegation/main.ts": 3611, + "generator-default-return-pattern.ts": 3352, + "generator-delegation-values.ts": 3047, + "generator-inferred-date.js": 3314, + "generator-mixed-checked-channels.ts": 3576, + "generator-untyped-consumer/main.ts": 3225, + "generic-base-specializations.ts": 2247, + "generic-binding-ownership.ts": 3517, + "generic-class-js-functions/main.ts": 2300, + "generic-class-recovery.ts": 2961, + "generic-namespace-factories/main.ts": 3104, + "generic-nullable-collections.ts": 2983, + "generic-pattern-bindings.ts": 3518, + "generic-record-index.ts": 3239, + "generic-visitor-void.ts": 3402, "global-accumulator-loops.ts": 3531, - "global-error-subclasses.ts": 2383, - "global-runtime-probes.js": 3149, - "global-stored-probes.js": 3656, - "global-string-cache/main.js": 2944, - "global-symbol-cache/main.js": 3152, - "guarded-native-iterables.ts": 3442, - "heap-input-aliases.ts": 3338, - "heap-input-collections.ts": 3866, - "in-array-runtime-index.ts": 4870, - "indexed-assignment-values.js": 3555, - "indexed-assignment-values.ts": 3263, - "indexed-element-field-reads.ts": 3648, - "inferred-array-assignment-values.mjs": 2599, - "inferred-class-default.mjs": 2738, - "inferred-compound-values.mjs": 3388, - "inferred-conditional-class.mjs": 2376, - "inferred-error-fields.js": 2452, - "inferred-map-patterns.mjs": 3504, - "inferred-method-override.js": 2889, - "inferred-partial-destructuring.mjs": 3489, - "inferred-primitive-properties.mjs": 2842, - "inferred-record-return.mjs": 3292, - "inferred-recursive-record.mjs": 3932, - "inferred-undefined-field.mjs": 2401, - "input-lifetime-intervals.ts": 3651, - "input-lifetimes-modules/main.ts": 3648, - "instanceof-class-record-union.ts": 3935, - "integer-flow-arithmetic.ts": 3336, - "integer-loop-forms.ts": 3549, - "integer-view-control.ts": 2594, - "integer-view-numbers.ts": 3585, - "integer-view-storage.ts": 3667, - "intl-grapheme-conformance/main.ts": 4680, - "intl-grapheme.ts": 4135, - "iterator-typed-returns.ts": 4766, - "js-abort-portable.js": 3961, - "js-array-constructor.js": 3335, - "js-array-default-buffer.js": 2734, - "js-array-iterators.js": 3671, - "js-arrow-bind.cjs": 5214, - "js-buffer-callback-brand.cjs": 4283, + "global-error-subclasses.ts": 2754, + "global-runtime-probes.js": 2804, + "global-stored-probes.js": 3113, + "global-string-cache/main.js": 2090, + "global-symbol-cache/main.js": 3628, + "guarded-native-iterables.ts": 3327, + "heap-input-aliases.ts": 3457, + "heap-input-collections.ts": 3653, + "in-array-runtime-index.ts": 3275, + "indexed-assignment-values.js": 3011, + "indexed-assignment-values.ts": 2182, + "indexed-element-field-reads.ts": 3247, + "inferred-array-assignment-values.mjs": 2906, + "inferred-class-default.mjs": 2977, + "inferred-compound-values.mjs": 2759, + "inferred-conditional-class.mjs": 3292, + "inferred-error-fields.js": 3405, + "inferred-map-patterns.mjs": 2764, + "inferred-method-override.js": 2696, + "inferred-partial-destructuring.mjs": 2539, + "inferred-primitive-properties.mjs": 2255, + "inferred-record-return.mjs": 2589, + "inferred-recursive-record.mjs": 2186, + "inferred-undefined-field.mjs": 2551, + "input-lifetime-intervals.ts": 3191, + "input-lifetimes-modules/main.ts": 3221, + "instanceof-class-record-union.ts": 3279, + "integer-flow-arithmetic.ts": 3347, + "integer-loop-forms.ts": 2940, + "integer-view-control.ts": 2093, + "integer-view-numbers.ts": 2680, + "integer-view-storage.ts": 3947, + "intl-grapheme-conformance/main.ts": 5064, + "intl-grapheme.ts": 2412, + "iterator-typed-returns.ts": 3466, + "js-abort-portable.js": 4587, + "js-array-constructor.js": 3296, + "js-array-default-buffer.js": 3604, + "js-array-iterators.js": 3215, + "js-arrow-bind.cjs": 3596, + "js-buffer-callback-brand.cjs": 3526, "js-builder-string-method-names/main.ts": 5400, "js-callable-builder.js": 10100, - "js-callable-proxy.js": 3329, - "js-chained-native-results.mjs": 3307, - "js-checked-array-iterator.js": 3738, - "js-checked-array-reference.js": 3849, - "js-checked-number-negation.mjs": 3465, - "js-checked-sort-result.js": 2437, - "js-child-error-listener.cjs": 2606, - "js-cjs-callable-snapshots/main.cjs": 3122, - "js-class-added-parameters.js": 3654, - "js-class-checked-overrides.js": 3726, - "js-class-computed-fields.js": 3260, + "js-callable-proxy.js": 3865, + "js-chained-native-results.mjs": 3076, + "js-checked-array-iterator.js": 2790, + "js-checked-array-reference.js": 2884, + "js-checked-number-negation.mjs": 2418, + "js-checked-sort-result.js": 2906, + "js-child-error-listener.cjs": 2538, + "js-cjs-callable-snapshots/main.cjs": 2461, + "js-class-added-parameters.js": 2522, + "js-class-checked-overrides.js": 2542, + "js-class-computed-fields.js": 2281, "js-class-constructor-returns/main.ts": 5400, - "js-class-enumeration.js": 4284, - "js-class-field-accessor-override.js": 3902, - "js-class-fluent-overrides.js": 3667, - "js-class-late-method-values.js": 3068, - "js-class-member-dispatch.js": 4117, - "js-class-return-shapes.js": 3935, - "js-class-shadowed-methods.js": 4040, - "js-class-stored-method-receiver.js": 2904, - "js-class-subclass-properties.js": 5036, - "js-class-symbol-spread.cjs": 3637, - "js-computed-prototype-additions.js": 2620, - "js-constructor-returned-callable.js": 2532, - "js-constructor-spread.js": 3024, - "js-dataview-dispatch.js": 3608, - "js-declared-fields.cjs": 5015, - "js-default-listener-arguments.cjs": 2326, - "js-default-options/main.ts": 3910, - "js-deferred-field-initializers.js": 2418, - "js-deferred-registry-effects.js": 3462, - "js-derived-constructor-hoisting.js": 2798, - "js-dormant-array-write.js": 3572, - "js-dormant-overrides.js": 2747, - "js-expando-records.js": 3967, + "js-class-enumeration.js": 3084, + "js-class-field-accessor-override.js": 3865, + "js-class-fluent-overrides.js": 3368, + "js-class-late-method-values.js": 2526, + "js-class-member-dispatch.js": 3846, + "js-class-return-shapes.js": 2639, + "js-class-shadowed-methods.js": 2891, + "js-class-stored-method-receiver.js": 2685, + "js-class-subclass-properties.js": 3775, + "js-class-symbol-spread.cjs": 3550, + "js-computed-prototype-additions.js": 3462, + "js-constructor-returned-callable.js": 3346, + "js-constructor-spread.js": 3311, + "js-dataview-dispatch.js": 2423, + "js-declared-fields.cjs": 3098, + "js-default-listener-arguments.cjs": 2941, + "js-default-options/main.ts": 3442, + "js-deferred-field-initializers.js": 2409, + "js-deferred-registry-effects.js": 2980, + "js-derived-constructor-hoisting.js": 2695, + "js-dormant-array-write.js": 2014, + "js-dormant-overrides.js": 3783, + "js-expando-records.js": 2526, "js-function-prototype-value.js": 5100, - "js-implicit-call-results.js": 2920, - "js-inferred-callback-exports/main.js": 4360, - "js-inferred-class-array-return.js": 3664, - "js-inferred-object-values.js": 3561, - "js-inherited-field-storage.js": 2906, - "js-inherited-parameter-abi.js": 2442, - "js-iterable-spread.js": 2766, - "js-loose-dynamic-primitives.js": 3050, - "js-map-object-seeds.js": 3816, - "js-member-increment.js": 4372, - "js-module-function-values.js": 3724, - "js-mutable-null-members.js": 3894, - "js-nested-native-descriptors.js": 3332, - "js-normalize-dispatch.js": 3662, - "js-nullish-inherited-fields.mjs": 3226, + "js-implicit-call-results.js": 2892, + "js-inferred-callback-exports/main.js": 3776, + "js-inferred-class-array-return.js": 3477, + "js-inferred-object-values.js": 3358, + "js-inherited-field-storage.js": 3527, + "js-inherited-parameter-abi.js": 3324, + "js-iterable-spread.js": 3504, + "js-loose-dynamic-primitives.js": 2079, + "js-map-object-seeds.js": 3322, + "js-member-increment.js": 4257, + "js-module-function-values.js": 3135, + "js-mutable-null-members.js": 2750, + "js-nested-native-descriptors.js": 2725, + "js-normalize-dispatch.js": 3264, + "js-nullish-inherited-fields.mjs": 3080, "js-number-parse-dynamic.js": 4350, - "js-object-receiver-storage.js": 3635, - "js-object-returning-constructors.mjs": 3324, - "js-object-shared-arrays.js": 3926, - "js-omitted-typed-arguments.js": 3274, - "js-open-binding-writes.js": 3161, - "js-optional-class-fields.js": 3414, - "js-optional-member-call.js": 3623, - "js-primitive-union-addition.js": 3186, + "js-object-receiver-storage.js": 3515, + "js-object-returning-constructors.mjs": 3015, + "js-object-shared-arrays.js": 2539, + "js-omitted-typed-arguments.js": 2295, + "js-open-binding-writes.js": 1944, + "js-optional-class-fields.js": 3252, + "js-optional-member-call.js": 3095, + "js-primitive-union-addition.js": 2779, "js-process-destructure.mjs": 4600, - "js-promise-all-values.js": 3364, - "js-promise-catch-handler.js": 2469, - "js-promise-finally-order.js": 3631, - "js-promise-pending-reactions.js": 3621, - "js-prototype-host-boundary.js": 40863, - "js-reflect-receivers.js": 3717, - "js-regex-record-captures.js": 4129, + "js-promise-all-values.js": 3443, + "js-promise-catch-handler.js": 2034, + "js-promise-finally-order.js": 2084, + "js-promise-pending-reactions.js": 3602, + "js-prototype-host-boundary.js": 4779, + "js-reflect-receivers.js": 3486, + "js-regex-record-captures.js": 2214, "js-reshaped-object-literal.js": 7750, - "js-scalar-iterables.js": 3831, - "js-shared-method-dispatch.js": 3185, - "js-specialized-field-method.js": 2772, - "js-static-accessors.js": 3403, - "js-static-method-values.js": 3866, - "js-static-registries.cjs": 3795, - "js-super-accessor-initialization.js": 3887, - "js-uninitialized-native-fields.js": 3361, - "json-guarded-map-values.ts": 3542, - "json-output-bulk.ts": 3334, - "json-runtime-options.mjs": 2995, - "json-stringify-value.js": 3147, - "json-typed-parse-direct.ts": 3768, + "js-scalar-iterables.js": 3719, + "js-shared-method-dispatch.js": 2114, + "js-specialized-field-method.js": 3011, + "js-static-accessors.js": 3435, + "js-static-method-values.js": 3174, + "js-static-registries.cjs": 3047, + "js-super-accessor-initialization.js": 2998, + "js-uninitialized-native-fields.js": 2354, + "json-guarded-map-values.ts": 2502, + "json-output-bulk.ts": 3214, + "json-runtime-options.mjs": 2794, + "json-stringify-value.js": 2833, + "json-typed-parse-direct.ts": 3580, "json-typed-parse-index-signatures.ts": 3707, "json-typed-parse-optional-members.ts": 4645, "json-typed-parse-union-members.ts": 2884, - "literal-switch-dispatch.ts": 3317, - "live-reference-shared-converters.ts": 9504, - "llvm-read-receiver-lifetime.ts": 4439, - "local-class-call-spreads.js": 3630, - "local-class-declaration.ts": 3068, - "local-class-evaluation.ts": 3450, - "local-class-inheritance.ts": 3339, - "local-class-lifetimes.ts": 3623, - "local-class-namespace/main.js": 3916, - "local-class-prototype-data.js": 3797, - "local-class-specialization.js": 3033, - "local-class-unknown.ts": 2900, - "local-class-values.ts": 2584, - "local-union-storage.ts": 3820, - "locale-compare-root-order.ts": 3234, - "logical-assignment-dynamic.js": 3066, - "logical-assignment-values.ts": 3751, - "logical-runtime-optional-record.ts": 3473, - "loop-reference-lifetimes.ts": 2819, - "map-checked-boundary/main.ts": 3663, - "map-checked-seed.js": 3370, + "literal-switch-dispatch.ts": 2951, + "live-reference-shared-converters.ts": 19276, + "llvm-read-receiver-lifetime.ts": 3803, + "local-class-call-spreads.js": 3495, + "local-class-declaration.ts": 2661, + "local-class-evaluation.ts": 3104, + "local-class-inheritance.ts": 2552, + "local-class-lifetimes.ts": 3344, + "local-class-namespace/main.js": 3630, + "local-class-prototype-data.js": 3990, + "local-class-specialization.js": 2812, + "local-class-unknown.ts": 3002, + "local-class-values.ts": 2009, + "local-union-storage.ts": 3026, + "locale-compare-root-order.ts": 3444, + "logical-assignment-dynamic.js": 3230, + "logical-assignment-values.ts": 3566, + "logical-runtime-optional-record.ts": 3322, + "loop-reference-lifetimes.ts": 3339, + "map-checked-boundary/main.ts": 2843, + "map-checked-seed.js": 2966, "map-get-set-fusion.ts": 3638, - "map-number-keys-dense.ts": 4412, - "map-read-lifetimes-exits.ts": 2579, - "map-read-lifetimes.ts": 3849, - "map-seeds-and-spreads.ts": 3171, - "map-typed-array-values.ts": 3666, - "math-function-values.js": 2486, - "missing-read-lambda-results.ts": 3345, - "missing-read-narrowed-storage.ts": 3729, - "missing-read-number-conversions.ts": 3696, - "module-byte-loops.ts": 3029, - "module-fallback-functions/main.js": 3321, - "narrowed-nullish-values.ts": 3184, - "native-any-timer-callback.ts": 2884, - "native-array-borrowed-find-last.js": 3352, - "native-array-borrowed-slice.js": 3286, - "native-array-copying-methods.js": 2464, - "native-array-fill-copywithin.js": 2771, - "native-array-frozen-noops.js": 3256, - "native-array-index-boundaries.js": 2917, - "native-array-integrity.js": 2583, - "native-array-length.js": 2372, - "native-array-named-properties.js": 3684, - "native-array-prototype/main.js": 3743, - "native-array-read-lifetimes.ts": 3932, - "native-array-reduce-find-last.js": 2450, - "native-array-search-from-index.js": 2847, - "native-array-splice-coercion.js": 3405, - "native-array-splice-flat.js": 3104, - "native-buffer-coercion.js": 3322, - "native-callback-dispatch.ts": 3832, - "native-class-array-boundaries.ts": 3342, - "native-class-cache.js": 3840, - "native-class-properties.cjs": 5572, - "native-class-property-cycles.cjs": 3155, - "native-class-property-order.cjs": 3170, - "native-class-type-predicates.ts": 3052, - "native-factory-records.js": 3387, - "native-method-values.js": 4924, - "native-method-values.ts": 3868, - "native-npm-imports/main.ts": 3901, - "native-object-descriptors.js": 3247, - "native-object-for-in-minimal.js": 3446, - "native-object-property-attributes.js": 3224, - "native-object-prototype.js": 2952, - "native-property-names.ts": 2920, - "native-proxy-env.js": 4531, - "native-worker-arena-reuse.ts": 9740, - "native-worker-bounded-errors.ts": 3428, - "native-worker-buffer-consumers.ts": 4341, - "native-worker-cancel-hot.ts": 3046, - "native-worker-class-fields.ts": 3987, - "native-worker-clone-errors.ts": 3205, - "native-worker-commonjs.cjs": 3563, - "native-worker-delayed-messages.ts": 3820, - "native-worker-discarded-heaps.ts": 9491, - "native-worker-environment.ts": 3678, - "native-worker-error.ts": 3443, - "native-worker-exception-state.ts": 3795, - "native-worker-exit-listeners.ts": 3786, - "native-worker-io.ts": 3497, - "native-worker-loop-cancellation.ts": 3485, - "native-worker-message-graphs.ts": 3324, - "native-worker-messages.ts": 3248, - "native-worker-poll-exceptions.ts": 3463, - "native-worker-port-lifetime.ts": 3679, - "native-worker-process-exit.ts": 25459, - "native-worker-publish-classes.ts": 39360, - "native-worker-publish-refusals.ts": 3725, - "native-worker-published-graphs.ts": 3934, - "native-worker-references.ts": 4072, - "native-worker-roots/main.ts": 3317, - "native-worker-shared-views.ts": 34203, - "native-worker-stack-overflow.ts": 3534, - "native-worker-terminate-exception-state.ts": 4664, - "native-worker-terminate-loop.ts": 3303, - "native-worker-terminate-recursion.ts": 4325, - "native-worker-terminate-suspended.ts": 3580, - "native-worker-terminate-tested-loops.ts": 3001, - "native-worker-terminate-wait.ts": 3399, - "native-worker-typed-arrays.ts": 3056, - "nested-map-cycles.ts": 2892, - "nested-map-values.ts": 4020, - "never-returning-calls.ts": 3353, - "next-tick-commonjs-entry.cjs": 3537, - "node24-buffer-encoding-errors.ts": 3190, - "node24-buffer-encoding.ts": 3056, - "node24-crypto-kdf-errors.ts": 3983, - "node24-crypto-kdf-options.ts": 3444, - "node24-crypto-kdf.ts": 3815, - "node24-crypto-sha2.ts": 3261, - "node24-deep-equality-properties.js": 3213, - "node24-deep-equality.cjs": 4348, - "node24-deep-equality.ts": 4931, - "node24-env-files-errors.ts": 3190, - "node24-env-files.ts": 3237, - "node24-env-imports.cjs": 2806, - "node24-env-parse-errors.ts": 3175, - "node24-env-parse.ts": 2442, - "node24-esm-metadata/main.mjs": 3178, - "node24-file-url-buffer.ts": 2578, - "node24-file-url-errors.js": 3662, - "node24-file-url-options.ts": 3335, - "node24-fs-links-callbacks.cjs": 2914, - "node24-fs-links-errors.cjs": 2718, - "node24-fs-links-options.cjs": 5212, - "node24-fs-links-promise-errors.cjs": 3623, - "node24-fs-links-promises.ts": 3653, - "node24-fs-links.ts": 2754, - "node24-fs-statfs-callbacks.cjs": 3304, - "node24-fs-statfs-errors.cjs": 3642, - "node24-fs-statfs-options.cjs": 3933, - "node24-fs-statfs.ts": 3769, - "node24-fs-timestamps-callbacks.cjs": 3563, - "node24-fs-timestamps-errors.cjs": 3595, - "node24-fs-timestamps-promises.ts": 4047, - "node24-fs-timestamps-symlinks.ts": 2514, - "node24-fs-timestamps.ts": 3364, - "node24-no-error-assertions-coercion.js": 3593, - "node24-no-error-assertions.cjs": 2425, - "node24-no-error-assertions.ts": 4527, - "node24-parseargs.js": 5067, - "node24-string-decoder.ts": 2945, - "node24-style-text-environment.js": 3145, - "node24-style-text-validation.js": 4525, - "node24-style-text.cjs": 3538, - "node24-style-text.ts": 3894, - "node24-system-error-validation.js": 3199, - "node24-system-errors.cjs": 2805, - "node24-system-errors.ts": 3782, - "node24-text-codec-properties.ts": 3181, - "node24-text-encode-into.ts": 2752, - "node24-text-utilities-coercion.js": 2713, - "node24-text-utilities-validation.js": 3711, - "node24-text-utilities.cjs": 3142, - "node24-text-utilities.ts": 3686, - "node24-url-authority-coercion.js": 3699, - "node24-url-authority.ts": 3174, - "node24-url-factories.ts": 3606, - "node24-url-factory-errors.ts": 3314, - "node24-url-mutation-coercion.js": 3050, - "node24-url-mutation.ts": 2529, - "node24-util-types.cjs": 2859, - "node24-util-types.js": 3337, - "node24-util-types.ts": 3883, - "non-null-class-iteration.ts": 3145, - "nonnull-element-arguments.ts": 2747, - "nonnull-forwarded-class-values.ts": 3637, - "nullable-object-extension.mjs": 3028, - "nullish-asserted-class-arms.ts": 2996, - "nullish-assignment-values.ts": 3685, - "nullish-long-chain.ts": 4539, - "number-parse-statics.ts": 2378, - "number-predicates-unknown.ts": 3263, - "numeric-call-specialization.ts": 3397, - "object-enumeration-array-reads.ts": 3721, - "object-from-checked-entries.js": 4400, - "object-inherited-to-string.js": 3338, - "object-key-indexes.js": 4004, - "object-prototype-identity.mjs": 3277, - "object-reexport/main.js": 3532, - "object-spread-computed.ts": 3618, - "opentui-byte-queue.js": 2761, - "optional-callback-arity.ts": 2368, - "optional-class-flows.ts": 2553, - "optional-element-defaults.ts": 3275, - "optional-flag-comparisons.ts": 3105, - "optional-native-callables.js": 3200, - "optional-node-list-iteration.ts": 3422, - "optional-string-index/main.ts": 2937, - "path-to-file-url-options.ts": 3680, - "performance-presence.ts": 3328, - "primitive-and-function-descriptors.js": 3559, - "primitive-union-string.ts": 3162, - "process-builtin-values.js": 4636, - "process-constrained-memory.ts": 2246, - "process-env-computed-keys.js": 3276, - "process-hrtime.js": 3203, - "process-named-signals.cjs": 3440, - "process-uncaught-handler-throws.cjs": 2812, - "process-uncaught-loop.cjs": 2427, - "process-uncaught-module.mjs": 2982, - "process-uncaught-monitor.cjs": 3049, - "process-uncaught-rejection.cjs": 2978, - "process-uncaught-sync.cjs": 2919, - "process-version-pin.ts": 3275, - "process-versions-storage.ts": 3558, - "projected-collection-lifetimes.ts": 3501, - "promise-checked-rejections.ts": 2387, - "promise-resolve-void.ts": 2676, - "prototype-method-overrides.mjs": 7058, - "prototype-named-data-records.ts": 3518, + "map-number-keys-dense.ts": 2773, + "map-read-lifetimes-exits.ts": 2761, + "map-read-lifetimes.ts": 3024, + "map-seeds-and-spreads.ts": 3502, + "map-typed-array-values.ts": 3300, + "math-function-values.js": 2815, + "missing-read-lambda-results.ts": 3370, + "missing-read-narrowed-storage.ts": 2854, + "missing-read-number-conversions.ts": 2326, + "module-byte-loops.ts": 2961, + "module-fallback-functions/main.js": 2737, + "narrowed-nullish-values.ts": 3160, + "native-any-timer-callback.ts": 2388, + "native-array-borrowed-find-last.js": 2571, + "native-array-borrowed-slice.js": 3010, + "native-array-copying-methods.js": 3608, + "native-array-fill-copywithin.js": 2996, + "native-array-frozen-noops.js": 3132, + "native-array-index-boundaries.js": 2225, + "native-array-integrity.js": 3091, + "native-array-length.js": 2365, + "native-array-named-properties.js": 2772, + "native-array-prototype/main.js": 3257, + "native-array-read-lifetimes.ts": 3805, + "native-array-reduce-find-last.js": 2524, + "native-array-search-from-index.js": 2027, + "native-array-splice-coercion.js": 2902, + "native-array-splice-flat.js": 2702, + "native-buffer-coercion.js": 2533, + "native-callback-dispatch.ts": 3850, + "native-class-array-boundaries.ts": 3272, + "native-class-cache.js": 3290, + "native-class-properties.cjs": 4583, + "native-class-property-cycles.cjs": 2888, + "native-class-property-order.cjs": 2105, + "native-class-type-predicates.ts": 2960, + "native-factory-records.js": 3080, + "native-method-values.js": 3222, + "native-method-values.ts": 2808, + "native-npm-imports/main.ts": 2750, + "native-object-descriptors.js": 2979, + "native-object-for-in-minimal.js": 2411, + "native-object-property-attributes.js": 3057, + "native-object-prototype.js": 3409, + "native-property-names.ts": 2077, + "native-proxy-env.js": 4372, + "native-worker-arena-reuse.ts": 33854, + "native-worker-bounded-errors.ts": 2556, + "native-worker-buffer-consumers.ts": 38253, + "native-worker-cancel-hot.ts": 28908, + "native-worker-class-fields.ts": 3286, + "native-worker-clone-errors.ts": 3629, + "native-worker-commonjs.cjs": 3085, + "native-worker-delayed-messages.ts": 28752, + "native-worker-discarded-heaps.ts": 39440, + "native-worker-environment.ts": 27133, + "native-worker-error.ts": 2958, + "native-worker-exception-state.ts": 3945, + "native-worker-exit-listeners.ts": 4052, + "native-worker-io.ts": 3361, + "native-worker-loop-cancellation.ts": 2798, + "native-worker-message-graphs.ts": 2738, + "native-worker-messages.ts": 3079, + "native-worker-poll-exceptions.ts": 2575, + "native-worker-port-lifetime.ts": 3213, + "native-worker-process-exit.ts": 4104, + "native-worker-publish-classes.ts": 24713, + "native-worker-publish-refusals.ts": 2820, + "native-worker-published-graphs.ts": 3534, + "native-worker-references.ts": 3358, + "native-worker-roots/main.ts": 2808, + "native-worker-shared-views.ts": 3012, + "native-worker-stack-overflow.ts": 2597, + "native-worker-terminate-exception-state.ts": 3340, + "native-worker-terminate-loop.ts": 2222, + "native-worker-terminate-recursion.ts": 2829, + "native-worker-terminate-suspended.ts": 4348, + "native-worker-terminate-tested-loops.ts": 3576, + "native-worker-terminate-wait.ts": 3222, + "native-worker-typed-arrays.ts": 2653, + "nested-map-cycles.ts": 3041, + "nested-map-values.ts": 2382, + "never-returning-calls.ts": 2642, + "next-tick-commonjs-entry.cjs": 2624, + "node24-buffer-encoding-errors.ts": 2695, + "node24-buffer-encoding.ts": 3038, + "node24-crypto-kdf-errors.ts": 2745, + "node24-crypto-kdf-options.ts": 2029, + "node24-crypto-kdf.ts": 3632, + "node24-crypto-sha2.ts": 2849, + "node24-deep-equality-properties.js": 3355, + "node24-deep-equality.cjs": 2682, + "node24-deep-equality.ts": 4058, + "node24-env-files-errors.ts": 3202, + "node24-env-files.ts": 3044, + "node24-env-imports.cjs": 2529, + "node24-env-parse-errors.ts": 2062, + "node24-env-parse.ts": 3684, + "node24-esm-metadata/main.mjs": 2492, + "node24-file-url-buffer.ts": 2158, + "node24-file-url-errors.js": 3331, + "node24-file-url-options.ts": 2772, + "node24-fs-links-callbacks.cjs": 3549, + "node24-fs-links-errors.cjs": 2633, + "node24-fs-links-options.cjs": 3571, + "node24-fs-links-promise-errors.cjs": 2445, + "node24-fs-links-promises.ts": 2105, + "node24-fs-links.ts": 2967, + "node24-fs-statfs-callbacks.cjs": 3035, + "node24-fs-statfs-errors.cjs": 2969, + "node24-fs-statfs-options.cjs": 3557, + "node24-fs-statfs.ts": 3067, + "node24-fs-timestamps-callbacks.cjs": 3095, + "node24-fs-timestamps-errors.cjs": 3110, + "node24-fs-timestamps-promises.ts": 3573, + "node24-fs-timestamps-symlinks.ts": 3390, + "node24-fs-timestamps.ts": 3032, + "node24-no-error-assertions-coercion.js": 2850, + "node24-no-error-assertions.cjs": 2814, + "node24-no-error-assertions.ts": 4358, + "node24-parseargs.js": 5971, + "node24-string-decoder.ts": 3185, + "node24-style-text-environment.js": 4225, + "node24-style-text-validation.js": 3673, + "node24-style-text.cjs": 3476, + "node24-style-text.ts": 3037, + "node24-system-error-validation.js": 3005, + "node24-system-errors.cjs": 3631, + "node24-system-errors.ts": 2849, + "node24-text-codec-properties.ts": 30185, + "node24-text-encode-into.ts": 3601, + "node24-text-utilities-coercion.js": 3094, + "node24-text-utilities-validation.js": 2330, + "node24-text-utilities.cjs": 2768, + "node24-text-utilities.ts": 3312, + "node24-url-authority-coercion.js": 3307, + "node24-url-authority.ts": 2639, + "node24-url-factories.ts": 3240, + "node24-url-factory-errors.ts": 2819, + "node24-url-mutation-coercion.js": 2399, + "node24-url-mutation.ts": 3257, + "node24-util-types.cjs": 3263, + "node24-util-types.js": 2199, + "node24-util-types.ts": 3506, + "non-null-class-iteration.ts": 3295, + "nonnull-element-arguments.ts": 2857, + "nonnull-forwarded-class-values.ts": 3303, + "nullable-object-extension.mjs": 2652, + "nullish-asserted-class-arms.ts": 2669, + "nullish-assignment-values.ts": 2125, + "nullish-long-chain.ts": 2641, + "number-parse-statics.ts": 2471, + "number-predicates-unknown.ts": 2568, + "numeric-call-specialization.ts": 2498, + "object-enumeration-array-reads.ts": 2246, + "object-from-checked-entries.js": 3478, + "object-inherited-to-string.js": 2987, + "object-key-indexes.js": 3206, + "object-prototype-identity.mjs": 3083, + "object-reexport/main.js": 2466, + "object-spread-computed.ts": 2806, + "opentui-byte-queue.js": 3532, + "optional-callback-arity.ts": 2417, + "optional-class-flows.ts": 2497, + "optional-element-defaults.ts": 2632, + "optional-flag-comparisons.ts": 2536, + "optional-native-callables.js": 2751, + "optional-node-list-iteration.ts": 2564, + "optional-string-index/main.ts": 3419, + "path-to-file-url-options.ts": 2301, + "performance-presence.ts": 2913, + "primitive-and-function-descriptors.js": 3070, + "primitive-union-string.ts": 3434, + "process-builtin-values.js": 2781, + "process-constrained-memory.ts": 2857, + "process-env-computed-keys.js": 3185, + "process-hrtime.js": 2662, + "process-named-signals.cjs": 3171, + "process-uncaught-handler-throws.cjs": 2344, + "process-uncaught-loop.cjs": 3141, + "process-uncaught-module.mjs": 2646, + "process-uncaught-monitor.cjs": 2837, + "process-uncaught-rejection.cjs": 2664, + "process-uncaught-sync.cjs": 2858, + "process-version-pin.ts": 3005, + "process-versions-storage.ts": 2055, + "projected-collection-lifetimes.ts": 3232, + "promise-checked-rejections.ts": 2914, + "promise-resolve-void.ts": 2846, + "prototype-method-overrides.mjs": 4119, + "prototype-named-data-records.ts": 3179, "rc-last-use-moves.ts": 4127, "rc-private-array-writes.ts": 4075, - "record-field-presence.ts": 4445, - "record-key-order.ts": 2786, - "record-optional-json-presence.ts": 3499, - "record-presence-copies.ts": 4175, - "record-presence-delete-json.ts": 2958, - "record-unchecked-read-presence.ts": 3597, - "record-unknown-values.ts": 4381, - "reflect-own-keys.mjs": 2660, - "reflect-record-union-keys.mjs": 2359, - "reflect-typed-record-keys.ts": 2855, - "regex-callback-replacements.ts": 3541, - "regex-callback-values.js": 3624, - "regex-checked-casts.ts": 3867, - "regex-checked-storage.js": 3704, - "regex-exec-long-subject.ts": 8130, + "record-field-presence.ts": 3698, + "record-key-order.ts": 2706, + "record-optional-json-presence.ts": 3216, + "record-presence-copies.ts": 3381, + "record-presence-delete-json.ts": 3160, + "record-unchecked-read-presence.ts": 2953, + "record-unknown-values.ts": 4095, + "reflect-own-keys.mjs": 2705, + "reflect-record-union-keys.mjs": 2815, + "reflect-typed-record-keys.ts": 2683, + "regex-callback-replacements.ts": 2631, + "regex-callback-values.js": 3741, + "regex-checked-casts.ts": 2405, + "regex-checked-storage.js": 3560, + "regex-exec-long-subject.ts": 5584, "regex-exec-result-arrays.ts": 4036, "regex-fs-text-surfaces.ts": 4013, - "regex-input-lifetimes.ts": 2860, - "regex-native-matcher.ts": 4866, - "regex-optional-captures.ts": 3208, - "regex-optional-templates.ts": 3554, - "regex-split-captures.ts": 3707, - "regex-text-paths.ts": 2943, - "regexp-constructor-repeat.ts": 3471, - "regexp-optional-constructor.ts": 3547, - "regexp-string-coercion.js": 2902, - "renderer-export-dictionaries.js": 2853, - "renderer-null-state.js": 3392, - "renderer-specializations.js": 3361, - "repeat-and-typed-read-errors.ts": 3813, - "rest-optional-array-arguments.ts": 4116, - "rest-optional-elements.ts": 3072, - "return-void-through-finally.ts": 2672, - "runtime-optional-string-flows.ts": 3420, - "scalar-string-slices.ts": 3228, - "set-checked-methods.js": 3654, - "set-checked-storage.ts": 3542, - "set-iterator-seed-references.ts": 3832, - "set-iterator-seeds.ts": 3864, - "set-optional-seeds.ts": 3189, - "small-collection-transitions.ts": 3703, + "regex-input-lifetimes.ts": 3241, + "regex-native-matcher.ts": 3652, + "regex-optional-captures.ts": 2740, + "regex-optional-templates.ts": 2802, + "regex-split-captures.ts": 3590, + "regex-text-paths.ts": 2840, + "regexp-constructor-repeat.ts": 2602, + "regexp-optional-constructor.ts": 2950, + "regexp-string-coercion.js": 2621, + "renderer-export-dictionaries.js": 3415, + "renderer-null-state.js": 2259, + "renderer-specializations.js": 2837, + "repeat-and-typed-read-errors.ts": 3220, + "rest-optional-array-arguments.ts": 2860, + "rest-optional-elements.ts": 2445, + "return-void-through-finally.ts": 2861, + "runtime-optional-string-flows.ts": 2977, + "scalar-string-slices.ts": 2840, + "set-checked-methods.js": 3072, + "set-checked-storage.ts": 2667, + "set-iterator-seed-references.ts": 3159, + "set-iterator-seeds.ts": 3269, + "set-optional-seeds.ts": 2164, + "small-collection-transitions.ts": 3586, "speculative-integer-globals.ts": 2999, "speculative-integer-loops.ts": 4097, "speculative-integer-reads.ts": 3960, - "stack-depth-async-bodies.ts": 3593, - "stack-overflow-async.ts": 3327, - "stack-overflow-caught.ts": 3619, - "stack-overflow-finally.ts": 4048, - "stack-overflow-shapes.ts": 4840, - "stack-overflow-uncaught.ts": 3019, + "stack-depth-async-bodies.ts": 2727, + "stack-overflow-async.ts": 2942, + "stack-overflow-caught.ts": 3056, + "stack-overflow-finally.ts": 3694, + "stack-overflow-shapes.ts": 3565, + "stack-overflow-uncaught.ts": 2532, "stackless-async-concurrency.ts": 5553, "stackless-async-context.ts": 3712, "stackless-async-exceptions.ts": 4059, "stackless-async-ordering.ts": 4230, "stackless-async-unhandled.ts": 3409, - "static-field-updates/main.ts": 3160, - "static-method-receivers.ts": 3269, - "stdio-values.mjs": 3241, - "stdio-write-errors.mjs": 3357, - "stdio-write-overrides.mjs": 3279, - "stored-native-builtins.js": 3593, - "stored-object-helpers.js": 3366, + "static-field-updates/main.ts": 2914, + "static-method-receivers.ts": 2350, + "stdio-values.mjs": 2761, + "stdio-write-errors.mjs": 2672, + "stdio-write-overrides.mjs": 3205, + "stored-native-builtins.js": 3341, + "stored-object-helpers.js": 2959, "stream-dynamic-entry-kinds.cjs": 8165, "stream-dynamic-entry-kinds.ts": 2619, "stream-encoded-from-entries.cjs": 4394, "stream-encoded-from-entries.ts": 4716, - "string-char-code-integer-loops.ts": 3604, - "string-code-points.ts": 2747, - "string-concat-number-parts.ts": 3145, - "string-construction-order.ts": 3430, + "string-char-code-integer-loops.ts": 2575, + "string-code-points.ts": 2460, + "string-concat-number-parts.ts": 2155, + "string-construction-order.ts": 3307, "string-field-append.ts": 3228, - "string-lifetimes-boundaries.ts": 3759, - "string-lifetimes-evaluation.ts": 3595, - "string-lifetimes-iteration.ts": 2950, - "string-lifetimes-operations.ts": 3231, - "string-normalize.ts": 3407, - "string-pattern-replacement.ts": 3745, - "string-scan-fast-paths.ts": 3455, - "string-split-checked-separator.mjs": 3539, - "string-split-traversal.ts": 4073, - "structural-class-properties.ts": 3685, - "structured-text-boundaries.js": 4089, - "structured-text-storage.ts": 3938, - "switch-integer-dispatch.ts": 3542, - "symbol-checked-boundary/main.ts": 3823, - "symbol-class-fields.ts": 3105, - "symbol-class-fields/main.cjs": 3306, - "symbol-class-methods/main.ts": 3168, - "symbol-fields-deferred-factory.ts": 2465, - "symbol-fields-inferred.js": 2781, - "symbol-object-properties/main.js": 2729, - "synchronous-callback-lifetimes.ts": 3805, - "terminal-stream-properties.ts": 2859, - "text-codec-values/main.ts": 24961, - "text-codec-var.ts": 35233, - "text-encode-into-boundaries.ts": 2835, - "timers-clear-many.ts": 3438, + "string-lifetimes-boundaries.ts": 3304, + "string-lifetimes-evaluation.ts": 2835, + "string-lifetimes-iteration.ts": 2037, + "string-lifetimes-operations.ts": 2789, + "string-normalize.ts": 2348, + "string-pattern-replacement.ts": 3823, + "string-scan-fast-paths.ts": 3224, + "string-split-checked-separator.mjs": 2349, + "string-split-traversal.ts": 3258, + "structural-class-properties.ts": 2627, + "structured-text-boundaries.js": 3452, + "structured-text-storage.ts": 3201, + "switch-integer-dispatch.ts": 2387, + "symbol-checked-boundary/main.ts": 2796, + "symbol-class-fields.ts": 2814, + "symbol-class-fields/main.cjs": 2659, + "symbol-class-methods/main.ts": 1948, + "symbol-fields-deferred-factory.ts": 2721, + "symbol-fields-inferred.js": 2792, + "symbol-object-properties/main.js": 3376, + "synchronous-callback-lifetimes.ts": 2872, + "terminal-stream-properties.ts": 2946, + "text-codec-values/main.ts": 18964, + "text-codec-var.ts": 3480, + "text-encode-into-boundaries.ts": 2224, + "timers-clear-many.ts": 3073, "truthy-object-logical.ts": 4450, - "tuple-and-string-search.ts": 3771, - "tuple-array-union.ts": 3450, - "tuple-callback-visitation.ts": 3975, - "tuple-forof-visitation.ts": 3491, - "typed-array-bulk-conversion.mjs": 5922, - "typed-array-byte-io.js": 9466, - "typed-array-checked-index.js": 3008, - "typed-array-constructor-alias.ts": 3321, - "typed-array-constructor-identity.js": 3143, - "typed-array-constructor-union.ts": 2529, - "typed-array-constructor-values.mjs": 3170, - "typed-array-dynamic-methods.js": 4053, - "typed-array-integer-widths.ts": 3519, - "typed-array-nan-coded-reads.ts": 3945, - "typed-array-numeric-import.ts": 4121, - "typed-array-present-reads.ts": 3332, - "typed-array-reversed-storage.ts": 2465, - "typed-array-unknown.ts": 3664, - "typed-collection-iterator-references.ts": 4059, - "typed-collection-iterators.ts": 4014, - "typed-collection-views/main.ts": 2915, - "typed-index-arguments.ts": 3055, - "typed-prototype-methods.ts": 3929, - "typed-rest-callables.ts": 2298, - "typed-rest-filtered-return.ts": 3531, - "typedarray-native-inputs.js": 3581, - "typeof-checked-comparison.js": 2656, - "uint8array-sort-domains.ts": 3223, - "unicode-case-paths.ts": 2409, - "unicode-process-argv.ts": 3053, - "union-discriminant-width.ts": 4248, - "union-literal-scalar-discriminants.ts": 4306, - "union-literal-slot-conversion.ts": 3424, - "union-nested-layout-discriminant.ts": 3343, - "union-optional-semantic-identity.ts": 4104, - "union-record-clone.ts": 3572, - "union-record-structural-copy.ts": 2990, - "union-reference-comparison.ts": 4026, - "unknown-array-holes.ts": 3098, - "unknown-collections.ts": 4172, - "unknown-object-enumeration.ts": 5046, - "unknown-record-views.ts": 2982, - "url-runtime-base.ts": 2879, - "utf8-span-decoding.ts": 37919, - "util-parseargs-wrapped/main.ts": 4014, - "virtual-runtime-optional-returns.ts": 4644, - "weak-map-array-buffer.ts": 3584, - "weak-map-fresh-array.js": 2803, - "weak-map-native.js": 3743, - "weak-native-class-identity.ts": 3008, - "weak-set-native.js": 2800, - "worker-class-instance-clone.ts": 39705 + "tuple-and-string-search.ts": 2595, + "tuple-array-union.ts": 3305, + "tuple-callback-visitation.ts": 3801, + "tuple-forof-visitation.ts": 3276, + "typed-array-bulk-conversion.mjs": 5346, + "typed-array-byte-io.js": 41314, + "typed-array-checked-index.js": 2607, + "typed-array-constructor-alias.ts": 2778, + "typed-array-constructor-identity.js": 2769, + "typed-array-constructor-union.ts": 2366, + "typed-array-constructor-values.mjs": 3448, + "typed-array-dynamic-methods.js": 3373, + "typed-array-integer-widths.ts": 3014, + "typed-array-nan-coded-reads.ts": 4239, + "typed-array-numeric-import.ts": 3499, + "typed-array-present-reads.ts": 3561, + "typed-array-reversed-storage.ts": 2954, + "typed-array-unknown.ts": 3453, + "typed-collection-iterator-references.ts": 3531, + "typed-collection-iterators.ts": 3385, + "typed-collection-views/main.ts": 2577, + "typed-index-arguments.ts": 3036, + "typed-prototype-methods.ts": 2475, + "typed-rest-callables.ts": 2463, + "typed-rest-filtered-return.ts": 2800, + "typedarray-native-inputs.js": 3164, + "typeof-checked-comparison.js": 2913, + "uint8array-sort-domains.ts": 2505, + "unicode-case-paths.ts": 2924, + "unicode-process-argv.ts": 2793, + "union-discriminant-width.ts": 3726, + "union-literal-scalar-discriminants.ts": 3704, + "union-literal-slot-conversion.ts": 2972, + "union-nested-layout-discriminant.ts": 2841, + "union-optional-semantic-identity.ts": 3100, + "union-record-clone.ts": 3480, + "union-record-structural-copy.ts": 3563, + "union-reference-comparison.ts": 3338, + "unknown-array-holes.ts": 2088, + "unknown-collections.ts": 3765, + "unknown-object-enumeration.ts": 4219, + "unknown-record-views.ts": 3040, + "url-runtime-base.ts": 2778, + "utf8-span-decoding.ts": 2655, + "util-parseargs-wrapped/main.ts": 2482, + "virtual-runtime-optional-returns.ts": 3876, + "weak-map-array-buffer.ts": 2826, + "weak-map-fresh-array.js": 2495, + "weak-map-native.js": 3627, + "weak-native-class-identity.ts": 2943, + "weak-set-native.js": 3056, + "worker-class-instance-clone.ts": 35222 } } From a08aada5f5eea6ac4049e39dfca7f1374210683d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 12:48:38 -0500 Subject: [PATCH 108/117] Name 5980-cycle-components.ts in its order baseline The program moved from 5973 with its baseline, but the baseline still recorded the old path as the module order. --- .../order-parity/tests/corpus/5980-cycle-components.ts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5980-cycle-components.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5980-cycle-components.ts.json index e97b429fa..cdbf47751 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5980-cycle-components.ts.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5980-cycle-components.ts.json @@ -1,6 +1,6 @@ { "order": [ - "/tests/corpus/5973-cycle-components.ts" + "/tests/corpus/5980-cycle-components.ts" ], "diags": [] } From f3b5696d5d5ed51279f5a25b697a51bf2f80d5ea Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 13:08:49 -0500 Subject: [PATCH 109/117] Stop repeating two frontend scans Class dynamic dispatch decides whether a class family keeps a fixed field layout from the property names a delete can remove. It cached that set with ??=, but the scan returns null when the program reflects on properties, so a program that does recomputed it, walking every source file, for each class in every dispatch wave. Only an undefined value now means the set has not been computed. npm-static re-export pruning read and parsed a package's package.json for every file whose purity it checked, and for every package boundary an import crossed. Each plan now parses each package.json once. Output is unchanged. three.js nodes lowering takes 6 s less and an Effect fixture's frontend load 4 s less. --- .../lowering/class-dynamic-dispatch.ts | 4 +- .../compiler/src/frontend/npm-static-prune.ts | 47 ++++++++++++++----- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index 444a9cf23..120032bf5 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -1159,7 +1159,9 @@ export class ClassDynamicDispatch { // Runtime-owned roots keep their dedicated property contracts. A // family whose fields all exist from construction and are never // deleted keeps a fixed layout, as TypeScript classes do. - this.deletedNames ??= deletedPropertyNames(lowerer.moduleOrder); + // null is a result too; undefined means not computed yet. + if (this.deletedNames === undefined) + this.deletedNames = deletedPropertyNames(lowerer.moduleOrder); if (!root.base?.def.runtime && !fixedFieldFamily(root, this.deletedNames)) track(root); } const loc = this.propertyBag.loc; diff --git a/packages/compiler/src/frontend/npm-static-prune.ts b/packages/compiler/src/frontend/npm-static-prune.ts index c6c1f9caf..a420b6b7c 100644 --- a/packages/compiler/src/frontend/npm-static-prune.ts +++ b/packages/compiler/src/frontend/npm-static-prune.ts @@ -15,7 +15,21 @@ export function isPrunedNpmReexport(program: ts.Program, stmt: ts.ExportDeclarat return program.analysis.prunedNpmReexports.has(stmt); } -function packageJson(path: string): Record | null { +type PackageJson = Record | null; + +/** Parsed package.json files by path, kept for one plan: every purity check + * reads the metadata of its file's package again. */ +type PackageJsonCache = Map; + +function packageJson(path: string, cache: PackageJsonCache): PackageJson { + const cached = cache.get(path); + if (cached !== undefined) return cached; + const json = readPackageJson(path); + cache.set(path, json); + return json; +} + +function readPackageJson(path: string): PackageJson { const source = trackedReadFile(path); if (source === null) return null; try { @@ -58,12 +72,16 @@ function sideEffectPattern(pattern: string): RegExp { /** A nested format scope such as dist/esm/package.json is not the package's * published metadata. Stay inside the resolved package while finding its * named root, including pnpm's realpath and workspace-linked installs. */ -function packageRootJsonPath(fromFile: string, packageName: string): string | null { +function packageRootJsonPath( + fromFile: string, + packageName: string, + cache: PackageJsonCache, +): string | null { let dir = dirname(resolve(fromFile)); let root: string | null = null; while (npmPackageNameOf(dir.replaceAll("\\", "/")) === packageName) { const path = join(dir, "package.json"); - if (packageJson(path)?.["name"] === packageName) root = path; + if (packageJson(path, cache)?.["name"] === packageName) root = path; const parent = dirname(dir); if (parent === dir) break; dir = parent; @@ -73,9 +91,13 @@ function packageRootJsonPath(fromFile: string, packageName: string): string | nu // An external package's executable sources may not be in this program. // Preserve the conservative whole-dependency promise in that case. -function pureExternalPackage(path: string, visiting = new Set()): boolean { +function pureExternalPackage( + path: string, + cache: PackageJsonCache, + visiting = new Set(), +): boolean { if (visiting.has(path)) return true; - const json = packageJson(path); + const json = packageJson(path, cache); const value = json?.["sideEffects"]; if (json === null || !(value === false || (Array.isArray(value) && value.length === 0))) return false; @@ -85,8 +107,8 @@ function pureExternalPackage(path: string, visiting = new Set()): boolea if (!dependencies || typeof dependencies !== "object" || Array.isArray(dependencies)) continue; for (const name of Object.keys(dependencies)) { const resolved = resolveBareModule(path, name, "js-only"); - const root = resolved === null ? null : packageRootJsonPath(resolved.typesFile, name); - if (root === null || !pureExternalPackage(root, visiting)) return false; + const root = resolved === null ? null : packageRootJsonPath(resolved.typesFile, name, cache); + if (root === null || !pureExternalPackage(root, cache, visiting)) return false; } } return true; @@ -135,10 +157,11 @@ export function planNpmStaticReexports( for (const path of extraRoots) request(program.getSourceFile(path) ?? null, null); const pureMemo = new Map(); + const packageJsons: PackageJsonCache = new Map(); const filePure = (sf: ts.SourceFile): boolean => { const pkg = npmPackageNameOf(sf.fileName) ?? npmStaticPackageOfPath(sf.fileName); - const path = pkg === null ? null : packageRootJsonPath(sf.fileName, pkg); - const json = path === null ? null : packageJson(path); + const path = pkg === null ? null : packageRootJsonPath(sf.fileName, pkg, packageJsons); + const json = path === null ? null : packageJson(path, packageJsons); const value = json?.["sideEffects"]; if (value === false) return true; if ( @@ -195,8 +218,10 @@ export function planNpmStaticReexports( const resolved = resolveBareModule(sf.fileName, edge.spec, "js-only"); const pkg = resolved === null ? null : npmPackageNameOf(resolved.typesFile); const root = - pkg === null || resolved === null ? null : packageRootJsonPath(resolved.typesFile, pkg); - return root !== null && pureExternalPackage(root); + pkg === null || resolved === null + ? null + : packageRootJsonPath(resolved.typesFile, pkg, packageJsons); + return root !== null && pureExternalPackage(root, packageJsons); }); }; const pure = visit(root); From 761252e173218ae53025ab5a1a3e4cc99f2bf489 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 13:20:51 -0500 Subject: [PATCH 110/117] Expect the run-time refusals of node24-file-url-conversion and stream-shims Both fixtures declare a function-local class whose base has no static lowering (`class FileURL extends URL {}`, `class Counter extends Readable`). The SC1090 for it used to come from the whole-program type queries, which collected the class outside any statement, so the build failed. Those queries now keep a refused local class out of their results and drop its diagnostics; the class declaration reports the refusal when it lowers, and in a JavaScript source a refused statement becomes a runtime fence. Both programs therefore compile and throw the fence when they reach a construct without a lowering, like the other fixtures listed with a run refusal. --- tests/harness/npm.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/harness/npm.test.ts b/tests/harness/npm.test.ts index a6cdee2b5..c4e70294e 100644 --- a/tests/harness/npm.test.ts +++ b/tests/harness/npm.test.ts @@ -73,7 +73,7 @@ const KNOWN: Record = { "node24-env": { run: "SC1090" }, "node24-esm-metadata": { run: "SC1090" }, "node24-event-emitter": { run: "SC2020" }, - "node24-file-url-conversion": { build: "SC1090" }, + "node24-file-url-conversion": { run: "SC2020" }, "node24-fs-descriptors": { run: "SC1090" }, "node24-mime": { run: "SC2020" }, "node24-mime-errors": { run: "SC1090" }, @@ -104,7 +104,7 @@ const KNOWN: Record = { "package-imports": { build: "SC2013" }, "promise-bridge": { build: "SC1090" }, "self-name": { build: "SC2013" }, - "stream-shims": { build: "SC1090" }, + "stream-shims": { run: "SC1090" }, "util-shims": { run: "SC2020" }, "web-streams": { build: "SC2013" }, "workspace-copied": { build: "SC2013" }, From fe7b1cd199d9a21f6b0765eeb7942cbabf449d76 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 13:33:41 -0500 Subject: [PATCH 111/117] Convert a Date to local time once for its local getters and follow TZ changes Each local-time getter (getFullYear, getMonth, getDate, getHours, ..., getTimezoneOffset) called localtime_r and walked the calendar for its own field. The thread now keeps its last local conversion, keyed by the instant and a timezone generation, so reading several local fields of one Date converts it once. The UTC walk and the second computation use integer division instead of floor. Writing or deleting process.env.TZ calls tzset and starts a new generation, so later local-time reads use the new zone, as in Node. Before, the zone the process started with stayed in effect. --- .../corpus/5683-date-local-fields-tz.ts.json | 6 ++ packages/runtime/src/scr_lib.c | 66 ++++++++++++- tests/corpus/5683-date-local-fields-tz.ts | 95 +++++++++++++++++++ tests/harness/corpus-costs.json | 2 + 4 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5683-date-local-fields-tz.ts.json create mode 100644 tests/corpus/5683-date-local-fields-tz.ts diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5683-date-local-fields-tz.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5683-date-local-fields-tz.ts.json new file mode 100644 index 000000000..7ac133650 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5683-date-local-fields-tz.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5683-date-local-fields-tz.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index 9307d9b01..fd51e9c78 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -824,6 +824,26 @@ static void scr_node_debug_capture(const ScrStr *name) { if (name->len == 10 && memcmp(name->data, "NODE_DEBUG", 10) == 0) (void)scr_node_debug_initial(); } +/* Counts writes and deletes of process.env.TZ. The local-time getters keep + * their last conversion for the generation it was made in. */ +#ifdef SCR_WORKERS +static atomic_uint scr_date_tz_generation; +#else +static unsigned scr_date_tz_generation; +#endif + +/* After a write or delete of the process's TZ, local time follows the new + * value, as in Node: tzset(3) rereads it for later localtime calls. */ +static void scr_env_tz_changed(const ScrStr *name) { + /* Compared by character: a string literal would join the merged + * read-only strings of every program that links this file. */ + if (name->len != 2 || name->data[0] != 'T' || name->data[1] != 'Z') return; +#if !defined(_WIN32) && !defined(__wasi__) + tzset(); +#endif + scr_date_tz_generation++; +} + /* process.env.NAME = v — setenv(3): later scr_env_get reads and spawned * children (posix_spawn inherits environ) observe the write, like Node. * Both args borrowed (NUL-terminated ScrStr data); setenv copies. */ @@ -842,6 +862,7 @@ void scr_env_set(const ScrStr *name, const ScrStr *value) { #else setenv(k, v, 1); #endif + scr_env_tz_changed(name); #ifdef SCR_WORKERS done: #endif @@ -861,6 +882,7 @@ void scr_env_unset(const ScrStr *name) { #else unsetenv(name->data); #endif + scr_env_tz_changed(name); } static ScrStr *scr_fs_read_file_core(ScrStr *path, bool env_file, size_t *ascii); @@ -10475,9 +10497,14 @@ typedef struct ScrDateParts { * endpoint. The checked wrapper is the public UTC-getter gate; the inner * walk accepts those bounded local-time values too. */ static void scr_date_utc_parts_unchecked(double t, ScrDateParts *out) { - double dayd = floor(t / 86400000.0); - long long msday = (long long)(t - dayd * 86400000.0); - long long z = (long long)dayd + 719468; + /* t is an integral number of milliseconds within about 2^53. */ + long long tms = (long long)t; + long long day = tms / 86400000, msday = tms % 86400000; + if (msday < 0) { + msday += 86400000; + day--; + } + long long z = day + 719468; long long era = (z >= 0 ? z : z - 146096) / 146097; unsigned long long doe = (unsigned long long)(z - era * 146097); unsigned long long yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; @@ -10487,7 +10514,7 @@ static void scr_date_utc_parts_unchecked(double t, ScrDateParts *out) { unsigned long long d = doy - (153 * mp + 2) / 5 + 1; unsigned long long m = mp < 10 ? mp + 3 : mp - 9; if (m <= 2) y++; - long long wday = ((long long)dayd + 4) % 7; + long long wday = (day + 4) % 7; if (wday < 0) wday += 7; out->year = y; out->month = (int)m - 1; @@ -10516,10 +10543,39 @@ static bool scr_date_localtime(double secd, struct tm *out) { #endif } +/* The thread's last local conversion: reading several local fields of one + * Date (getFullYear, getMonth, getDate, getHours, ...) converts it once. + * A change of process.env.TZ starts a new generation. */ +typedef struct { + bool valid; + unsigned generation; + double ms; + ScrDateParts parts; +} ScrDateLocalCache; +static SCR_TL ScrDateLocalCache scr_date_local_cache; + +static bool scr_date_local_parts_uncached(double clipped, ScrDateParts *out); + static bool scr_date_local_parts(double ms, ScrDateParts *out) { if (!isfinite(ms) || fabs(ms) > 8640000000000000.0) return false; double clipped = trunc(ms); - double secd = floor(clipped / 1000.0); + ScrDateLocalCache *c = &scr_date_local_cache; + unsigned generation = scr_date_tz_generation; + if (c->valid && c->ms == clipped && c->generation == generation) { + *out = c->parts; + return true; + } + if (!scr_date_local_parts_uncached(clipped, out)) return false; + c->valid = true; + c->generation = generation; + c->ms = clipped; + c->parts = *out; + return true; +} + +static bool scr_date_local_parts_uncached(double clipped, ScrDateParts *out) { + long long cms = (long long)clipped; + double secd = (double)(cms / 1000 - (cms % 1000 < 0)); struct tm tmv; double basis_secd = secd; if (!scr_date_localtime(basis_secd, &tmv)) { diff --git a/tests/corpus/5683-date-local-fields-tz.ts b/tests/corpus/5683-date-local-fields-tz.ts new file mode 100644 index 000000000..dc75011ed --- /dev/null +++ b/tests/corpus/5683-date-local-fields-tz.ts @@ -0,0 +1,95 @@ +// Local-time getters read repeatedly on one Date and alternately on two, +// on Dates parsed from strings, and across process.env.TZ writes and +// deletes: every read answers the fields of the zone in effect at that +// moment, as in Node. + +function fields(d: Date): string { + return [ + d.getFullYear(), + d.getMonth(), + d.getDate(), + d.getDay(), + d.getHours(), + d.getMinutes(), + d.getSeconds(), + d.getMilliseconds(), + d.getTimezoneOffset(), + ].join(","); +} + +const a = new Date(Date.UTC(2024, 2, 10, 6, 59, 59, 999)); +const b = new Date(Date.UTC(2024, 2, 10, 7, 0, 0, 0)); +const c = new Date(Date.UTC(2024, 10, 3, 5, 30, 0, 250)); + +function report(label: string): void { + console.log(label, fields(a), fields(a)); + console.log(label, fields(b), fields(c), fields(b)); + let mixed = 0; + for (let i = 0; i < 6; i++) mixed += a.getHours() * 100 + b.getHours() + c.getDate(); + console.log(label, "alternating", mixed); +} + +report("start"); +process.env.TZ = "America/New_York"; +report("new york"); +process.env.TZ = "Asia/Kolkata"; +report("kolkata"); +process.env.TZ = "Australia/Lord_Howe"; +report("lord howe"); + +// Dates parsed from strings with an explicit offset, read in local time. +const d = new Date("2024-06-01T23:45:00+05:30"); +console.log("offset string", fields(d), d.getTime()); +const e = new Date("2024-07-11T00:15:30.001Z"); +console.log("offset string", fields(e), e.getTime()); +console.log("first again", fields(d)); + +delete process.env.TZ; +report("deleted"); +process.env.TZ = "UTC"; +report("utc"); + +// Many instants read field by field. +process.env.TZ = "Europe/Berlin"; +let sum = 0; +for (let i = 0; i < 2000; i++) { + const t = new Date(1700000000000 + i * 3_599_999); + sum += t.getHours() + t.getDate() * 3 + t.getMonth() * 7 + t.getTimezoneOffset(); +} +console.log("berlin sum", sum); + +const invalid = new Date(Number.NaN); +console.log("invalid", fields(invalid), fields(invalid)); + +// Instants around day and second boundaries, before the epoch and at the +// ends of the Date range, in UTC and local fields; then 2000-2030 in a zone +// with DST. +function utcFields(d: Date): string { + return [ + d.getUTCFullYear(), + d.getUTCMonth(), + d.getUTCDate(), + d.getUTCDay(), + d.getUTCHours(), + d.getUTCMinutes(), + d.getUTCSeconds(), + d.getUTCMilliseconds(), + ].join(","); +} +const edges = [ + 0, -0, -0.5, 0.5, -1, 1, -999, -1000, -1001, 999.9, -86_400_000, -86_400_001, 86_399_999, + -62_198_755_200_000, -62_198_755_200_001, 8_640_000_000_000_000, -8_640_000_000_000_000, + 8_639_999_999_999_999, -8_639_999_999_999_999, 951_782_400_000, 4_107_542_399_999, +]; +process.env.TZ = "UTC"; +for (const t of edges) { + const x = new Date(t); + console.log(t, utcFields(x), fields(x)); +} +process.env.TZ = "America/Sao_Paulo"; +let walk = 0; +for (let t = 946_684_800_000; t < 1_893_456_000_000; t += 77_777_777) { + const x = new Date(t); + walk = (walk * 31 + x.getUTCDate() + x.getUTCHours() * 7 + x.getDate() + x.getMinutes() + x.getDay()) % 1_000_003; +} +console.log("walk", walk); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 7d8030e95..907f27383 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1997,6 +1997,7 @@ "5680-array-growth-after-copy.ts": 3791, "5681-array-pop-and-length.ts": 3754, "5682-publish-wide-objects.ts": 3326, + "5683-date-local-fields-tz.ts": 3848, "5700-cycle-release-retained.ts": 2156, "5701-cycle-release-old-edges.ts": 2601, "5702-publish-candidate-buffers.ts": 3469, @@ -5019,6 +5020,7 @@ "5680-array-growth-after-copy.ts": 4581, "5681-array-pop-and-length.ts": 3216, "5682-publish-wide-objects.ts": 3376, + "5683-date-local-fields-tz.ts": 3911, "5700-cycle-release-retained.ts": 3414, "5701-cycle-release-old-edges.ts": 4210, "5702-publish-candidate-buffers.ts": 3848, From f80eb5fc39ce2232abd2fd793241786a20951b84 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 13:39:12 -0500 Subject: [PATCH 112/117] Give every arm of record unions that share arms a collector header A shape union's arms all carry a collector header when one of them does. The emitter applied that rule in one pass over the unions in module order, so a header that a later union gave a shared arm did not reach the other arms of an earlier union. With First = A | B and Second = B | C, where only C is cyclic, B got a header through Second, First's trace helper then called A's trace function, and A had none: the module failed LLVM verification with "use of undefined value '@sc_rtrace_r0'". The rule now repeats until no union adds a header. Corpus 5919-record-unions-shared-arms chains Third = D | A, First = A | B and Second = B | C, so the requirement passes from Second through First to Third. --- packages/compiler/src/backend/llvm/emitter.ts | 26 +++++--- .../5919-record-unions-shared-arms.ts.json | 6 ++ .../corpus/5919-record-unions-shared-arms.ts | 60 +++++++++++++++++++ tests/harness/corpus-costs.json | 2 + 4 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5919-record-unions-shared-arms.ts.json create mode 100644 tests/corpus/5919-record-unions-shared-arms.ts diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 775e771ca..26c3b840e 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1395,13 +1395,25 @@ export class LlEmitter { this.tracedUnions = traced.unions; // A shape union's value is whichever record it holds, and the collector // visits it as that record: when one arm carries a collector header, - // every arm must (nullable-unions.ts). - for (const union of this.nullableUnions.allShapeUnions()) - if ( - this.tracedUnions.has(union.unionId) || - union.arms.some((arm) => this.tracedShapes.has(`record:${arm.shapeId}`)) - ) - for (const arm of union.arms) this.tracedShapes.add(`record:${arm.shapeId}`); + // every arm must (nullable-unions.ts). Unions that share an arm pass a + // header on to each other's arms, so repeat until no union adds one. + const shapeUnions = this.nullableUnions.allShapeUnions(); + for (let changed = true; changed;) { + changed = false; + for (const union of shapeUnions) { + if ( + !this.tracedUnions.has(union.unionId) && + !union.arms.some((arm) => this.tracedShapes.has(`record:${arm.shapeId}`)) + ) + continue; + for (const arm of union.arms) { + const key = `record:${arm.shapeId}`; + if (this.tracedShapes.has(key)) continue; + this.tracedShapes.add(key); + changed = true; + } + } + } this.shapeHost = { sizeType: this.sizeType, cycleBufOffset: this.cycleBufOffset, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5919-record-unions-shared-arms.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5919-record-unions-shared-arms.ts.json new file mode 100644 index 000000000..bfb23e115 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5919-record-unions-shared-arms.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5919-record-unions-shared-arms.ts" + ], + "diags": [] +} diff --git a/tests/corpus/5919-record-unions-shared-arms.ts b/tests/corpus/5919-record-unions-shared-arms.ts new file mode 100644 index 000000000..89f34dd83 --- /dev/null +++ b/tests/corpus/5919-record-unions-shared-arms.ts @@ -0,0 +1,60 @@ +// Record unions that share arms: Third = D | A, First = A | B and +// Second = B | C. Only C is cyclic. Every arm of a union whose values the +// cycle collector can visit carries a collector header, and the shared +// arms pass that requirement from Second back through First to Third. +type A = { kind: "a"; v: number }; +type B = { kind: "b"; w: number }; +type C = { kind: "c"; kids: C[] }; +type D = { kind: "d"; label: string }; +type Third = D | A; +type First = A | B; +type Second = B | C; + +function third(u: Third): string { + return u.kind === "d" ? u.label : `a${u.v}`; +} + +function first(u: First): number { + return u.kind === "a" ? u.v : u.w; +} + +function second(u: Second): number { + return u.kind === "b" ? u.w : u.kids.length + u.kids.reduce((n, k) => n + second(k), 0); +} + +const zs: Third[] = [ + { kind: "d", label: "dee" }, + { kind: "a", v: 7 }, +]; +console.log(zs.map(third).join(",")); + +const xs: First[] = [ + { kind: "a", v: 1 }, + { kind: "b", w: 2 }, +]; +console.log(xs.map(first).join(",")); + +const leaf: C = { kind: "c", kids: [] }; +const ys: Second[] = [ + { kind: "b", w: 3 }, + { kind: "c", kids: [leaf, { kind: "c", kids: [leaf] }] }, +]; +console.log(ys.map(second).join(",")); + +// One record held through two unions. +const sharedA: A = { kind: "a", v: 5 }; +const sharedB: B = { kind: "b", w: 6 }; +const viaThird: Third = sharedA; +const viaFirst: First[] = [sharedA, sharedB]; +const viaSecond: Second = sharedB; +console.log(third(viaThird), viaFirst.map(first).join(","), second(viaSecond)); + +// A cyclic C reachable only through Second, dropped and rebuilt in a loop. +let total = 0; +for (let i = 0; i < 200; i++) { + const node: C = { kind: "c", kids: [] }; + node.kids.push(node); + const held: Second[] = [node, { kind: "b", w: i }]; + total += held.length + node.kids.length; +} +console.log("total", total); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index c393620c3..8ef52f39a 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -2136,6 +2136,7 @@ "5913-prototype-type-error-messages.ts": 3102, "5914-dyn-in-class-prototype-members.ts": 2530, "5915-dyn-error-string-conversions.ts": 3023, + "5919-record-unions-shared-arms.ts": 3182, "5920-promise-try-args.ts": 3028, "5921-promise-try-args-js.js": 3179, "5922-matchall-groups-callbacks.ts": 4418, @@ -5154,6 +5155,7 @@ "5913-prototype-type-error-messages.ts": 3454, "5914-dyn-in-class-prototype-members.ts": 3792, "5915-dyn-error-string-conversions.ts": 3851, + "5919-record-unions-shared-arms.ts": 4941, "5920-promise-try-args.ts": 3195, "5921-promise-try-args-js.js": 3082, "5922-matchall-groups-callbacks.ts": 5275, From fa64c19fdc8a536867144474fcae3e7d22d3fb42 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 09:51:38 -0700 Subject: [PATCH 113/117] Build the coverage result without a conditional spread over its tiers The self-hosted compiler refuses a conditional spread of `tiers` over a LowerResult that already declares the field, so assign it instead. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/frontend/lowering/lowerer.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index c535d603f..d104eae39 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1091,7 +1091,7 @@ export function lowerToIr( // Unreached JS statements whose fences deferred to runtime count as // failed statements in the remainder's stats, so their diagnostics must // travel with them: a failed statement is never left unexplained. - return { + const covered: LowerResult = { ...result, stats: { ...result.stats, statementsDynamic }, unreached: { @@ -1099,8 +1099,9 @@ export function lowerToIr( stats: rem.stats, ...(rem.runtimeFences.length > 0 ? { runtimeFences: rem.runtimeFences } : {}), }, - ...(tiers !== undefined ? { tiers } : {}), }; + if (tiers !== undefined) covered.tiers = tiers; + return covered; } /** The native namespace type produced by a literal static import() of a From a5548597e5d4481a5fb79dc0978308770cddf4f0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 14:02:03 -0500 Subject: [PATCH 114/117] Read zlib options held in typed objects A zlib options object that reaches the runtime as a typed reference (a cast object literal such as `{ level: 0 } as zlib.ZlibOptions`, which the checked-dynamic options slot holds by reference) was not a plain checked-dynamic object, so the options reader found no keys: every option was ignored and out-of-range values were not reported. The sync, callback and promisified one-shots and the stream constructors compressed with the defaults instead. scr_zlib_options_parse and scr_zlib_stream_new now read a typed reference through its materialized view, as the blob and fetch option readers do, so the options apply and invalid ones throw Node's ERR_OUT_OF_RANGE. --- .../corpus/5633-zlib-typed-options.ts.json | 6 ++ packages/runtime/src/scr_zlib.c | 15 +++++ packages/runtime/src/scr_zlib_stream.c | 7 +++ tests/corpus/5633-zlib-typed-options.ts | 58 +++++++++++++++++++ tests/harness/corpus-costs.json | 2 + 5 files changed, 88 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5633-zlib-typed-options.ts.json create mode 100644 tests/corpus/5633-zlib-typed-options.ts diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5633-zlib-typed-options.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5633-zlib-typed-options.ts.json new file mode 100644 index 000000000..f4d9673d5 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5633-zlib-typed-options.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5633-zlib-typed-options.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_zlib.c b/packages/runtime/src/scr_zlib.c index b61cdc1cb..ff09e7ea1 100644 --- a/packages/runtime/src/scr_zlib.c +++ b/packages/runtime/src/scr_zlib.c @@ -420,7 +420,22 @@ void scr_zlib_options_drop(ScrZlibOptions *o) { o->dict = NULL; } +static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibOptions *out); + +/* A typed options object (a record that crossed into a checked-dynamic + * slot by reference) is read through its materialized view, as a plain + * object is. */ bool scr_zlib_options_parse(int mode, const ScrDyn *opts, ScrZlibOptions *out) { + if (opts == NULL || opts->kind != SCR_DYN_TYPED_REF) return scr_zlib_options_parse_object(mode, opts, out); + ScrDyn *view = scr_dyn_typed_ref_materialize(opts); + bool ok = false; + if (scr_exc_pending()) memset(out, 0, sizeof *out); + else ok = scr_zlib_options_parse_object(mode, view, out); + scr_dyn_release(view); + return ok; +} + +static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibOptions *out) { memset(out, 0, sizeof *out); out->window_bits = 15; out->level = Z_DEFAULT_COMPRESSION; diff --git a/packages/runtime/src/scr_zlib_stream.c b/packages/runtime/src/scr_zlib_stream.c index 14d8747e8..4ed717d53 100644 --- a/packages/runtime/src/scr_zlib_stream.c +++ b/packages/runtime/src/scr_zlib_stream.c @@ -431,6 +431,13 @@ static const char *scr_zs_class_name(int mode) { } ScrStream *scr_zlib_stream_new(double mode_d, ScrDyn *opts) { + /* A typed options object is read through its materialized view. */ + if (opts != NULL && opts->kind == SCR_DYN_TYPED_REF) { + ScrDyn *view = scr_dyn_typed_ref_materialize(opts); + ScrStream *stream = scr_exc_pending() ? NULL : scr_zlib_stream_new(mode_d, view); + scr_dyn_release(view); + return stream; + } int mode = (int)mode_d; const ScrDyn *o = opts != NULL && scr_dyn_truthy(opts) ? opts : NULL; ScrZlibOptions zo; diff --git a/tests/corpus/5633-zlib-typed-options.ts b/tests/corpus/5633-zlib-typed-options.ts new file mode 100644 index 000000000..da657ca14 --- /dev/null +++ b/tests/corpus/5633-zlib-typed-options.ts @@ -0,0 +1,58 @@ +// zlib options held in a typed object (a cast object literal that crosses +// into the options slot by reference) are read like a plain options +// object: levels, windowBits and strategies apply, and out-of-range values +// throw Node's ERR_OUT_OF_RANGE from the sync, callback, promisified and +// stream forms. +import * as zlib from "node:zlib"; +import { promisify } from "node:util"; + +const data = Buffer.from("hello hello hello hello hello"); +const stored = { level: 0 } as zlib.ZlibOptions; +const fast = { level: 1 } as zlib.ZlibOptions; +const huffman = { strategy: zlib.constants.Z_HUFFMAN_ONLY } as zlib.ZlibOptions; +const smallWindow = { windowBits: 9, memLevel: 1 } as zlib.ZlibOptions; +const badLevel = { level: 99 } as zlib.ZlibOptions; +const badWindow = { windowBits: 3 } as zlib.ZlibOptions; + +function attempt(label: string, run: () => void): void { + try { + run(); + console.log(label, "ok"); + } catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(label, err.name, err.code, err.message); + } +} + +console.log("sync stored", zlib.deflateSync(data, stored).toString("hex")); +console.log("sync fast", zlib.deflateSync(data, fast).toString("hex")); +console.log("sync huffman", zlib.deflateSync(data, huffman).toString("hex")); +console.log("raw small window", zlib.deflateRawSync(data, smallWindow).toString("hex")); +console.log("gzip stored", zlib.gzipSync(data, stored).subarray(10).toString("hex")); +attempt("sync bad level", () => zlib.deflateSync(data, badLevel)); +attempt("sync bad window", () => zlib.inflateSync(zlib.deflateSync(data), badWindow)); +attempt("callback bad level", () => zlib.gzip(data, badLevel, () => console.log("not called"))); +attempt("stream bad level", () => zlib.createDeflate(badLevel)); + +const deflateAsync = promisify(zlib.deflate); + +async function main(): Promise { + const viaCallback = await new Promise((resolve, reject) => + zlib.deflate(data, stored, (err, out) => (err ? reject(err) : resolve(out))), + ); + console.log("callback stored", viaCallback.toString("hex")); + console.log("promise stored", (await deflateAsync(data, stored)).toString("hex")); + try { + await deflateAsync(data, badLevel); + console.log("promise bad level fulfilled"); + } catch (e) { + console.log("promise bad level", (e as NodeJS.ErrnoException).code); + } + const stream = zlib.createDeflate(fast); + const parts: Buffer[] = []; + stream.on("data", (chunk: Buffer) => parts.push(chunk)); + stream.on("end", () => console.log("stream fast", Buffer.concat(parts).toString("hex"))); + stream.end(data); +} + +main().catch((e) => console.log("unexpected", String(e))); diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index acaa95479..33d8c4c1d 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1976,6 +1976,7 @@ "5630-promisify-zlib.ts": 2503, "5631-promisify-crypto.ts": 2200, "5632-promisify-dns.ts": 1700, + "5633-zlib-typed-options.ts": 1800, "5644-net-socket-addresses.ts": 2220, "5645-net-socket-callbacks.ts": 2442, "5646-net-server-connections.ts": 2389, @@ -5006,6 +5007,7 @@ "5630-promisify-zlib.ts": 3392, "5631-promisify-crypto.ts": 2600, "5632-promisify-dns.ts": 2000, + "5633-zlib-typed-options.ts": 2200, "5644-net-socket-addresses.ts": 2393, "5645-net-socket-callbacks.ts": 2060, "5646-net-server-connections.ts": 2755, From f6499596099e02d46a31520dee83fc518ad67150 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 09:31:23 -0700 Subject: [PATCH 115/117] Report refused local classes from speculative type queries again The previous change dropped the diagnostics of a function-local class refused during a speculative whole-program type query, expecting the class's own declaration to report them. In JavaScript that declaration only defers them to a runtime fence, so two npm programs that the compile refused (stream-shims and node24-file-url-conversion, both SC1090) began to compile and diverged from Node at run time. The speculative query now leaves the refusal reported, as it was wherever such an analysis already caught the poison, and only stops the poison from escaping the compiler. The JavaScript crash repro becomes a diagnostics fixture (local-class-type-query-js.js); the corpus program 6102 never crashed the base compiler and is removed. Co-Authored-By: Claude Opus 5.5 --- .../compiler/src/frontend/lowering/lowerer.ts | 14 ++----- .../6102-local-class-type-query.js.json | 6 --- .../local-class-type-query-js.js.json | 6 +++ tests/corpus/6102-local-class-type-query.js | 42 ------------------- .../diagnostics/local-class-type-query-js.js | 26 ++++++++++++ .../local-class-type-query-js.js.txt | 6 +++ 6 files changed, 42 insertions(+), 58 deletions(-) delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-js.js.json delete mode 100644 tests/corpus/6102-local-class-type-query.js create mode 100644 tests/diagnostics/local-class-type-query-js.js create mode 100644 tests/harness/__snapshots__/local-class-type-query-js.js.txt diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index bf4ed5464..94f99185a 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -9804,27 +9804,21 @@ export class Lowerer { * instance type. Collection and body lowering own a refusal of that * class: the poison reaches the declaration or statement that asked, as * before. A speculative whole-program analysis owns none, so there the - * class is unmappable for the query and its diagnostics are dropped; - * lowering the class's own declaration collects it again and reports - * them if the program reaches it. */ + * refusal stays reported (the build fails with it, as it did where such + * an analysis already caught the poison) and the class is unmappable for + * the query instead of the poison escaping the compiler. */ collectLocalClassForType(decl: ts.ClassLikeDeclaration): boolean { if (this.speculativeTypeQueryDepth === 0 || this.fnStack.length > 0) { this.lowerClassExpressionInfo(decl); return true; } - const sink: ScrDiagnostic[] = []; - const previousSink = this.diagSink; - this.diagSink = sink; try { this.lowerClassExpressionInfo(decl); + return true; } catch (e) { if (e instanceof PoisonError) return false; throw e; - } finally { - this.diagSink = previousSink; } - for (const d of sink) this.pushDiag(d); - return true; } lowerClassExpression(expr: ts.ClassLikeDeclaration): IrExpr { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json deleted file mode 100644 index 86c6ba9e8..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/corpus/6102-local-class-type-query.js" - ], - "diags": [] -} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-js.js.json new file mode 100644 index 000000000..6bf774cd8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/local-class-type-query-js.js" + ], + "diags": [] +} diff --git a/tests/corpus/6102-local-class-type-query.js b/tests/corpus/6102-local-class-type-query.js deleted file mode 100644 index 92fe35725..000000000 --- a/tests/corpus/6102-local-class-type-query.js +++ /dev/null @@ -1,42 +0,0 @@ -// A whole-program analysis that queries types before reachability is known -// (the computed-key write census here) can name a function-local class whose -// collection is refused. That query has no owner for the refusal: the class -// stays unmapped for it, and the refusal belongs to the class's own -// declaration, which this program never executes (it used to crash the -// compiler with an uncaught PoisonError). -function main(run) { - if (!run) return "skipped"; - const Project = class { - constructor() { - this.name = "p"; - } - close() { - if (this.missingFilesMap) { - this.missingFilesMap.clear(); - this.missingFilesMap = void 0; - } - } - add(k) { - (this.missingFilesMap || (this.missingFilesMap = new Map())).set(k, 1); - } - }; - const holder = { p: new Project() }; - const key = String(run); - holder.p[key] = "q"; - return holder.p.name; -} - -class Counter { - constructor() { - this.counts = {}; - } - bump(key) { - this.counts[key] = (this.counts[key] || 0) + 1; - return this.counts[key]; - } -} - -const counter = new Counter(); -const word = process.argv.length > 99 ? "unused" : "word"; -counter.bump(word); -console.log(main(0), counter.bump(word)); diff --git a/tests/diagnostics/local-class-type-query-js.js b/tests/diagnostics/local-class-type-query-js.js new file mode 100644 index 000000000..2da619133 --- /dev/null +++ b/tests/diagnostics/local-class-type-query-js.js @@ -0,0 +1,26 @@ +// A whole-program analysis that queries types before reachability is known +// (the computed-key write census here, through `holder.p`) names a +// function-local class whose collection is refused. The refusal is reported, +// once, at the class; it used to crash the compiler with an uncaught +// PoisonError. +function main() { + const Project = class _Project { + constructor() { + this.name = "p"; + } + close() { + if (this.missingFilesMap) { + this.missingFilesMap.clear(); + this.missingFilesMap = void 0; + } + } + add(k) { + (this.missingFilesMap || (this.missingFilesMap = new Map())).set(k, 1); + } + }; + const holder = { p: new Project() }; + const key = process.argv.length > 5 ? String(process.argv.length) : "name"; + holder.p[key] = "q"; + console.log(holder.p.name); +} +main(); diff --git a/tests/harness/__snapshots__/local-class-type-query-js.js.txt b/tests/harness/__snapshots__/local-class-type-query-js.js.txt new file mode 100644 index 000000000..60422a5dc --- /dev/null +++ b/tests/harness/__snapshots__/local-class-type-query-js.js.txt @@ -0,0 +1,6 @@ +local-class-type-query-js.js:14:9 - error SC1090: fields assigned outside the constructor's top level ('this.missingFilesMap' would be undefined until the first assignment runs — assign it unconditionally at the top of the constructor) is not supported yet + + 13 | this.missingFilesMap.clear(); + 14 | this.missingFilesMap = void 0; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 15 | } \ No newline at end of file From 5746dc30c5fb4db460563988ef19beb2fe79018e Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 12:05:40 -0700 Subject: [PATCH 116/117] Expect the compile to refuse stream-shims and node24-file-url-conversion again With the local-class refusal reported again, both npm fixtures fail to compile with SC1090 as they did before #1303; restore their build expectations. The deleted corpus program 6102 also leaves the measured cost table. Co-Authored-By: Claude Opus 5.5 --- tests/harness/corpus-costs.json | 2 -- tests/harness/npm.test.ts | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index 810e6a798..e413e9d3a 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -2209,7 +2209,6 @@ "605-closures-forward-capture-tdz.ts": 3277, "6100-record-get-or-create.ts": 3771, "6101-record-get-or-create-unchecked/main.ts": 2107, - "6102-local-class-type-query.js": 2600, "6103-typeof-builtin-bindings.cjs": 2202, "6104-typeof-builtin-bindings.mjs": 2031, "6105-cjs-top-level-this/main.js": 1371, @@ -5245,7 +5244,6 @@ "605-closures-forward-capture-tdz.ts": 4638, "6100-record-get-or-create.ts": 3173, "6101-record-get-or-create-unchecked/main.ts": 3228, - "6102-local-class-type-query.js": 1967, "6103-typeof-builtin-bindings.cjs": 1796, "6104-typeof-builtin-bindings.mjs": 1715, "6105-cjs-top-level-this/main.js": 3213, diff --git a/tests/harness/npm.test.ts b/tests/harness/npm.test.ts index c4e70294e..a6cdee2b5 100644 --- a/tests/harness/npm.test.ts +++ b/tests/harness/npm.test.ts @@ -73,7 +73,7 @@ const KNOWN: Record = { "node24-env": { run: "SC1090" }, "node24-esm-metadata": { run: "SC1090" }, "node24-event-emitter": { run: "SC2020" }, - "node24-file-url-conversion": { run: "SC2020" }, + "node24-file-url-conversion": { build: "SC1090" }, "node24-fs-descriptors": { run: "SC1090" }, "node24-mime": { run: "SC2020" }, "node24-mime-errors": { run: "SC1090" }, @@ -104,7 +104,7 @@ const KNOWN: Record = { "package-imports": { build: "SC2013" }, "promise-bridge": { build: "SC1090" }, "self-name": { build: "SC2013" }, - "stream-shims": { run: "SC1090" }, + "stream-shims": { build: "SC1090" }, "util-shims": { run: "SC2020" }, "web-streams": { build: "SC2013" }, "workspace-copied": { build: "SC2013" }, From 470d3177030e799b15f5b67016210892e8959c93 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 14:21:32 -0500 Subject: [PATCH 117/117] Keep class methods named kind and code direct in the compiler resolveInferredReturn turns a return statement into a runtime fence through a Record view with element writes (`mutable["kind"] = ...`). The class method census treats a literal element write as a possible write to every method of that name, so in the native compiler every method named `kind` or `code` became a dynamic callback: AstWireFile.kind, called for each AST node access, went through a property bag and a method value. Property writes go through the receiver check instead, and no class instance is assignable to Record, so those methods are called directly again. Output of the compiler is unchanged. --- .../src/frontend/lowering/function-returns.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/function-returns.ts b/packages/compiler/src/frontend/lowering/function-returns.ts index d3c5eb1ba..5ba63be26 100644 --- a/packages/compiler/src/frontend/lowering/function-returns.ts +++ b/packages/compiler/src/frontend/lowering/function-returns.ts @@ -429,11 +429,14 @@ export function resolveInferredReturn( if (ice.length > 0) lowerer.diags.push(...ice); lowerer.runtimeFences.push(...captured.filter((d) => d.code !== "SC9001")); const first = captured.find((d) => d.code !== "SC9001"); + // Property writes, not literal element writes: the class method + // census reads `x["kind"] = …` as a possible write to every method + // named `kind`, which would make those methods dynamic in native builds. const mutable = e.stmt as unknown as Record; - delete mutable["value"]; - mutable["kind"] = "runtimeFence"; - mutable["code"] = first?.code ?? "SC1090"; - mutable["message"] = first + delete mutable.value; + mutable.kind = "runtimeFence"; + mutable.code = first?.code ?? "SC1090"; + mutable.message = first ? `${first.message} [${first.code}]` : "this return value has no lowering onto the instance's settled return type [SC1090]"; }