Repository navigation
Conversation
…ion one identity A generic `function` declared inside another function compiles: it is specialized like a top-level generic declaration, over the bindings it captures. A generic function used as a value has one identity per declaration. Its value instances are rooted in one interned closure, so `===`, Map and Set keys and listener removal agree with JavaScript when one declaration is held at several signatures, across objects, worker threads and library instances. The build-time pins that refused or warned about such comparisons are gone with the comparisons' bookkeeping. An initializer that names a thread-local is refused by name. A program that holds one generic declaration at two value instances gains one closure initializer field; other programs are unchanged. Co-Authored-By: Claude Code <noreply@anthropic.com>
A Proxy stored where a class instance or a record type is declared has no native layout to be read through: the read would bypass the handler. The store is now a build-time refusal that names the slot's type, whether the Proxy has traps or not, instead of a failure when the program runs. A binding a Proxy initializes is held as a checked-dynamic value, also when a closure captures it above its declaration, and a shorthand read of it is refused. Co-Authored-By: Claude Code <noreply@anthropic.com>
…rguments onto its shell line Process streams. A process stream passed or stored where a stream class is declared (a `Readable` parameter, for example) is answered by the thread's one runtime stream, created on first use (runtime unit `scr_stream_stdin.c`, linked only by programs that use the form). Once `setEncoding` has been called, a consumer compiled for bytes is refused by name where a chunk is handed to it (a bytes `'data'` listener, `read()`, `for await`); async iteration hands out Buffers. While an encoding is set the stream still receives every raw chunk, so a character split across two reads is not lost. Child processes. `spawn` and `spawnSync` with `shell` enabled and a separate argument list join the arguments onto the command as Node does, sparse lists included, with the DEP0190 warning; `shell` may be a boolean decided at run time (runtime unit `scr_child_shell.c`, linked only by programs that use the form). Values Node rejects stay refused. `cp.shellLine` and `stream.stdioReadable` are declared never-throwing, and the shell unit's reference to the warning functions is listed as reached only through `cp.shellLine`. The stdin checks live in the one build of `scr_events.c`, so every executable that links the stdin delivery path changes by a few hundred bytes; IR and LLVM are unchanged for them. Co-Authored-By: Claude Code <noreply@anthropic.com>
Each is a rule a neighbouring form already had. - A typed `Headers` iterates through `keys()`, `values()`, `entries()` and `for...of`. - `Promise.all` over an entry of type `Promise<T | undefined> | undefined`: the absent side joins as a promise fulfilled with undefined, so the position has one type whichever side settled. An optional entry whose promise cannot fulfill undefined keeps a refusal that names the spelling that compiles. - `reduce` and `reduceRight` on a checked-dynamic array, also with a rest-parameter callback: the dynamic call passes JavaScript's four arguments. - `Object.keys` and `Object.entries` over what `typeof v === "object"` leaves of a JSON value: an array or primitive arm beside the record arms answers through the checked-dynamic walk. `Object.entries` converts an index signature's values with the general untyped conversion and hands them back by reference, so a write through an entry reaches the object. - `left ?? right` where the right side's type is wider: the present value converts into the result after the nullish test, and the default stays lazy. (A later commit keeps this form refused where the conversion would copy the left value.) - A function created above `let x: T;` without an initializer: the dead-zone box of a forward-captured `const` serves when the slot can hold the unassigned state; a type that cannot keeps a refusal (SC1030). - A call through an optional callable member that every arm of a record union declares, inside a generic function whose type parameter is bound to the union. - A rest binding in a generic function is typed by the type argument's fields, so it keeps the fields the argument adds beyond the constraint. Co-Authored-By: Claude Code <noreply@anthropic.com>
…nary type as one type however it is spelled
A dictionary that keeps identity (it holds the record or class instance it was given, so writes are shared) can be an arm of a recursive union such as a JSON value: the union holds it by reference, and enumeration, writes and narrowing go through the same object.
A dictionary type is one type however it is written: `{ [key: string]: V }`, `Record<string, V>`, an alias, or the same spelling in another module share one decision about identity storage, so a value passed between two spellings is the same object. A mapped type whose members are not known yet is not compared.
Co-Authored-By: Claude Code <noreply@anthropic.com>
…choose a union arm by the value's properties Union members that share a literal of the member that separates them best form a class and are stored as one record over the members of all of them (members only some declare are optional slots), so a value of one member is the object the union holds and entering the union does not copy it. A member outside a class keeps its own arm when its discriminant names it, and a value under assertions is asked for the discriminant that names its arm. Library builds keep the member layouts. A class record that would have to be copied into a slot is refused. Where several arms hold a record of optional members, a value entering the union takes the arm that declares the properties it has; routes by properties exist only among arms that keep each property at its own type, and an arm no rule places takes its site route first. A dictionary record that is a union arm reads its key map at its own field when it converts to an untyped value (it crashed). `scripts/union-matrix.mjs` generates the matrix of union shapes these rules were measured on. Co-Authored-By: Claude Code <noreply@anthropic.com>
`left ?? right` whose default has a wider type than the left side's value lowers the present value through the conversion a slot of the result type applies. JavaScript answers the left side itself, so that is right only where the conversion keeps the value. Where it copies, the result was a second object: after `const list = papers ?? editions; list.push(x)` the push was missing from `papers`, and `list === papers` was false. The copy warning (SC6001) does not make that answer right, and before the rule existed the expression was refused. The rule now asks what the conversion it built does (conversionCopy in width-copies.ts, which owns the copy families). A copy is a call of a copy helper in the conversion or in any helper or adapter it reaches: a routing helper that copies in one run-time arm, an adapter that copies a result of each call. A checked conversion between two typed layouts is one too (a promise stays the same promise, its array payload would be copied when it settles), and so is an object built in place of the value. Such an expression is refused with SC1090; the message names the copy (an array, a tuple, a record, a class instance entering a record type) and the spellings that compile: one type on both sides, or the copy written out where a copy is meant, which Node then makes too. What keeps the value still compiles: a function entering a function type with more parameters or a wider result (its adapter is that function to `===`), a class entering the type of its base class, a promise whose payload type widens to a union of numbers and strings. A value with no identity converts freely. The default stays lazy and the left side is evaluated once, as before. The check runs only inside this rule, which is reached after every other `??` rule declined, so a program that compiled without the rule lowers as it did: the IR and LLVM of existing `??` programs are byte-identical. Tests: corpus nullish-wider-default-keeps-left replaces nullish-default-widens-array, whose array cases are refused now, and pins the forms that keep the value (identity, writes through both names, laziness, present and absent, the explicit copy). Diagnostics fixture nullish-wider-default-copies-left pins the refused forms: an array, a tuple, a record of another layout, a class instance entering a record type, a promise of an array; as a member read, a lookup and a parameter. width-copies.test.ts covers conversionCopy on hand-built conversions. Co-Authored-By: Claude Code <noreply@anthropic.com>
The test compared the peak resident set of two runs of one fixture binary (800,000 and 1,600,000 keys) with `large < small * 1.05 + 8 MB`. The peak of a run is not one number: one binary on one machine peaks at about 105 MB or about 110 MB for 200,000 keys and for 2,000,000 alike, and on a loaded runner the smaller run peaked 15 MB below the larger one with nothing leaked, missing the bound by 2 to 4 MB. The measure is now the difference of the two peaks divided by the number of additional keys, over a longer lever for the same number of iterations (400,000 against 2,000,000 keys, the collection cadence fixed at 20,000). The bound is 32 bytes per key; the levels can account for 12, and a leak costs 865 to 970 bytes per key (measured with the cross-heap collector off). The test also runs the leaking pair and requires more than ten times the bound from it, so the measure is shown to see a leak. Co-Authored-By: Claude Code <noreply@anthropic.com>
A dictionary that keeps the object it was given is an untyped value in the lowered program. Converted to a dictionary type with another value type it becomes a native dictionary built from its entries: a copy, as a record converted to another layout is, and a write through either name or an identity comparison tells the two apart. The lowered program alone does not say where that happens. The conversion is the checked conversion every untyped value takes, alone or inside a copy helper that is shared by layout, and only the checker's type of the converted value says that the value is such a dictionary. The lowering notes the conversion where it makes it. After a slot conversion of an untyped value, or of a value that holds one, it asks whether the value's checker type has a dictionary that keeps identity where the slot's lowered type has a native dictionary: the value itself, or a field, an element or an entry of it. The note names the lowered conversion by its place and type and carries the dictionary's own type and the layout of its entries. It is a table beside the program, so the lowered program is the same with and without it; a unit that adds a note has no record and lowers again instead of being replayed without one. The width copy scan counts the lowered conversions that carry a note as a kind of their own. The copy is observed as every copy is: a key of its type is written or deleted, values of its type are compared, or it reaches code the scan cannot follow. The original has no layout to look for, so any store through an untyped value counts as a write to it; the dynamic store facts now hold the first such store, for the message. An entry whose layout the copy's value type lacks is rebuilt as well and is a member fact, paired as the checked conversions pair layouts. One conversion is one warning, and its hint names the dictionary's own type. The assertion predicate no longer counts such a dictionary as a copy. An assertion that initializes a binding keeps the dictionary's object, so the refusal of a write through that binding rejected programs that print what Node prints. Co-Authored-By: Claude Code <noreply@anthropic.com>
Generated by the lane's update mode over the whole lane (427 programs), then checked without it. - `npm/types-boundary` (island:rowparse) and `npm/zod3-boundary` (island:zod) match Node now and leave the list: the union and generic forms they stopped at compile. - `npm/zod4-boundary` (island:zod) is refused with SC8010 alone instead of SC1090 and SC8010. - `npm/hono-zod-validator` (island:@hono/zod-validator) no longer stops at the refusal of Headers iteration, which compiles now; it stops at the next difference, a TypeError of the Headers constructor. Co-Authored-By: Claude Code <noreply@anthropic.com>
The scan of noted dictionary copies called `this.layoutPairs`, which is a function of the module since the `??` change, and the text of a conversion's copy had no case for a dictionary copy: the two changes were written side by side and the compiler package did not type-check with both. The scan calls the function with the union lookup read into a local first (called as `this.unionArms(…)` the lookup is handed the scan as its receiver), and a dictionary copy has its own sentence. Co-Authored-By: Claude Code <noreply@anthropic.com>
A record whose field is a dictionary of one value type, declared or passed as a record whose field is a dictionary of another, is refused when the program writes through the declared name, the callee writes through the parameter, or a write lands on an assertion's binding (SC2021, SC1090): the conversion copies, and the write would reach only the copy. Those rules compare the layouts of the two fields. Since every spelling of a dictionary type that keeps the object it was given is that one type, such a field is untyped, and so is a record literal that holds it: the rules found no pair of fields, and the conversion compiled as a copy with a warning. The three rules now ask the width copy module for that case: a record that is untyped where it holds such a dictionary, converted into a record with the same fields whose field is a native dictionary. They refuse with their own codes, and the message names the field, the two dictionary types and the spelling that compiles. The question is answered for a field whose dictionary type keeps identity as another spelling of the type an object entered: that field had a native layout before, and its conversion was the one refused. A field declared with the very type the object entered never had one; its conversion stays a reported copy, as it was. The note of a copied dictionary now also covers the conversions that reach the same copy another way: a tuple and a class instance that hold the dictionary, and the checked conversion an assertion makes. They built the copy with no warning. Co-Authored-By: Claude Code <noreply@anthropic.com>
…self-compile class guard Sixteen files conflicted. withChildArgsCheck (builtins/child-process.ts) is one function for both sides. It keeps main's evaluation by source order and its `maxBuffer` checks, and this branch's mapping of a shell launch with separate arguments onto its joined line: the file, the arguments and `cwd` are checked, the line is built, the environment is checked. The mapping is the eighth parameter, after main's source order. No entry point passes both a limit and a mapping today; the function orders them as Node does all the same (a limit validated after the launch's values is validated after the line is built, execFile's before it). The unit test's helper reports both sides' calls, and both sides' tests are kept. The diagnostics snapshot is regenerated. The feature tables (executable features, link info, contracts, the unit list, the runtime pack, the executable cache, the runtime feature rules, the pack matrix) keep each side's rows: streamStdin and childShellLine from this branch; streamPipeEvents, processFeatures, childStreamFlow and functionOwnWrite from main. The table of calls that never throw keeps both sides' rows. lowerer.ts: finishModule takes main's signature and settleLoaderShareEnv and does not call checkGenericIdentityPins, which this branch deletes; coerceIntoSlot keeps this branch's Proxy and class-record checks and main's CommonJS module fence. width-copies.ts: layoutPairs stays the module function this branch made it (main edited the method to keep the scan out of the dynamic tier; the function takes the union lookup as a parameter, which serves the same end). Co-Authored-By: Claude Code <noreply@anthropic.com>
The note of a dictionary copy compares the checker's type of a converted value with the slot's lowered type, member by member and four steps deep, to find a dictionary that keeps its object where the slot has a native one. For a union of many record types whose fields hold the union again (a syntax tree) every member was compared with every arm at every step: the compiler's own build did not get past one declaration of lower-comptime.ts, an untyped array converted to an array of IR expressions (stopped after 55 minutes in that search; the whole build takes about twelve). A copy can only be found where the target is a native dictionary or holds one within the steps left, which is a question about lowered types alone. The search asks it first, per search and per type, and asks the checker nothing about a target, an arm or a field that holds none. A pair of a source type and an arm that was compared at a depth is not compared again: the search ends at its first find, so the pair held none. Neither changes what the search answers. Co-Authored-By: Claude Code <noreply@anthropic.com>
…ts record The members of a union that share one discriminant literal are stored as one record (a class), and a value typed as one of those members is that record. A value whose type is not one of the members but has the layout of one (an inferred literal type, the member's type written a second time, an `as const` literal, a function's inferred result, the type an assertion names for a parsed value) kept that member's own layout. Storing it in the union would have copied it into the class's record, so the conversion was refused with SC1090. Before the classes such a value was the union's arm, the one object under both types: programs that built and printed what Node prints stopped building. A type that belongs to no class and maps to the layout one of a class's types has on its own now maps to the class's record (classRecordOfLayout in type-mapper.ts). The value is built as that record where it is created, so it enters the union at a binding, an argument, a return, a push, a property or an assertion with no conversion: writes through either name reach the one object and `===` holds. A class is decided the first time one of its types is mapped; a type with a member's property names that is mapped earlier decides the class then, so every type has one answer in a pass. A member that itself holds such a type leaves the class separate, like a member that holds its class. Three places follow the record: - A read of a member that the receiver's type requires and the class's record holds as optional is the checked extraction for these types too, not only for the class's own types: a value asserted past the member throws a TypeError instead of reading a slot that holds nothing. - A rest binding whose type is a class's record leaves the members only the class's other types declare absent, where it refused them as fields the source does not carry. - The same member written in two unions is two types with one layout. Their classes are now one class, so a value is one record in both unions; it was copied from one record into the other (reported by SC6001, and a runtime TypeError where the two records could not hold each other's value). Where the two unions' other members declare one name with different types no record holds both classes, and neither is a class: each member keeps its own layout, which the unions share. The refusal is gone with its fixture: no use it covered was wrong before the classes. A conversion that still copies (a value with a property no member declares, or without a member's optional property) is the record width copy it always was, in the helper family the SC6001 scan reads. With the layout rule switched off and the refusal removed, every such copy the program could tell from its source was reported. Programs without a class map every type as before. Among programs with a class, only those that hold a type with a member's layout outside the class, or the same member in two unions, change. Co-Authored-By: Claude Code <noreply@anthropic.com>
This reverts "Refuse at compile time a Proxy that enters a class or record slot" with its programs and fixtures. The refusal named a Proxy stored where a record type or a class is declared. Where the store runs it replaced a wrong answer. Where the store is in code the program never reaches it rejected a program that builds today and prints what Node prints: a Proxy assigned to a record-typed field and passed to a record-typed parameter inside a function that is never called. A build must not turn red for a program that works. Proxy stores behave as they did before the branch. The form comes back as a store that throws by name when it is reached, with a build warning, in a change of its own. Co-Authored-By: Claude Code <noreply@anthropic.com>
…tries One file conflicted: the generated IR codec, where both sides add entries. It is main's file regenerated on the merged tree by scripts/generate-ir-codec.mjs; nothing else is written by hand. Twenty-five other files changed on both sides and merged without a conflict, the feature tables among them (executable features, link info, contracts, the runtime pack, the executable cache, the runtime feature rules, the pack matrix): each keeps both sides' rows. Co-Authored-By: Claude Code <noreply@anthropic.com>
The test feeds process.stdin three lines 150 ms apart and compares the compiled program's output with Node's. The fixture printed the bytes of its first read() and the byte count of the iteration that follows separately, so its output depended on how many of the writes had arrived when each process took its first read. On a loaded machine Node started late and read two lines at once while the compiled program read one; both were right for what they saw, and the test failed. The fixture now reports that the first read and every iterated piece are Buffers, and the count and bytes of all of them together. Under Node and as a plain and a sanitized binary it prints the same three lines whether the input arrives at once, as two writes and one, as one and two, or spaced; the old fixture printed three different outputs over those runs. Co-Authored-By: Claude Code <noreply@anthropic.com>
…d download changes Two files conflicted. lower-calls.ts: the list of method names a checked-dynamic value dispatches at run time. Main adds findLast, findLastIndex and flat where this branch added reduce and reduceRight, and main adds those two as well: the list is main's. The diagnostics snapshot of array-callback-rest-parameters.ts: main removed the fixture's three calls a checked-dynamic array now runs and recorded the snapshot again; this branch had only recorded it again. The snapshot is main's. Fourteen other files changed on both sides and merged without a conflict. Regenerating the codec, the surface manifest, the Node compatibility ledgers and the refusal baseline on the merged tree changes none of them. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main's fixture logical-value-over-closure-assigned-binding.ts pins three
pairs over a `let` that only a closure assigns. The checker narrows such a
binding to its null initializer and types `seen ?? word()` as the right
operand alone. Main refuses that line at build time. This branch's `??`
rule builds it: the left side's stored value is converted into the pair's
type, and a value that type cannot hold stops the program by name
("value is not representable in the target union") instead of being
refused. While the binding is still null the program answers as Node
does; once it holds a value the program stops with that TypeError, where
Node answers the binding. The `||` pair and the always-null `&&` stay
refused.
The snapshot loses the line's error and the fixture's comments say what
happens. Over 100 programs of the shape (five stored types of the left
side, five types of the right, `??` and `||`, the binding holding a value
or not), three that main refuses stop by name, three that main refuses
answer as Node does, none answers differently in silence, and `||` is
unchanged. The build does not warn at such a site yet.
Co-Authored-By: Claude Code <noreply@anthropic.com>
…l line's mapping Two files conflicted. withChildArgsCheck (builtins/child-process.ts) stays one function. Main adds `effect` steps to the source order: the value of an option the launch does not read is evaluated where its member sits, so the function no longer returns early when the order holds one. This branch maps a shell launch with separate arguments onto its joined line. The early return takes main's condition and still answers the mapped launch when nothing is checked, limited or ordered. The tail is this branch's: checkAll() adds the checks that can be refused and answers the arguments the entry point takes. For a launch without a mapping it adds exactly main's statements: nothing where main's new guard adds nothing, the check before the limit where a value can be refused. An effect is evaluated at its step before the first check, with or without a mapping. The doc comment keeps both sides' paragraphs. project-config.test.ts: both sides append entries to the node-types list; all three are kept. Twenty-nine other files changed on both sides and merged without a conflict, the feature tables among them. Regenerating the codec, the surface manifest, the Node compatibility ledgers, the refusal baseline and the child-process diagnostics snapshot on the merged tree changes none of them. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
The gate-only round on this head (
Not run on this head: the full lanes, both native bootstraps, bench-runtime and Test262. They ran on the head before the three merges of main and the two test-only commits (the body's "Full round"); the third merge resolved a conflict in the child launch check function, which this round and both sides' child-process tests cover. |
|
HOLD: do not merge yet. The review bot left one finding on this train ( 🤖 Generated with Claude Code |
In Node process.stdin is the Readable: handing it on creates no second stream. The compiled program kept two paused states, one in the stdin unit and one in the stream. After process.stdin.pause() the stream's reads resumed nothing, the unit delivered nothing and counted as no pending work, and the program exited 0 having read nothing where Node reads the input: through async iteration, 'readable' with read(), readline, a pipe, or a 'data' listener after resume(). isPaused() answered for one name only. The stream now holds the one state for both names. It starts in the state process.stdin was put in before the hand-on (paused, resumed, read by a 'readable' listener, an encoding), and pause(), resume(), isPaused() and setEncoding() through process.stdin act on it. The stdin unit becomes the stream's source: the stream's _read is a pull, answered with the next input whether the stream flows or is read in paused mode, so pausing stops 'data' events and not reads. A 'data' listener registered on process.stdin gets each chunk as the stream takes it, which is also what a read() hands such a listener in Node; 'readable' and 'end' listeners registered there follow the stream's events, and process.stdin.read() reads the stream. A pull holds the process until the stream emits 'pause', as Node's stdin stops reading there: the pull is taken back and the stream's read in flight is closed with an empty chunk, so a paused stdin releases the event loop and the next read, iteration step, 'readable' listener or resume() asks again. Two forms are refused by name (TypeError, SC2020) instead of answering otherwise: for await over process.stdin in a program that also hands it on (iterate the Readable), and a pipe of the Readable while process.stdin has a 'readable' listener (in Node that listener keeps the stream paused; the runtime's pipe starts the flow whatever listens). A closed descriptor 0 is now an input that ends at once, as in Node, which opens /dev/null there. Before, any program that read stdin with descriptor 0 closed waited forever. Programs that do not hand process.stdin on take none of the new paths. Co-Authored-By: Claude Code <noreply@anthropic.com>
…he input does Node reads a pipe, a socket or a terminal through a stream that reads once more after the end of the input, and a file through one that does not. With nothing held and nobody reading, a pipe's stream therefore emits 'readable' and 'end', and a file's stream emits 'readable' and waits: 'end' follows the next read, whoever makes it. The stream process.stdin is handed on as ended in both cases. Under a 'readable' listener that never reads, with input redirected from an empty file (or from a closed descriptor 0, where Node opens /dev/null), a 'data' or readline consumer of the stream saw an 'end' that Node does not emit. The stdin unit now tells the stream what its input is. For a file the stream takes the end without reading on: a paused stream with nothing held emits 'readable' and ends at the next read() through either name, the next iteration step, a 'readable' listener added later, or resume(), which reads once in Node whether or not the stream then flows. A stream that flows, holds input or has an iteration waiting is read at its end in any case and ends as before. The two functions this adds to the stream unit are linked only by programs that hand process.stdin on. Co-Authored-By: Claude Code <noreply@anthropic.com>
…the type walk memo Main gained three things this branch also touches. Headers iteration is on main with its own profile rows, fixture and test. This branch had turned the same rows on: main's rows, messages and test stand, and this branch keeps its corpus program. The fence for Headers iteration stays removed here, since nothing calls it once iteration is static. A union arm that enters the destination union by its own discriminant is one more plan beside this branch's route by declared properties: both plans, both branches of the conversion, and the copy scan takes the noted dictionary conversions as well as main's named-copy filter. The `??` rule keeps this branch's present-value conversion and main's rule for a left side that holds only null or undefined. The type walk memo keeps what a type mapped to inside one walk. The frame keeps main's shape with this branch's class-record step after the structural mapping; the back-reference sites note the back-reference and then answer the checked-dynamic value where a dictionary keeps identity. While a class of union members that share a discriminant literal is mapped, a member answers its own layout to the class and the class record to everyone after it: one type with two answers in one walk. From the first read of a class that is unmapped or in progress the walk therefore keeps and serves no more entries. Promise.all and Promise.allSettled take main's lowering whole: its promise-or-value entries cover this branch's optional promise entry. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main's test of a binding initialized from `read && other` also pins that `seen || fresh()` and `seen ?? fresh()` over a `let` only a closure assigns are refused. On this branch the `??` pair builds: the stored value is converted into the pair's type after the nullish test, and a value that type cannot hold stops the program with a TypeError that names it. The diagnostics fixture and its snapshot already say so; the unit test now does too. `||` stays refused. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Held again: please do not merge yet. The review of 21:38 UTC on head 53e1c31 is right, reproduced: after Three lines piped in, read 300 ms later (
With empty input every runner prints 0 / 0. The cause is the one the review names: 🤖 Generated with Claude Code |
In Node, process.stdin and the Readable it is passed as are one object with one readable state. The conversion this branch added answers a stream beside the stdin unit, and the two still answer apart without a diagnostic: - process.stdin.readableLength answers 0 while the stream holds the unread input (Node answers the same number through both names); - after process.stdin.destroy() the stream answers destroyed false and readable true; - input the stdin unit held before the conversion is not in the stream at the conversion: readableLength answers 0 and read() answers null through the stream, where Node hands out the held bytes; - with input from a file, the stream answers destroyed and closed true after the end, where Node's stream for a file answers false. Before the conversion existed such a program stopped at the Readable slot with a TypeError that names both types. A stop by name must not become a wrong answer, so the conversion is not made until the two names answer as one: processStreamAs no longer answers stream.stdioReadable, and the program stops as before (TypeError: expected Readable, got ProcessStream). The runtime unit, its link feature and the fixtures stay; nothing emits the call that links the unit. The differential cases and the tests of the conversion are skipped with their Node answers kept, and one test pins the stop by name for every fixture that converts. process.stdout and process.stderr as a Writable are unchanged. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
On the review of 21:38 UTC ( The cells of the finding, three lines piped in, read 300 ms later (
The TypeError is main's: Why not the one-function fix. Before trusting it I printed every readable-state property the two names share through both names (
Through the Main stops every one of these programs at the hand-on, and a stop by name must not become a different answer. Three of the five causes need more than the helper (one is how the stream is created, one needs a ruling on listener order), so the conversion leaves this train and returns with all five cured and this family as its evidence. Now, on
The one run that differs from main in the last row is a control without a hand-on (a What the commit changes: The hold of 21:46 UTC is lifted for this finding: the head no longer answers differently from main where 🤖 Generated with Claude Code |
process.stdout or process.stderr passed, stored or returned where a node:stream Writable is declared no longer asks for the general stream representation by itself. The flow stops at the build by name (SC1090: 'WriteStream' values where 'Writable' is expected), as on main. In Node the process stream and the Writable it is handed on as are one object with one writable state. With the conversion made for every such program, the two names answered apart without a diagnostic: - a write through process.stdout after stream.end() or stream.destroy() was written and returned true, where Node reports 'write after end'; - the stream stayed ended, finished, destroyed and closed, where Node's stdio stream is writable again after end() and destroy(); - stream.setDefaultEncoding was not seen by process.stdout.write; - with the reader gone, Node ends with the EPIPE error and exit status 1; the program ended with status 0 and no error on the stream. A program that asks for the general representation by another member (cork, end with data, a pipe) reaches the conversion as it does on main. The fixture stdout-writable-parameter stays and is now tested to stop by name. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Held again: please do not merge head 83489c4. The question left open in the last comment has an answer: A family of 500 runs, each against Node (stdout and stderr; handed to a function typed The clearest rows on this head:
The stopgap is the same as for stdin: the hand-on stops by name again, as on main. It is committed and in the sandbox checks now. One push follows; the full table against main comes with it, and the hold is lifted in a comment then. 🤖 Generated with Claude Code |
|
Pushed The writable-state family, 500 runs, each against Node, one source per cell in every tree (stdout and stderr; a function typed
On Also on the pushed tree: build, lint, format and the ts7 baseline check pass; the project-config tests pass plain and sanitized (102, the fixture The diff is one clause out of 🤖 Generated with Claude Code |
|
Hold lifted for head With the rows in the comment above, both process-stream conversions are withheld on this head and stop by name as on main: 🤖 Generated with Claude Code |
…s and the release preparation Main moved from a57eaac to cf9b741 (trains lang-13 #3451 and perf-7 #3450, #3452, #3454, #2178 and the release preparation). One file conflicted, tests/harness/coverage.test.ts: both sides added a test after the Node island copies test. Both are kept, this branch's dictionary-copies test first and main's key-order (SC6014) test after it; neither side's lines changed. Nineteen files merged without a conflict although both sides changed them, the lowering and backend files among them (generic-functions.ts, lower-calls.ts, lower-stmts.ts, lowerer.ts, narrowing.ts, binary.ts, type-mapper.ts, emitter.ts, dyn.ts, the builtin and feature tables). No generated file conflicted, and regeneration on the merged tree changes none. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Merged main
Main has since gained #3455 (four files, none of this train's, no conflict). 🤖 Generated with Claude Code |
|
CI on
So the branch has no conflict with main and no red of its own; it cannot be green on Linux until main is. Once main has the two tests fixed, I merge main again. That fix will edit the table of builtins that can throw, which this train also changes, so the merge gets the type check, the fast test list and a gate round of its own. 🤖 Generated with Claude Code |
Main is 0424e4e: train cli 27 and the fix of main's five red tests (#3457). Two files conflicted. In narrowing.ts both sides added a function at one place, the train's classRecordMemberRead and main's check of a generic instance's slot read at its declared type: both are kept. codec.generated.ts is regenerated from the merged IR types with scripts/generate-ir-codec.mjs. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Pushed The merges
Main has since gained #3461 ( Proof on
The allow list grew by two, to 178. The first round on 🤖 Generated with Claude Code |
|
The timing rerun promised above (round 17: the same head CI on this head, by cause: Main has since moved to 🤖 Generated with Claude Code |
Main is 44f9f34: #3461 (the receiver proof no longer follows a call that redefines call or apply), #3464 (one ts7 preflight baseline re-recorded) and #3462 (the TypeScript 7 frontend moves to TypeScript 7.1). Two files conflicted, both hand-written. packages/compiler/src/frontend/lowering/class-protocols.ts: both sides added an import at the same line, this branch TypeSameness and main extendsElementOf. Both stay; no other line of either side changed. tests/harness/__snapshots__/child-process.ts.txt: this branch removed the two shell-argument refusals from the fixture, which moved the remaining overload diagnostic from line 37 to line 26, and main re-recorded that diagnostic's type text as TypeScript 7.1 prints it. The snapshot is re-recorded by its test on the merged tree, not typed: it is this branch's file with 7.1's type text in its first line. lowerer.ts merged by itself. No generated file conflicted. The ts7 baselines are unchanged: the whole order-parity suite passes on the merged tree as recorded. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main is 7569a9c: #3466 (arenas keep objects reachable through virtual calls, generators, library callbacks and callback-made cycles) and #3467 (the entry a layout-mode property copy builds names its fields). No conflict. Main changes no file this branch changes: its files are the arena and region analyses, may-throw.ts, scr_dyn.h, scr_json.c, and seven new corpus programs with their costs and baselines. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main is 8152700: #3469 (a literal right operand of &&, || and ?? is answered as it was built). No textual conflict, but both sides change lowerNullishPair in expressions/binary.ts, and one line is changed by hand in this merge. Main lowers the default of `a ?? b` once, where it can be a literal built wider than the checker typed the pair, and replaced every later lowering of the default in that function with lowerDefault(). This branch adds one more place that lowers the default, for a present value that converts into the result and stays the value it is, which main could not see. Merged as written it would lower the default a second time and outside main's rule, so it calls lowerDefault() like the others. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main is e0d4334: #3465 (one object when an untyped value meets a typed record slot; typed arrays read through untyped values from the array itself), #3470 (types that carry the collector header only for the weak analysis stay out of the collector) and #3472 (CI: the sanitized native-frontend builds run on two cores). One file conflicted, codec.generated.ts. It is regenerated from the merged IR types with scripts/generate-ir-codec.mjs, not resolved by hand. Eight files that both sides change merged by themselves: dyn.ts, emit-module.ts, emitter.ts, coercions/structural.ts, expressions/narrowing.ts, lowerer.ts, ir.ts and runtime-features.ts. Main's hunks there are additions (a new expression kind in ir.ts, a function after checkedDynCast in narrowing.ts, feature rules). Co-Authored-By: Claude Code <noreply@anthropic.com>
Main is 9a6d729: #3473 (one descriptor per source file in the TypeScript 7.1 symbol table), #3471 (the macOS process.hrtime clock and three corpus tests made deterministic) and #3474 (a shared module's var export read only after its declaration ran, a dynamic import evaluated before a member read or call, package data members read through a copy). No file conflicted. Three files that both sides change merged by themselves, and both sides' hunks were read: lower-stdlib.ts: independent. Main changes npmMemberFence and its import; the train changes the Headers fences (fenceStaticHeadersMember, and it removes fenceStaticHeadersIteration). type-mapper.ts: independent. Main adds packageMemberIsData after packageTypeIsData; it calls packageDeclarations and packageDataPart, which the train does not change. lower-calls.ts: both change lowerOrdinaryCall, in different branches. Main moves the namespace member call into lowerNsMemberCall and answers a receiver that evaluates (a dynamic import); the train adds lowerUnionOptionalCallableCall as the last typed attempt before the method-call fence, about 450 lines later. Main's branch returns only for a namespace member, the train's only for a receiver that maps to a union of records, so neither sees the other's calls. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Pushed The merges since the last pushed head
On the pushed head
The full rounds, on the heads before
Not rerun on the pushed head, and what CI proves
🤖 Generated with Claude Code |
|
CI on
Nothing is pushed for this; the cure is one environment entry in that test, outside this train. 🤖 Generated with Claude Code |
Lowering fixes for typed code, as commits by compiler area on current main. This replaces #3352: the same compiler changes with test programs rewritten around the one behaviour each pins, minus one refusal that is taken back out, plus the corrections the rebuild needed.
What the commits do
functiondeclared inside another function compiles. A generic function used as a value has one identity per declaration (===, Map and Set keys, listener removal), across objects, worker threads and library instances; the build-time pins that stood in for that are gone. A nested generic function used as a value is still refused, by name.process.stdoutandprocess.stderrpassed or stored wherestream.Writableis declared are withheld (see "Not in this train"): such a program stops at the build by name (SC1090), as on main.process.stdinwherestream.Readableis declared is withheld (see "Not in this train"): such a program stops at the slot with the TypeError main gives it. A program that readsprocess.stdinwith descriptor 0 closed ends, as in Node, instead of waiting forever. OncesetEncodinghas been called onprocess.stdin, a consumer compiled for bytes stops by name where a chunk is handed to it (SC2020 at run time), and a'data'listener whose parameter is declaredstringreceives the decoded text. The stream unitscr_stream.cis main's file and its objects are byte-identical to main's.spawnandspawnSyncwithshelland a separate argument list join the arguments onto the command as Node does (with DEP0190), andshellmay be decided at run time. Merged with main'smaxBufferwork and with main's evaluation of option values a launch does not read: one check function orders the launch's values, the joined line, those option values and the limit as Node does.Object.keysandObject.entriesover whattypeof v === "object"leaves of a JSON value;left ?? rightwith a wider right side (see 7); a function created abovelet x: T;; a call through an optional callable member every arm of a record union declares; a generic rest binding typed by the type argument's fields. (Three more forms of Train pi 1: lowering fixes on pi's path (generic identity, Proxy slots, shell arguments, stdin as a stream, dictionaries and unions) #3352 reached main by other changes meanwhile: iterating a typedHeaders,Promise.allover an entry of typePromise<T | undefined> | undefined, andreduceandreduceRighton a checked-dynamic array. Main's lowering stands for them; this branch keeps its test programs.){ [key: string]: V },Record<string, V>, an alias, another module), so a value passed between two spellings is the same object.as const, a function's inferred result, an assertion's type) is built as that record where it is created, so it enters the union with no copy: every program of that shape that builds on main builds here and prints the same (a family of 1,491 programs: 1,332 equal Node; 144 differ from Node exactly as on main, with main's copy warning; 15 are refused, as on main). The same member written in two unions is one record in both. Where several arms hold a record of optional members, a value takes the arm that declares the properties it has. A dictionary record that is a union arm no longer crashes when it converts to an untyped value.left ?? rightwith a wider right side compiles where taking the left side keeps the value, and stays refused where it would copy it (SC1090, with the spellings that compile). JavaScript answers the left side itself; converting an array, a tuple or a record of another layout builds a second object, so a write through the result would miss the left side. Main refuses every such expression. In a family of 2,156 programs (7 forms of the left side, 19 kinds of value, a plain or side-effecting right side, present or absent, five things the program observes): main has 642 equal to Node, 1,324 refused and 190 that differ; this branch has 738, 1,228 and the same 190 with the same output. No program main builds is refused; 96 that main refuses compile and equal Node.1c406f827c, before the merges of main).??change did not type-check together. And the search that finds a copied dictionary compared a large union of record types with itself at every step: the compiler's own build did not get past one declaration (stopped after 55 minutes there; the build takes about nine). The search now asks first whether the target can hold a native dictionary at all. With it the self-compile budget check (scripts/self-compile-budget.mjs --check) passes: 454 s, one lowering pass, 131 bytes per source byte against a budget of 136, andCopyScanstays out of the dynamic tier (main alone in the same sandbox: 487 s, 132 bytes). The compiler's own build prints 9,850 copy reports here against 9,770 on main.??over a binding only a closure assigns builds,||stays refused. The stdin iteration test this branch adds printed the bytes of its first read and of the iteration that follows separately, so its output depended on where the pipe's chunks ended; it failed once on a loaded machine. Its fixture now reports all the bytes together (one output over twelve runs with four arrival patterns, where the old fixture had three). And the snapshot of one of main's fixtures is recorded again; see "A build-time refusal that becomes a run-time stop" below.Not in this train
process.stdout/process.stderrpassed or stored wherestream.Writableis declared is withheld by the last commit (e5da0f4dc3). The train had made that flow ask for the general stream representation by itself, so every such program reached main's conversion. Printing the writable state through both names after one operation through one name (500 runs, see "Evidence") found 103 runs on83489c44ecthat main refuses by name and that differed from Node with no diagnostic: a write throughprocess.stdoutafterstream.end()orstream.destroy()was written; the stream stayed ended, destroyed and closed where Node's stdio stream is writable again; with the reader gone the program ended with status 0 where Node ends withEPIPEand status 1; a 200 kB write to a pipe and a corked write readwritableLength0 where Node reports the queued bytes. Now the flow stops at the build withSC1090: 'WriteStream' values where 'Writable' is expected is not supported yet, as on main; a program that asks for the general representation through another member reaches the conversion as on main, with main's 52 silent runs of the family unchanged. The cure (one writable state behind both names) is a train of its own, with the stdin one.process.stdinpassed or stored wherestream.Readableis declared is withheld by the commit before it (83489c44ec). In Node the two names are one object with one readable state. The review of 21:38 UTC found thatprocess.stdin.readableLengthanswered 0 while the stream held the unread input. Printing every readable-state property through both names (41 programs, two inputs each) found 20 cells on53e1c31e7ethat differ from Node with no diagnostic, from five causes: that one;process.stdin.destroy()not destroying the stream; input held before a late conversion missing from the stream;destroyedandclosedafter the end of a file's input;closedright afterdestroy()on a file's input. Main stops such a program by name, so the conversion is not made until the two names answer as one: the program stops with main's TypeError (expected Readable, got ProcessStream). The runtime unitscr_stream_stdin.c, its link feature and its fixtures stay in the tree and no program links the unit; the differential cases and tests of the conversion are skipped with Node's answers kept, and one test pins the stop by name for the 14 fixtures that convert. The conversion returns with those five causes cured and that family as its evidence.What is refused
Every diagnostics fixture this branch adds or changes was built with main's compiler and with this branch's, site by site: no site is refused here that main builds. Three fixtures hold lines main refuses and this branch compiles (the typed union arm and the two nested generic function fixtures). Refusals this branch words anew, all at sites main refuses too:
left ?? rightwhere the left side would be copied to reach the result type (SC1090): give both sides one type, or write the copy out.let x: T;with no initializer that readsx(SC1030 instead of main's SC1090).process.stdinwherestream.Readableis declared stops at run time with a TypeError that names both types, exactly as on main (see "Not in this train"). The limitations page says so.A build-time refusal that becomes a run-time stop
let seen: { n: number } | null = null, assigned only inside a closure, thenseen ?? word()withword(): string | undefined. The checker narrowsseento null and types the pair asstring | undefined. Main refuses the line at build time. This branch builds it: while the binding is still null the program answers as Node does; when it holds a value the program stops withTypeError: a '{ n: number }' value is not representable in the target union (a value narrowed or asserted past it still held it), where Node answers the binding. Over 100 programs of the shape (five stored types of the left side, five types of the right,??and||, the binding holding a value or not): 3 that main refuses stop with that error, 3 that main refuses now equal Node, none answers differently in silence,||is unchanged, and nothing main builds is refused. The build does not warn at such a site yet; that warning is the first item of the next train.Evidence
All in Vercel Sandboxes. The pushed head is
0e6a32a9c3: five merges of main on top of6ad5580db0. It holds main9a6d7290f2(#3471, #3473, #3474). Main wasb4e908ef00when it was pushed (#3476, #3477, #3478, #3479, #3480 and train cli 28 #3463 on top): that delta merges without a conflict, nine files are both sides' and no hunk of main's lies in a region this train changes, but nothing below ran on that merge; CI's merge commit runs it (see "Not run").0e6a32a9c3merges main9a6d7290f2. No file conflicted and no line is changed by hand. Three files that both sides change merged by themselves, and both sides' hunks were read. Inlower-stdlib.tsmain changesnpmMemberFenceand this train theHeadersfences; intype-mapper.tsmain addspackageMemberIsData, which calls two functions this train does not change. Inlower-calls.tsboth changelowerOrdinaryCall, in different branches: main answers a member call off a receiver that evaluates ((await import("./m")).f(1)) as the namespace member's own call, and this train adds the call of an optional callable that every arm of a record union declares, about 450 lines later; main's branch returns only for a namespace member, this train's only for a receiver that is a union of records (see "Where the two sides meet").33d8ebd7d8merges maine0d43347aa(#3465, #3470, #3472). One file conflicted, the generatedpackages/compiler/src/ir/codec.generated.ts: it was regenerated from the merged sources, not resolved by hand. Eight files that both sides change merged by themselves (dyn.ts,emit-module.ts,emitter.ts,coercions/structural.ts,expressions/narrowing.ts,lowerer.ts,ir.ts,runtime-features.ts); main's hunks there are additions.859d769484merges main8152700b48(#3469). There is no textual conflict, but both sides changelowerNullishPairinexpressions/binary.ts, and one line is changed by hand in the merge: main now lowers the default ofa ?? bonce, where it can be a literal built wider than the checker typed the pair, and replaced every later lowering of the default in that function withlowerDefault(); this train adds one more place that lowers the default (the present value that converts into the result and stays the value it is), which main could not see, and that place now callslowerDefault()like the others.067bd10eedmerges main7569a9ca6b(#3466 and #3467): no conflict, and main changes no file this train changes.dd8031f5b4merges main44f9f34d6b(#3461, #3464, and #3462, which moves the TypeScript 7 frontend to TypeScript 7.1). Two files conflicted there, both hand-written. Inpackages/compiler/src/frontend/lowering/class-protocols.tsboth sides added an import at the same line (this trainTypeSameness, mainextendsElementOf), and both stay. Intests/harness/__snapshots__/child-process.ts.txtthis train's fixture has two refusals fewer, which moves the remaining overload diagnostic from line 37 to line 26, and main re-recorded that diagnostic's type text as TypeScript 7.1 prints it; the snapshot was re-recorded by its test on the merged tree and is this train's file with 7.1's type text in its first line. The ts7 baselines are unchanged: the whole order-parity suite passes on the merged tree as recorded (353 of 353).6ad5580db0is a merge of main6ae2f2d365(train perf 8a #3458 and #3459) into20e05369a6. One file conflicted there, the generatedpackages/compiler/src/ir/codec.generated.ts: it was regenerated from the merged sources, not resolved by hand.20e05369a6is a merge of main0424e4e684(train react 1 #3455, train cli 27 #3456, and #3457, which makes main's five red Linux tests green) intod57ec3e16c. Two files conflicted. Inpackages/compiler/src/frontend/lowering/expressions/narrowing.tsboth sides added a function at the same place (this trainclassRecordMemberRead, main the functions for stranded instance arms), and both stay, no line of either changed.packages/compiler/src/ir/codec.generated.tsis generated: it was regenerated from the merged sources, not resolved by hand, and regeneration on the merged tree changes no generated file.d57ec3e16cis a merge of maincf9b741144(trains #3451 and #3450, #3452, #3454, #2178 and the release preparation) intoe5da0f4dc3. One file conflicted there,tests/harness/coverage.test.ts: both sides added a test at the same place, and both stay; nineteen files that both sides change merged by themselves, the lowering and backend files among them, and no generated file conflicted.e5da0f4dc3is83489c44ecplus the commit that withholds the Writable hand-on, and83489c44ecis53e1c31e7eplus the one commit that withholds the stdin conversion.53e1c31e7eis the head of the full round below, then the commit that moves two stdin functions out of the stream unit, then four merges of main (6c1e5ac877, no conflict;d3f840eb2e, one conflict: both sides added a function at the same place in the call lowering, and both stay;5d42c2b87canda57eaacffd, no conflict). After each, the files both sides change were read. Main's runtime is built with the hardening flags of #3442 from the second of them on.0e6a32a9c3, against main9a6d7290f2(round 21; lanes, bench-runtime and Test262 skipped): passes. Type check passes. Gate: 5,814 programs identical, 176 allowed (below), 367 fail to build on both sides, none outside the list and no executable-only row outside it. The three more that fail on both sides are the Node island programs main gained with Read a shared module's var export only after its declaration ran, evaluate a dynamic import before a member read, and read package data members through a copy #3474: the gate builds without the Node pack, and the test list below builds and runs them with it. No program joins the list: main's new2607-dynamic-import-member-readis byte-identical, and the twoprocess-stream-write-errorprograms main changed with Fix the macOS process.hrtime clock and make the three macOS-failing corpus tests deterministic #3471 were listed already (they link the event dispatcher). Timing: bench geomean +0.44% [-0.29%, +1.32%] and fixtures +0.39% [+0.29%, +1.06%] within tolerance; compiler self-timing +1.37% [+0.57%, +2.20%], which this round reports as inconclusive (two runs; the full round one merge earlier, with the same train commits, measured +0.64% [-0.12%, +0.88%]). The compiler builds its own source in 548 s in one lowering pass, at 135 bytes per source byte against a budget of 136.9a6d7290f2built beside it:readableLengthcells: 9 of 9 rows are main's. The readable-state family: 73 of 73. The stdin family of 400 runs: 4 equal Node, 396 stop by name, 0 differ in silence, 0 hang; main: 3, 396, and the one control cell that hangs.lowerOrdinaryCall: a program that calls a function off(await import("./m.ts")), calls the optional callable on records made through a namespace and through a dynamic import, and calls it on a namespace member that holds such a record (the one call both branches look at): 18 of 18 lines equal Node here and on main. The generic-function identity probe described below: 8 of 8 lines equal Node here; main differs in 4. The??probe of Answer a literal right operand of &&, || and ?? as it was built #3469 (next bullet): 7 of 7 here and on main.33d8ebd7d8against maine0d43347aa(round 20, nothing skipped; the lanes, bench-runtime and Test262 were not rerun on the pushed head, whose only difference is the merge of main9a6d7290f2): passes. Lanes: plain 26,296 passed, 0 failed; sanitized 22,599 passed, 0 failed; both native bootstraps among them. Gate: 5,813 programs identical, 176 allowed (below), 364 fail to build on both sides, none outside the list and no executable-only row outside it. Timing, all within tolerance: bench geomean +0.31% [-0.13%, +0.98%], compiler self-timing +0.64% [-0.12%, +0.88%], fixtures -0.09% [-0.87%, +0.37%]. The compiler builds its own source in 560 s in one lowering pass, at 142 bytes per source byte against a budget of 136, inside the gate's 5% tolerance; that number is main's since Move TypeScript 7 support to TypeScript 7.1 #3462 (see the round ondd8031f5b4below). bench-runtime: 75 workloads, geomean +0.5%, 74 neutral, 1 slower:value-records+11.4% [+2.7%, +37.1%], whose executable is byte-identical to main's in the same round's gate, so the mark is measurement (the two rounds before had it neutral). Test262 (Function, Reflect, JSON, Proxy, Object): 0 regressed, 0 gained.33d8ebd7d8, in a sandbox with maine0d43347aabuilt beside it: the same test list with the same counts (without the order-parity suite), the cell families row for row main's, and the 5 programs main gained with Keep one object when an untyped value meets a typed record slot, and read typed arrays through untyped values from the array itself #3465 and Keep types that carry the collector header only for the weak analysis out of the collector #3470 and the one of Answer a literal right operand of &&, || and ?? as it was built #3469, in both backends (12), sanitized (6) and in verify mode (6), each of which builds to a byte-identical executable on main's tree and on that one. The??rules of Answer a literal right operand of &&, || and ?? as it was built #3469 and of this train (a present class instance defaulted to a literal that builds wider than the checker typed the pair, directly and through a||pair, with a write through the answer): 7 of 7 lines equal Node there and on main.859d769484against main8152700b48(round 19): passes. Lanes: plain 26,278 passed, 0 failed; sanitized 22,581 passed, 0 failed; both native bootstraps among them. Gate: 5,808 identical, 176 allowed, 364 fail to build on both sides, none outside the list and no executable-only row outside it. Timing: bench geomean -0.56% [-1.31%, +0.41%] and fixtures +0.54% [-0.25%, +1.38%] within tolerance; compiler self-timing +0.79% [+0.21%, +2.02%], which that round reports as inconclusive (the rounds before and after it measure it within tolerance). bench-runtime: 75 workloads, geomean -0.3%, 75 neutral. Test262: 0 regressed, 0 gained.dd8031f5b4against main44f9f34d6b(round 18):self-hosting-serialization.test.ts"llvm round-trips IR and produces a working program" at its 300 s limit (plain), andcommander-calcat its 120 s limit innpm.test.tsand innpm-shape-overlay.test.ts(sanitized, one shard). Each passes alone, on this tree and on main's tree in the same sandbox, in the same time. The round trip: 120 s here, 117 s on main.commander-calc, sanitized, from a cold cache: 96.5 s here, 96.6 s and 93.8 s on main, of which 85 to 87 s are the sanitized link. Its compile by phase is equal on both trees, and its LLVM module has the same number of lines and functions. These are two budgets that main's tree nearly fills by itself and a busy lane machine exceeds; both tests have timed out in rounds of unrelated branches.dd8031f5b4all of them, with the same counts (612 unit tests) and the cell families row for row main's; on067bd10eedand859d769484the build, the static checks, the unit, type mapper and diagnostics tests and the members' corpus programs in both backends and in verify mode. On067bd10eedalso the 7 programs main gained with Arenas no longer drop objects kept reachable through virtual calls, generators, library callbacks or callback-made cycles #3466 and Name the fields of the entry a layout-mode property copy builds #3467, in both backends (14), sanitized (7) and in verify mode (7): each builds to a byte-identical executable on main's tree and on this one.6ad5580db0, against main6ae2f2d365:20e05369a6against main0424e4e684(the same train commits): 5,798 identical, 176 allowed, 364 fail on both sides, none outside the list; bench geomean -0.23% [-1.66%, +1.22%], compiler self-timing +0.40% [-0.10%, +0.63%], fixtures +0.48% [-0.21%, +1.45%], all within tolerance; self-compile 594 s. The round before that one, with the list of 176, had two rows outside it of 6,356 programs compared:terminal-color-methods-piped.tsandterminal-method-answers-collected.mjs, which main gained with Train cli 27: destructured parameters without a static type, Promise.all entries, held createRequire loader members, primitive constructors as values, generic instances that bind several layouts, the terminal color methods, one island round per statement #3456 and which link the event dispatcher (see "Gate rows").Set, used as aMapkey and searched withindexOf: 8 of 8 lines equal Node here; main differs from Node in 4 of them without a diagnostic.20e05369a6with the same counts, there with the 27 programs main gained with that merge (56, 28 and 28).6ae2f2d365in the same sandbox: the writable-state family, 500 runs: 410 refused on both, 36 silent on both, 44 equal on both, 10 stop by name at run time on both, 0 hang; all 256 rows are main's, verdict and text. ThereadableLengthcells: 9 of 9 rows are main's. The readable-state family: 73 of 73. The stdin family of 400 runs: 4 equal Node, 396 stop by name, 0 differ in silence, 0 hang; main: 3, 396, and the one control cell that hangs.1c406f827cagainst the main it contains (a7783ba94c): type check passes. Lanes: plain 25,737 passed, 0 failed; sanitized 22,237 passed, 0 failed; both native bootstraps are among them, plain and sanitized. bench-runtime: 73 workloads, geomean -0.3%, 73 neutral. Test262 (Function, JSON, Proxy, Reflect, Object): 0 regressed, 0 gained. Timing: bench geomean -0.17% [-1.53%, +1.20%], compiler self-timing +0.55% [-0.29%, +1.05%], fixtures -0.36% [-1.42%, +0.81%]; the compiler builds its own source in 704 s in one lowering pass at 131 bytes per source byte (budget 136).scr_stream.cmade the C compiler lay the unit's other functions and string constants out in another order (equal file size, equal symbol names and sizes). The two functions now live in the stdin unit;scr_stream.cis main's file andscr_stream.ois byte-identical to main's in all 12 flavor objects.f6d05db1acagainst main6c1e5ac877): 5,724 programs identical, 173 allowed (below), 358 fail to build on both sides, none outside the list and no stream program among the rows; bench geomean +0.52% [-0.26%, +1.68%], compiler self-timing +0.30% [-0.37%, +1.13%], fixtures +0.69% [-0.77%, +2.16%]; self-compile 758 s, one pass, 131 bytes per source byte.cd0bd7c6dbagainst maind3f840eb2e): 5,736 identical, 173 allowed, 358 fail on both sides, none outside the list; bench geomean +0.73% [+0.08%, +1.42%], compiler self-timing +0.55% [-0.19%, +1.23%], fixtures +0.15% [-1.03%, +0.92%], all within tolerance; self-compile 535 s, one pass, 130 bytes per source byte.ce3c3e0a04against main5d42c2b87c) the gate-only round was cut off by a restart of the machine that drives it, before its self-compile and timing lines: at that point 5,742 of 6,294 programs were identical, 358 failed on both sides and none differed outside the list. It was not repeated; the next round covers its tree.53e1c31e7eagainst maina57eaacffd: 5,748 programs identical, 173 allowed, 358 fail to build on both sides, none outside the list and no stream program among the rows; bench geomean +0.31% [-0.48%, +1.23%], compiler self-timing -0.26% [-0.90%, +0.27%], fixtures +0.47% [-0.69%, +1.07%]; self-compile 498 s, one pass, 130 bytes per source byte.a57eaacffd(on its first formb8867c93a4; the pushed83489c44ecdiffers from it in two test files only): 5,748 identical, 173 allowed, 358 fail on both sides, none outside the list and no executable-only row outside it; bench geomean +0.82% [-0.09%, +1.83%], compiler self-timing +0.59% [-0.05%, +1.17%], fixtures -0.35% [-1.22%, +1.63%], all within tolerance; self-compile 494 s, one pass, 130 bytes per source byte.process.stdinbefore the hand-on, 11 consumers of the Readable, 4 inputs). On the pushed tree: 4 equal Node, 396 stop by name with main's TypeError, 0 differ in silence, 0 hang. Main: 3 equal Node, 396 stop by name, 1 hangs; the one cell that differs is a control without a conversion (a'data'listener with descriptor 0 closed), which hangs on main and ends here. With the conversion, on53e1c31e7e: 340 equal Node, 60 stop by name.process.stdoutandprocess.stderr; handed to a function typedWritable, stored in a typed field, or only apipe/pipelinedestination; 19 operations through one name; 11 writable-state properties read through both names; the reader holding a pipe, a file, or a pipe it closed early; 500 runs, each against Node, one source per cell in every tree). Maina57eaacffdagainst83489c44ec: 103 refused by name to silent, 105 refused to equal, 202 refused on both, 52 silent on both, 28 equal on both, 10 stop by name at run time on both, 0 hang. Main against the pushed tree: 410 refused on both, 52 silent on both, 28 equal, 10 loud; all 256 rows are main's, verdict and text.53e1c31e7e: 20 runs differ from Node with no diagnostic (see "Not in this train"). On the pushed tree: all 73 rows are main's, row by row (64 stop with the TypeError, 9 are refused at build time by name).83489c44ec: the build, lint, format, the ts7 baselines, the stdin tests plain and sanitized (44 passed and 18 skipped each; the skipped ones are the conversion's), and the cell families above. On its first formb8867c93a4, which has the same compiler and runtime source: the generated-file checks (regeneration changes nothing), 23 files of guard and unit tests (610 tests), the type mapper tests and the whole diagnostics suite (428).53e1c31e7e: the build, the generated-file checks (regeneration changes nothing), lint, format, the ts7 baselines, 23 files of guard and unit tests (610 tests: the stream layout test and the island value matrix, 239 of 239, among them), the type mapper tests, the whole diagnostics suite (428), the members' corpus programs and main's newest in both backends (984 cases), the same programs and the diagnostics with the type walk memo in verify mode (524 cases), the stdin tests plain and sanitized (48 of 48 each, on the runtime built with the hardening flags of Harden the vendored libraries and the runtime's stack #3442).1c406f827c, before the merges of main: island conformance in check mode (460 passed, 0 failed), order parity (153 of 153), the docs gate (25 route tests).c909fcd1a5against the main it contains: the 13 fixtures site by site (above); 26 hand-written programs, each member's feature in a function the program never calls and in one it runs: every program main builds builds here with the same answer; the Proxy programs answer exactly as on main.c909fcd1a5: this branch reports about three fifths as many lowering errors as main alone (main measured one merge earlier), no site that main does not report, and one site with the??wording of 7 where main refuses the same expression in its own words. On1c406f827cit reports the same 18 sites.Gate rows
178 programs are allowed by id, one reason per class:
scr_events.ccarries the stdin checks of 2, soscr_events_dispatchis resized: +0.07% to +0.33% of the executable. None is fully typed; the dynamic benchmarkline-readeris among them. Seventeen of them are programs main gained while this branch was validated, the last two with Train cli 27: destructured parameters without a static type, Promise.all entries, held createRequire loader members, primitive constructors as values, generic instances that bind several layouts, the terminal color methods, one island round per statement #3456 (terminal-color-methods-piped.ts, +0.30%, andterminal-method-answers-collected.mjs, +0.27%); a later program that links the dispatcher joins the class until this merges. A stream program that does not convert stdin is byte-identical: none is in the list.generic-interface-type-arguments.ts, which main gained with Train lang 13: the arguments object, Object.assign key order, generic instances, function kind tags, rejections across views, a removeAllListeners use after free, untyped Map and Set in typed slots, global object names, typed records across unknown #3451 and which holds one generic function as a value at two signatures (the same row: one field, 64 bytes of 862,696).union-dictionary-arm-untyped.ts,asserted-method-param-union-arm.ts,nullish-wider-default-keeps-left.ts. Main compiles the forms they pin differently or refuses them.unassigned-let-slot-kinds.tsdiffers in the order of one entry of the module's union table; its LLVM and its executable are byte-identical.Not run
0e6a32a9c3the lanes (plain and sanitized, with the native bootstraps), bench-runtime and Test262 did not run. They ran on33d8ebd7d8, one merge earlier, and passed with 0 failed (round 20); the pushed head adds the merge of main9a6d7290f2, which got the gate-only round and the test list above.9a6d7290f2(Leave out code a constant condition never runs, and scan text through the UTF-16 units copy in more loops #3476, Train perf 9d: answer typeof, in and Reflect.has on a stream behind an untyped value without building its member view #3477, Re-record the two @hono/zod-validator island conformance entries #3478, Give the same IR with tsgo 7.1 as with tsc-ts #3479, Train perf 9e: answer Object.keys and own-key questions about a typed record from its static layout #3480, Train cli 28: var requires of island modules, Reflect.apply and Reflect.getPrototypeOf as values, Buffer.alloc and fill with untyped arguments, stream members through optional chains, builtin globals off a stored global object, optional-chain tails, chained JavaScript declarations #3463) ran nowhere but in CI's merge commit. It merges without a conflict. One place where the two sides can meet there, which CI's corpus programs only cover by chance: Train perf 9e: answer Object.keys and own-key questions about a typed record from its static layout #3480 answersObject.keysand own-key questions about a typed record from its static layout, and this train stores the members of a union that share a discriminant literal as one record, in which the members only some of them declare are optional slots.tests/harness/coverage.test.ts's whole-corpus case exceeds its 600 s limit when the file runs alone and unsharded, on main as well (601 s on main, 600 s here, same 32-CPU sandbox); the lanes split it.🤖 Generated with Claude Code