Commit Graph
2195 Commits
Author SHA1 Message Date
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
Chris Tate e1c27176a6 Throw checked-dynamic primitives as primitives so catch typeof tests see them (#1510) 2026-10-20 04:19:32 -05:00
Malte UblandClaude Opus 5.5 b74224f31c Throw checked-dynamic primitives as primitives so catch typeof tests see them
A value thrown from `unknown` storage (`throw values[i]`) that holds a
number, string or boolean now throws as that primitive, like a statically
typed `throw 5`. Before, it threw as a checked-dynamic reference, so
`typeof e === "number"` (and "string"/"boolean") on the catch
binding answered false and the narrowed reads were unreachable. A
primitive has no identity to keep, and reading the binding as `unknown`
converts it back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 00:50:32 -07:00
Chris Tate c8b22e3435 Merge main 2026-10-20 02:40:17 -05:00
Chris Tate d5d9a1185a Compile process.send presence, process.exitCode reads, wider stream hooks, void race entries and promisify of callbacks (#1429) 2026-10-20 02:18:40 -05:00
Chris Tate 391b9ac00e Merge main 2026-10-20 02:15:13 -05:00
Chris Tate d3a567f830 Pass rest-parameter functions into slots with fixed parameters (#1480) 2026-10-20 02:13:34 -05:00
Chris Tate b6ef49d39d Promisify callback-last functions that return a value
The promisified executor typed its call of the function as void, so a
function with a non-void return type failed to compile with SC9001. The
call now has the function's return type, and its value is discarded, as
in Node.
2026-10-20 02:09:48 -05:00
Chris Tate bdf1bb9734 Pass rest-parameter functions into nullable and optional fixed-parameter slots
Structural conversion lifts a function into a union's function arm only
when cleanFuncAdaptable accepts the pair, and it refused every rest
signature. A typed-rest function assigned to `((m: string) => void) |
null`, an optional parameter of that type, or a `| undefined` binding
therefore failed with SC2003. cleanFuncAdaptable now accepts the pairs
the rest packing adapter serves, so these slots use the same adapter as
a plain fixed-parameter slot.

6445 covers the nullable, optional and undefined slots, and 6445 and
6446 get their corpus costs.
2026-10-20 02:06:21 -05:00
Chris Tate f6f4ad1b00 Give errors held as any their own stack accessor (#1450) 2026-10-20 02:05:17 -05:00
Chris Tate d45a542221 Compile esbuild's bundled CommonJS chunks and CommonJS cycles statically (#1411) 2026-10-20 02:00:58 -05:00
Chris Tate 0c3a7ae73e Keep error stacks through computed keys, clones and throwing getters
A read through a computed key now counts as a stack read when the program
contains the string "stack", so `e[key]` captures frames like `e.stack`
does. A key the program assembles from other strings or from data it
reads keeps the static answer.

structuredClone of an error held as `any` copies a stack that was already
formatted as a non-enumerable data property, as it did before the stack
became an accessor.

When a name or message getter throws while the stack is formatted, the
stack accessor propagates the exception instead of reading the missing
string.
2026-10-20 02:00:21 -05:00
Chris Tate 7551434bd7 Support freezing and redefining fields of class instances (#1385) 2026-10-20 01:57:15 -05:00
Chris Tate b8ee250c4a Narrow unions of records by intersection refinements, and keep members an assertion attaches (#1484) 2026-10-20 01:50:19 -05:00
Chris Tate f77298ea82 Merge main 2026-10-20 01:49:45 -05:00
Chris Tate 85d420540d Keep the stored type for annotated asserted bindings
A const annotated with the asserted type (const view: Route & { order: number } = route as Route & { order: number }) took the annotated layout, so the initializer was coerced into it: a width copy that read members the writes had not created yet, and writes through the binding no longer reached the original object. Local and module-level consts now keep the stored type when it hosts the annotation, as unannotated ones do.
2026-10-20 01:46:11 -05:00
Chris Tate 6054b5b5f6 Version typed-array loops on one bounds guard and tag typed-array memory for alias analysis (#1126) 2026-10-20 01:45:49 -05:00
Chris Tate 5a3bd5302b Merge main 2026-10-20 01:39:43 -05:00
Chris Tate 40f6dd25c8 Revert "Give interfaces extending class-backed protocols checked identity" 2026-10-20 01:35:23 -05:00
Chris Tate ca65f57626 Speed up native string character tests, optional-string switches, fromCharCode and long-string length (#1498) 2026-10-20 01:20:11 -05:00
Malte Ubl 25e40afa83 Merge remote-tracking branch 'origin/main' into opt/bc-node-surface 2026-10-19 23:16:41 -07:00
Malte UblandClaude Opus 5.5 8c5d65212a Throw Node's ReferenceError for __dirname in a JavaScript ES module
The read used to defer a refusal, which kept the corpus program from
compiling statically. It now throws Node's catchable ReferenceError
("__dirname is not defined"), and typeof answers "undefined" as in
Node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:11:39 -07:00
Chris Tate ba8849a269 Speed up native string character tests, optional-string switches, fromCharCode and long-string length
`s.charAt(i) === "c"`, and `s[i] === "c"` where the index is proven in
bounds, built a one-character string to compare with the literal. When
the literal is one UTF-16 code unit, the comparison now reads
`s.charCodeAt(i)` and compares the number. charCodeAt converts the index
the same way charAt does, and an index out of range answers NaN, which
equals no unit, as "" equals no one-unit literal. A switch on
`s.charAt(i)` whose case tests are all one-unit literals switches on the
code unit the same way.

A switch on a `string | undefined` value with string literal cases, such
as an array element or an optional field, lowered to a chain of union
equalities. It now tests for undefined, which matches no case, and
dispatches the string through the string switch: by byte length, then by
the literal's leading bytes.

`String.fromCharCode(a, b, ...)` with up to sixteen arguments passes the
codes to the runtime in a stack array instead of a heap f64[], and up to
64 code units encode into a stack buffer instead of a heap scratch block.

`.length` of a string that is not ASCII counts its UTF-16 units. The
string index keeps four entries, so a program that read the lengths of
more long texts than that in turn (the text of every source file) walked
each whole string on every read. Lengths of non-ASCII strings longer than
64 bytes now go into a 1024-slot table keyed by address, allocated by
the first length it records. A slot is dropped when the string is freed
or reallocated and when an append changes it in place, which is where
the index drops its facts.
2026-10-20 01:11:36 -05:00
Chris Tate 9d80738297 Run LeakSanitizer over the sanitized corpus on Linux CI (#1492) 2026-10-20 00:47:53 -05:00
Chris Tate a495dc35a6 Run LeakSanitizer over the sanitized corpus on Linux CI
The Linux test jobs set ASAN_OPTIONS=detect_leaks=0 for both flavors and
left leak detection to the RC audit, which does not see runtime tables
allocated with calloc. A worker thread's record-source table leaked that
way, and only local runs reported it. The san shards' case-sharded corpus
task now sets detect_leaks=1 and an LSAN_OPTIONS suppressions file,
tests/harness/lsan.supp, which starts empty. Plain shards, the side queue,
the Effect jobs and macOS, whose ASan has no LeakSanitizer, keep leak
detection off.
2026-10-20 00:38:58 -05:00
Chris Tate ddc5d50204 Refuse JSON and dynamic copies of object literals with accessors (#1490) 2026-10-20 00:37:25 -05:00
Chris Tate 88f2061f62 Refuse JSON and dynamic copies of object literals with accessors
An object literal with get/set accessors keeps the accessors' closures in
reserved slots of its record. Since function values became convertible to
checked-dynamic values, these records passed the JSON and conversion
checks: JSON.stringify omitted the getter's property, as it omits
function-valued ones, and a copy held as `any` or `unknown` read the
getter's property as undefined and listed the slot's internal name among
its keys. Node invokes the getter in both cases.

Records with accessor slots are now outside the JSON-safe and
dyn-convertible domains, so JSON.stringify of such a value and its
conversion to `unknown` or `any` are refused at compile time. A literal
written directly into an `any` slot keeps its accessors and is unchanged.
2026-10-20 00:31:25 -05:00
Chris Tate 80c760f2b1 Format checked-dynamic arguments under %d and %i as Node does (#1488) 2026-10-20 00:25:46 -05:00
Chris Tate 12d0215c4d Link the child-process unit only in programs that spawn (#1403) 2026-10-20 00:18:21 -05:00
Chris Tate bae0570c2c Format checked-dynamic arguments under %d and %i as Node does
util.format's %d validated a checked-dynamic argument as a number and
threw "expected number" for anything else, where Node prints
Number(arg), and %i of such an argument had no lowering. Both now follow
Node: a bigint prints as `${n}n`, a symbol as NaN, and any other value
as Number(arg) under %d or parseInt(String(arg)) under %i.
2026-10-20 00:17:34 -05:00
Chris Tate 8df5e8d48a Accept readline's dispose, instanceof, dynamic streams and non-string prompts (#1401) 2026-10-20 00:13:26 -05:00
Chris Tate 89625ef91c Borrow typed-array locals read from fields and parameters (#1481) 2026-10-20 00:12:50 -05:00
Chris Tate ac0ae29b18 Construct CommonJS constructor functions imported through a member alias (#1453) 2026-10-20 00:10:40 -05:00
Chris Tate 3944a70017 Compile module exports that pass this on with apply or call (#1444) 2026-10-20 00:09:54 -05:00
Chris Tate 98a7d3b33d Merge main 2026-10-20 00:08:29 -05:00
Chris Tate 5cf51c46b0 Read x.constructor on EventEmitter and stream instances (#1442) 2026-10-20 00:06:32 -05:00
Chris Tate 226ba9672f Borrow typed-array locals read from fields and parameters
A local initialized from a typed-array field or parameter, such as
`const chars = this.chars`, took a reference and released it at the end
of its block, like any owned binding. Class instances, records, arrays
and strings already borrow such a projection when the rest of the block
writes none of the locations it reads, and walk and rebound parameters
use the same test. Typed arrays are one plain pointer as well, so they
now take the same paths: the field or the caller's binding keeps the
array alive while the local reads it, and a block that may replace the
field still retains its own reference.
2026-10-20 00:05:09 -05:00
Chris Tate 59dd6d1742 Read member aliases only while the binding holds the exported value
A member export resolves to its binding only when the binding is declared
before the write and never reassigned, so a consumer reads the value the
member stored. A module that re-exports another module's exports through
module.exports = require("./x") now counts its own writes after the
re-exported module's: a member it adds resolves, and a member both modules
write stays refused. The exports rebinding refusal and its test now cover
the form that stays refused, exports = value without module.exports.
2026-10-20 00:02:49 -05:00
Chris Tate 679227aeb1 Read an Error subclass's own code through NodeJS.ErrnoException (#1471) 2026-10-19 23:59:55 -05:00
Chris Tate 63cb11ff83 Keep DataView's own behavior through unknown (#1470) 2026-10-19 23:59:13 -05:00
Chris Tate b690f8f8f4 Count destructuring and for-of writes of a factory's parameter
A factory's parameter counts as the argument it was called with only
while the factory can't change it. The check saw assignments and updates
of the name, but not a write through a destructuring pattern
(`[body] = ...`, `({ body } = ...)`) or a for-in or for-of target, so a
factory could replace its callback with one that reads `this` and the
call still compiled without the module object.

The parameter now counts as changed by any assignment, update,
destructuring or for-in/for-of target that writes it, by a declaration
of the same name, by a write to an element of `arguments`, and by a call
of `eval`.
2026-10-19 23:56:22 -05:00
Chris Tate d321ea5780 Leave the error marker out of own property names
Object.getOwnPropertyNames, Reflect.ownKeys and
Object.getOwnPropertyDescriptors on errors held as `any` or `unknown`
listed "%error", the key that marks the checked-dynamic error encoding.
Node lists only the error's properties. The marker is now left out of
own property names; the runtime's own checks still read it.
2026-10-19 23:52:46 -05:00
Chris Tate e134489edc Unroll the MD5 block function (#1465) 2026-10-19 23:51:35 -05:00
Chris Tate 21e5e2cd69 Answer in on typed arrays held as any (#1473) 2026-10-19 23:47:59 -05:00
Chris Tate 9fc483b5c6 Box asserted class bindings into class-backed views (#1469) 2026-10-19 23:42:07 -05:00
Chris Tate cdd78b4502 Answer in on typed arrays held as any
`in` on a typed array, Buffer or DataView held as `any` or `unknown`
answered false for every key: indices, `length`, prototype methods and
Object.prototype names.

On a typed array, a canonical numeric key (one that ToString(ToNumber(key))
reproduces, or "-0") now answers by bounds: an integral index, not -0,
below the length, so "1.5", "-0", "NaN" and "Infinity" answer false. Other
keys answer true for members of %TypedArray%.prototype, Buffer.prototype on
a Buffer, the constructors' BYTES_PER_ELEMENT and Object.prototype. A
DataView has no indexed elements and answers DataView.prototype's members
and Object.prototype's.
2026-10-19 23:36:14 -05:00
Malte UblandClaude Opus 5.5 1a65f234c9 Narrow unions of records by intersection refinements, and keep members an assertion attaches
'k' in u answers per value on arms that declare k as an optional slot.
A predicate or 'in' narrowing that intersects record arms views the
value through the stored arms that can hold it. An assertion
'r as R & { m: T }' gives R's arms m as an optional member, keeps the
object, and a binding initialized by it keeps the stored type, so
writes through it reach the original. Late writes through a union
receiver count as writes through the binding it was read from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:32:43 -07:00
Chris Tate 2259da3cf7 Give interfaces extending class-backed protocols checked identity (#1461) 2026-10-19 23:29:44 -05:00
Chris Tate 0b98a8c713 Read an Error subclass's own code through NodeJS.ErrnoException
`(err as NodeJS.ErrnoException).code` read the runtime error's errno
slot, which only runtime errors set, so an Error subclass with its own
`code` field answered undefined where Node reads the own property. When
a class in the program under the receiver's class has its own `code`
field or a dynamic property bag, the read goes through the error's
dynamic view, which answers the own property and the errno code alike.
2026-10-19 23:28:36 -05:00
Chris Tate bc9ef21b90 Keep DataView's own behavior through unknown
A DataView reached as a checked-dynamic value behaved like a Uint8Array
over its bytes: it printed as `Uint8Array(2) [ 0, 0 ]`, its string and
tag were the typed array's, `.length` and index reads answered from the
bytes, and typed array methods ran on it. It now inspects as Node's
`DataView { [byteLength], [byteOffset], [buffer] }`, answers
"[object DataView]", has no length or indexed elements, and throws
"is not a function" for typed array methods.
2026-10-19 23:28:21 -05:00