Commit Graph
2626 Commits
Author SHA1 Message Date
Chris Tate 6a658c6ae3 Compile the remaining safe-fetch shapes: Promise<never> race entries, typed Array(n).fill, narrowed header entries, lookup option unions and CommonJS export aliases (#1521) 2026-10-20 09:38:23 -05:00
Chris Tate cb99a06fe5 Shadow the export alias only in the scope that declares it again
The export-alias rewrite skipped a whole function when a let or const
anywhere inside it declared the alias's name, so the function's other
references to the alias kept the alias name after its declaration was
removed. A function now shadows the alias only through its parameters,
its own name, its vars and the declarations directly in its body; a
block, case block, catch clause or for loop shadows it through its own
declarations, and the walk skips just that scope.
2026-10-20 09:35:14 -05:00
Chris Tate 39e3b4a5dd Adopt thenable entries and place tuple slots by position in mixed Promise.all
- A checked-dynamic entry of a tuple Promise.all goes through
  PromiseResolve (`dyn.promiseResolve`): a native promise is itself, a
  thenable adopts its settlement through its resolve job, and any other
  value fulfills. Before, a thenable fulfilled the slot with the object.
- Tuple fields read their entry by position. Shape fields are sorted by
  name, so tuples of more than ten entries paired fields with the wrong
  entries.
2026-10-20 09:34:19 -05:00
Chris Tate 90ff0af5b7 Merge main 2026-10-20 09:33:27 -05:00
Chris Tate 53f41e1a09 List an error's own name where it was created (#1482) 2026-10-20 09:31:04 -05:00
Chris Tate e6ca194308 Merge main 2026-10-20 09:26:26 -05:00
Chris Tate c4ce357a9e Merge main and answer false for fixed-parameter function patterns that need more arguments
- Merge origin/main (e1c27176a).
- matchInferSignature answers false when a function needs more arguments
  than a fixed-parameter pattern passes, as TypeScript's assignability
  does (corpus 6398).
- Record corpus costs for the programs this change adds.
2026-10-20 09:24:29 -05:00
Malte UblandClaude Opus 5.5 2081aaa721 Compile readable-stream 3.x as Node's stream module too
readable-stream 3.x is a copy of Node 10's streams. Like 2.x and 4.x it
now compiles as node:stream: readable.js as stream.Readable carrying the
stream classes, Stream, finished and pipeline, and lib/_stream_*.js as the
matching builtin classes. Unlike them, this is not the package's own
READABLE_STREAM=disable mode, which throws on Node 24 (it Object.assigns
every stream export onto stream.Readable, which inherits the getter-only
`promises` accessor). The limitations and dependencies pages and the
compatibility notes say so.

The corpus program readable-stream-3 runs the vendored 3.6.2 under Node and
keeps to behavior its streams share with the builtin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:22:27 -07:00
Chris Tate 575f6491f4 Fix silent wrong output: object identity, Object.prototype values, Date parsing, stored builtins (#1336) 2026-10-20 09:18:37 -05:00
Chris Tate 56de47defc Check programs with tsc-ts by default (#1353) 2026-10-20 09:12:30 -05:00
Chris Tate 0ccb58943a Compile esbuild's lazily initialized ES modules; select @types-typed and untyped dependencies by default (#1422) 2026-10-20 09:06:46 -05:00
Chris Tate 68a3d8f846 Merge main 2026-10-20 09:06:21 -05:00
Chris Tate 7d555c4cf3 Merge main 2026-10-20 09:04:02 -05:00
Chris Tate 55f4eaca5b Merge main 2026-10-20 09:02:52 -05:00
Chris Tate 7cd7b483bf Merge main 2026-10-20 09:02:06 -05:00
Chris Tate ee33951924 Refuse returns a generic callback's inferred result would drop members of (#1507) 2026-10-20 09:01:42 -05:00
Chris Tate 58c858338a Iterate class instances whose Symbol.iterator is a generator method (#1405) 2026-10-20 09:01:06 -05:00
Chris Tate 9e54b4a198 Merge main 2026-10-20 09:00:02 -05:00
Chris Tate f1d78a48b5 Merge main 2026-10-20 08:59:06 -05:00
Chris Tate d850e14d50 Refuse dropped members through conditional and satisfies returns
The refusal of callback returns that the inferred result type would cut
down found the return by walking up through parentheses and await only,
so a return inside a conditional's branch or a `satisfies` expression
converted silently and lost the extended members. It now walks through
every parent whose value can be the expression's own: parentheses,
await, satisfies, non-null assertions, conditional branches, the
operands of ??, || and &&, and the right operand of a comma.
2026-10-20 08:58:50 -05:00
Chris Tate acf8b28f40 Merge main 2026-10-20 08:57:09 -05:00
Chris Tate da4f131651 Merge main 2026-10-20 08:56:12 -05:00
Chris Tate f31f856783 Convert object literals with accessors to unknown again (#1506) 2026-10-20 08:55:35 -05:00
Chris Tate 8a40fb5a9c Compile the packages an import()-loaded module requires; compile TypeScript enums in packages (#1517) 2026-10-20 08:55:04 -05:00
Chris Tate 02fc8ab13c Keep one process-stream Writable per descriptor and never end it from a pipe
Under the general stream representation, every conversion of
process.stdout or process.stderr into a Writable slot made a new stream,
so two NodeJS.WritableStream slots holding process.stdout compared
unequal and kept separate listeners and writable state. A pipe into such
a slot also ended the converted Writable at the source's end, so later
writes through the slot failed; Node never ends process.stdout or
process.stderr from a pipe.

scr_stream_stdio_writable now keeps one Writable per descriptor and
thread, released at exit. Under the general representation, a pipe into
a Writable slot lowers to readable.pipeGeneral (scr_stream_pipe_general,
last in the stream unit), which keeps end off when the destination is
one of those Writables; programs without the general representation
lower pipes as before.

The fallback stream.Writable's on() and once() overloads for drain,
finish, close and error return the stream again, so listener chains such
as out.on("finish", listener).end(data) type-check.

Adds corpus 6468.
2026-10-20 08:54:18 -05:00
Chris Tate fe589fdddf Run SHA-384 and SHA-512 with AVX2, AVX-512VL or the arm64 SHA-512 instructions (#1464) 2026-10-20 08:53:46 -05:00
Chris Tate 5632decbb9 Skip untaken global-detection arms, and fix the shim test checks
- An if statement whose condition is a global-detection test
  (static-typeof.ts) lowers only its taken arm, unless the untaken arm
  declares a var or function binding. Code Node never runs no longer
  counts as a deferred site, so global-detection-typeof.cjs is fully
  static.
- The resolver parity sweep skips specifiers the package-shim registry
  serves: they resolve to the built-in module by design.
- undici-shim-types.test.ts joins the TypeScript 5 import allowlist.
- node-types-timers uses a 200 ms timer, so the immediate runs first on
  a loaded machine as well.
2026-10-20 08:52:39 -05:00
Chris Tate ea6b51fdf1 Merge main 2026-10-20 08:52:14 -05:00
Chris Tate b281d36264 Merge main 2026-10-20 08:51:23 -05:00
Chris Tate 8e87f6f9ef Resolve const aliases when deciding a child stream's setEncoding state
An untyped child-stream 'data' listener takes strings when a setEncoding
call on the same stream precedes it. A const alias of an access path
(`const out = child.stdout`) now resolves to that path, so a setEncoding
through one alias and a listener through another, or through the stream
itself, agree. A setEncoding on another receiver that can hold the same
stream (a let copy, a parameter, a call result) leaves the state unclear
and reports the existing SC1090. Receivers that name different members
of one root, or two const roots each initialized by a call or new, are
treated as different streams.
2026-10-20 08:49:48 -05:00
Malte UblandClaude Opus 5.5 8284e61f1e Add corpus programs for JavaScript stream objects in NodeJS stream slots
6480 passes a plain object, a constructor-function stream and a native
Readable through a NodeJS.ReadableStream function and consumes them in
TypeScript (on("data"), pipe()) and JavaScript, including identity and a
native pipe into JavaScript sinks. 6481 covers NodeJS.WritableStream
slots and a copy helper across native and JavaScript sources and
destinations. 6482 covers the helper shapes real code writes: an async
producer, pipe with { end: false } and unpipe, pause/resume/setEncoding,
an optional destroy through an intersection type, for await and pipeline
over native values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 06:49:37 -07:00
Chris Tate ce5e4294ad Merge main 2026-10-20 08:49:25 -05:00
Chris Tate 6b708392d7 Merge main 2026-10-20 08:48:08 -05:00
Chris Tate f2f667fffb Use classes that extend EventEmitter or a stream class as values (#1479) 2026-10-20 08:46:00 -05:00
Chris Tate f288ddf707 Merge main 2026-10-20 08:43:43 -05:00
Chris Tate c475aabc2a Refuse arguments to inherited stream constructors from untyped code
Construction from checked-dynamic code (`new F(options)` with F an
untyped value holding a ctor-less subclass of a stream class or
EventEmitter) dispatched to the class's constructor and completed the
arguments against the inherited signature, which takes none here, so the
options were dropped. The checked construction dispatch now reports
those arguments at run time with the message typed construction reports
at compile time, located at the class: a fixed argument count refuses at
the call, and a spread call refuses when its argument list is not empty.
2026-10-20 08:41:04 -05:00
Chris Tate 924d5b96de Merge main 2026-10-20 08:39:29 -05:00
Malte UblandClaude Opus 5.5 465abda816 Compile the remaining safe-fetch shapes: Promise<never> race entries, typed Array(n).fill, narrowed header entries, lookup option unions and CommonJS export aliases
- Promise.race admits a Promise<never> entry (the deadline idiom) under
  any result type: it can only reject, so its fulfillment adapter traps.
  A Promise<never> executor's one-parameter resolve validates against the
  void inner.
- Array(n).fill(v) and new Array(n).fill(v), which the checker types as
  any[], take v's type.
- Object.entries/values over an index-signature record cast to a narrower
  value type check each value into the element type instead of refusing.
- dns.LookupAllOptions and the lookup-function option union that holds it
  (LookupOneOptions | LookupAllOptions | number | undefined) ride
  checked-dynamic storage, and dns.lookup passes a cast of a
  checked-dynamic options value through unchanged.
- npm packages: a CommonJS module that names its export object through a
  variable (`var ip = exports; ip.isPrivate = ...`, the ip package) is
  respelled through `exports`, and tsc output that adds a default-export
  object (`exports.default = { metrics: metrics_api_1.metrics }`, the
  @opentelemetry/api index) keeps its named exports linked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 06:36:48 -07:00
Malte UblandClaude Opus 5.5 205b552104 Return the Set from add() when its result is used
`s.add(a).add(b)`, `s.add(x) === s`, `return s.add(x)` and other reads of
add()'s result were refused with "chained Set method calls": the lowered
add was a void intrinsic. A used result now reads the receiver once into a
slot, adds, and answers the slot, as Map's set() already does. Discarded
results (statements, arrow expression bodies, `void`, for headers, comma
left operands) keep the plain intrinsic, so existing programs compile
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 05:41:23 -07:00
Malte UblandClaude Opus 5.5 db68255cbc Read typescript-go's unreadable match-or-empty unions through their widened members; compile tuple spreads, Stats arrays, primitive then handlers and fielded error inspection
- `s.match(re) ?? []` / `|| []` made typescript-go's API panic whenever the
  union's members were serialized (the empty literal is a tuple clone
  without tuple data), poisoning the statement with SC0004. The members
  of the union's widened type are readable and describe the same values,
  so constituent reads answer with them; the empty tuple beside a match
  array is one of its values. `checker-panic-tuple.ts` compiles and moves
  to the corpus.
- Spreading a fixed tuple into an array literal copies its positions
  into the literal's element type.
- fs.Stats values are an array element kind, so `Promise.all` over
  `stat()` promises and `Stats[].reduce` compile.
- `.then(String)`, `.then(Number)` and `.then(Boolean)` over a number or
  boolean settled value convert it through an interned closure.
- Inspecting (util.format, %s, util.inspect) an Error-typed value whose
  runtime class declares fields prints the stackless base with Node's
  constructor-name header (`[Bailable [Error]: m]`) and the own
  properties, `[Bailable [Error]: m] { bail: true }`; it was refused. A
  subclass whose own fields cannot render (functions, or a field Node's
  error inspector treats specially) throws a named refusal on its own
  instances only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 05:17:42 -07:00
Malte UblandClaude Opus 5.5 256b7cd112 Inspect program-declared Error subclasses with Node's constructor-name header
Inspecting (util.format, %s, util.inspect, console) a value of an Error
class whose hierarchy contains program-declared subclasses was refused:
errorRenderable counted the subclass layout's repeated builtin prefix
fields (name, message) as declared fields. Those are the runtime slots
the error base already renders, so field-less subclasses now render.

The runtime builds the stackless base from the instance's `name`
(`[Error: m]`); Node's improveStack also names the constructor. Each
program class (most derived first) is an instanceof arm applying that
rule: `[Plain [Error]: m]`, or `[FetchFailedError: m]` when the
constructor name contains the error's name. Runtime error classes keep
their own header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 05:04:46 -07:00
Malte UblandClaude Opus 5.5 b9aaaa9d8c Answer server.address() with the socket path for Unix-socket servers
Node answers a Unix-socket server's address() with its path. Programs
that call listen() with a string argument now get a Unix-aware
address(): typed `string | AddressInfo | null` (the @types/node
declaration), it answers the path; typed as the AddressInfo record alone,
which cannot hold the path, it throws for such a server, as does the
composed address().port read. Every other program keeps the record-only
lowering, so their output is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:45:43 -07:00
Malte UblandClaude Opus 5.5 447e9bf000 Compile Transform option callbacks and loosely typed child-process listeners
@types/node types the transform/flush completion callback's data as any
and a child stream 'data' chunk as any, and ChildProcess accepts
(code: number, signal: string) exit and close listeners through its
catch-all overload. None of these compiled: the any-typed completion
callback crashed the LLVM emitter, and the child listeners were refused.

The completion callback's data parameter is typed Buffer | string |
undefined while the option callback lowers. Child stream 'data' listeners
with an unknown or any chunk box it as a checked-dynamic value, taking
strings when a setEncoding statement on the same stream precedes the
listener and Buffers when the function never calls setEncoding on it;
other placements are refused. Exit and close listener parameters declared
number or string bind as checked-dynamic values, so the body sees the
null Node passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:16:06 -07:00
Malte UblandClaude Opus 5.5 17220de52c Merge ctate's code-slot sync into opt/override-variance-error-expando
Brings in the review merge and "Keep an Error's code slot in step with
dynamic writes and own properties". With main's split, `'code' in err`
(now the runtime's error.hasCode) lands in expressions/relational.ts.
Corpus 6417-error-code-dynamic-writes renumbers to 6415 (main has its own
6417), and the corpus-cost entries of 6407/6408 follow their renumbering
to 6412/6413.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:05:42 -07:00
Malte UblandClaude Opus 5.5 835f6baed8 Refuse untyped promisify originals with own properties
Node's promisify copies the original's own property descriptors and
prototype onto the wrapper and consults util.promisify.custom. The
runtime wrapper now copies name and length and refuses, with SC2020 where
util.promisify runs, an original with any other own property, instead of
returning a wrapper that lacks them. The node24-util-adapters npm case
now gets past its promisify scenarios and stops at an unrelated deferred
Object.create refusal; its known state records that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:29:12 -07:00
Malte UblandClaude Opus 5.5 ac6b5ebe97 Throw a record extended by Object.assign as a checked-dynamic copy
`throw Object.assign(failure, { bail: true })`, where the record's type
lacks the source's member, used to fall to the Object.assign fence: a
fixed record cannot grow a field. As the operand of a throw, the call now
copies the target into a checked-dynamic object and adds the source's
members. The copy is unobservable, because control leaves with the throw
and nothing on that path reads the target again. Paths that already
lowered run first, so no compiled program changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:24:23 -07:00
Malte UblandClaude Opus 5.5 95b2f81716 Pipe into untyped destinations by unwrapping boxed native streams
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:24:08 -07:00
Malte UblandClaude Opus 5.5 18034065d6 Compile the packages a module loaded through import() requires
A workspace package loaded on demand had its npm dependency selected, but
the selection never scanned that dependency's own JavaScript: it is
outside the startup module order, so a compiled CommonJS dist requiring a
sibling package was refused with "the module is not supported yet". The
scan of the import() graph now follows opted-in package JavaScript through
its literal require() and import edges.

The lowering appended those modules by their import declarations only, so
a CommonJS file's requires never joined the compiled graph and their
bindings stayed fenced. Preflight's resolved module edges, require edges
included, now reach the walks that append import(), fork() and Worker
modules, with lazy requires ordered after their module and inline require
cycles answered as at startup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:22:43 -07:00
Malte UblandClaude Opus 5.5 40b80116e4 Merge origin/main into opt/http-socket-path
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:22:28 -07:00
Malte UblandClaude Opus 5.5 1e96179f3a Carry untyped streams, casts, for await and pipeline stages into the general stream representation
An 'unknown' value flowing or cast into a NodeJS.ReadableStream slot and
'for await' over one now select the general representation, where the
checked cast to Readable applies. pipeline() stages that arrive untyped
unwrap boxed native streams at run time. @types/node's zlib interface
declarations map to the runtime Transform.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:13:15 -07:00