Repository navigation
Conversation
A checked conversion accepts an island handle. A record reads each field through the handle, as Node reads a property; an array, tuple or index-signature record takes a native view of the value, with the view released at every exit. JSON.stringify, Object.keys and object spread and rest read the island object's own enumerable properties in Node, so a toJSON method, an accessor and a function-valued member keep their meaning. A program without islands emits the same code as before.
…in JSON.stringify
Two valid programs compiled and then threw at the Node island boundary.
A method call on a native value typed by an island's declarations
The island lowering claims `recv.m(args)` whenever the receiver's
declared type is island-declared. The type does not say where the value
lives: an island alias or interface may annotate a native array, Map,
object or class instance (`const messages: Input = []`). Every other
operation already follows the value at run time, but a call did not in
two cases:
- When an argument runs code, the call lowers to a member read
(`nodeIsland.get`, before the arguments, as JavaScript orders it) and
`nodeIsland.applyTo`, which assumed the held member was a native
closure or an island function. A builtin member of a native value
(`push` on an array, `set` on a Map) has no function value, so the read
answered something that is not callable and the call threw
"scriptc: a call needs a Node island value". The reported shape is a
generic instance pushing `{ ..., call_id: model + i }`; nothing in it is
specific to generics or to push.
- A native class instance threw "take is not a function" for every call,
inert arguments included: the runtime's by-name call has no table of
class methods, which only the class dispatch pass knows.
`islandMethodCall` now lowers the call in two arms. An island receiver
takes the bridge exactly as before. A native receiver takes the ordinary
checked-dynamic method call, the `dynInvoke` node the rest of the
compiler lowers `value.m(args)` to, so class methods, generator steps
and iterator helpers are dispatched by the passes that rewrite that
node. The arguments cross once, into hidden locals both arms read, and a
member that is a function value is still called as it was read
(`nodeIsland.calls`). `islandCaughtRead` already routes a caught value
this way. A call that spreads an argument keeps the runtime's routing:
`nodeIsland.applyTo` carries the member name, so a native receiver's
builtin member is called by name there too.
JSON.stringify reaching an island object
The stringify walk knew native containers only, so an island handle,
as the root or anywhere inside a native value, threw "JSON.stringify of
a runtime handle is not supported yet". The walk now serializes an
island object as it does a native one, with V8 answering every question
about the object through the island ops slot: IsArray, the length, the
own enumerable string keys in V8's order, each member's Get, and its
toJSON, called with the real key. The replacer runs with the real
holder, a property list reads the listed keys, and a native value an
island object holds is walked as the native value it is. A replacer
that is an island function or an island array is honoured, for native
values too: scr_json_stringify_value tested the native kinds only and
dropped it silently, so `JSON.stringify(nativeValue, islandReplacer)`
printed the unreplaced text. One host helper, `scriptc:json`, answers
what V8 keeps in internal slots: the text of a boxed primitive or a raw
JSON object, and the constructor name the circular-structure TypeError
prints.
All of the walk is under SCR_NODE_ISLANDS, the existing node-island
build of scr_json.c, so the default object is unchanged; ScrNiDynOps
gains two slots at its end.
Tests
- tests/corpus/8885-node-island-native-receiver-calls: the reported
push, other array members with calls, operators and spreads as
arguments, a native Map, a native object with a closure member, a
class instance and a subclass through a binding and a parameter, the
same calls on island objects, and Node's TypeError for a member that
is not a function.
- tests/corpus/8886-node-island-json-stringify: handle roots, gaps,
native and island replacers, native and island property lists (on
island and on native values), a Date's toJSON, omitted members, a
getter, boxed primitives, a raw JSON object, toJSON keys, handles
inside native records, arrays and dictionaries, a native value held by
an island object, four circular shapes, and util.format's %j.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…all them with spread arguments Two failures of a native class instance held in a binding typed by a Node island's interface. A class instance crossing into an island without its methods An island reads a class instance's prototype methods from a table. The table was registered by the crossing expression: an expression whose static type is a class was wrapped with nodeIsland.classMethods, and the runtime kept the first table it was given for each capsule type key. So: - An instance that reached the island any other way (a binding typed by the island's interface, `unknown`, a member of a record, an array or a Map, the result of a program callback) had no methods unless its class had crossed directly earlier in the run. The island threw "s.take is not a function", or silently saw `typeof s.take === "undefined"`. - The table was the static class's. A subclass instance held as its base class ran the base class's method in the island (7 where Node prints 14) and lacked the methods only the subclass declares. - The export table keeps an object's first capsule, so the static type an object first crossed under decided its methods for the rest of the run. The table now comes from the class the object was constructed as, and is looked up when the island first reads a method of the object. A program that holds island values has one function, %island.classMethods, from a capsule to that table: it tests the capsule's key and then the instance's class, most derived first, over every class a checked-dynamic value can hold (the classes the class dispatch pass found boxed, with their constructed subclasses). %main registers it once (nodeIsland.classTables) and the export keeps the answer. Nothing is registered at crossings: nodeIsland.classMethods and the per-key table are gone, and the shared-module class registration keeps only its constructor helper (nodeIsland.classConstructor). A method call with a spread argument on a class instance `sink.take(...values)` threw "take is not a function". The native arm of an island method call is the dynInvoke node, which has a fixed argument list, so a call with a spread kept the runtime's call by name, and the runtime has no table of class methods. The spread form now lowers its native arm the way the ordinary tier lowers such a call: the member read (a dynKeyGet with a literal key, which the class dispatch pass answers with the method value) before the arguments, and a dynCall that spreads the argument pack. That serves the receivers whose members compiled code dispatches (nodeIsland.isCapsule: a class instance, a generator). Other native receivers keep the runtime's call by name, which takes a list of any length and is what dynInvoke ends in for them; the ordinary tier has no method values for a native Map or Set. Programs without island values are unchanged: the function and its registration exist only when the IR holds an island operation. Co-Authored-By: Claude Code <noreply@anthropic.com>
…nd interface A generator is the other kind of native value whose members compiled code dispatches. Typed by an island's interface and stepped with `stepper.next(...steps)`, it takes the same native arm as a class instance: the member read and a call that spreads the argument pack. Co-Authored-By: Claude Code <noreply@anthropic.com>
The class dispatch pass builds the island method tables only for a program whose IR holds an operation on a Node island value. The calls that copy JSON both ways (nodeIsland.callSync, nodeIsland.call) do not count: no value crosses by reference through them. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main at 4fc60de. Conflicts, all of the "both sides added an entry at the same place" kind, resolved by keeping both: the `ScrNiDynOps` table and its initializer (main added `object_tag`, this branch `is_array` and `json_query`), the bootstrap's `load` (main added `scriptc:clone` and `scriptc:objectTag`, this branch `scriptc:json`), and the generated `scr_node_island_host.h`, regenerated with `scripts/node-island-host.mjs`. Co-Authored-By: Claude Code <noreply@anthropic.com>
eb7546b made `scr_node_island_apply_to` refuse a native receiver's member that the arguments turned into a function: JavaScript read the member before them, so the call is the TypeError for that value. That covers a call that spreads its arguments. A call with a fixed argument list does not go through it: compiled code asks `nodeIsland.calls` and, for a native receiver whose member was not a function value, makes the by-name call itself, which reads the member again and called the function the arguments had stored (`late.take(swap(late, fn, 3))` returned `fn`'s result where Node throws `late.take is not a function`). `nodeIsland.calls` now takes the member's name and the callee's text, makes the same second read after the arguments ran, and answers false with that TypeError pending; it joins the may-throw set so the pending check follows it. Members with no function value before or after (an array's push, a class method) and members that are still not functions take the by-name call as before. Corpus 8885 pins the fixed-argument forms: a function replaced by another function (the first is called), a number replaced by a function and a missing member added (both throw, naming the callee), and calls whose arguments leave the member alone. Found by the Vercel review bot on #3124. Co-Authored-By: Claude Code <noreply@anthropic.com>
Brings in #3124's new head: the fix for the bot's JSON thread and the spread call (eb7546b), main merged in at 4fc60de, and the same refusal for a call without a spread (47e4b09). Three conflicts, all where main's island crossing changes (#3005, #3093, which #3124 now contains) meet this branch's class tables: - `toIsland` (lower-node-island.ts): main's `crossByReference` wrapped a class instance with `withClassMethods`, which this branch deletes (an instance's methods come from its own class's table when the island first reads one). Kept main's structure, with `crossByReference` only boxing the value. - `scr_ni_host_export_has` (scr_node_island_export.c): main's new branch for an inherited name calls `ni_class_method`, whose signature this branch changed. It now passes the export id and clears an exception the resolver left, like the branch beside it. - `scr_node_island.h`: the two declarations side by side (`scr_node_island_calls` with its new arguments, `scr_node_island_is_capsule`). Co-Authored-By: Claude Code <noreply@anthropic.com>
#3029 (ctate/islands-value-island-a1a34a) already serializes an island value in JSON.stringify inside the existing protocol walk: the island object's kind from an `is_array` slot in ScrNiDynOps, its keys and members through scr_dyn_obj_keys and scr_dyn_obj_read, an array's length read in Node, its toJSON with the real key, and cycles by the handle's referent. This branch carried a second walk for the same thing (scr_json_island_write, its own `is_array` slot with another signature, a member-read branch, a toJSON branch and an entry in the compact walker). Both together would leave two live paths and one struct slot declared twice, so this merge deletes ours and builds on #3029's. This PR is now stacked on #3029 and merges after it. What stays is what #3029's walk does not do, each a small addition on top of it under SCR_NODE_ISLANDS. Measured with this branch's 37 JSON.stringify cases against #3029 merged with main: 27 match, and these four behaviours account for the other 10. - A replacer that is an island function or an island array is honoured (scr_json_stringify_value tested the native kinds only and ignored it, for island and native values alike), with the boxed String and Number keys of an island property list. - A boxed primitive or a raw JSON object an island made writes V8's text. Walked as an object it printed `{}`, `{"0":"s"}` or `{"rawJSON":"…"}`. The `scriptc:json` host helper answers it through the `json_query` slot, which is kept; the walk asks before it enters an island object that is not an array. - An island symbol is omitted like a native one: `[Symbol()]` inside an island object printed `[{}]` where Node prints `[null]`. - The circular-structure TypeError names an island object's constructor (`'Link'`, not `'Object'`): the walk marks the entry it pushes for an island object. Corpus 8886 gains a line for the symbol, with a Map, a Set, a hole, NaN and -0 beside it. The receiver two-arm call and its tests are untouched by the merge. Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Merging #3029 with main changes how most kinds of value cross an island boundary, and the value matrix main gained after #3029 branched pins the old answers: 107 of its 239 programs fail on #3029 merged with main, and the same 107 on this branch. The table is regenerated here for this tree (SCRIPTC_ISLAND_MATRIX=update, then a pinned run: 239 of 239). Of its change against main, 4213 entries to 3509, all but two entries are #3029's and are the same on #3029 merged with main alone, whose own regenerated table has 3511 entries: 856 gone, 154 new, 172 with another status. This PR's part is two entries gone and none new: reading a native Map-holding record back by key through an island (map-obj.p, n2i2n/N.read.getByKey with and without the island callee) threw and now matches Node. Co-Authored-By: Claude Code <noreply@anthropic.com>
Brings the island value matrix recorded for #3124's tree. Co-Authored-By: Claude Code <noreply@anthropic.com>
#3029 gained a commit (3787c75) after this branch merged it: its walk now omits an island symbol like a native one, a toJSON that is an island function on a native object is called, a handle is tracked by the value behind its box in the conversion visit, and Array.isArray follows a proxy in the bridge. The symbol was one of the four things this branch added on top of that walk, so the addition here (scr_json_island_symbol and its test in scr_json_omitted) is deleted and both conflicts resolve to #3029's side. Three remain on top: island replacers, the text of a boxed primitive or a raw JSON object, and the constructor name in the circular-structure TypeError. Co-Authored-By: Claude Code <noreply@anthropic.com>
#3029's new commit changes a few more cells (a proxied array, symbols). Regenerated for this tree and rerun pinned: 239 of 239. The table has 3515 entries; #3029 merged with main alone regenerates to 3517, and the difference is the same two entries as before, both gone here (map-obj.p, n2i2n/N.read.getByKey with and without the island callee). Co-Authored-By: Claude Code <noreply@anthropic.com>
ScrNiDynOps (scr_node_island.h and its initializer): main appended function_identity and function_of_identity (#3234), this branch json_query. All three are kept, main's first. scr_json_stringify_value: #3234 made an island function a replacer function, and this branch had made an island function or an island array one. After the merge the branch's function arm could not be reached, so main's block takes the function and the branch's block the array alone. The island value matrix is recorded again on the merged tree: 3,515 entries become 3,499. The 16 that are gone now match Node: the twelve x.constructor reads main compiles since #3165 (pinned refused:SC2020; main's own table still has them, #3298 removes them) and four identity facts of an island function that #3234 fixes. None is new and none changed status. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main's #3293 refreshes the island conformance list. Nothing conflicted. Co-Authored-By: Claude Code <noreply@anthropic.com>
Regenerated on top of main's refreshed list (#3293), with a libnode pack built from this tree's bridge: 85 entries become 67. Eighteen programs now match Node, most of them through JSON.stringify of an island value and a value an island made passing the checked conversions; six fail at a later point than before. None is new. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main's #3318 regenerates the island value matrix for main's tree. This branch's table was recorded on this branch merged with the same compiler and runtime sources (main has changed two test lists since), so it is kept as recorded; it already has #3318's two changes (the x.constructor reads, and async-iterable.p without the S.make lines that used to end the program). Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Merged main into this branch, three times as main moved while the proof ran: What conflicted.
What did not conflict and needed a decision. #3234 made an island function a replacer function in Island conformance list. Main refreshed its list (#3293) while this was in proof. This tree moves entries of its own (most of them through #3029's conversions and this PR's Re-run on the merged head (Linux x64 Sandboxes, Intel Xeon 2.90 GHz, libnode pack built from this tree's bridge; the compiler and runtime sources are those of
Not run on this head: the full lanes and the native bootstraps (the two-arm call lowering is untouched by the merge; both ran before the restack, as the description says). What #3029 still needs (not touched here; this branch contains its head
|
…all them with spread arguments (#3198)
lower-node-island.ts: main's #3254 replaced stripTypeWrappers by the shared withoutParenthesesTypeWrappers and dropped its import, next to the import this branch added. The branch's import stays, the removed one goes. scr_node_island_export.c: both sides added fields to an export slot, main the twin class state of #3271 (twin, attachment, adopts, adopted), this branch a class instance's method table (methods_known, methods). Both are kept; each side's initialization and release of its fields merged without a conflict and is intact. Co-Authored-By: Claude Code <noreply@anthropic.com>
Main's #3331 drops the stale semver entry of the island conformance list. The list recorded for this tree already lacks it (semver runs in an island by default here too), so it is kept as recorded. Co-Authored-By: Claude Code <noreply@anthropic.com>
The island value matrix conflicted again: main's #3335 changed 43 of its lines (a read of a missing member that the types decide now throws where it was wrong). The table is recorded again on the merged tree: 3,499 entries, the same 43 facts change status here (wrong to throws), none is new and none is gone. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Main moved under this branch four more times after my comment above, and the maintainer merged #3198 into it ( What the three later merges resolved.
Re-run (Linux x64 Sandboxes, Intel Xeon 2.90 GHz, libnode pack from this tree's bridge, ABI 13):
Not run on this head: the zero-cost gate (it ran on What #3029 still needs is unchanged from the comment above: an answer for its 244 differing programs and 3,301 runtime-only rows against plain main, and its own matrix and conformance tables once it takes main. |
Stacked on #3029 (
ctate/islands-value-island-a1a34a): this branch merges that PR's head and builds itsJSON.stringifypart on #3029's walk, so it must merge after #3029. Until then the diff here shows #3029's commit as well; review that one there.Two valid programs compiled and then threw at the Node island boundary. Both now match Node. Both fixes are island-only: the lowering runs only in a program with islands, and the runtime code is in island units or under
SCR_NODE_ISLANDSin the existingnode-islandbuild ofscr_json.c.1. A method call on a native value typed by an island's declarations
Before:
Uncaught TypeError: scriptc: a call needs a Node island value, exit 1. Node prints the JSON.The island lowering claims
recv.m(args)whenever the receiver's declared type is island-declared, wherever the value lives. Every other operation follows the value at run time (scr_node_island_get,_set,_invoke,_applyand_constructtake the checked-dynamic path for a non-handle). A call did not, in two cases:nodeIsland.getandnodeIsland.applyTo, andscr_node_island_apply_toassumed the held member was a native closure or an island function. A builtin member of a native value (push, a Map'sset) has no function value, so the read answered something not callable and the call reached the bridge. Nothing here is specific to generics or topush: any member, any native receiver, any argument that is not inert.const sink: Sink = new Counter(); sink.take(5)threwtake is not a function: the runtime's by-name call has no table of class methods, which only the class dispatch pass knows.islandMethodCalllowers the call in two arms:nodeIsland.invoke, or the member read first andnodeIsland.applyToafter the arguments).dynInvokenode the rest of the compiler lowersvalue.m(args)to. So class methods, generator steps and iterator helpers are dispatched by the passes that rewrite that node, and the native arm is the same code a value typedanygets.The arguments cross once, into hidden locals both arms read. A member that is a function value (a closure on a native object, an island function a native object holds) is still called as it was read (
nodeIsland.calls).islandCaughtReadalready routes a caught value with the samenodeIsland.isHandletest. A call that spreads an argument has no fixed argument list fordynInvokeand keeps the runtime's routing;nodeIsland.applyTonow carries the member name, so a native receiver's builtin member is called by name there too.2.
JSON.stringifyreaching an island object: three things on top of #3029's walk#3029 already serializes an island value inside the stringify walk (the object's kind from an
is_arrayslot inScrNiDynOps, keys and members throughscr_dyn_obj_keysandscr_dyn_obj_read, an array's length read in Node,toJSONwith the real key, omitted functions and symbols, cycles by the handle's referent). This PR used to carry a second walk for the same thing. It no longer does: the branch merges #3029 (through3787c75b9), deletes its own walk (scr_json_island_write, itsis_arrayslot, its member-read andtoJSONbranches, its symbol test and its entry in the compact walker) and keeps only what #3029's walk does not do.I ran this PR's 37
JSON.stringifycases against #3029 merged with main, compiled and under Node 24.22.1. 28 match as they are. Three behaviours account for the other 9, and each is a small addition underSCR_NODE_ISLANDSon top of that walk:JSON.stringify({ a: "x", n: 1, label: "l" }, islandFn)and(…, islandArray), on island and native values, with boxedString/Numberkeys{"a":"X","n":1,"label":"L"},{"label":"l","n":1}{"a":"x","n":1,"label":"l"}(the same on main, silently)new Number(1.5),new String("s"),new Boolean(true),JSON.rawJSON("12345678901234567890")1.5,"s",true,12345678901234567890{},{"0":"s"},{},{"rawJSON":"…"}Link… object with constructor 'Link'… object with constructor 'Object'scr_json_stringify_valuetested the native kinds of the replacer only, so an island function or an island array was dropped. It is honoured now, for island and native values, and an island property list reads boxedStringandNumberkeys with theirToString(the review fix already on this branch).scriptc:json, reached through ajson_queryslot, answers the JSON text of a boxed primitive or a raw JSON object; the walk asks before it enters an island object that is not an array.Zero cost: every line this PR adds to
scr_json.cis underSCR_NODE_ISLANDS, the unit'snode-islandbuild, so against #3029 the default object is unchanged.Evidence
tests/corpus/8885-node-island-native-receiver-calls/: the reported push; other array members with calls, operators and spreads as arguments; a native Map; a native object with a closure member; a class instance and a subclass through a binding and a parameter, with inert arguments and arguments that run code; the same calls on island objects; Node's TypeError for a member that is not a function, after the arguments ran.tests/corpus/8886-node-island-json-stringify/: handle roots (object,any, array, index-like keys); gaps; native and island replacers; native and island property lists; a Date'stoJSON; omitted undefined and function members; a getter; boxed primitives, a symbol and a function inside an array; a raw JSON object;toJSONkeys as a root, a record member and an array element; handles inside a native record, array and dictionary; a native value held by an island object; four circular shapes;util.format's%j.tests/harness/island-value-matrix/expected.jsonis regenerated for this tree. Merging islands: a value an island made passes the checked conversions #3029 with main changes how most kinds of value cross, and the matrix main gained after islands: a value an island made passes the checked conversions #3029 branched pins the old answers: 107 of its 239 programs fail on islands: a value an island made passes the checked conversions #3029 merged with main alone, and the same 107 here before the regeneration. Against main the table goes from 4213 entries to 3515. All but two of those changes are islands: a value an island made passes the checked conversions #3029's: islands: a value an island made passes the checked conversions #3029 merged with main regenerates to 3517 (857 entries gone, 161 new, 171 with another status). This PR's part is two entries gone and none new (map-obj.p,n2i2n/N.read.getByKey, with and without the island callee: threw, now matches Node). When islands: a value an island made passes the checked conversions #3029 records its own table this file will conflict and is regenerated again.Since the merge with main (
adb045cfe, main326aef394)x.constructorreads main compiles since Read an instance's class through x.constructor, and compile static accessors #3165 and four identity facts of an island function that Use a Node island's function as a value: one typed view, one identity #3234 fixes now match Node; none new). The conformance list is regenerated on top of main's Refresh the Node island conformance list to what main gives #3293: 85 entries become 67, none new.scr_json_stringify_value: main's Use a Node island's function as a value: one typed view, one identity #3234 takes an island function replacer, this PR's block the island array alone.50bcfe1b3+ islands: a value an island made passes the checked conversions #30293787c75b9,--gate-corpus=all: PASS, 5,295 identical, 109 both-fail, 0 differing, 0 runtime-only. Island suites and matrix 354/354 plain and sanitized, island corpus 234/234 plain and sanitized, conformance lane 413 passed, the 37-case table 37/37. Details and what was not re-run are in the merge comment below.9cdb212dd, main23f1b176f): Give class instances their own class's methods in Node islands, and call them with spread arguments #3198 is merged into this branch (its own delta: gate PASS, 5,295 identical), and main was merged three more times; the matrix table is recorded again (3,499 entries, 43 status changes that main's Evaluate the operand of a comparison with undefined or null that the types decide #3335 also made, none new). Island suites and matrix 374/374 and island corpus 264/264 on that head. See the second merge comment.Gates
Proved against #3029 merged with main (
4775581e3= main716cb8626+ #30293787c75b9), so the comparison is this PR's own delta. Head2ba11f120; the gate ran on70d98a984, which differs from the head only in the regenerated matrix table. Sandboxes: Intel Xeon 2.50 and 2.90 GHz.--gate-corpus=all: PASS. 5247 identical, 103 both-fail (the island programs: the gate runs without a libnode pack, on both sides), 0 differing, 0runtime-onlyrows, over the benchmarks, the whole corpus, the fixtures and the self-hosted compiler ("candidate compiler source builds with the candidate"). Bench geomean +0.21 % (95 % CI −0.94 %, +1.01 %). The runtime pack differs only in thenode-islandbuilds ofscr_json.cand inscr_node_island.c/scr_node_island_handle.c. An earlier round on the first merge (b92abbd93against main + islands: a value an island made passes the checked conversions #30292d07592af) gave the same counts.node-islandandisland-valuecorpus program in the differential and LLVM-differential suites, plain 174/174 and sanitized 174/174; the eight island suites and the value matrix, 344/344 (matrix 239/239 pinned); their,node-islandsand host-header unit tests, 874/874;pnpm lint,pnpm format:check,pnpm test:ts7 --baselines-only.JSON.stringifytable: 37/37 here, 28/37 on islands: a value an island made passes the checked conversions #3029 merged with main.5de1aa70b, the gate and both bootstraps again for the review fixes at47e4b09e7, and a pi before/after pair with identical diagnostics (62 and 62). The stacked Give class instances their own class's methods in Node islands, and call them with spread arguments #3198 reruns the bootstraps on this tree plus its own commits.8810-node-island-sdk-request-values+88 B,6834-node-island-package-callbacks+2,496 B (+0.27 %),6848-node-island-handle-ops+23,800 B (+2.6 %). Programs without islands are byte-identical (the gate).Still failing, found on the way (not in this PR)
doc.when.getTime()for aDatemember,first(listOf<Rec>())), compiles and throwsexpected Date at $, got Objectat run time:fromIsland's last-resort checked cast. islands: a value an island made passes the checked conversions #3029 changes parts of this; the matrix table shows where.Promiseare lost, because every V8 promise crosses as a scriptc promise.🤖 Generated with Claude Code