Commit Graph
3918 Commits
Author SHA1 Message Date
Chris Tate affe386bbf Throw for every object on the right of an arrow instanceof, and give blocked bodies their this
- An arrow function or method on the right of an untyped `instanceof`
  has no prototype. Node throws "Function has non-object prototype
  'undefined' in instanceof check" for any object, but the runtime threw
  only for plain objects, arrays and functions, and answered false for
  typed arrays, native handles, promises and typed references. It now
  answers false only for primitives.
- Coverage lowers the body of a signature-blocked function for its
  diagnostics. A declared `this` parameter now gives that body its
  receiver, as lowerFunction does, so `this.label` reports nothing.
  Before, each use reported SC1080.
2026-10-22 10:09:43 -05:00
Chris Tate aeb429c066 Type empty array literals by their slots, and report package diagnostics accurately
- An empty `[]` whose own type is `never[]` (a `return []` in an async
  function, whose contextual type is `T[] | PromiseLike<T[]>`, or an
  object literal's `files: []` field) builds as the unit-only element
  array, like the empty tuple, so typed array slots receive it through
  the checked empty-array lift. It was `number[]`, so `string[]` slots
  refused it with SC1090 or SC2002.
- The refusal "instanceof against this native constructor" names its
  site, and coverage lists the sites whose right-hand side is `Object` or
  `Function`, which always reach it. An arrow function or method on the
  right of an untyped `instanceof` throws Node's "Function has non-object
  prototype" TypeError for an object.
- Coverage lists the diagnostics of a function whose signature did not
  compile. A use of a parameter whose type did not compile reports SC2004.
- Coverage lists deferred fences in a module's top-level code under "runs
  at startup", and the diagnostics envelope marks them `startup: true`.
2026-10-22 05:45:38 -05:00
Chris Tate ed1a5b21c4 Resolve repeated checker objects from their ids without decoding them (#1795) 2026-10-22 05:32:46 -05:00
Chris Tate 54e3b0ce13 Test an array read's hole-free prefix before its capacity (#1793) 2026-10-22 05:32:26 -05:00
Chris Tate 14dfb37161 Skip declaration files when looking for writes to a narrowed binding (#1794) 2026-10-22 05:28:51 -05:00
Chris Tate 999fef551e Resolve repeated checker objects from their ids without decoding them
Checker replies name every type, symbol and signature they reach in
full, and most of them are objects the client already holds: building
tsc-ts, 96% of the types, 79% of the symbols and 80% of the signatures
in replies are cached by id. Object replies are now read as bytes, each
element's extent is found by a scan that skips strings, and an element
whose leading "id" is cached resolves to the cached object without its
text being decoded. The other elements are parsed as before.
2026-10-22 05:27:07 -05:00
Chris Tate 9893630810 Skip declaration files when looking for writes to a narrowed binding
Narrowing stability looked for writes to a binding by walking the whole
file that declares it. For globals such as `console` and `JSON` that file
is a declaration file (scriptc-node-fallback.d.ts, lib.es5.d.ts), so every
build that read one of them materialized about 46,000 AST nodes and kept
them until the end of the build. A declaration file holds no code that
runs, so none of its writes happen: the walk now returns no writes for it.
2026-10-22 05:26:43 -05:00
Chris Tate 1917d1aa00 Test an array read's hole-free prefix before its capacity
The dense path of an element read that may be undefined (the
`%arr.idxOr` reads behind `a[i]` as `T | undefined`, the store
`a[x] = a[y]!`, and the element reads of the lowered array methods)
tested the index against the capacity, then against the hole-free prefix
(`filled`), and only above the prefix against the length and the slot's
state. `filled` is at most the length and the capacity (scr_array.h), so
an index below it needs no other test: the read now tests `filled` first
and takes the value path on that test alone. Above the prefix it tests
the capacity, the length and the state as before.

A double index first branches to the runtime lookup when it is not an
exact integer, then takes the same tests on its i64 value, which a 32-bit
target compares before truncating it.
2026-10-22 05:25:02 -05:00
Chris Tate 13dccd5b99 Map a JS binding's declared type only for a nullish write (#1792) 2026-10-22 05:12:43 -05:00
Chris Tate c09801c064 Map a JS binding's declared type only for a nullish write 2026-10-22 05:08:24 -05:00
Chris Tate 30bfe1ac65 Run two-counter for loops on integer counters (#1790) 2026-10-22 04:53:39 -05:00
Chris Tate 883f22ddd6 Run two-counter for loops on integer counters
`for (let lo = a, hi = b; lo < hi; lo++, hi--)` kept both counters as
doubles: the counted-loop match takes a single counter, so every
`a[lo]`/`a[hi]` converted and tested its index. A loop whose two counters
close in on each other by positive literal steps, are not written by the
body and index something now stores both as i64: on every body entry both
lie between the first start and the second. A start without a proven
integer range is tested at run time on a versioned loop, as a counted
loop's is.
2026-10-22 04:50:13 -05:00
Chris Tate 3703c94387 Call typed-array callbacks directly and visit on an integer counter (#1789) 2026-10-22 04:49:08 -05:00
Chris Tate feec4bf4df Call typed-array callbacks directly and visit on an integer counter
The helpers of the typed-array callback methods (forEach, map, filter,
some, every, find, findIndex, findLast, findLastIndex, reduce,
reduceRight) called their callback through the closure's code pointer on
every element, and one helper served every call with the same signature,
so the callback was never inlined. A literal callback now gets a helper
of its own, as for the array methods, and the constant-callback census
accepts the typed-array helpers, so the helper calls that function
directly.

The visit is now a loop on its own counter, `for (let i = 0; i < a.length;
i++)` or down from the last index, instead of a loop on a counter
declared before it, so the counter is an integer and element reads need no
index test. reduce and reduceRight without an initial value read their
seed at the first visited index and start one past it.

Adds reduce, some and map callbacks to the typed-array-kernels workload.
2026-10-22 04:44:34 -05:00
Chris Tate af2597016c Resolve 7058's promises with undefined so both checkers agree (#1788) 2026-10-22 04:38:01 -05:00
Chris Tate b03e965bf9 Resolve 7058's promises with undefined so both checkers agree 2026-10-22 04:35:27 -05:00
Chris Tate 72f6293e26 Drop the Cipheriv stream fence from the node-types fixture (#1787) 2026-10-22 04:30:34 -05:00
Chris Tate cab2db4f96 Drop the Cipheriv stream fence from the node-types fixture 2026-10-22 04:27:50 -05:00
Chris Tate 6e25c5ddb7 Compile js-yaml and smol-toml statically and match Node (#1751) 2026-10-22 04:15:26 -05:00
Chris Tate d5489cabd7 Merge main 2026-10-22 04:10:59 -05:00
Chris Tate 544110bed2 Revert "Read error constructors as values and destructure workerData in JavaScript" (#1783) 2026-10-22 04:08:00 -05:00
Chris Tate b99094543f Revert "Read error constructors as values and destructure workerData in JavaScript"
This reverts #1776, which made main CI fail.
2026-10-22 04:04:16 -05:00
Chris Tate ce2e517f6b Fix recursive JSON unions and primitive constructors as array callbacks (#1782) 2026-10-22 04:01:35 -05:00
Chris Tate ebbc6c1831 Fix recursive JSON unions and primitive constructors as array callbacks 2026-10-22 03:56:15 -05:00
Chris Tate 4f70f46e34 Name lowered helpers and closures independently of lowering order (#1781) 2026-10-22 03:50:43 -05:00
Chris Tate a9e23d2a09 Store assignment expressions into module lets declared without an initializer (#1780) 2026-10-22 03:45:00 -05:00
Chris Tate 79684d0ef4 Name lowered helpers and closures independently of lowering order
Lowering named helpers by the size of their registry at first use
(%union.retag.N, %arr.map.N, ...), lifted closures and optional-chain
locals by compiler-wide counters (%fnN, chain.N), generic instances by
their instance count, and records and unions by creation order (rN, uN).
Class expressions, mixin instances, function-local generics, non-exported
namespace segments and some module globals carried the byte offset of their
declaration. A name therefore depended on which unit lowered first and on
the positions of unrelated code.

Helpers, instances, records and unions are now named by a hash of the key
they are interned by (keyedHelperName). Closures and optional-chain ids are
named by their lowering unit, their structural position and a count per
key within the unit. Offset-based names use the structural position: the
chain of enclosing named declarations (each with its kind, name and
ordinal) and the node's ordinal among same-kind nodes inside the nearest
one, so an edit outside that declaration leaves the name unchanged.
Interfaces and type aliases anchor the positions inside them, and default
library files are named by their base name, so tsgo and tsc-ts, which
install them in different directories, give the same positions.

Recursive record and union placeholders are named by the printed type, the
structural position of the declaration and the same for up to three levels
of type arguments; a description that two types still share gets a
numbered suffix for the later one. A generic class instance keyed by a
literal type argument is named by the literal's text or the argument's
description instead of its checker type id. Two different keys with the
same name throw an InternalCompilerError.

The SC6101 performance warning recognizes the new closure names
(fn.<hash>, with _<name> for a named function expression) and lists the
functions that rank alike in source order. The module lists its records
and unions by id. The generated program is unchanged apart from these
names and that order, and test:lowering-order now fails on any name
difference.
2026-10-22 03:44:38 -05:00
Chris Tate 144bfb2724 Store assignment expressions into module lets declared without an initializer
A module `let` declared without an initializer whose type uses its null
pointer as the TDZ sentinel (a function, for example) is initialized when
its declaration runs, while its slot is still empty. markUninitializedWrites
marked the assignment statements that run after the declaration as
initializing, but not assignments in expression position. Those ran the
pointer check and threw "ReferenceError: Cannot access 'g' before
initialization" where Node stores the value, so the deferred-resolver
pattern `let resolve!: ...; new Promise((r) => (resolve = r))` failed, as
did `(h) => (g = h)` and `const r = (g = h)`.

An assignment expression to such a binding now becomes an initializing
`assign` whose value a temp holds and yields. Writes that can run before
the declaration keep the flag check, so they still throw Node's
ReferenceError.
2026-10-22 03:41:43 -05:00
Chris Tate 12973aadfa Evaluate the extends expression of classes defined inside functions (#1779) 2026-10-22 03:41:29 -05:00
Chris Tate 931f6d48b5 Evaluate the extends expression of classes defined inside functions
A class defined inside a function whose base resolves to a known class
lowered to its class value alone, so the `extends` expression never ran.
Node evaluates it each time the definition runs, so its calls and other
effects were missing (`class Local extends select(2) {}` never called
select). The class value now follows the heritage expression's
evaluation when that expression can have effects: a call, construction,
assignment, update, delete, await or yield outside nested functions.
Module-scope classes already evaluated it.
2026-10-22 03:35:33 -05:00
Chris Tate 8e3c115cec Serialize the self-hosted emitter's IR compactly in its test (#1778) 2026-10-22 03:32:27 -05:00
Chris Tate e37b94cc94 Serialize the self-hosted emitter's IR compactly in its test
The pretty-printed IR of the self-hosted LLVM emitter is close to the
JavaScript string length limit on CI checkouts, so any growth of the
emitter fails the test with "Invalid string length".
2026-10-22 03:29:38 -05:00
Chris Tate f3efa0b38b Read error constructors as values and destructure workerData in JavaScript (#1776) 2026-10-22 03:29:21 -05:00
Chris Tate be5fc9e874 Make Cipheriv and Decipheriv Transforms and accept function stages anywhere in pipeline() (#1764) 2026-10-22 03:29:01 -05:00
Chris Tate 3a879f4f05 Read error constructors as values and destructure workerData in JavaScript 2026-10-22 03:24:50 -05:00
Chris Tate 7d20212dd4 Merge main 2026-10-22 03:24:23 -05:00
Chris Tate c4d91bf2d9 Give runtime globals definitions, export only the declared library symbols, and fence the new libFn spellings 2026-10-22 03:18:35 -05:00
Chris Tate 7019893664 Compute index temps of a typed-array loop counter as integers (#1775) 2026-10-22 03:16:13 -05:00
Chris Tate fe02190d1d Compile JavaScript-path calls that Node runs (#1756) 2026-10-22 03:15:48 -05:00
Chris Tate 921f054891 Extend a generic factory's local class returned through a constructor type (#1761) 2026-10-22 03:15:25 -05:00
Chris Tate ec0574f44b Read the byte offset of every untyped ArrayBuffer Buffer.from in one place
All Buffer.from paths over an untyped ArrayBuffer or SharedArrayBuffer now
go through one function that takes the byte offset explicitly, as Node's
fromArrayBuffer does. The start-offset RangeError prints the offset as
JavaScript does (-1.5, -1e+21, -Infinity) and builds its message without a
fixed-size buffer, which a large negative offset overran.
2026-10-22 03:13:24 -05:00
Chris Tate 42dd9390c1 Compute index temps of a typed-array loop counter as integers
In `for (let i = 0; i < out.length; i++) { const j = i * 4; ... px[j + 1] }`
the fast copy of the typed-array loop version computed `j` as a double and
converted every index back. The version gives each affine index operand
its range under the guard's bound on the counter, but kept the range an
operand already had, and the counter of a loop to a length is only known
to be below 2^53, so `i * 4` stayed a double multiply. The version now
narrows the existing range to the guard's.

A constant number local whose initializer has an exact integer form now
keeps that integer in an i64 slot beside the double, and its reads carry
both, so `px[j + 1]` indexes with integer arithmetic. Only optimized
synchronous functions keep these integers, and every other declaration of
the local drops its integer, since one declaration is emitted once per
loop copy.
2026-10-22 03:10:30 -05:00
Chris Tate b2b216c3df Extend a generic factory's anonymous local class returned through a constructor type
A generic factory declared to return a constructor type now also extends
when it returns an anonymous class expression (`return class { ... } as
Struct<S>`) or a `const` bound to one (`const Hold = class { ... }; return
Hold`). The result's class value is the class expression's own
constructor type; before, it was read through the class's name, so an
anonymous class refused with SC1090 and SC2008.
2026-10-22 03:10:12 -05:00
Chris Tate 8706aeec6f WebCrypto: the crypto global, node:crypto's webcrypto, and secret-key SubtleCrypto (#1772) 2026-10-22 02:58:00 -05:00
Chris Tate f00428ccb1 Keep pipe() answering its destination and evaluate pipeline() arguments in source order 2026-10-22 02:53:03 -05:00
Chris Tate 1773ffbef3 WebCrypto: the crypto global, node:crypto's webcrypto, and secret-key SubtleCrypto 2026-10-22 02:52:01 -05:00
Chris Tate 2eec7f5213 Revert "Run two-counter for loops on integer counters" (#1770) 2026-10-22 02:51:11 -05:00
Chris Tate d1ff061833 Revert "Run two-counter for loops on integer counters"
This reverts #1768 (8fec4484d), which made main CI fail.
2026-10-22 02:48:13 -05:00
Chris Tate 8fec4484de Run two-counter for loops on integer counters (#1768) 2026-10-22 02:16:04 -05:00
Chris Tate de7437ed7f Convert clamped stores inline and test thread-owned views once in typed-array loops (#1767) 2026-10-22 02:14:03 -05:00