mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
Keep the helper for callbacks that read a local class's captures
A lone array callback in a local class's method could read a binding the method reaches through its class's captures. Those bindings are shared by every method of the class, so another method can assign one while the loop runs, but the copied loop read the value once when the call started. stableTarget now counts a method's class captures as inherited, so such a callback keeps its helper and reads the current value on every call.
This commit is contained in:
@@ -950,11 +950,14 @@ class PipelineFusion {
|
||||
* nothing assigns after their declaration: `fn`'s own locals and
|
||||
* parameters, written neither by `fn` nor by any closure that shares
|
||||
* them, and not by the callback body. A binding a local class captures
|
||||
* counts as written, since its methods may assign it. The callback must
|
||||
* counts as written, since its methods may assign it; so does a binding
|
||||
* a method reads through its class's captures. The callback must
|
||||
* not observe the ambient receiver (AmbientReceiverReaders). */
|
||||
private stableTarget(fn: IrFunction): InlineTarget {
|
||||
const locals = new Map(fn.locals.map((l) => [l.id, l]));
|
||||
const inherited = new Set((fn.captures ?? []).map((c) => c.localId));
|
||||
const inherited = new Set(
|
||||
[...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId),
|
||||
);
|
||||
const written = this.written.get(fn.name);
|
||||
const classCaptured = this.classCaptured(fn);
|
||||
return (arg) => {
|
||||
|
||||
@@ -249,3 +249,20 @@ console.log(out.join(","), hit);
|
||||
${postlude}`);
|
||||
expect(helperCalls(init(mod))).toEqual(["%arr.loop", "%arr.loop"]);
|
||||
});
|
||||
|
||||
test("a lone call in a local class's method keeps its helper for the class's captures", async () => {
|
||||
const mod = await lowerSource(`${prelude}
|
||||
let k = 1;
|
||||
class Box {
|
||||
set(v: number): void { k = v; }
|
||||
go(): number[] {
|
||||
const b = new Box();
|
||||
return rows.map((r) => { b.set(r.id); return r.value + k; });
|
||||
}
|
||||
}
|
||||
console.log(new Box().go().join(","));
|
||||
${postlude}`);
|
||||
const go = mod.functions.find((f) => f.name.endsWith(".Box.go"));
|
||||
expect(go).toBeDefined();
|
||||
expect(helperCalls(go!)).toEqual(["%arr.map"]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user