mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[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: 8581edb8be
Pull Request resolved: https://github.com/facebook/react/pull/30466
This commit is contained in:
@@ -196,6 +196,7 @@ export function createNewFunctionNode(
|
||||
}
|
||||
|
||||
function insertNewOutlinedFunctionNode(
|
||||
program: NodePath<t.Program>,
|
||||
originalFn: BabelFn,
|
||||
compiledFn: CodegenFunction,
|
||||
): NodePath<t.Function> {
|
||||
@@ -216,14 +217,6 @@ function insertNewOutlinedFunctionNode(
|
||||
*/
|
||||
case 'ArrowFunctionExpression':
|
||||
case 'FunctionExpression': {
|
||||
CompilerError.invariant(
|
||||
originalFn.parentPath.isVariableDeclarator() &&
|
||||
originalFn.parentPath.parentPath.isVariableDeclaration(),
|
||||
{
|
||||
reason: 'Expected a variable declarator parent',
|
||||
loc: originalFn.node.loc ?? null,
|
||||
},
|
||||
);
|
||||
const fn: t.FunctionDeclaration = {
|
||||
type: 'FunctionDeclaration',
|
||||
id: compiledFn.id,
|
||||
@@ -233,8 +226,7 @@ function insertNewOutlinedFunctionNode(
|
||||
params: compiledFn.params,
|
||||
body: compiledFn.body,
|
||||
};
|
||||
const varDecl = originalFn.parentPath.parentPath;
|
||||
const insertedFuncDecl = varDecl.insertAfter(fn)[0]!;
|
||||
const insertedFuncDecl = program.pushContainer('body', [fn])[0]!;
|
||||
CompilerError.invariant(insertedFuncDecl.isFunctionDeclaration(), {
|
||||
reason: 'Expected inserted function declaration',
|
||||
description: `Got: ${insertedFuncDecl}`,
|
||||
@@ -468,7 +460,11 @@ export function compileProgram(
|
||||
reason: 'Unexpected nested outlined functions',
|
||||
loc: outlined.fn.loc,
|
||||
});
|
||||
const fn = insertNewOutlinedFunctionNode(current.fn, outlined.fn);
|
||||
const fn = insertNewOutlinedFunctionNode(
|
||||
program,
|
||||
current.fn,
|
||||
outlined.fn,
|
||||
);
|
||||
fn.skip();
|
||||
ALREADY_COMPILED.add(fn.node);
|
||||
if (outlined.type !== null) {
|
||||
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
return <View {...props} />;
|
||||
}
|
||||
|
||||
const View = React.memo(({items}) => {
|
||||
return (
|
||||
<ul>
|
||||
{items.map(item => (
|
||||
<li key={item.id}>{item.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
});
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: 2, name: 'foo'},
|
||||
{id: 3, name: 'bar'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
3 | }
|
||||
4 |
|
||||
> 5 | const View = React.memo(({items}) => {
|
||||
| ^^^^^^^^^^^^^^
|
||||
> 6 | return (
|
||||
| ^^^^^^^^^^
|
||||
> 7 | <ul>
|
||||
| ^^^^^^^^^^
|
||||
> 8 | {items.map(item => (
|
||||
| ^^^^^^^^^^
|
||||
> 9 | <li key={item.id}>{item.name}</li>
|
||||
| ^^^^^^^^^^
|
||||
> 10 | ))}
|
||||
| ^^^^^^^^^^
|
||||
> 11 | </ul>
|
||||
| ^^^^^^^^^^
|
||||
> 12 | );
|
||||
| ^^^^^^^^^^
|
||||
> 13 | });
|
||||
| ^^ Invariant: Expected a variable declarator parent (5:13)
|
||||
14 |
|
||||
15 | export const FIXTURE_ENTRYPOINT = {
|
||||
16 | fn: Component,
|
||||
```
|
||||
|
||||
|
||||
+3
-3
@@ -50,9 +50,6 @@ const Component2 = (props) => {
|
||||
}
|
||||
return t1;
|
||||
};
|
||||
function _temp(item) {
|
||||
return <li key={item.id}>{item.name}</li>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component2,
|
||||
@@ -65,6 +62,9 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
},
|
||||
],
|
||||
};
|
||||
function _temp(item) {
|
||||
return <li key={item.id}>{item.name}</li>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
return <View {...props} />;
|
||||
}
|
||||
|
||||
const View = React.memo(({items}) => {
|
||||
return (
|
||||
<ul>
|
||||
{items.map(item => (
|
||||
<li key={item.id}>{item.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
});
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: 2, name: 'foo'},
|
||||
{id: 3, name: 'bar'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props) {
|
||||
t0 = <View {...props} />;
|
||||
$[0] = props;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
const View = React.memo((t0) => {
|
||||
const $ = _c(4);
|
||||
const { items } = t0;
|
||||
let t1;
|
||||
if ($[0] !== items) {
|
||||
t1 = items.map(_temp);
|
||||
$[0] = items;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
let t2;
|
||||
if ($[2] !== t1) {
|
||||
t2 = <ul>{t1}</ul>;
|
||||
$[2] = t1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
});
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{ id: 2, name: "foo" },
|
||||
{ id: 3, name: "bar" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
function _temp(item) {
|
||||
return <li key={item.id}>{item.name}</li>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <ul><li>foo</li><li>bar</li></ul>
|
||||
Reference in New Issue
Block a user