for await reads the value of a done result only through the
async-from-sync wrapper; an async iterator's done result is not read.
The source's generator read it for both, so an async iterator whose
done result has a throwing value getter rejected the pipeline. It now
reads and awaits the final value only when the iterator is sync.
With SCRIPTC_CHECKER_SERVER=1 on Linux and macOS, the native compiler's
checker connections go to a shared `tsc-ts --api --listen` server, which
keeps the files it parsed for the next build. When the variable is unset,
nothing changes.
checkerServerName names the server by a digest of the tsc-ts executable's
identity, the working directory, the file system callbacks, the timing
flag and the TSC_TS_* environment. scriptc_ts7_attach takes the server's
lock file with a non-blocking flock, connects to its socket in this
user's private server directory ($XDG_RUNTIME_DIR/scriptc or
/tmp/scriptc-<uid>), and starts the server when none answers: in its own
process group, with its standard streams on /dev/null and no other
descriptor of the build, with --idle-exit 300 and TSC_TS_LISTEN_MEMORY=2048
unless the environment sets it. A build that finds the server in use,
cannot start or reach it, or gets no answer to a ping checks with its own
tsc-ts process, as without the variable; so does a tsc-ts without
--listen, which exits as it starts. The syntax-only source parser, which
reads no libraries, always uses its own process and leaves the server to
the program's checker.
The paired copy's test read the stored and read arrays' headers whatever
the row range, so a nest whose arrays the program assigns only for a
nonempty range dereferenced their NULL headers on an empty range, where
the loop as written never reads them. The overlap tests now run only
when the nest has at least two rows, and an array that is not there
answers that it is not disjoint, so the loop runs as written.
The run-time resolver parsed package.json as it read it, so a file that
starts with a UTF-8 byte order mark failed to parse and computed require
and require.resolve ended with the invalid-package-config refusal. Node's
reader skips the mark; the resolver now does too.
The corpus program writes the package with the marked package.json to a
fresh directory at run time and resolves it by its absolute path, so no
committed file contains the mark.
- A binding that a local class captures counts as written: the class's
methods may assign it while the loop runs, so the call keeps its helper.
- Copied bodies rename the labels of switch and for-of statements and the
binding of for-of loops.
- The known-union and record-temporary cleanups rewrite switch cases and
for-of bodies, where they left declarations of removed locals.
- Copied locals keep their source bindings. In programs that write
contract types, a parameter with a source binding keeps its own local,
so an Int32 parameter is checked against the elements the loop passes.
- A function whose whole body is `return [a, b]` or `return { a, b }`,
with number, boolean or string fields, is now inlined where its result
is only destructured (`const [head, tail] = split(text, at)`). The
parameters are declared from the arguments, then each field straight
into its destructured binding, in the literal's order; an unread field
still evaluates into a binding of its own. No record is built, and a
slice field read only through its length or char codes becomes a
scalar slice that copies nothing. Arguments may own their value, but
as for numeric records nothing inside an argument may hold a
temporary of its own.
- A scalar slice of a proven-ASCII string computes its range inline:
the bounds clamp over the byte length exactly as scr_str_slice_range
does, and no boundary can split a surrogate pair. Other strings keep
the runtime call, which gains the same ASCII fast path.
- value-records' tuples section, `[head, tail] = split(...)` read only
through lengths, goes from two heap slices per step to none.
for await over a sync iterator awaits the value of the result that ends
it too, so a sync iterator that returns a rejected promise rejects the
pump. The source's generator skipped that value and reported success.
It now awaits a final value that is an object (a promise included)
before it stops, without closing the finished iterator.
createPrivateKey decoded a string passphrase as UTF-8 whatever the
options' encoding, so a correct passphrase given in that encoding failed
to decrypt, and an encrypted export read its passphrase the same way.
Both now decode it with the encoding, as Node does.
An RSA-PSS key whose parameters name a digest the runtime does not sign
with, such as sha512-224 or sha512-256, was imported without its digest,
MGF1 and salt restrictions, so it allowed operations the key forbids. It
now throws a coded SC2020 error that names the digest. Parameters that
are malformed still leave the key unrestricted, as OpenSSL reads them.
The packing path for `(T | undefined)[]` rest parameters saved plain
arguments to temporaries but read tuple fields only when it built the
pack, after every later argument had run. A later argument that wrote
the tuple changed values already spread into the call. Each tuple field
is now saved where its spread appears, in argument order.
A server with requestCert read a runtime rejectUnauthorized through
JavaScript truthiness, so null, 0 or "" let clients without a valid
certificate through, and tls.connect read it the same way. Both now treat
only false as off, as Node's options.rejectUnauthorized !== false does; a
standalone TLSSocket keeps Node's truthiness test.
An X509Certificate's methods read the record's raw Buffer, so writing
into the Buffer that certificate.raw answers changed later checks, the
PEM and the public key. The record now keeps a hidden copy of the DER
that the methods read, and raw stays the same Buffer at every read, as
in Node.
A function that reads arguments.length and is called through a value
reads the count its adapter stored, then clears the slot. That read ran
after the parameter prologue, so a parameter binding that threw would
leave the slot set for the next direct call. The count is now taken, and
the slot cleared, before any parameter binds.
Preflight admits a createRequire loader's require.resolve call with a
computed request inside a try block, but lowering refused the call, so
in JavaScript source the whole statement became a runtime fence. The
fence threw before the request expression ran, and before anything else
in the statement: `try { where = load.resolve(candidate(name)); }`
skipped candidate()'s side effects, so the catch clause saw a different
state than in Node.
Such calls (a computed request, another argument shape, or
runtime-computed options, on require.resolve and require.resolve.paths)
now evaluate their arguments in order and then throw the fence, as a
computed require call does. The addon-probe fixture checks that a
computed candidate path runs before each failed lookup.
A hoisted call runs before the rest of its write. An argument such as
`i++` in `acc = acc * 3 + i + tally(i++)` would then move that write
ahead of the write's earlier read of `i`, so such a call stays where it
is and the write is not speculated.
- Checked conversions from dynamic values key their builders and matchers
by the type with `?` after every `(T | undefined)[]`, at any depth.
`number[][]` and `(number | undefined)[][]` share a typeKey, so the
second conversion reused the first one's builder and rejected undefined
elements.
- The dynamic matcher of a `(T | undefined)[]` takes undefined elements,
so a union with such an arm matches arrays that hold undefined.
- An optional-element rest parameter packs tuple-spread values and plain
arguments together as present undefined elements, each evaluated once in
argument order, instead of converting each value to T.
- The element-state scan counts an argument in a rest position that may be
undefined, and a spread tuple with undefined elements, as undefined
elements of the rest array, so reads in the callee check element states.
- A union index read keeps the receiver in a temporary when the key can
assign it, so `a[(a = other, 0)]` reads the array `a` held before the key.
A loop nest that sums one term per row,
for (let i = start; i < end; i++) {
let t = 0;
for (let j = from; j < to; j++) t += term;
out[i] = t;
}
where the term only reads numbers, the counters and typed-array
elements, now runs two rows per pass when both row bounds are int32,
the start is at most the end, and the stored array shares no byte with
any array the term reads. Each row keeps its order of additions, so each
sum has the bits of the loop as written; an odd row count runs its last
row as written, and any other case runs the nest as written. Element
reads that do not depend on the row are read once per column for both
rows. With two independent sums in the inner loop, neither waits on the
other's addition, and LLVM computes both rows' terms in one vector.
bytes.disjoint compares two typed arrays' element ranges in memory.
- Intl.Segmenter accepts an options object literal made only of
`granularity` entries again, including the empty `{}` main accepted;
with none the segmenter is a grapheme segmenter, and a repeated key
takes its last value, as in JavaScript.
- Namespace reads of a CommonJS module refuse a name that any module it
re-exports assigns inside a function, not only the module itself:
Node's namespace keeps the values from the end of evaluation.
- The named-import link check treats `module.exports` as an export every
CommonJS module provides, as Node 24 does, instead of throwing its
missing-export SyntaxError.
- The npm cases cjs-esm-named and cjs-lexer-aligned, which the batch no
longer refuses at build time, are listed with the run-time SC1090 their
CommonJS exports-object reads report.
- A speculated write with hoisted calls resumes over its stored call
results only when its own check failed. Reached in the resume copy
from an earlier write's failed check, its calls never ran on that
iteration, so it now runs as written: the calls happen once and the
arithmetic reads their fresh results.
- A literal divisor is a power of two only when it is exactly 2^k with k
in [0, 52]. Math.log2 rounds 2^52 + 1 to 52, so `Math.floor(v / (2^52 + 1))`
was emitted as a shift by 52.
- A helper expands only when every call in its body is of another helper
that expands, so an expansion never moves a call with effects ahead of
an argument read. Hoisting already refused such writes; the
classification now says so itself.
- A built-in typed-array constructor set as a view's `constructor` is its
own species, as the getter it inherits from %TypedArray% returns it:
`u8.constructor = Float64Array; u8.map(f)` makes a Float64Array. An own
Symbol.species on the constructor still wins.
- TypedArray.prototype.slice with a species constructor creates the
result first and then copies the source's current elements, up to its
current length: a constructor that changes the source is seen.
- Object.defineProperty on a typed-array element reads the descriptor as
ToPropertyDescriptor does, through its getters and in its order, and
throws a TypeError for a primitive descriptor or an accessor with a
value. The generic object path shares the same reader.
`const X = require("crypto").X509Certificate; new X(data)` now resolves
to the builtin class, so the standard-library constructor fence reported
SC2020 for it before the X509Certificate lowering ran. That lowering now
runs ahead of the fence. Corpus 8231 constructs a certificate through the
binding.
`s.unshift("e9", "hex")` on a native stream held as an untyped value
dropped the encoding argument and put the string's UTF-8 bytes at the
front. A byte-mode stream now takes a string chunk with an encoding as the
bytes Buffer.from(chunk, encoding) holds, as Node's
readableAddChunkUnshift converts it, and an unknown encoding throws
ERR_UNKNOWN_ENCODING. Object-mode streams keep the string as the entry.
An instance's `constructor` read that reaches a class prototype's own property now reads it with the
instance as the receiver (Reflect.get), so an accessor's getter sees the instance as `this`, as in
Node, instead of the prototype.
A JavaScript prototype method value runs over the call-site receiver when its private members are
fields (brand-checked reads and writes) or private methods it calls. A private accessor, or a private
method read as a value, would read a public property of the same name, so such a method keeps its
native receiver, as before. A super method call with spread arguments over the call-site receiver
now spreads them into the dynamic call instead of rejecting them.
fs.read and fs.readSync with arguments the compiler could not type
validated the length with `length |= 0` and then converted it again for
the read. A length with a valueOf method ran valueOf twice, and the read
used the second result. Node converts the length once.
scr_fs_read_validate now returns the converted length, and both reads
use it.
- The assert comparison methods read as function values (equal,
strictEqual, deepEqual, partialDeepStrictEqual and their negations)
throw Node's ERR_MISSING_ARGS TypeError, `The "actual" and "expected"
arguments must be specified`, when called with fewer than two
arguments, where `[assert.equal][0]()` passed.
- Untyped `instanceof Object` starts at the value's prototype, so
Object.prototype itself, whose prototype is null, is not an Object.
- Untyped `instanceof Function` follows the whole prototype chain through
objects and functions: an object whose prototype is a function, or a
function whose prototype was set to such an object, is a Function.
A union without recursion builds its matched arm without a visit
session, so its getters and proxy traps ran without marking the
conversion. A nested union then took its arm from the earlier match,
even when the getter returned another value. A getter or trap that runs
during a trusted build outside a session now marks it as well, and the
outermost trusted build clears the mark when it ends.
An optional read tested against a one-unit literal is replaced by a test
of its code unit, built from the read's receiver and index. When that
receiver or index tested a held character local, as in
`src[c === "a" ? pos + 1 : pos] === "b"`, the inner test was kept as it
was and still compared the local as a string|undefined union while the
local's binding became a number, which failed IR validation. The same
held for a held local's own initializer. The receiver, index and temps of
both reads are now rewritten first.
lastIndexOf with a needle of the element type read every non-hole index
as the element type. An undefined or foreign element written through a
dynamic view (or a hole that toSorted turned into undefined) has no
element-typed payload, so the read aborted with "array index N is
undefined". The search now reads an index only when it holds a value,
and skips undefined and foreign elements, as Node's strict equality
does for a string or number needle.
A reference in `export { m }` resolved to the export's alias symbol, not to
the local binding, so the inference did not see the export and typed the
collection from its local uses. An importing module then used it as an
untyped Map and failed to compile (SC9001). An unrenamed export specifier
now resolves to the binding it exports, which refuses the inference as
`export const` does. Corpus 7985 adds `export { listed, renamed as alias }`.
The product of two exact integers was treated as exact everywhere when one
of them was a constant power of two, tested with Number.isInteger(Math.log2).
Math.log2 rounds to 52 for 2^52 - 1, so a product by 2^52 - 1 that passes
2^53 was compared as its integer instead of its rounded double. The test now
compares 2 ** Math.round(Math.log2(value)) with the value. Corpus 7983 adds
products by 2^52 - 1 compared with products by 4.
The string comparison emission test matched only x86-64 `call`
instructions to unprefixed symbols, so on AArch64 and macOS hosts it
counted no calls and failed its positive-count check. It now also matches
AArch64 `bl` and Mach-O's leading underscore, and it runs for the host and
for aarch64-linux-gnu and x86_64-macos assembly, so every host checks all
three spellings.