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
+};