@samitouri / QOS-React-1 / commits / 200d2c379d

Fix for loops with value block index initial value

Joe Savona committed Mar 22, 2024 at 14:51 UTC 200d2c379dd3acb024ec0b2ef9d649bb1d149bdd
3 files changed +121 -11
compiler/packages/babel-plugin-react-forget/src/SSA/LeaveSSA.ts
+22 -11
@@ -23,6 +23,7 @@ import {
23 eachInstructionValueOperand,
24 eachPatternOperand,
25 eachTerminalOperand,
26 + eachTerminalSuccessor,
27 terminalFallthrough,
28 } from "../HIR/visitors";
29
@@ -340,8 +341,14 @@ export function leaveSSA(fn: HIRFunction): void {
341 * To avoid generating a let binding for the initializer prior to the loop,
342 * check to see if the for declares an iterator variable.
343 */
343 - while (init.id !== initContinuation) {
344 - for (const instr of init.instructions) {
344 + const queue: Array<BlockId> = [init.id];
345 + while (queue.length !== 0) {
346 + const blockId = queue.shift()!;
347 + if (blockId === initContinuation) {
348 + break;
349 + }
350 + const block = fn.body.blocks.get(blockId)!;
351 + for (const instr of block.instructions) {
352 if (
353 instr.value.kind === "StoreLocal" &&
354 instr.value.lvalue.kind !== InstructionKind.Reassign
@@ -362,25 +369,29 @@ export function leaveSSA(fn: HIRFunction): void {
369 }
370 }
371
365 - let next: BlockId | null = null;
366 - switch (init.terminal.kind) {
372 + switch (block.terminal.kind) {
373 case "maybe-throw": {
368 - next = init.terminal.continuation;
374 + queue.push(block.terminal.continuation);
375 break;
376 }
377 case "goto": {
372 - next = init.terminal.block;
378 + queue.push(block.terminal.block);
379 + break;
380 + }
381 + case "branch":
382 + case "logical":
383 + case "optional":
384 + case "ternary":
385 + case "label": {
386 + for (const successor of eachTerminalSuccessor(block.terminal)) {
387 + queue.push(successor);
388 + }
389 break;
390 }
391 default: {
392 break;
393 }
394 }
379 - if (next === null) {
380 - break;
381 - }
382 -
383 - init = fn.body.blocks.get(next)!;
395 }
396
397 if (terminal.kind === "for" && terminal.update !== null) {
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/for-loop-with-value-block-initializer.expect.md new
+77
@@ -0,0 +1,77 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +const TOTAL = 10;
6 +function Component(props) {
7 + const items = [];
8 + for (let i = props.start ?? 0; i < props.items.length; i++) {
9 + const item = props.items[i];
10 + items.push(<div key={item.id}>{item.value}</div>);
11 + }
12 + return <div>{items}</div>;
13 +}
14 +
15 +export const FIXTURE_ENTRYPOINT = {
16 + fn: Component,
17 + params: [
18 + {
19 + start: null,
20 + items: [
21 + { id: 0, value: "zero" },
22 + { id: 1, value: "one" },
23 + ],
24 + },
25 + ],
26 +};
27 +
28 +```
29 +
30 +## Code
31 +
32 +```javascript
33 +import { unstable_useMemoCache as useMemoCache } from "react";
34 +const TOTAL = 10;
35 +function Component(props) {
36 + const $ = useMemoCache(5);
37 + let items;
38 + if ($[0] !== props.start || $[1] !== props.items) {
39 + items = [];
40 + for (let i = props.start ?? 0; i < props.items.length; i++) {
41 + const item = props.items[i];
42 + items.push(<div key={item.id}>{item.value}</div>);
43 + }
44 + $[0] = props.start;
45 + $[1] = props.items;
46 + $[2] = items;
47 + } else {
48 + items = $[2];
49 + }
50 + let t0;
51 + if ($[3] !== items) {
52 + t0 = <div>{items}</div>;
53 + $[3] = items;
54 + $[4] = t0;
55 + } else {
56 + t0 = $[4];
57 + }
58 + return t0;
59 +}
60 +
61 +export const FIXTURE_ENTRYPOINT = {
62 + fn: Component,
63 + params: [
64 + {
65 + start: null,
66 + items: [
67 + { id: 0, value: "zero" },
68 + { id: 1, value: "one" },
69 + ],
70 + },
71 + ],
72 +};
73 +
74 +```
75 +
76 +### Eval output
77 +(kind: ok) <div><div>zero</div><div>one</div></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/for-loop-with-value-block-initializer.js new
+22
@@ -0,0 +1,22 @@
1 +const TOTAL = 10;
2 +function Component(props) {
3 + const items = [];
4 + for (let i = props.start ?? 0; i < props.items.length; i++) {
5 + const item = props.items[i];
6 + items.push(<div key={item.id}>{item.value}</div>);
7 + }
8 + return <div>{items}</div>;
9 +}
10 +
11 +export const FIXTURE_ENTRYPOINT = {
12 + fn: Component,
13 + params: [
14 + {
15 + start: null,
16 + items: [
17 + { id: 0, value: "zero" },
18 + { id: 1, value: "one" },
19 + ],
20 + },
21 + ],
22 +};