Commit Graph
413 Commits
Author SHA1 Message Date
Chris Tate 1221104388 Merge main and fix CI 2026-10-23 07:50:09 -05:00
Chris Tate b6d6eb60ae Replace a scheduled _construct hook, and keep runtime option values in order
Node's constructNT reads _construct on the construction tick, so an
assignment after the constructor and before that tick replaces a scheduled
construct hook. The assignment was dropped, so the original hook ran. It
now lowers to stream.replaceConstruct, which swaps the hook while its tick
has not run and has no effect after it or on a stream without a hook.

Runtime decodeStrings and defaultEncoding values are read into locals
before the constructor evaluates the other option members, while Node
evaluates the members in order. A runtime value after a member whose value
has effects (a call or an assignment) now refuses instead of reading a
value that member could still change.
2026-10-23 01:34:19 -05:00
Chris Tate 9dbb16d7f8 Support new.target in class constructors (#1917) 2026-10-22 21:52:42 -05:00
Chris Tate df9f83bbc1 Refuse new.target over function-local subclasses lowered later
Lowering collects a function-local class with the body declaring it, so
a local subclass whose function lowers after its base's constructor was
missing from new.target's dispatch, which then answered with the base for
its instances. The refusal no longer depends on that order: the program's
function-local classes are found once, and one that extends the
constructor's class, directly or through other classes its extends
clauses name, refuses new.target as a collected one does.
2026-10-22 21:47:37 -05:00
Chris Tate 6115135d96 Dispatch new.target over generic subclasses and own static names
A constructor's new.target dispatch skipped generic class families, so a
generic subclass instantiated only in a body lowered later answered with
the base's name, and `new.target === Base` held for its instances. A
family now has its own arm, tested by its instanceof interval, which holds
every instantiation: `new.target.name` reads the family's name and
comparisons with a program class are false. Under an instantiation, the
generic subclasses of its family are candidates too. `new.target` as a
value refuses generic subclasses, which have no common class value.

`new.target.name` reads a class's own static `name` field, which replaces
its name (a subclass has its own name); a static method `name` or a
non-string field is refused.
2026-10-22 21:18:48 -05:00
Chris Tate 8c67f04062 Throw Node's TypeError for class constructors called through call/apply (#1892) 2026-10-22 20:36:01 -05:00
Chris Tate 5966f23bd3 Keep the class-value call fence when a subclass declares a static call
`C.call(...)` through a class value typed as `Base` may run a subclass's own
static `call`, which Node calls instead of the class constructor. The
constructor-call lowering now applies only when no class the receiver can
hold declares a static `call` or `apply`: the class and its bases (any
static member of that name, including accessors, fields without
initializers and computed names), and, for a receiver that may hold a
subclass, every subclass. Otherwise the call keeps its existing
diagnostic.
2026-10-22 20:33:33 -05:00
Chris Tate fbaa71a66f Run the fromEntries aliasing program and drop compiled Iterable entries from the iterator fences
Since Iterable<T> values compile (#1875), two diagnostics fixtures changed:

- fromentries-aliased-entries.ts compiles and prints what Node prints:
  the entries' one array stays shared by both fields. It moves to the run
  corpus as 7440-fromentries-aliased-entries.ts.
- iterator-slot-fences.ts no longer reports its Iterable<number>
  parameter (SC2020) and the call through it (SC2004). That part leaves
  the fixture, which keeps the class-iterator fence; corpus 7380-7383
  cover Iterable values.
2026-10-22 19:54:17 -05:00
Malte UblandClaude Opus 5.5 ac940ed936 Support new.target in class constructors
Inside a class constructor new.target is the class of the instance under
construction. A compiled new allocates the instance with its concrete class
before the constructor chain runs, and the class hierarchy is closed, so
new.target lowers to a static dispatch over the constructor's class and its
descendants (deepest instanceof first). new.target.name reads the exact
class's name and new.target === C is an exact-class test, without a class
value, so subclasses may construct with other signatures. new.target as a
class value requires every subclass to share the constructor's signature.
Plain functions and function-local subclasses keep explicit refusals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 17:43:09 -07:00
Chris Tate f132cf5f39 Compile Iterable<T> values (#1875) 2026-10-22 18:30:45 -05:00
Chris Tate a0c207cc25 Merge main 2026-10-22 18:12:20 -05:00
Malte UblandClaude Opus 5.5 089ec6739b Compile Iterable<T> values
Iterable<T> maps to a union of the sources that keep their own
representation (T[], Set<T>, Map<K, V> for [K, V] entries, string) and a
generator over T that holds every iterator. An array stays the same
multi-pass object; a generator stays single-pass. for-of gives the array
arm its own array loop, so iterating an Iterable that holds an array runs
at array speed. Spread, Array.from, the Set/Map constructors and
Object.fromEntries consume it; optional Iterables narrow into it;
generator functions may declare an Iterable return. Class iterables and
typed arrays are refused at the conversion with a named diagnostic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:00:41 -07:00
Chris Tate 98712c364a Merge main 2026-10-22 17:49:58 -05:00
Chris Tate 4f6c55a8e6 Narrow filter results through written type predicates with checked conversions (#1819) 2026-10-22 17:21:41 -05:00
Chris Tate e4dc0900d7 Fence arguments.length in function expressions that call themselves by name
A function expression stored in a function type with more parameters
folds `arguments.length` to that type's parameter count, the count every
call through the slot passes. A named expression that calls itself
through its own name passes only its declared parameters there, so no
constant answers both calls. Such a read now reports SC1090 with the
reason, and expressions that do not refer to their own name keep the
fold.
2026-10-22 10:09:08 -05:00
Chris Tate 2f3e25b431 Accept Buffer-compatible chunk annotations and keep super(undefined) in byte mode 2026-10-22 08:35:56 -05:00
Chris Tate 12563f720e Compile conditional spreads of several properties and 2026-10-22 07:58:53 -05:00
Chris Tate dd3ea7c00c Narrow filter results through written type predicates with checked conversions
`.filter` with a written type predicate (`(p): p is Cat => ...`, or a
guard function passed as a value such as `filter(isDog)`) was refused with
SC1090, because TypeScript does not check the predicate. An inferred
predicate that keeps several union arms (`v => v !== undefined` over
`(string | number | undefined)[]`) was refused too.

The filter loop now keeps the receiver's element type, and the result
converts to the predicate's type element by element
(filter-predicates.ts):
- a union element to one of its arms, or to a union of some of its arms,
  by its tag;
- a checked-dynamic element by dynCheck;
- a class instance to a subclass by its class;
- a tuple or record to one with the same fields, field by field.

An element the predicate's type does not describe, kept because the
predicate returned true for it, throws a catchable TypeError: "a kept
element is not a 'Cat' (a type predicate returned true for a value of
another type)". The diagnostics fixture filter-narrow.ts, which pinned
the three refusals, compiles now; corpus 7007 covers its cases.

Fixes #1680.
2026-10-22 07:47:03 -05:00
Chris Tate 41ef12e463 Construct builtins through stored constructors and fix function-local class names and dispatch 2026-10-22 06:44:59 -05:00
Chris Tate 3edec984d5 Compile JSX with the classic runtime (#1786) 2026-10-22 06:29:40 -05:00
Chris Tate 8ff58d2810 Match Node for generic arrow bindings used before their declarations (#1773) 2026-10-22 06:19:57 -05:00
Chris Tate df6de14c94 Support new tls.TLSSocket and tls.connect({ socket }) (#1791) 2026-10-22 06:01:47 -05:00
Chris Tate 1360830149 Support new tls.TLSSocket and tls.connect({ socket }) 2026-10-22 04:52:44 -05:00
Chris Tate c47a0e90ae Compile JSX with the classic runtime
Fixes #889
Co-authored-by: papack <33105506+papack@users.noreply.github.com>
2026-10-22 04:27:35 -05:00
Chris Tate b5fb4115e1 Merge main 2026-10-22 03:33:29 -05:00
Chris Tate 70697b45c3 Give generic arrow bindings Node's behavior before their declarations run
Generic arrow and function-expression bindings compile to shared
instances, and their declarations emit no store. Code that can run before
the declaration then diverged from Node.

- Inside a function, a nested function lowered before the declaration
  reads the binding through a TDZ box that nothing initialized. That
  covers closures above the declaration and hoisted function
  declarations. Such a read threw a ReferenceError even after the
  declaration ran. The declaration now stores the instance its declared
  signature pins into that box.
- At module scope, calls and pinned value reads went straight to the
  instances even when a hoisted function or an earlier closure ran them
  before the declaration. A binding with such a use now has a flag that
  its declaration sets.
  - Uses that can run first check the flag.
  - A let or const throws Node's ReferenceError before the arguments
    run.
  - A var runs the arguments and then throws "is not a function".
- Uses that follow the declaration stay direct calls: later statements,
  closures created after it, its own initializer, and function
  declarations that only such code calls.

A var binding inside a function that is called from a place that can run
before its declaration would need a per-call flag shared with its
closures. That shape now fails with SC1090 instead of calling the
instance.
2026-10-22 02:56:39 -05:00
Chris Tate 1773ffbef3 WebCrypto: the crypto global, node:crypto's webcrypto, and secret-key SubtleCrypto 2026-10-22 02:52:01 -05:00
Chris Tateandsaboursepideh 1a240fbf10 Support asymmetric keys, signatures and Ed25519 in node:crypto and WebCrypto
Co-authored-by: saboursepideh <25549001+saboursepideh@users.noreply.github.com>
2026-10-22 02:49:33 -05:00
Chris Tate 10820d488c Support SNICallback in tls.createServer (#1700) 2026-10-21 22:00:41 -05:00
Chris Tate ca446b2c30 Read the tls.createServer SNICallback in source order
The runtime call reads the cert and key options before the SNICallback,
so a cert or key initializer after the callback that reassigned the
callback's binding changed the callback the server used, and the server
could serve the wrong certificate. When SNICallback comes before a cert
or key entry, the callback is now saved just before the next of them is
evaluated. With the callback read in order, a callback expression with
side effects lowers instead of being refused.
2026-10-21 21:56:08 -05:00
Chris Tateandsaboursepideh a7e84cd48c Support SNICallback in tls.createServer
tls.createServer({ cert, key, SNICallback }) hands each ClientHello's
servername to the callback and serves the SecureContext it answers,
synchronously or later, or the default cert and key when it answers none.
An error answer closes that connection. This uses the SNI handling that
http2.createSecureServer already has. A callback expression with side
effects, or SNICallback combined with ALPNProtocols, minVersion, maxVersion
or the other options the runtime walk reads, fails with SC2020.

A tls.connect or https.request client whose peer closes or resets the
connection before the handshake completes now fails with Node's ECONNRESET
"Client network socket disconnected before secure TLS connection was
established" instead of closing without an error.

Refs #1438

Co-authored-by: saboursepideh <25549001+saboursepideh@users.noreply.github.com>
2026-10-21 13:56:07 -05:00
Chris Tateandjlucaso1 d858d840f9 Accept file URL paths in synchronous fs functions
readFileSync, writeFileSync, appendFileSync, statSync, lstatSync,
readdirSync, mkdirSync, rmSync, rmdirSync, mkdtempSync, accessSync,
unlinkSync, chmodSync, chownSync, lchownSync, truncateSync, copyFileSync,
renameSync, realpathSync, realpathSync.native, openSync and opendirSync
accept a file: URL wherever they accept a path. The URL converts as
fileURLToPath converts it, with Node's errors for other schemes, hosts,
encoded separators and null bytes.

Arguments after a URL path that have side effects are evaluated into
hidden locals before the conversion, so they run even when it throws. A
URL path after a string path, or with options that are not literals,
fails with SC2020, because Node checks those arguments before it converts
the URL. existsSync and the fs.promises functions also fail with SC2020
for URL paths: existsSync answers false for a URL it cannot convert, and
fs.promises reports conversion errors as rejections.

Fixes #1616

Co-authored-by: jlucaso1 <55464917+jlucaso1@users.noreply.github.com>
2026-10-21 08:46:44 -05:00
Chris Tate 8b4e74d050 Type empty arrays filled by later writes inside functions by their reads (#1632) 2026-10-21 04:23:15 -05:00
Chris Tate 095acffb46 Compile generic arrow bindings inside functions that use no enclosing frame (#1627) 2026-10-21 02:54:32 -05:00
Chris Tate 3e08632467 Refuse values of generic bindings declared inside functions
Each call of a function makes a new function object for a generic arrow
or function expression bound inside it, so `make() !== make()` when make
returns the binding, and such values are distinct Map and Set keys. The
compiled instances are shared module functions, which cannot give that
identity, so a value use of such a binding keeps an SC1090 fence that
names the reason. Calls of the binding still compile.
2026-10-21 02:51:36 -05:00
Chris Tateandejc3 009a01d074 Type empty arrays filled by later writes inside functions by their reads
An unannotated `const xs = []` (or `let`) inside a function, which
TypeScript types by the elements written before each read, takes the array
type its settled reads have: records pushed in a loop give a record array,
numbers a number[], strings a string[]. Reads inside closures, which the
checker leaves unsettled, do not count. When settled reads disagree or the
binding is reassigned, the binding is a dynamic array, as the same binding
already is at module scope. Before, such a binding was always number[] and
pushes of other values were refused.

Fixes #1623

Co-authored-by: ejc3 <1694850+ejc3@users.noreply.github.com>
2026-10-21 02:40:20 -05:00
Chris Tateandsaboursepideh e3d31c2a65 Answer typed-array member probes and destructure into typed-array elements
A typed array or Buffer in a compiled program is always a built-in kind
(programs cannot subclass them, add own properties or change their
prototypes), so Node 24's prototype chains for them are known exactly.

- A read of a member the type does not declare (in JavaScript, or under
  @ts-ignore) answers undefined when that chain lacks the name, as Node's
  GetV does: the base64 and hex feature probes (`typeof bytes.toHex`) that
  libraries such as @noble/hashes make. Names Node has, including the
  Buffer prototype's members on a Uint8Array that may hold a Buffer, keep
  the fence.
- `"name" in bytes` with a literal member name answers from the same
  chains, and `bytes.BYTES_PER_ELEMENT` is the element size.
- Array destructuring assignment into typed-array elements
  (`[high[i], low[i]] = [h, l]`) evaluates the receiver, the index and the
  value in order and writes the element as `b[i] = v` does.

Refs #1437

Co-authored-by: saboursepideh <25549001+saboursepideh@users.noreply.github.com>
2026-10-21 02:28:56 -05:00
Chris Tateandejc3 89beb65cc6 Compile Math.max and Math.min with spreads among other arguments
Math.max and Math.min with a spread and other arguments (`Math.max(...xs,
5)`) pack their arguments, in order and with each spread flattened, into
one number[] that the runtime folds, as Math.hypot already does. The fold
keeps NaN poisoning, -0 below +0 and the empty fold's infinities, and the
arguments evaluate left to right before it. The refusal hint now names
the supported forms.

Fixes #1621

Co-authored-by: ejc3 <1694850+ejc3@users.noreply.github.com>
2026-10-21 02:17:47 -05:00
Chris Tateandejc3 45d3d02bf0 Compile generic arrow bindings inside functions that use no enclosing frame
A generic arrow or function expression bound inside a function or method
compiles when it uses nothing from the enclosing function's frame: no
`this`, `super`, `arguments` or `new.target`, and no local, parameter or
type parameter of an enclosing function. Its instantiations are module
functions, as for a module-scope binding, and may call the binding itself
and read module-scope bindings. Instances of bindings in functions and
blocks take the declaration's position in their names, so two functions
may declare bindings of the same name. Bindings that use the enclosing
frame keep their SC1090 fence.

Fixes #1624

Co-authored-by: ejc3 <1694850+ejc3@users.noreply.github.com>
2026-10-21 01:58:22 -05:00
Chris Tate e41f642a55 Compile literal-key 'in' over index-signature records, fresh array spread insertions, and any-annotated dictionaries (#1514) 2026-10-20 18:46:29 -05:00
Chris Tate 145268ed55 Inspect program-declared Error subclasses with Node's constructor-name header (#1520) 2026-10-20 18:43:16 -05:00
Chris Tate 71325b2a00 Keep exported const arrays out of fresh spread conversion
Another module can import an exported const (`export const` or an
`export { name }` specifier) and reach its elements, so a spread of it
is not their only reference. Those spreads keep the element-layout
refusal instead of copying the elements.
2026-10-20 18:40:37 -05:00
Chris Tate 3195f98401 Convert a const array spread only when it runs once per initializer
A const initialized by an array literal and spread once can still run
that spread more than once: in a loop body, loop test or update, a
function, or a class field initializer. Each run inserts the same
elements in JavaScript, so copying them into the destination's layout
would break identity. Those spreads keep the element-layout refusal.
2026-10-20 18:11:57 -05:00
Chris Tate b70cadb402 Merge main 2026-10-20 17:56:44 -05:00
Chris Tate a601cba268 Merge main 2026-10-20 14:27:36 -05:00
Chris Tate 178e524662 Compile events.once with an AbortSignal and over streams, and combine Promise.race entries around it (#1531) 2026-10-20 13:04:20 -05:00
Chris Tate 3751afa51f Merge main 2026-10-20 13:02:01 -05:00
Chris Tate e0d14fefaa Merge main 2026-10-20 12:55:55 -05:00
Chris Tate e181687405 Merge main 2026-10-20 12:55:10 -05:00
Chris Tate 19835975ea Bind generic overload calls by the overload's own type parameters 2026-10-20 12:25:57 -05:00