Skip to content

Commit ec35670

Browse files
committed
[compiler] Implement support for non-declaration for initializers
ghstack-source-id: 894914a Pull Request resolved: #31712
1 parent 76d603a commit ec35670

File tree

6 files changed

+101
-53
lines changed

6 files changed

+101
-53
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -519,27 +519,23 @@ function lowerStatement(
519519

520520
const initBlock = builder.enter('loop', _blockId => {
521521
const init = stmt.get('init');
522-
if (!init.isVariableDeclaration()) {
523-
builder.errors.push({
524-
reason:
525-
'(BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement',
526-
severity: ErrorSeverity.Todo,
527-
loc: stmt.node.loc ?? null,
528-
suggestions: null,
522+
if (init.isVariableDeclaration()) {
523+
lowerStatement(builder, init);
524+
} else if (init.isExpression()) {
525+
lowerExpressionToTemporary(builder, init);
526+
} else {
527+
lowerValueToTemporary(builder, {
528+
kind: 'Primitive',
529+
loc: stmt.node.loc ?? GeneratedSource,
530+
value: undefined,
529531
});
530-
return {
531-
kind: 'unsupported',
532-
id: makeInstructionId(0),
533-
loc: init.node?.loc ?? GeneratedSource,
534-
};
535532
}
536-
lowerStatement(builder, init);
537533
return {
538534
kind: 'goto',
539535
block: testBlock.id,
540536
variant: GotoVariant.Break,
541537
id: makeInstructionId(0),
542-
loc: init.node.loc ?? GeneratedSource,
538+
loc: init.node?.loc ?? GeneratedSource,
543539
};
544540
});
545541

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from '../HIR';
1919
import {
2020
HIRFunction,
21+
InstructionKind,
2122
ReactiveBreakTerminal,
2223
ReactiveContinueTerminal,
2324
ReactiveFunction,
@@ -364,26 +365,25 @@ class Driver {
364365
const init = this.visitValueBlock(terminal.init, terminal.loc);
365366
const initBlock = this.cx.ir.blocks.get(init.block)!;
366367
let initValue = init.value;
367-
if (initValue.kind === 'SequenceExpression') {
368+
const initBlockHasDeclarations = initBlock.instructions.some(
369+
instr =>
370+
instr.value.kind === 'DeclareContext' ||
371+
instr.value.kind === 'DeclareLocal' ||
372+
((instr.value.kind === 'StoreContext' ||
373+
instr.value.kind === 'StoreLocal') &&
374+
instr.value.lvalue.kind !== InstructionKind.Reassign),
375+
);
376+
if (
377+
initValue.kind === 'SequenceExpression' &&
378+
initBlockHasDeclarations
379+
) {
368380
const last = initBlock.instructions.at(-1)!;
369381
initValue.instructions.push(last);
370382
initValue.value = {
371383
kind: 'Primitive',
372384
value: undefined,
373385
loc: terminal.loc,
374386
};
375-
} else {
376-
initValue = {
377-
kind: 'SequenceExpression',
378-
instructions: [initBlock.instructions.at(-1)!],
379-
id: terminal.id,
380-
loc: terminal.loc,
381-
value: {
382-
kind: 'Primitive',
383-
value: undefined,
384-
loc: terminal.loc,
385-
},
386-
};
387387
}
388388

389389
const testValue = this.visitValueBlock(

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,8 @@ function codegenForInit(
13541354
init: ReactiveValue,
13551355
): t.Expression | t.VariableDeclaration | null {
13561356
if (init.kind === 'SequenceExpression') {
1357+
// We may end up emitti
1358+
const temp = cx.temp;
13571359
const body = codegenBlock(
13581360
cx,
13591361
init.instructions.map(instruction => ({
@@ -1363,7 +1365,7 @@ function codegenForInit(
13631365
).body;
13641366
const declarators: Array<t.VariableDeclarator> = [];
13651367
let kind: 'let' | 'const' = 'const';
1366-
body.forEach(instr => {
1368+
for (const instr of body) {
13671369
let top: undefined | t.VariableDeclarator = undefined;
13681370
if (
13691371
instr.type === 'ExpressionStatement' &&
@@ -1375,30 +1377,29 @@ function codegenForInit(
13751377
top?.init == null
13761378
) {
13771379
top.init = instr.expression.right;
1378-
} else {
1379-
CompilerError.invariant(
1380-
instr.type === 'VariableDeclaration' &&
1381-
(instr.kind === 'let' || instr.kind === 'const'),
1382-
{
1383-
reason: 'Expected a variable declaration',
1384-
loc: init.loc,
1385-
description: `Got ${instr.type}`,
1386-
suggestions: null,
1387-
},
1388-
);
1380+
} else if (
1381+
instr.type === 'VariableDeclaration' &&
1382+
(instr.kind === 'let' || instr.kind === 'const')
1383+
) {
13891384
if (instr.kind === 'let') {
13901385
kind = 'let';
13911386
}
13921387
declarators.push(...instr.declarations);
1388+
} else {
1389+
/*
1390+
* We found instructions in the initializer that don't correspond to a variable declarator:
1391+
* emit as an expression instead
1392+
*/
1393+
cx.temp = temp;
1394+
return codegenInstructionValueToExpression(cx, init);
13931395
}
1394-
});
1395-
CompilerError.invariant(declarators.length > 0, {
1396-
reason: 'Expected a variable declaration',
1397-
loc: init.loc,
1398-
description: null,
1399-
suggestions: null,
1400-
});
1401-
return t.variableDeclaration(kind, declarators);
1396+
}
1397+
if (declarators.length > 0) {
1398+
return t.variableDeclaration(kind, declarators);
1399+
} else {
1400+
cx.temp = temp;
1401+
return codegenInstructionValueToExpression(cx, init);
1402+
}
14021403
} else {
14031404
return codegenInstructionValueToExpression(cx, init);
14041405
}

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,6 @@ let moduleLocal = false;
8686
8787
Todo: (BuildHIR::lowerStatement) Handle ClassDeclaration statements (5:10)
8888
89-
Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (20:22)
90-
91-
Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (23:25)
92-
93-
Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (26:28)
94-
9589
Todo: (BuildHIR::lowerStatement) Handle empty test in ForStatement (26:28)
9690
9791
Todo: (BuildHIR::lowerExpression) Handle tagged template with interpolations (30:32)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
## Input
3+
4+
```javascript
5+
function Foo() {
6+
let i = 0;
7+
for (42; i < 1; i += 1) {}
8+
for (bar(); i < 1; i += 1) {}
9+
for (; i < 1; i += 1) {}
10+
for (i = 0; i < 1; i += 1) {}
11+
}
12+
13+
function bar() {}
14+
15+
export const FIXTURE_ENTRYPOINT = {
16+
fn: Foo,
17+
params: [],
18+
};
19+
20+
```
21+
22+
## Code
23+
24+
```javascript
25+
function Foo() {
26+
let i = 0;
27+
for (42; i < 1; i = i + 1, i) {}
28+
for (bar(); i < 1; i = i + 1, i) {}
29+
for (undefined; i < 1; i = i + 1, i) {}
30+
for (i = 0; i < 1; i = i + 1, i) {}
31+
}
32+
33+
function bar() {}
34+
35+
export const FIXTURE_ENTRYPOINT = {
36+
fn: Foo,
37+
params: [],
38+
};
39+
40+
```
41+
42+
### Eval output
43+
(kind: ok)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function Foo() {
2+
let i = 0;
3+
for (42; i < 1; i += 1) {}
4+
for (bar(); i < 1; i += 1) {}
5+
for (; i < 1; i += 1) {}
6+
for (i = 0; i < 1; i += 1) {}
7+
}
8+
9+
function bar() {}
10+
11+
export const FIXTURE_ENTRYPOINT = {
12+
fn: Foo,
13+
params: [],
14+
};

0 commit comments

Comments
 (0)