Skip to content

Commit 9f3bbb0

Browse files
committed
[compiler] Make inserting outlined functions more resilient
To handle more cases, always append the synthetic outlined function as a new child of the module rather than make assumptions about the original function. This should handle whatever case where the original function expression may be a child of a variety of parents ghstack-source-id: 8581edb Pull Request resolved: #30466
1 parent d529a43 commit 9f3bbb0

File tree

5 files changed

+100
-76
lines changed

5 files changed

+100
-76
lines changed

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export function createNewFunctionNode(
196196
}
197197

198198
function insertNewOutlinedFunctionNode(
199+
program: NodePath<t.Program>,
199200
originalFn: BabelFn,
200201
compiledFn: CodegenFunction,
201202
): NodePath<t.Function> {
@@ -216,14 +217,6 @@ function insertNewOutlinedFunctionNode(
216217
*/
217218
case 'ArrowFunctionExpression':
218219
case 'FunctionExpression': {
219-
CompilerError.invariant(
220-
originalFn.parentPath.isVariableDeclarator() &&
221-
originalFn.parentPath.parentPath.isVariableDeclaration(),
222-
{
223-
reason: 'Expected a variable declarator parent',
224-
loc: originalFn.node.loc ?? null,
225-
},
226-
);
227220
const fn: t.FunctionDeclaration = {
228221
type: 'FunctionDeclaration',
229222
id: compiledFn.id,
@@ -233,8 +226,7 @@ function insertNewOutlinedFunctionNode(
233226
params: compiledFn.params,
234227
body: compiledFn.body,
235228
};
236-
const varDecl = originalFn.parentPath.parentPath;
237-
const insertedFuncDecl = varDecl.insertAfter(fn)[0]!;
229+
const insertedFuncDecl = program.pushContainer('body', [fn])[0]!;
238230
CompilerError.invariant(insertedFuncDecl.isFunctionDeclaration(), {
239231
reason: 'Expected inserted function declaration',
240232
description: `Got: ${insertedFuncDecl}`,
@@ -468,7 +460,11 @@ export function compileProgram(
468460
reason: 'Unexpected nested outlined functions',
469461
loc: outlined.fn.loc,
470462
});
471-
const fn = insertNewOutlinedFunctionNode(current.fn, outlined.fn);
463+
const fn = insertNewOutlinedFunctionNode(
464+
program,
465+
current.fn,
466+
outlined.fn,
467+
);
472468
fn.skip();
473469
ALREADY_COMPILED.add(fn.node);
474470
if (outlined.type !== null) {

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-outlining-in-react-memo.expect.md

Lines changed: 0 additions & 62 deletions
This file was deleted.

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/outlining-in-func-expr.expect.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ const Component2 = (props) => {
5050
}
5151
return t1;
5252
};
53-
function _temp(item) {
54-
return <li key={item.id}>{item.name}</li>;
55-
}
5653

5754
export const FIXTURE_ENTRYPOINT = {
5855
fn: Component2,
@@ -65,6 +62,9 @@ export const FIXTURE_ENTRYPOINT = {
6562
},
6663
],
6764
};
65+
function _temp(item) {
66+
return <li key={item.id}>{item.name}</li>;
67+
}
6868

6969
```
7070
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
2+
## Input
3+
4+
```javascript
5+
function Component(props) {
6+
return <View {...props} />;
7+
}
8+
9+
const View = React.memo(({items}) => {
10+
return (
11+
<ul>
12+
{items.map(item => (
13+
<li key={item.id}>{item.name}</li>
14+
))}
15+
</ul>
16+
);
17+
});
18+
19+
export const FIXTURE_ENTRYPOINT = {
20+
fn: Component,
21+
params: [
22+
{
23+
items: [
24+
{id: 2, name: 'foo'},
25+
{id: 3, name: 'bar'},
26+
],
27+
},
28+
],
29+
};
30+
31+
```
32+
33+
## Code
34+
35+
```javascript
36+
import { c as _c } from "react/compiler-runtime";
37+
function Component(props) {
38+
const $ = _c(2);
39+
let t0;
40+
if ($[0] !== props) {
41+
t0 = <View {...props} />;
42+
$[0] = props;
43+
$[1] = t0;
44+
} else {
45+
t0 = $[1];
46+
}
47+
return t0;
48+
}
49+
50+
const View = React.memo((t0) => {
51+
const $ = _c(4);
52+
const { items } = t0;
53+
let t1;
54+
if ($[0] !== items) {
55+
t1 = items.map(_temp);
56+
$[0] = items;
57+
$[1] = t1;
58+
} else {
59+
t1 = $[1];
60+
}
61+
let t2;
62+
if ($[2] !== t1) {
63+
t2 = <ul>{t1}</ul>;
64+
$[2] = t1;
65+
$[3] = t2;
66+
} else {
67+
t2 = $[3];
68+
}
69+
return t2;
70+
});
71+
72+
export const FIXTURE_ENTRYPOINT = {
73+
fn: Component,
74+
params: [
75+
{
76+
items: [
77+
{ id: 2, name: "foo" },
78+
{ id: 3, name: "bar" },
79+
],
80+
},
81+
],
82+
};
83+
function _temp(item) {
84+
return <li key={item.id}>{item.name}</li>;
85+
}
86+
87+
```
88+
89+
### Eval output
90+
(kind: ok) <ul><li>foo</li><li>bar</li></ul>
File renamed without changes.

0 commit comments

Comments
 (0)