Widening an array or union of object literals gives each literal an
optional `undefined` member for every property only its siblings
declare. A record shape took its key order from the checker's member
list, where those members sit wherever the checker put them: TypeScript
7.0.2 by the literal its checker widened first, TypeScript 7.1 and
tsc-ts by the sibling that declares them. tsgo and tsc-ts then gave
webassembly-wpt-jsapi.mjs different LLVM IR. The members are never own
keys of the literal's value, so they now follow the declared members,
by name.
Pushes to main now run every lane except macos, so a merged commit no
longer queues the macOS native build, the darwin test slices and the
macOS LLVM artifact jobs. The nightly sweep and manual runs still run
every lane. Pull requests keep running the macOS lane when
scripts/ci-lanes.mjs selects it.
- The iOS runtime pack builds move from mobile_runtime_packs (linux lane)
to mobile_runtime_packs_ios (macos lane), since they run on macOS
runners. The Android pack stays in the linux lane.
- The macos_full dispatch input is replaced by macos_suite (full or
darwin, default full). Manual runs run the complete macOS suite unless
macos_suite is darwin.
- ci-lanes.mjs also selects the macos lane for paths naming kqueue, the
runtime's platform header, and every file of the darwin suite in
scripts/ci-test-plan.mjs (adding tests/harness/differential.test.ts
and the darwin runtime pack's archive test).
- The required test check counts a skipped macOS job as passing when the
macos lane is off, as it already did for pull requests.
The frontend calls tokenStartOfNode, getTextOfNode, getSourceFileOfNode and
forEachChild instead of AstNode's position and traversal methods. Node lists
answer hasTrailingComma(), and a declaration's modifiers are a modifier list
with their flags.
Symbol, Type, Signature, IndexInfo, TypePredicate, Program, TypeChecker and
Diagnostic have tsc-ts/api's members and types. Compiler code reads symbol
names with symbolName(symbol).
tsc-ts goes to 0.0.5. api-conformance.ts asserts that AstNode, AstNodeList,
SourceFile and each node interface are assignable to tsc-ts/api's interface of
the same name, and names the members where the wire format differs.
A key forwarded through functions with several call sites made the search
visit every call path. Each search now visits a local once, and a local
keeps its answer: true once a search reached a key that can be "stack"
from it, false once a search that found none passed it.
The fixture's launch() helper calls run().then, which used to be the
first statement these programs fenced at (SC1090). It compiles since
#1503, so node24-web-stream-pipe-abort and
node24-web-stream-readable-lifecycle now stop at 'new ReadableStream'
and node24-web-stream-tee at 'ReadableStream.tee', which have no
lowering (SC2020).
A constructor-function stream now reads `_final` and `_flush` when its
writable side finishes, and `_transform` for each chunk, as Node does. A hook
assigned after `Writable.call(this)` or `Transform.call(this)` runs, and an
override of a PassThrough's `_transform` replaces the pass-through. Without
`_final` or `_flush` the finish continues as Node's does.
A runtime stream passed to a constructor-function stream's listeners, such
as the source of a 'pipe' event, is the view whose pipe and unpipe accept
constructor-function streams, so `src.unpipe(this)` in a 'pipe' listener
unpipes instead of throwing.
The backend can emit scr_wasm_memory_construct, scr_wasm_table_construct,
scr_wasm_global_construct, scr_wasm_construct_without_new,
scr_wasm_module_imports, scr_wasm_module_exports,
scr_wasm_module_custom_sections and scr_wasm_value_of (#1410), and
scr_stream_dyn_native, scr_stream_pipe_dyn and scr_stream_unpipe_dyn
(#1524). Their prototypes were in scr_wasm.c or nowhere, so the runtime
ABI guard failed. They are now in scr_wasm.h and scr_stream.h, and
scr_wasm.c no longer repeats the header's declarations.
The speculative-hoisting test relied on `v instanceof Num` in a
JavaScript function failing, which constructor-function instanceof now
compiles (#1512). Its hoisted function reads the prototype through
Reflect.getPrototypeOf instead, which still fences.
With checked-dynamic stream slots, readable.unpipe() also unpipes every
JavaScript destination stream.pipeDyn registered from the source, oldest
pipe first. Each destination hears 'unpipe' and the source pauses, as in
Node's unpipe(), which empties every pipe. Before, those pipes stayed
attached and later chunks still reached them.
pipe() into an untyped destination now comes from main's pipeIntoDyn
(stream.unboxDyn); programs with constructor-function streams unbox
through scr_dyn_builtin_stream.c, which also takes those streams, so the
separate dyn.builtinStreamPipe entry point is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bundled npm code (from2, bl, tar-stream, yazl, multistream) builds its
streams as ES5 constructor functions: util.inherits(Ctor, Readable) and
Readable.call(this, opts), with _read/_write/_transform on the
prototype. Readable.call(this) threw SC2020.
A new runtime unit, scr_dyn_builtin_stream.c (feature
dynBuiltinStream), gives the untyped stream constructors their stream
half. Base.call(this, opts) creates a runtime stream over the receiver
and keeps it in a hidden slot; the runtime calls the receiver's
underscore methods through its property lookup; the stream prototypes
carry Node's methods and accessors over the hidden stream; and
EventEmitter's methods register listeners with the runtime stream's
emitter, so runtime events and pipes reach JavaScript listeners with the
receiver as this. _readableState/_writableState are live views.
Stream class values now come from dyn.builtinStreamClass, so only
programs that use them link the stream half. Typed code sees these
objects as their runtime streams: checked casts to the stream classes
take them, readable.pipe() into an untyped destination pipes into them,
and runtime streams crossing into JavaScript answer the constructor
object.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
readMemargFlags took its reader as a `{ u32(): number }` record, and the
validator (Reader) and translator (WasmCursor) pass class instances. The
self-hosted compiler refuses a class instance in a record-typed parameter
(SC2002), so the self-hosted LLVM emitter, the native frontend programs
and the bootstrap seed builds failed. readMemargFlags now takes the
reader's u32 function, and each caller passes `() => r.u32()`.
Object.fromEntries(...) as T passed the entries through the
checked-dynamic bridge, which copies native arrays and records: an array
shared by two entries, or held elsewhere, became separate copies, and
writes through the asserted object no longer reached it. The bridge now
applies only when the entries' values are scalars or checked-dynamic
values, which pass by value or by identity; other entries keep the
exact-shape fence (SC2002). Corpus 6467 checks that entries held as
unknown keep their identity; diagnostics fixture
fromentries-aliased-entries.ts pins the fence.
The bakeability check tracks the unions it is inside as well as the
records, so a union reachable from itself through an array
(`type Tree = number | Tree[]`) reports SC1090 instead of recursing without
end. The message names both recursive records and recursive unions.
- Merge origin/main (e9fb01603); the import lines at the top of
lowerer.ts conflicted and both are kept.
- Corpus 6385 gains a wrapper whose block-local `args` alias shadows an
outer one in the same function; each call forwards its own arguments.
- EventEmitter.defaultMaxListeners on the untyped constructor is Node's
accessor over the default the typed EventEmitter reads: assignments
validate as validateNumber(arg, 'defaultMaxListeners', 0) does, and
getMaxListeners() of emitters without their own limit answers the new
value.
- dyn.builtinInstanceOf and dyn.functionInstanceOf link the
constructor-function unit and the units it calls (dyn-invoke, inspect,
symbol, emitter), so a program whose only use is `this instanceof F`
links.
- The legacy pipe's cleanup runs once: when the destination emits
'close' from end(), the cleanup still queued on the source's 'end'
finds the listeners removed and emit('end') answers true.
pipe() called from untyped JavaScript on a native stream went through
scr_stream_pipe directly, so a helper that piped into the converted
process.stdout or process.stderr ended it at the source's end, and later
writes through the program's NodeJS.WritableStream slots failed. The
stream view's pipe now calls scr_stream_pipe_general, which keeps end off
for those Writables, as Node's pipe() does for process.stdout and
process.stderr.
Adds corpus 6469.