Commit Graph
6750 Commits
Author SHA1 Message Date
Chris Tate 08c7930958 Support crypto.createECDH and ECDH.convertKey (#1589) 2026-10-20 20:18:22 -05:00
Chris Tate 7ccd9fb3ac Name functions stored in JavaScript object literals as Node (#1591) 2026-10-20 20:17:19 -05:00
Chris Tate f32c309baa Declare function adapter scratch locals in the adapter
A function value whose result is a union of records, assigned to a slot
that returns one record type, lifts each record arm into the slot's
record. The lift declares a scratch local, which went into the function
that requested the adapter, so calling the adapted function failed IR
validation. The adapter body now lowers in its own function context and
the adapter declares those locals.
2026-10-20 20:16:46 -05:00
Chris Tate fae56ff409 Run exec on regular expressions held as any (#1600) 2026-10-20 20:16:04 -05:00
Chris Tate 9eae4af46c Drop the undici shim type test from the TypeScript 5 import allowlist
The test checks the shims with the TypeScript 7 checker and no longer
imports typescript5, so test-ts7 reported its allowlist entry as stale.
2026-10-20 20:08:11 -05:00
Chris Tate a5294f1ec5 Read runtime keys of package enum objects as checked-dynamic values (#1603) 2026-10-20 20:07:13 -05:00
Chris Tate b04166a8f0 Read runtime keys of package enum objects as checked-dynamic values
The enum rewrite turns a package's numeric enum into one object holding
its names and its reverse mapping, so the object's fields have different
types. A reverse read with a runtime key, such as
DiagLogLevel[DiagLogLevel.WARN] in @opentelemetry/api, then failed with
SC1090 ("the declared fields have no one common type").

A keyed read of such a record already answers a checked-dynamic value in
JavaScript files. It now does the same where the checker types the read
'any'. The new npm case tsc-enum-reverse-reads matches Node, as does the
opentelemetry-api case again.
2026-10-20 20:04:06 -05:00
Chris Tate 904b773d0a Adopt thenables in await of untyped values, and read Promise.prototype as a value (#1562) 2026-10-20 19:58:53 -05:00
Chris Tate 4e80351f87 Merge main 2026-10-20 19:53:23 -05:00
Chris Tate aec7758dfb Revert the checked-cast fallback (#1561); keep the optional-chain fix (#1601) 2026-10-20 19:46:23 -05:00
Chris Tate 97e9a10a13 Destructure runtime computed keys from records and checked-dynamic values (#1552) 2026-10-20 19:40:42 -05:00
Chris Tate 5f737e8d9c Await each value of for await over an untyped array (#1599) 2026-10-20 19:39:36 -05:00
Chris Tate ca379c5d14 Run exec on regular expressions held as any
exec on a regular expression held as an untyped value threw "Native RegExp
method has no lowering". It now returns Node's match array: the captures,
with undefined for one that did not participate, then index, input and
groups, or null without a match. Global and sticky expressions read and
advance lastIndex and reset it when nothing matches, as the typed exec
does.
2026-10-20 19:38:31 -05:00
Malte UblandClaude Opus 5.5 ce6be86afb Await each value of for await over an untyped array
A JavaScript array literal that mixes promises and plain values lowers as
a checked-dynamic value, and for await over it took the synchronous
iteration path, binding the promises themselves. It now takes the async
mode of the checked-dynamic loop, which awaits each value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:37:15 -07:00
Chris Tate dffefb4120 Keep missing runtime-key entries undefined in parameter patterns
- The indexed-read prepass now scans parameter patterns with the parameter's type. A function that destructures a missing runtime-key entry of an index-signature record from a parameter (`function pick(k, { [k]: v }: Record<string, number>) { return v; }`) returns undefined instead of throwing a TypeError, nested patterns included.
- Corpus 6492 adds a function, an arrow and a nested parameter pattern; 6492 and 6493 get their per-program cost files.
2026-10-20 19:37:06 -05:00
Malte UblandClaude Opus 5.5 22b9db26b5 Short-circuit optional chains on any values only on the guarded step
`a?.b.c` on an `any` value answered undefined when `a` was present and
`a.b` undefined: every later step of the chain read optionally. Node
short-circuits only on the guarded receiver and throws reading `.c`.

An `any` receiver now makes the tail an optional chain like a dyn one,
and inside the chain's guarded body the consumed `?.` no longer marks
the later dynamic reads optional. (Kept from #1561, whose checked-cast
fallback is reverted.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:36:52 -07:00
Malte UblandClaude Opus 5.5 0cf62ebecf Answer EventEmitter methods read as values off compiled emitters
Reading an EventEmitter.prototype method off a compiled emitter (a program
class extending EventEmitter, or new EventEmitter()) through an untyped
value answered undefined (`typeof o.on`, `const f = o.on; f.call(o, ...)`,
`o.emit.bind(o)`), and EventEmitter.prototype.on in JavaScript was a fence.

Such reads, typed value reads, computed keys, `in`, and
EventEmitter.prototype.<method> now answer the runtime's
EventEmitter.prototype functions, the ones constructor-function emitters
inherit, so `o.on === o.addListener === EventEmitter.prototype.on` and
names and lengths match Node. The first read installs a program dispatch
that those functions call for a compiled emitter receiver; it invokes the
method through the existing untyped dispatch with the call's argument
count (emit forwards up to 16 arguments after the name, then fences).

An untyped emit on, or read of emit from, a class that overrides emit now
fences instead of bypassing the override for the native emit. A subclass
visited under the boxed EventEmitter capsule keeps its own dispatch plan
for values boxed as itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:36:37 -07:00
Chris Tate 121a3ed8f6 Check the optional-record path test's cast at the cast (#1592) 2026-10-20 19:29:13 -05:00
Chris Tate 1f4f7d822f Merge main 2026-10-20 19:27:58 -05:00
Chris Tate 2230ffbb27 Check the optional-record path test's cast at the cast
The test from #1548 casts JSON.parse to Partial<Envelope> into a
block-local const, which continues as its parsed value since #1561, as
in Node. The path messages are now pinned with the cast passed to a
typed parameter, which is checked at the cast, and the block-local form
is pinned against Node.
2026-10-20 19:25:18 -05:00
Chris Tate c812518fb3 Merge main 2026-10-20 19:24:28 -05:00
Chris Tate 35c48c93a6 Name functions stored in JavaScript object literals as Node does
A function stored in a JavaScript object literal's property printed as
[Function (anonymous)] and had an empty `.name`. The property's boxed
function now takes the name Node gives it: a function read by name keeps
that name (`{ f }`, `{ k: f }`), and an anonymous function, arrow or method
takes the property's key (`{ g: function () {} }`, `{ m() {} }`,
`{ 'a-b': () => 1 }`, a computed key that folds to one string).
2026-10-20 19:23:31 -05:00
Chris Tate eac75404d5 Merge main 2026-10-20 19:19:07 -05:00
Chris Tate 2582e46e76 Support crypto.createECDH and ECDH.convertKey
crypto.createECDH returns a native ECDH handle backed by mbedTLS for
prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1,
secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1 and
brainpoolP512r1. generateKeys, computeSecret, getPublicKey,
getPrivateKey, setPrivateKey, setPublicKey and ECDH.convertKey follow
Node 24: compressed, uncompressed and hybrid points, input and output
encodings, the private key range, key pair validation, and Node's error
codes and messages.

Curve names follow OpenSSL's short-name lookup: names of other curves
from crypto.getCurves() are refused at compile time when literal and
throw a coded SC2020 error when computed, other OpenSSL short names
throw ERR_CRYPTO_OPERATION_FAILED, and unknown names throw
ERR_CRYPTO_INVALID_CURVE. Calls whose arguments no @types/node overload
accepts, and computeSecret(view, encoding), are refused at compile time.

The runtime unit scr_ecdh.c links, with the mbedTLS archive, only into
programs that use ECDH. wasm32-wasi builds refuse it.
2026-10-20 19:17:05 -05:00
Chris Tate f63e99a7de Name the spread expression in not-iterable errors for values held as any
Spreading a value held as any that is not iterable into an array literal
threw `TypeError: value`. It now throws V8's message, which names the
spread expression: `x is not iterable` for an identifier or property path,
through parentheses and type assertions, and `f is not a function or its
return value is not iterable` for a call of one. for...of and array spread
share the helper that spells it.
2026-10-20 19:10:56 -05:00
Chris Tate 222ea51bd8 Keep missing runtime-key entries undefined in nested module-scope patterns
- The indexed-read prepass now visits nested object patterns with the nested element's own type. A module-scope binding from a missing runtime-key entry of a nested index-signature record (`const { limits: { [key]: limit } } = config`) holds undefined instead of throwing a TypeError, with or without a default for the nested source.
- Corpus 6492 adds both nested forms.
2026-10-20 19:09:12 -05:00
Chris Tate 50f93d0be0 Merge main 2026-10-20 19:05:22 -05:00
Chris Tate f1d694b47b Move the emitter's loop optimization state into loop-state.ts
LlEmitter's field list and constructor are where most concurrent edits to
emitter.ts collide. A feature now defines its state in its own file with
defineModuleState (emitter-state.ts) and reads it through the returned key,
so it no longer edits the class. The loop optimizations' twelve fields and
their per-function setup move to loop-state.ts; the emitted IR is unchanged.

scripts/split holds the transforms used for the emitter and lowering
splits, and rehome-split.mjs, which carries an open branch across a split.
2026-10-20 18:58:42 -05:00
Chris Tate f7e8d7c490 Compile import cycles whose class is reached only after initialization (#1495) 2026-10-20 18:55:01 -05:00
Chris Tate 4a90c59cf3 Await a synchronous iterator's final value in for await
for await over a synchronous iterator held as any reads and awaits the value
of the result that finishes the loop, as the async-from-sync iterator does, so
a throwing value getter or a rejected promise there rejects the loop.
2026-10-20 18:49:56 -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
Malte Ubl c76892dc74 Revert "Continue a failed checked cast with its value in a dynamic tail (#1561)"
This reverts commit 6bb2711c4b, reversing
changes made to cd833e68a4.
2026-10-20 16:42:01 -07: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 3df33dc0ab Keep the process.versions scan flag on the lowerer (#1579) 2026-10-20 18:38:46 -05:00
Chris Tate 32630717ed Return the Set from add() when its result is used (#1523) 2026-10-20 18:36:59 -05:00
Chris Tate c5eb832ef1 Keep the process.versions scan flag on the lowerer 2026-10-20 18:36:38 -05:00
Chris Tate 9baa93b799 Keep missing runtime-key entries undefined at module scope, and check nullish sources before runtime keys
- The indexed-read prepass now treats a computed pattern key like the name it folds to, and a runtime key over a record with no declared fields as an index-signature read. A module-scope binding from a missing entry (`const { [name]: v } = table` over `Record<string, number>`) now holds undefined instead of throwing a TypeError.
- An object pattern over a checked-dynamic value whose first key is computed at run time checks the source first. A null or undefined source throws a TypeError before the key's expression runs, as in Node. In JavaScript declarations whose source V8 can spell, the message is Node's ("Cannot destructure 'f(...)' as it is null.").
- Corpus 6492 adds a module-scope missing entry; 6493 adds nullish sources in front of side-effecting keys, including a nested pattern and an element default.
- The retired-engine-2104 diagnostics snapshot drops the refusals of `const { [key]: got } = src` over an `any` source, which now compile. The remaining refusals are unchanged.
2026-10-20 18:34:42 -05:00
Chris Tate 710d203a97 Shrink the array header to 48 bytes (#1489) 2026-10-20 18:30:40 -05:00
Chris Tate f3da708774 Compile polyfill packages that are Node builtins as the builtins (#1458) 2026-10-20 18:28:42 -05:00
Chris Tate a24542e772 Keep inferred Promise.prototype bindings checked-dynamic in TypeScript
The checker types Promise.prototype as Promise<any>, so an inferred binding
of it, a module const or a local, inserted a promise check against the
ordinary object and threw a TypeError at initialization. Such bindings,
including promise.constructor.prototype, now stay checked-dynamic in
TypeScript as they already did in JavaScript, and corpus 6590 covers them.
2026-10-20 18:26:08 -05:00
Chris Tate 5b20bf1e77 Merge main 2026-10-20 18:25:49 -05:00
Chris Tate 7f777f36a3 Carry runtime-decided dns.lookup answers dynamically, dial Node-typed net lookups, and keep tsc enum exports undefined until assigned (#1528) 2026-10-20 18:25:22 -05:00
Chris Tate 90315ca7ea Bind builtin static functions and read Buffer.alloc, fs.realpathSync and String methods as values (#1553) 2026-10-20 18:21:56 -05:00
Chris Tate 74633db92f Merge main 2026-10-20 18:21:35 -05:00
Chris Tate 71a5f2c02c Compile SDK-declared data types, any-valued members and Pick views of classes (#1466) 2026-10-20 18:18:56 -05:00
Chris Tate 6ec7e4e4a0 Keep each runtime benchmark workload in its own file (#1570) 2026-10-20 18:18:31 -05:00
Chris Tate 8ba4208ca5 Build the Node compatibility backlog from the ledger instead of committing it
node-v24-backlog.json is a pure function of the committed ledger, and only
the backlog command read it. Its summary counts changed with every
classification change, so concurrent compatibility changes conflicted on
them. pnpm node-compat:backlog now builds the backlog in memory from
node-v24-internal.json with the same output, the generator no longer
writes the file, and the local check fails if a merge brings it back.
2026-10-20 18:17:57 -05:00
Chris Tate 18400d098d Sort the runtime feature lists (#1569) 2026-10-20 18:17:35 -05:00
Chris Tate 4e5864bed4 Iterate generators from Symbol.asyncIterator and check return() results in for await
A Symbol.asyncIterator method that returns a compiled generator is iterated
instead of refused. Async yield* awaits a synchronous delegate's final value,
and return() results that are not objects throw V8's TypeError, which names
primitive results. The coverage fixture drops its async yield* example, which
now compiles.
2026-10-20 18:16:20 -05:00