Repository navigation
Conversation
…ition A checked-dynamic value that flows into a generator-typed slot (Generator, IterableIterator, Iterator) goes through the iterator adapter, a new native generator that steps its source. Beside a Node island that made three silent wrong answers: - An island iterator was another object in the program each time it crossed (`kept() === made` was false, a Map keyed by it missed), and the adapter went back into the island as a native export, a third object there (`same(made)` was false). - A generator the program handed to the island came back wrapped in an adapter (`keep(own) === own` was false). - The adapter read every value out of an island iterable before its first step, so the program's first `next()` ended the island's generator, and an island generator that never ends could not be read at all. Now an island iterator the program gives a generator type is one native generator for each such type. The island unit keeps the pair in its pin table (NH_PIN_ITER, beside promises, errors, byte views and symbols) until the table is the generator's last holder. In a program that uses an island: - every conversion of a dynamic value into a generator-typed slot goes through `%iter.exact`, the helper arrays of generators already use: the value itself when it is the native generator of the slot's type (a generator back from the island), the generator already paired with an island iterator, else a new adapter, which is paired; - a checked cast into a generator type, and the argument check of a native callback, take a paired island iterator as its generator; - a generator's dynamic value is the island iterator it is paired with, as its handle (the backend boxes generators through scr_node_island_iter_ref), so it goes back into the island as the island's own object, compares equal to a handle of it and is the same key of a dynamic collection; - the adapter steps an island value's own iterator in the island, one value at a time (scr_node_island_iterator). The bridge protocol and the crossing paths do not change (the bridge ABI stays 20). A program without islands compiles as before: the helper, the boxing entry and the cast's question exist only where the program links an island. Arrays of generators beside an island stay refused. An island iterator handed to a native callback whose parameter has a generator type still throws the TypeError it threw unless the program already holds that iterator with that type. tests/corpus/node-island-iterator-identity pins both directions, the untyped views, two generator types of one iterator, the shared position and an endless island generator. Co-Authored-By: Claude Code <noreply@anthropic.com>
Regenerated by the matrix's update mode. In the generator, lazy generator, endless generator, array iterator and iterator object programs with a declared type, 187 observations that were pinned as wrong (77), unsupported (79), throwing (25) or crashing (6) now match Node: identity through a parameter, a field, a Map key and a round trip in both directions, reads in order on both sides, and reads of a generator that never ends. Eight observations that matched are pinned as unsupported: `for (k in v)` over a generator-typed island value held as `unknown` (`i2n/U.forin` and `clo-i2n/U.forin` of four programs). The value is the island's iterator again where it is dynamic, and `for…in` over an island value is not implemented yet: it throws by name where it used to loop zero times over the adapter. Co-Authored-By: Claude Code <noreply@anthropic.com>
`for (k in v)` over an object that lives in a Node island (an object, an array, a function, an iterator, a Proxy, a package's exports) ended the program with "for-in over this checked-dynamic kind is not supported yet". It now visits the enumerable string keys of the object and of its prototype chain, in Node's order. A key that is gone when the loop reaches it is skipped and a key added during the loop is not visited, as in Node. The loop over a dynamic receiver keeps its form: a key snapshot when it starts and a test of each key before its visit. In a program that uses an island a final pass (island-for-in.ts) routes both to the island unit, which asks Node for an island value and the native entries for every other value. Programs without islands keep their IR. Node answers through two helpers of the island host, loaded like its other intrinsics, so the bridge and its ABI are unchanged. The key list crosses as one JSON text. A chain of ordinary objects is walked by V8's own for-in and tested with `in`. A Proxy is asked what for-in asks it, when for-in asks it: `ownKeys` and `getPrototypeOf` when the loop starts, the key's descriptor when the loop reaches the key, so its traps run in Node's order between the loop's passes. Kept loud by name: for-in over the namespace that require() answers for an ES module with a default export. That object is Node's facade of the module and carries an `__esModule` key the module's own namespace does not have. Corpus: node-island-for-in (kinds of value, views, changes during the loop, Proxy traps, a callback, both directions) and node-island-for-in-exports (a package's exports from a CommonJS program). Co-Authored-By: Claude Code <noreply@anthropic.com>
Values of a Node island keep what they are: an iterator that crosses an island keeps its identity and its position, and for-in over an island value visits what Node visits. The branch's two regenerations after this commit (the value matrix re-pin and one line of the conformance list) are not merged: both files are main's here and are regenerated on the train by their update modes. Conflict: builtin-never-throw.ts (main's dyn.nativeSearchParamsIs and the branch's two iterator entries, both kept). The island value matrix is main's file. Co-Authored-By: Claude Code <noreply@anthropic.com>
…alues Regenerated by the matrix's update mode on this tree. 438 pins leave (3,476 to 3,038), every one because the cell matches Node now; no pin is added and no pin changes its kind. - 251 pins in 76 programs: for-in over an island value (`forin` and its `forin#…` observations), which was `unsupported`. - 187 pins in the five iterator programs (generator, generator-lazy, generator-infinite, iter-array, iter-object): an island iterator keeps its identity and its position, so observations that were `wrong`, `unsupported`, `throws` or `crash` match. Co-Authored-By: Claude Code <noreply@anthropic.com>
Regenerated by the lane's update mode on this tree (453 passed, 68 skipped); one signature moves. The program now gets past its for-in over an island object and stops three lines later at `Object.getOwnPropertyNames(islandObject)`, which is refused by name (SC2020). Loud before, loud after. Co-Authored-By: Claude Code <noreply@anthropic.com>
No conflict; nine files from main, none the train changes. Co-Authored-By: Claude Code <noreply@anthropic.com>
One conflict, the island value matrix: main's file is taken here and the matrix is regenerated by its update mode in the next commit. The island host script, its generated header, the lowerer and the conformance list merged without one. Co-Authored-By: Claude Code <noreply@anthropic.com>
Regenerated by the matrix's update mode after the merge of main, from main's file: the same 438 pins leave (3,450 to 3,012), every one because the cell matches Node now; no pin is added and no pin changes its kind. 251 are for-in observations over island values, 187 are in the five iterator programs. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
HOLD: do not merge yet. The review thread on |
|
HOLD, confirmed: do not merge head An island iterator that the program holds with a generator type and as The pair of the island iterator and its native generator is dropped while an untyped holder of the value is alive. The details and the three outputs are in the thread. This comment is followed by a fix on this branch or by the removal of the unit. 🤖 Generated with Claude Code |
Reverts the member's merge 0206a8e and the train's own commits that depend on it: the island value matrix re-pin 482ca94 (1c65865 had already given way to main's file in the merge 78c93f0) and the conformance list 2ceab61. The tree is now the tree of main d3f840e, the last main this train merged. The member's iterator commit 38942de drops the pair of an island iterator and its native generator while an untyped holder of the value is alive: nh_pin_dead calls an NH_PIN_ITER pin dead once the table's capsule is the generator's last holder, and an `unknown` holder holds the island handle, not the capsule. A cast back to the generator type after the next island entry then throws "expected Generator at $, got Object from a Node island" where Node and main step the iterator. The for-in commit d8db4fb was proven only stacked on the iterator commit, so both go back to their owner. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
The head is now main's tree: The finding in the review thread was real (Node and main step the iterator, 🤖 Generated with Claude Code |
|
Closing: this train is withdrawn. The review finding was a real regression (an island iterator held as 🤖 Generated with Claude Code |
Withdrawn: this train carries no change
The head
b72aa656d2has the same tree as maina57eaacffd. The train's one member,fix/islands-values-batch-2(d8db4fb85d), is reverted ind3ea93cbc8together with the value matrix re-pin and the conformance list entry that depended on it. Merging this PR changes no file. It can be closed.Why
The review bot's finding on
packages/compiler/src/backend/llvm/dyn.ts:2991-2995is real, and it is a regression of the member's iterator commit38942dee84("An iterator that crosses a Node island keeps its identity and its position").A program holds an island iterator with a generator type and as
unknown. The typed holder goes away, the program enters the island again, and the untyped value is cast back to the generator type and stepped. Program: an eight-case repro over thetunespackage oftests/corpus/node-island-iterator-identity; it is in the review thread.482ca941dfThe throw is
expected Generator at $, got Object from a Node island. The plain and the sanitized builds print the same.The cause is the lifetime of the pin that pairs an island iterator with its native generator.
nh_pin_deadinpackages/runtime/src/scr_node_island_handle.ccalls anNH_PIN_ITERpin dead once the table's capsule is the generator's last holder. Anunknownholder holds the island handle, not the capsule, so the sweep at the next island entry (the young pins) or at 64 pins (every pin) drops the pair, and the checked cast finds no generator for the handle.The fix is not a small one: the runtime cannot read how many references the generator itself holds on the island value. Both commits of the member go back to their owner; the for-in commit
d8db4fb85dwas proven only stacked on the iterator commit.What had passed on the withdrawn head
For the record: the gate-only round, the island conformance lane, the value matrix, the weak-key tests, the island harness, 3,000 stress runs and 600 ThreadSanitizer runs all passed on
482ca941dfor on its parent78c93f0d1b(the two differ only in the value matrix's expected file). None of them holds an island iterator only as an untyped value across an island entry.🤖 Generated with Claude Code