Commit Graph
3145 Commits
Author SHA1 Message Date
Malte UblandClaude Opus 5.5 22edb6deb0 Test bundled chunks, cycles and refusals
Unit tests run each split bundle against its original under Node and
pin the refusal reasons; npm-static tests compile the new cases and
compare them with Node byte for byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:20:28 -07:00
Malte UblandClaude Opus 5.5 17647d8bfd Add esbuild chunk and CommonJS cycle npm fixtures
Real esbuild output (0.25 plain and whitespace/syntax minified, 0.17)
of one bundle with lazily and eagerly required chunks, a chunk that is
itself an esbuild dist, an external through __toESM, a .cjs bundle in a
type-module package, and per-file esbuild CommonJS cycles entered from
either side. Split chunks are require-only modules: their whole export
table is their surface.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:17:13 -07:00
Malte UblandClaude Opus 5.5 6b1f1c5991 Admit require cycles through esbuild's live export tables
The interop rewrite certifies a file whose esbuild export object is
installed before anything can run another module's code; the CommonJS
cycle rule then treats its tail table as settled at that point. A
top-level plain read of a cycle member's function-declaration export is
exact as well: Node and the compiled read see the same function.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:07:43 -07:00
Malte UblandClaude Opus 5.5 ee8011cea5 Split esbuild CommonJS chunks into their own modules
Recognize esbuild's __commonJS helper (keyed and arrow forms, the
Object.keys spelling of 0.11) and move every chunk body into a virtual
sibling CommonJS module, so require_x() becomes a require of that module
and the ordinary CommonJS machinery compiles it. Also accept minified
helper declarations that share one var statement, counter-suffixed
helper names inside bundled bundles, and treat .cjs files as CommonJS
in the interop rewrite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:03:34 -07:00
Malte Ubl dc66837001 Merge remote-tracking branch 'origin/opt/webcrypto-hmac' into opt/jose-gaps 2026-10-19 10:51:59 -07:00
Malte UblandClaude Opus 5.5 1a61c4daa0 Keep the verdict-cache test's blocker refused now that array position patterns compile
The test used `const { length } = [1, 2] as number[]` as its coverage
blocker. That compiles now, so no diagnostic was left to replay. The blocker
destructures a `number[] | string` union instead, which keeps the SC1031
object-pattern fence. The comment-only replay and code-edit relower
assertions are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:51:12 -07:00
Malte UblandClaude Opus 5.5 cf198952e2 Compile the real jose root entry: string durations, chained builders, navigator
jose 6.2.12 now compiles natively through its root entry (`import { jwtVerify,
errors } from "jose"`), from TypeScript and JavaScript, with chained SignJWT
builders and string durations:

