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.
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).
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.
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.
- 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.
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.
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.
- 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.
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.
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.
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.
The stream probes for untyped values (pipe destinations, pipeline
stages, readline input and output, and the checks against the stream
classes) read the vtable word of any boxed object. Instances with a
class id in the rc word have no vtable word, so a hierarchy instance
whose first field is a number crashed those probes. scr_stream_vt_of
answers NULL for them, and each probe treats that as no stream.
workloads.json listed every workload in one array, and its README table
listed them in one hand order, so changes that each added a workload
appended at the same place and conflicted. Each workload is now a JSON
file in benchmarks/runtime/workloads/ named after it, read through
benchmarks/runtime/workloads.mjs by the bench runner, the zero-cost
gate, the strace script and the dynamic-tier test, ordered by category
and then name. The loader still reads workloads.json in a checkout from
before this change, so the gate can compare against one. The README
table follows the same order.
hot-shots, a StatsD client compiled from its JavaScript, failed when a
program constructed a client. Each gap on its UDP path is closed
generically:
- Sloppy-mode functions with named parameters may read `arguments`
where the aliasing of their parameters cannot show: only
`arguments.length`, or element reads without parameter or element
writes.
- An `any` slot admits any boxable function value, including functions
with optional parameters (`C.prototype.m = function (...)` through an
untyped receiver).
- In a JavaScript file TypeScript does not check, a prototype method
takes its documented parameters as checked-dynamic values, as
constructors already did.
- JavaScript dgram sends run completion callbacks, buffer lists,
connected sends and the six-argument offset/length form.
- A dgram socket crosses into the checked-dynamic tree as a handle
(SCR_DYNH_DGRAM_SOCKET) whose methods are function values, with
untyped listeners that survive 'close'. The handle lives in its own
runtime unit (scr_dgram_dyn.c, the dgramDyn feature), linked only
when a program converts a socket to or from an untyped value.
- `String.prototype.concat` on strings, and `parseInt` over a possibly
missing or untyped value in JavaScript.
Corpus programs 6590-6596 and the hot-shots-udp npm
case (hot-shots 8.5.0 vendored) match Node in both lanes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When an operand of a bitwise operator is a hoisted optional boolean, the
operands evaluate into temporaries before the operation. A left operand
that is safe to repeat, such as a variable read, kept its place in the
operation while the right operand's temporary ran first, so a right
operand that assigns that variable changed the value the left operand
read: `seen ^ (seen = !seen)` gave 0 where Node gives 1.
The left operand now takes a temporary whenever the right one does, so
both evaluate in source order. The corpus program covers an assignment
in the right operand of ^ and <<.