3230 Commits
Author SHA1 Message Date
Chris Tate 928697324f Reject class capsules of other classes without materializing them (#2075) 2026-10-23 23:14:24 -05:00
Chris Tate 260cf6e8c0 Answer builtin prototype reflection in untyped code as Node does (#2054) 2026-10-23 22:26:47 -05:00
Chris Tate 5c131cba35 Report dictionary copies of {} views, and keep method calls direct after writes into dictionaries of dictionaries (#1855) 2026-10-23 22:18:05 -05:00
Chris Tate 9e07382bcd Merge main 2026-10-23 21:48:59 -05:00
Chris Tate 1df99a8414 Convert checked-dynamic expected errors in assert.throws and assert.match (#2066) 2026-10-23 21:41:23 -05:00
Chris Tate 43b0f29011 Guard direct calls after dot-property method writes through dictionary views 2026-10-23 21:34:14 -05:00
Chris Tate ee237c3276 Keep literal key order through self copies and conversions that build no records (#1982) 2026-10-23 21:21:37 -05:00
Chris Tate 10e3476a55 Convert checked-dynamic expected errors in assert.throws and assert.match
An expected regex or string read from a JavaScript object literal's
field is a checked-dynamic value while its checker type is RegExp or
string. assert.throws chose its regex comparison from the checker type
and passed the value unconverted, an internal compiler error, and
assert.match and the expected-object form refused it. Such a value now
converts to the regex or string its type names.
2026-10-23 21:12:15 -05:00
Chris Tate 02aa5d4184 Keep the run-time result of overloaded calls with untyped arguments (#2064) 2026-10-23 21:00:49 -05:00
Chris Tate e59fdca0f4 Search TypedArrays, read stdin through 'readable', and assign constructor-function globals (#1974) 2026-10-23 20:57:24 -05:00
Chris Tate f9e9f3cb52 Keep an error's name and message where a JavaScript factory created them (#2055) 2026-10-23 20:55:51 -05:00
Chris Tate cecab7fc0f Keep null and undefined through non-null assertions into nullable destinations (#2050) 2026-10-23 20:48:03 -05:00
Chris Tate 0392a032c5 Merge main and fix the self-copy key order 2026-10-23 20:47:40 -05:00
Chris Tate 6dfde9919c Keep checked dictionary protocols and invalidate direct calls after method writes 2026-10-23 20:45:37 -05:00
Chris Tate 0f75f5b952 Keep the run-time result of overloaded calls with untyped arguments
The checker resolves an overloaded call whose argument is `any` to the
first overload that argument satisfies, but in JavaScript the value can
select another one: generateKeyPairSync("ec", options) returns KeyObjects
or PEM strings by the options, and digest(encoding) returns a Buffer when
the encoding is undefined. The result was converted to the first
overload's return type, so such calls threw a TypeError where Node
returns the other overload's value.

When a checked-dynamic argument could take another overload whose return
type differs (trailing untyped or undefined arguments may also be
absent), the call's result in a JavaScript source is checked-dynamic. So
are the unannotated bindings it initializes, destructured or not, and
the unannotated functions that return it. fs.globSync keeps choosing its
result form from the resolved overload, since the runtime checks that
withFileTypes agrees with it.
2026-10-23 20:31:12 -05:00
Chris Tate a5db27a5a7 Merge main and fix the review comments 2026-10-23 20:24:35 -05:00
Chris Tate e813250813 Keep a constructor's name ahead of later properties in the runtime fallback 2026-10-23 20:22:14 -05:00
Chris Tate b2e609d73e Merge main 2026-10-23 20:20:34 -05:00
Chris Tate 01e802ff9d Box JavaScript class instances at their exact class (#2047) 2026-10-23 20:18:12 -05:00
Chris Tate d06e6ab0a5 Keep checked narrowing for optional standard library parameters, and merge main 2026-10-23 20:11:11 -05:00
Chris Tate 1af3a86370 Compile unions of typed-array classes (#2011) 2026-10-23 20:00:12 -05:00
Chris Tate 37df3c4dfd Support split CommonJS require bindings (#1945) 2026-10-23 19:50:13 -05:00
Malte UblandClaude Opus 5.5 c9f1f95d5b Box JavaScript class instances at their exact class
A class instance converted to an untyped value was boxed in a capsule of
its static class. Before any member table read it,
%dyn.class.normalize tested it against each subclass and boxed it again
at the instance's own class: two capsules per crossing for every value
of a class with subclasses, and the subclass tests on every member read.

After the dispatch tables settle, each conversion of a value whose static
JavaScript class has a normalization branch now calls
%dyn.class.boxExact:<Class>, which runs the same subclass tests in the
same order once, at the conversion. The capsule is created at the exact
class, and normalization falls through for it. TypeScript hierarchies,
classes that are never boxed, and hierarchies without subclasses are
untouched.

zod 3, z.array(Order).parse over 500 orders: 178.5M -> 174.4M
instructions per round (-2.3%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:41:28 -07:00
Chris Tate a4e7a03761 Address review comments 2026-10-23 19:37:04 -05:00
Chris Tate 3a613c31a8 Merge main 2026-10-23 19:33:44 -05:00
Chris Tate d56a884011 Merge main 2026-10-23 19:28:30 -05:00
Chris Tate 4206155ac9 Convert non-null asserted operands that hold undefined or null as Node does (#2049) 2026-10-23 19:25:15 -05:00
Chris Tate cc325de274 Merge main 2026-10-23 19:24:16 -05:00
Chris Tate bf68b3860c Skip split require calls by identity and climb parentheses in early-read checks 2026-10-23 19:05:58 -05:00
Chris Tate fbaf51c032 Decide string or number concatenation at run time for untyped partners 2026-10-23 18:53:36 -05:00
Chris Tate 9adb9692cd Accept file URL paths in existsSync and fs.promises (#2042) 2026-10-23 18:47:49 -05:00
Malte UblandClaude Opus 5.5 f896786ef4 Give the zod4-record npm case the zod 4 cases' timeout
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:42:23 -07:00
Malte UblandClaude Opus 5.5 e81c9ddaa4 Give the hono-zod-default-hook npm case the zod 4 cases' timeout
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:42:19 -07:00
Malte UblandClaude Opus 5.5 09f0342641 Keep an error's name and message where a JavaScript factory created them
zValidator's default failure hook serializes zod 4's ZodError with
`name` after `message` natively, and with the first `name` zod's factory
assigns ("$ZodError") when the second assignment took the typed slot.
ZodError instances are views of a JavaScript class extending Error: each
view rebuilds `message` and `name` from the error slots at fixed
positions (after `stack`, and after every other property), and the
property bag that holds the dynamically added properties copied its
committed, possibly stale, values over them.

A JavaScript Error subclass with a property bag now marks its class
(errorBagOrder), and its view calls scr_error_dyn_follow_bag after the
bag is copied: `name` and `message` move to follow the property they
followed when the bag was committed, and data values come from the
slots. TypeScript classes keep their views.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:40:35 -07:00
Malte UblandClaude Opus 5.5 17721bae55 Answer builtin prototype reflection in untyped code as Node does
zod 4's z.record rejected every plain object natively ("expected record,
received object"): its isPlainObject reads o.constructor.prototype, which
was undefined, and asks whether that prototype has its own isPrototypeOf,
which Object.prototype answered false.

- The Object, Array and Error constructors held as values have their
  builtin prototype as a non-writable, non-enumerable, non-configurable
  own `prototype`; reading Function's constructor value's prototype
  throws SC2020 instead of answering undefined.
- hasOwnProperty / Object.hasOwn on Object.prototype answer its builtin
  members, and on Array.prototype its constructor;
  Object.getOwnPropertyNames lists them in Node's order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:40:07 -07:00
Chris Tate 6dace8e40b Compare and index with the integer beside a sum's double (#2040) 2026-10-23 18:34:30 -05:00
Malte UblandClaude Opus 5.5 0dfea3c642 Reject class capsules of other classes without materializing them
A dynMatch helper for a class target tested the capsule's class key and,
when it did not match, materialized the capsule's view and matched that.
A materialized view is a plain object, which never matches a class target,
so the answer was always false: the helper now answers false directly.
Checked casts from unknown to unions of classes no longer build a view per
non-matching arm (1,000 casts x 2,000 rounds: 255 ms -> 67 ms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:20:16 -07:00
Chris Tate b7f86b9bb5 Run TypedArray methods on typed arrays held as untyped values (#2043) 2026-10-23 18:14:18 -05:00
Chris Tate 3e73eee0c4 Evaluate fs.promises URL arguments once and fence the new fs entries 2026-10-23 18:12:45 -05:00
Chris Tate 39bb8a5b7e Require integer views to stay below 2^53 exactly, and fix corpus 1420 2026-10-23 18:05:10 -05:00
Chris Tate 5a4935ed9e Settle Promise.all over different entry types on Node's turns (#1843) 2026-10-23 17:49:52 -05:00
Chris Tate 537710f61d buffer: fromArrayBuffer ranges, the deprecated constructor, Buffer as a value (#1970) 2026-10-23 17:46:42 -05:00
Chris Tate b09d5c6862 Merge main 2026-10-23 17:43:25 -05:00
Chris Tate 47d573d216 Pass undefined as this to strict callbacks and read Symbol.iterator once 2026-10-23 17:41:37 -05:00
Chris Tate a095565bc8 Project zod 4 and @hono/zod-validator values at the declaration boundary (#2046) 2026-10-23 17:41:12 -05:00
Chris Tate b80666adb4 Keep null and undefined through non-null assertions into nullable destinations
JavaScript erases `x!`. scriptc lowered it on a union as a checked
narrowing to the asserted type, so a value that still held null or
undefined threw a TypeError, even where it went straight into a return
value or argument whose type holds it: `return cache.get(key)!` from a
function that returns `T | null`, with null stored in the map, threw
where Node returns null, and `String(names.get(key)!)` threw where Node
returns "null".

A non-null assertion that is a returned value, an arrow function's body,
or a call or new argument now keeps the value when the destination type
is any or unknown, or holds the null or undefined the assertion removes;
the destination's coercion re-tags it. Bindings and assignments keep the
checked narrowing, because the checker narrows them to the asserted type
for later reads.

The native compiler hit this in the bytes-loop versioning analysis,
which caches null results that way (`if (shapes.has(e)) return
shapes.get(e)!;`): it refused programs whose counted loop reads or
writes several typed arrays at one masked index with SC3004, including
tsc-ts's release build, which the Node-built compiler compiled.
typed-array-masked-index-stores.ts is such a program; the LLVM emitter
self-hosting test now emits and runs it with the natively built emitter.
2026-10-23 17:40:07 -05:00
Chris Tate 4b6a6e6bc4 Convert non-null asserted operands that hold undefined or null as Node does
`x!` performs no runtime check, but the compiler extracted the asserted arm
with a checked narrow, so a value that still held undefined or null threw
"TypeError: undefined is not representable in the target union" wherever it
was used. In Node the value reaches the operator, which converts it.

When `x!` is an operand of an arithmetic, bitwise or relational operator,
`+`, a compound assignment, a unary `-`, `+` or `~`, or an argument of a
Math function, and `x` is a union of numbers, strings, booleans, null and
undefined, the operand is now converted with ToNumber: undefined is NaN and
null is 0. As an operand of an equality operator, of `!`, of a template
span, of `+` with a string, or of a comparison with a string, the union
itself reaches the operator, so `x! === 0` is false and `${x!}` is
"undefined". Array and typed-array element reads keep their handling of a
missing element, and `+` whose result TypeScript types as a string keeps
the checked narrow where Node's result is NaN.

`x == null` on a union with both null and undefined arms evaluated its
operand twice, so an operand other than a plain read was refused. It is now
evaluated once into a hidden local.

Corpus 7392.
2026-10-23 17:34:59 -05:00
Chris Tate 68eda48251 Merge main 2026-10-23 17:27:47 -05:00
Chris Tate 7f8b0c2a09 Support X25519 keys and crypto.diffieHellman (#2039) 2026-10-23 17:23:19 -05:00
Chris Tate 02597fa3e8 Merge main and give split require cycles the const form's admission 2026-10-23 17:15:33 -05:00