- A discarded `a && b;` / `a || b;` statement whose value form fails on its own
  result type (jose's secs(): `(!m || m[4] && m[1]) && invalid()`) lowers as
  `if (a) b;` / `if (!a) b;`. The value form still lowers first, so statements
  that compiled before are unchanged.
- In JavaScript, a number-keyed read on a `T[] | null | undefined` value outside
  an optional chain (`m[2]` after a statement ruled `m` non-null) reads the
  array arm like any element read: a group that did not participate is
  undefined instead of a trap.
- A JavaScript fluent method whose returns all end in `this` (including comma
  sequences) narrows a used call result back to the receiver's subclass. A
  receiver lowered at an ancestor of the class a call needs is bridged with a
  verified downcast instead of an upcast the validator rejected (the
  "upcast JWTClaimsBuilder does not extend SignJWT" internal error).
- `typeof navigator` is "object" and `navigator.userAgent` is "Node.js/24", as
  in Node 24, for the free name in JavaScript and under @types/node. Both fold
  to literals; other members refuse by name.
- TypeScript object destructuring of an `any` result of a JavaScript function
  (jose's jwtVerify) reads its members like the member reads that already
  compiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:30:48 -07:00
Malte Ubl 643c0f5daa Merge commit '26946d6b2' into opt/webcrypto-hmac 2026-10-19 08:21:02 -07:00
Malte Ubl 675e70cc24 Merge commit '26946d6b2' into opt/pi-small-fixes 2026-10-19 08:21:01 -07:00
Malte Ubl 13efc5ffcd Merge commit '26946d6b2' into opt/tier-s3-jsval 2026-10-19 08:20:59 -07:00
Malte UblandClaude Opus 5.5 2f4edcc358 Keep existing objects in JavaScript var and destructured bindings
A JavaScript `var` binding hoists to its function, and its slot was
created with the checker's type before the initializer lowered. When the
initializer was an existing checked-dynamic object (an element of an
array built with push, a find result, the object a function returns),
the record-typed slot held a converted copy: writes through the binding
missed the object that the array or the function's caller still held,
and `===` against it was false. `let` and `const` already lowered the
initializer first and kept such a value checked-dynamic.

A `var` initialized with an existing value now lowers the initializer
before creating the slot, and a checked-dynamic value gets a
checked-dynamic slot. The same applies to `for (var x of ...)`, to array
destructuring with `var`, `let` and `const`, and to file-scope bindings,
whose module-entry `undefined` store follows the slot's final type. A
literal holding such an object builds checked-dynamic for a `var` as it
already did for `let`. TypeScript files and annotated bindings are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 07:59:01 -07:00
Chris Tate a405f856bc Iterate class instances whose Symbol.iterator is a generator method
A class with a parameterless *[Symbol.iterator]() generator method can now
be iterated by for-of, array spread, Array.from, Math.max and Math.min
spreads, new Set, new Map, Object.fromEntries and Iterator.from. Each site
calls the method once and drives the generator it returns.

obj[Symbol.iterator]() and the other well-known symbol methods called
through element access now call the class's method, so iterator helpers
apply to the result instead of failing on an untyped value.

Writes that can replace a well-known symbol method (a symbol-keyed write,
Object.defineProperty, a prototype write) now enter the method census, and
those classes keep the existing checked or refused paths.
2026-10-19 09:06:15 -05:00
Chris Tate 1f07166fbf Merge main 2026-10-19 08:56:48 -05:00
Chris Tate b9fbe4b50b Merge main 2026-10-19 08:42:36 -05:00
Chris Tate 0abf9a6395 Revert "Copy repeated childless IR nodes with a spread"
This reverts commit c836f93998. The
bootstrap seed build cannot compile the spread copies (SC1090).
2026-10-19 08:34:08 -05:00
Chris Tate 37bac645aa Read call arguments through NodeArray.nodes in the readline dispose and getTestContext checks 2026-10-19 08:32:43 -05:00
Chris Tate 178646baf0 Merge main 2026-10-19 08:31:43 -05:00
Chris Tate 7f907d23e3 Read getTestContext's arguments through their nodes (#1402) 2026-10-19 08:18:09 -05:00
Chris Tate 3d4f181cb7 Merge main 2026-10-19 08:15:47 -05:00
Chris Tate 720b6f6117 Merge main 2026-10-19 08:11:47 -05:00
Chris Tate 88a2c557d1 Link the child-process unit only in programs that spawn
The event loop called scr_children_pending, scr_children_poll and the other
child hooks directly on native targets, so every async program linked the
child-process unit (the reap pass, IPC service, pipe readers and writers).
The loop now reaches them through a nullable ScrLoopChildren table that the
child unit installs with its first spawned child or IPC channel, the shape
the events, net, dgram and fs.watch hooks already use. The WASI stubs for
the old direct calls are removed.
2026-10-19 07:59:51 -05:00
Chris Tate edd3874925 Run iterator helpers and destructuring on generators passed through untyped values (#1389) 2026-10-19 07:57:24 -05:00
Chris Tate c6e16d365b Read getTestContext's arguments through their nodes
lowerGetTestContext (#1393) read expr.arguments as an array. Since #1394
an AST list's elements are in nodes, so the compiler did not type-check.
2026-10-19 07:56:11 -05:00
Chris Tate 809f2cbea1 Merge main 2026-10-19 07:55:06 -05:00
Chris Tate a57089aebf Accept readline's dispose, instanceof, dynamic streams and non-string prompts
rl[Symbol.dispose]() closes the interface, as Node's dispose method
calls close(). rl instanceof readline.Interface and
readlinePromises.Interface answer which module created the interface:
rl.create's mode marks readline/promises interfaces, and the fallback
declarations declare both Interface classes as values.

In JavaScript, createInterface's input and output can be checked-dynamic
values (a function's result, an object's member, an element that may be
undefined): rl.inputFromDyn and rl.outputFromDyn unbox the stream they
hold, an output of null or undefined means no output, and other values
are refused.

In JavaScript, question() and setPrompt() accept a value that is not a
string. When such a prompt is written, an interface that is not a
terminal throws ERR_INVALID_ARG_TYPE as Node's kWriteToOutput does, and
the readline/promises question rejects with it; the question stays
pending and the previous prompt returns when it is answered. A terminal
interface writes String(value) of a primitive.

Corpus 5876-5878 match Node v24.22.0.
2026-10-19 07:51:54 -05:00
Chris Tate 9e628720ae Test the common IR node kinds first in child traversals (#1391) 2026-10-19 07:50:45 -05:00
Chris Tate 8320cc2289 Spin briefly before a mailbox wait blocks, and signal after the unlock
A worker message round trip cost about 12 µs, almost all of it in two
blocked waits: the poster signaled the waiting thread while it still held
the mailbox lock, so the woken thread went back to sleep on the lock, and
every wait paid a sleep and a wakeup. scr_mailbox_post and close now
signal after the unlock, and scr_mailbox_wait spins for up to 20 µs (or
the wait's timeout, if shorter) on a flag the queue keeps before it
blocks. A process that may run on only one CPU never spins.

A new bench:runtime workload, worker-messages, posts 100,000 round trips
between the main thread and a worker: 1296 -> 360 ms.
2026-10-19 07:46:06 -05:00
Malte UblandClaude Opus 5.5 1af8cfea7b Bump the IR version in main's new classes and thread-slots tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 05:43:59 -07:00
Malte Ubl a10ce583d7 Merge remote-tracking branch 'origin/main' into opt/tier-s3-jsval 2026-10-19 05:43:49 -07:00
Chris Tate 56850331b6 Copy repeated childless IR nodes with a spread (#1392) 2026-10-19 07:43:33 -05:00
Chris Tate 9b79eb8d32 Read declarations from symbols and signatures
symbol.declarations, symbol.valueDeclaration and signature.declaration
return nodes, as tsc-ts's Symbol and Signature do, instead of the
facade's declarationsOf, valueDeclarationOf and signatureDeclaration
resolving their handles. Each symbol and signature resolves its handles
in its own project on first read and keeps the nodes. The handles stay
available as declarationHandles, valueDeclarationHandle and
declarationHandle.

A program's checker and its symbols belong to the same project, so the
nodes are the ones the facade returned. The frontend's 432 calls of the
three facade methods become property reads, and the methods and their
caches go.
2026-10-19 07:41:28 -05:00
Chris Tate 8e0af5fc59 Add getTestContext to node:test (#1393) 2026-10-19 07:37:01 -05:00
Malte UblandClaude Opus 5.5 60e0b246e7 Choose record key order from the orders values are built in
Each record shape's enumeration table now follows the key order its object
literals, spreads, rest bindings and record copies create, and appends
optional keys assigned after construction. Shapes whose values are built
in more than one order keep their declaration order and SC6002.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 05:34:30 -07:00
Malte UblandClaude Opus 5.5 2b8cd22423 Add WebCrypto HMAC: crypto.subtle importKey, sign, verify and digest
crypto.subtle.importKey('raw', ...) for HMAC keys, HMAC sign and verify,
and the SHA-1/SHA-2 digests compile through the crypto global, with
CryptoKey values as native handles. scr_webcrypto.c is only the WebCrypto
layer (Web IDL conversion, algorithm normalization, the CryptoKey handle,
promise wrapping and Node's TypeErrors and DOMExceptions) over node:crypto's
digest core and deferred promise queue. It links only into programs that
call these methods (the new webcrypto link feature). Other algorithms, the
jwk format and the other SubtleCrypto methods are SC2020 refusals.

The real jose@6.2.12 HS256 path (SignJWT, jwtVerify) now runs natively. It
also needed four compiler fixes: object patterns of positions and length
over arrays, the Uint8Array base64/hex feature probes, a compile-time
String.fromCharCode.apply, and structuredClone of a parameter whose default
is {}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 05:34:26 -07:00
Malte Ubl 2fc52c47c9 Merge remote-tracking branch 'origin/opt/silent-bugs' into opt/silent-bugs 2026-10-19 05:34:13 -07:00
Malte UblandClaude Opus 5.5 9290f32e0d Treat constructor returns of chainable this-calls as returning this
three.js's Color constructor ends with `return this.set(r, g, b)`, and
every reachable `set` (Color's, and Color4's override returning
`super.set(...)`) returns `this`. The return analysis classified it as
returning another instance and refused `class Color4 extends Color`.
A return that is `this`, or a `this.m(...)`/`super.m(...)` call whose
every reachable implementation returns only `this`, a primitive or
nothing, now keeps the ordinary lowering, so such classes need no
result slot and subclasses construct through super() as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 05:34:05 -07:00
Malte UblandClaude Opus 5.5 a4131dfdb9 Read and write dynamic-tier properties through shapes and inline caches
Stage S4 of the two-tier design: dynamic-tier code reads, writes and
calls properties through per-site inline caches keyed on hidden-class
shapes.

- Runtime: scr_js_object.c (dynTier) attaches shapes to the existing
  checked objects: a shape is a node of the thread's transition tree
  over key sequences, computed on an object's first cache miss, and
  objects past 64 keys stay unshaped (dictionary mode). Attributes and
  the prototype are tested live on every hit. The dyn-tier build of
  scr_json.c (SCR_JS_TIER) resets a shape on every key-set change;
  typed programs keep linking the ordinary build.
- Sites: ir/js-ic.ts recognizes the lowering's property helpers by
  structure; calls to them from dynamic-tier functions, and method
  dispatch outside module initializers, become sites with a zeroed
  thread-local ScrJsIc. backend/llvm/js-ic.ts tests entry 0 inline
  (own property or one prototype link), probes out of line, and keeps
  the helper as the noinline cold slow path. Array length and dense
  number-key element reads are inline.
- Numbers: jsval reads of number properties are immediates, and a jsval
  number stored over an unshared number cell updates it in place; the
  jsval pass feeds cache stores jsvals and stops boxing discarded
  compound-assignment results. `%` and bitwise operators get integer
  paths.

Static functions are untouched: typed programs compile to byte-identical
LLVM and executables, and every static function of programs with
dynamic code is byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 05:34:01 -07:00
Malte Ubl 0b00819e40 Merge remote-tracking branch 'origin/opt/builtins-npm2' into opt/builtins-npm2 2026-10-19 05:33:31 -07:00
Malte UblandClaude Opus 5.5 e819e2af3d Record Number.prototype.toPrecision as static in the surface manifest
This branch lowers toPrecision statically, but STATIC_NUMBER_METHODS still
lacked it, so the regenerated manifest kept stdlib.number.toPrecision as
unsupported/SC2012 and a determinism fence on it had no reach detector.
List it with its num.toPrecision witness and 0 to 1 arguments, like
toFixed, and regenerate the manifest; the compatibility outputs are
unchanged.

library-profile's remediation test used that id as its SC2012 fence;
it now names the SC2012 code family (diagnostic.sc2012), so the explicit
remediations key still competes with fence-supplied SC2012 text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 05:33:16 -07:00
Malte UblandClaude Opus 5.5 78184a9869 WebAssembly W3–W4: translate modules to native code at build time, the JavaScript API over them, and Module transfer to workers
A build now translates every WebAssembly module whose bytes it can see
(W2's discovery) into LLVM IR with a TypeScript translator
(packages/compiler/src/wasm/module.ts, translate.ts) and appends it to the
program module, so the existing LLVM helper optimizes, partitions and
caches it with the program. The program also emits scr_wasm_registry, a
portable table of module descriptors (scr_wasm_abi.h). At run time,
WebAssembly.compile, instantiate, validate, new Module and new Instance
find the translated module by the SHA-256 of its bytes; bytes the build did
not see reject with a CompileError. There is no interpreter and no JIT.

The runtime (scr_wasm.c, link-gated by the new `wasm` feature, handle tags
inside W0's headroom) implements the JavaScript API once, over
descriptors, with Node's semantics and messages: exports (functions,
memories, tables, globals), imports (functions, immutable globals, and
memories, tables and globals other instances export), every trap as
WebAssembly.RuntimeError, the CompileError, LinkError and RuntimeError
classes, compile and instantiate settling on a later turn, and
globalThis.WebAssembly as a value. On 64-bit Linux and macOS, memories sit
in 8 GiB guard reservations and a SIGSEGV/SIGBUS handler turns faults into
traps or stack exhaustion; async fibers get a guard page on first use.
Sanitizer builds and Windows check bounds and the stack explicitly. A
WebAssembly.Module crosses to workers through W0's transfer hook (W4).

W1's refusals become lowerings; the Memory, Table and Global constructors,
Module.imports/exports/customSections and the streaming functions still
refuse with SC2020. The globals: WebAssembly compatibility row moves to
partial.

Evidence: differential corpus programs for the API, TypeScript use and the
codemode worker shape, plus five programs executing about 9,300 commands
of the WebAssembly 2.0 spec suite; all match Node in the plain and
sanitized lanes. quickjs-wasi runs through its own glue, matching Node
(apart from a pre-existing non-wasm fence) and on par with or faster than
V8. The zero-cost gate leaves every non-wasm program byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 05:33:11 -07:00
Chris Tate 098425ec78 Add an experimental young-in nursery for compiled classes and records (#1319) 2026-10-19 07:32:01 -05:00
Chris Tate 3c749a2895 Read AST lists through their nodes
The frontend's node lists become node lists, { pos, end, nodes }, the
shape of tsc-ts's NodeList, so that the frontend can later read tsc-ts's
own nodes. AstNode's list getters return an AstNodeList, ts.NodeArray<T>
is that class, and the frontend reads a list's elements through nodes.
The lists already carried their positions on the wire.

The class is the type, not a structural interface, because native code
represents a class and a record differently.

A decoded file keeps each list's nodes array, as before, and each read
of a list field returns a new AstNodeList over it, so the file holds no
more objects than before. nodes keeps its identity; a list object is not
the same object on each read.

The change is mechanical: a type-aware rewrite of each list field read,
plus hand edits where lists are read through casts, generic accessors
or test mocks. The generated getters and types follow from
generate-ts7-ast-schema.mjs. AstFile and Ts7Session drop their unused
listMetadata hook.
2026-10-19 06:33:33 -05:00
Chris Tate e82686eab7 Add getTestContext to node:test
node:test changes, matching Node 24.22:

- getTestContext() returns the context of the test, suite or hook whose
  code is running: undefined at module top level, the root's context in
  module-level hooks, the suite's in a suite body and in the suite's
  hooks, and the test's in its body. In the afterEach and t.after hooks
  of a subtest cancelled by its parent's timeout, it returns each hook's
  owner.
- The context rides the AsyncLocalStorage snapshot under a reserved id,
  so it follows a test across its awaits, into the async functions,
  promise callbacks, timers and other callbacks it schedules, and into
  concurrent subtests, which each see their own.
- The root's fullName is "<root>", as its name is.
- Optional chains over a test context, such as getTestContext()?.name,
  lower.

AsyncLocalStorage enter and restore move into the always-linked async
core so the test runner can use them. The snapshot holds the node's
index in a table of live nodes, so a snapshot that outlives its node
answers undefined.

The get-test-context and get-test-context-cancelled fixtures compare
the contexts seen at each point with Node, plain and with SCRIPTC_SAN=1.
2026-10-19 06:29:28 -05:00
Chris Tate c836f93998 Copy repeated childless IR nodes with a spread
unshareNodes gives every occurrence of a repeated node its own object.
Nodes with children are copied by mapExprChildren and mapStmtChildren,
which spread the node and keep its type and location objects. Childless
nodes were copied by reparseExpr and reparseStmt, which stringify the
node and parse the text, copying the type and location objects as well;
on the three.js nodes fixture that took about 6 s.

Childless nodes are now spread too. Analyses key their facts by node
identity, which each copy still has of its own. The type and location
objects are shared as they already are in every copied node with
children and in every function without a repeated node. The emitted IR
is unchanged for every corpus program.

unshareNodes takes about 2 s on the three.js nodes fixture instead of
8 s, and compiling it to LLVM text takes 171 s instead of 178 s (median
of five interleaved runs).
2026-10-19 06:18:17 -05:00
Chris Tate 60084fcf48 Test the common IR node kinds first in child traversals
everyExprChild, everyStmtChild, mapExprChildren and mapStmtChildren
switch over the node kind: 96 expression and 26 statement string cases,
which the engine tests one after another in source order. Every analysis
and rewrite walks the IR through them, and some of the most common kinds
were near the end: in the three.js nodes module, dynFrom, libCall and
dynCheck make up 27% of expression nodes and were the 64th, 94th and
96th cases.

The cases for the most common kinds now come first, in the order of how
often they occur in the three.js nodes and Effect fixtures. All other
cases keep their order, and no case changes. In those fixtures, seven
expression kinds make up 89% of expression nodes and four statement
kinds make up 88% of statements.

A full child walk of the three.js nodes module takes about 108 ns per
node instead of 154 ns. Compiling it to LLVM text takes 161 s instead
of 180 s (median of five interleaved runs), and the Effect schema
fixture 64 s instead of 69 s. The emitted IR is unchanged.
2026-10-19 06:14:15 -05:00
Chris Tate 26676e9df2 Flatten the last value a take delivers in full
In a fused helper chain, take(n) sets the chain's done flag as it
delivers its nth value, so nothing is pulled after it. A flatMap later in
the chain tested the same flag in its inner walk and stopped after the
first flattened value: gen().take(2).flatMap((x) => [x, x + 10]) gave
[0, 10] where Node gives [0, 10, 1, 11].

A flatMap stage after a take now holds the flag while it walks its inner
iterable, and sets it again afterwards. A terminal that short-circuits or
a take later in the chain still stops the inner walk.
2026-10-19 06:09:53 -05:00
Chris Tate 6a8732f57a Run iterator helpers and destructuring on generators passed through untyped values
A compiled generator that reached an untyped value, as in
`function f(it) { return it.map(g) } f(gen())`, refused its iterator
helper calls with SC1071 at run time: the runtime's helpers could not
step a generator's capsule. Array destructuring of untyped values only
handled arrays, strings and bytes, so `const [a, b] = it` threw "is not
iterable" for generators, iterators, Maps and Sets.

Programs that box a synchronous generator and call a helper method or
destructure an untyped value now register, first thing in %main, the
checked getters that read a generator capsule's next and return methods
(scr_dyn_set_generator_members). With them:

- helper calls on a generator capsule run the runtime's helpers, which
  step and close the generator through its own next() and return();
- reads of a helper name answer the runtime's helper function, so
  `typeof it.map` is "function" and `it.reduce.call(it, f, init)` works;
- destructuring of any other iterable steps it through the iterator
  protocol (scr_dyn_iter_take, and rest elements through
  scr_dyn_iter_pack), closing an iterator that has values left.

A return() through an untyped value with no argument, or with undefined,
now completes with undefined as the typed .return() does, instead of
converting undefined to the generator's return type. This also fixes
for-of loops over untyped generators with a typed return value that exit
early.
2026-10-19 05:52:22 -05:00
Chris Tate 48259bd7cd Refuse literal accessor descriptors for declared class fields at compile time
Object.defineProperty with an object-literal descriptor that declares get
or set for a declared class field is refused at compile time with SC2020,
naming the field. JavaScript sources report it as a deferred fence, so
coverage lists the call. Other accessor descriptors still throw SC2020
when the call runs.

The native descriptor test now compiles a data descriptor change on a
declared field and compares the output with Node, and checks that an
accessor descriptor stays fenced.
2026-10-19 05:41:16 -05:00
Chris Tate 2d859d3769 Merge main 2026-10-19 05:13:02 -05:00
Chris Tate 309fa897ec Use EventEmitter, the stream classes and the error classes as values
`function make(C: typeof EventEmitter) { return new C(); }`,
`const kinds: ErrorConstructor[] = [TypeError, RangeError]` and
`(typeof Readable)[]` stopped at SC2020 (the type has no mapping) or
SC1090 (builtin classes as values). These classes are now class values:
the name in a TypeScript file (or a const alias of it) is the class
object, `typeof EventEmitter`, `typeof Readable` and ErrorConstructor-
style types map to class values, and parameters, arrays, Map values and
object fields hold them.

Construction through a value calls %C.construct, which builds the
instance with the runtime constructor the direct `new` uses (emitter.new,
a stream's newDyn without options, error.newOptions for Error and its
six standard subclasses). instanceof, typeof, .name and === answer as in
Node. A Duplex value widens into a `typeof Readable` slot, and stream
values widen into `typeof EventEmitter` slots, as the constructor ABIs
match; a union of such class values (`const kinds = [Readable,
Writable]`) is a value of their nearest common ancestor, and `new K()`
through it answers the checker's union of instances. `instanceof`
through a value that may be Writable keeps the Duplex rule at run time.

EventEmitter and stream values constructed with options, runtime class
values stored as untyped values or printed, statics read through a value,
and DOMException, AggregateError, AssertionError and SuppressedError
values report SC1090. The existing static lowerings
(`EventEmitter.setMaxListeners`, `Error.stackTraceLimit`, the events
module) are unchanged. JavaScript files keep the identity token.
2026-10-19 04:48:10 -05:00