[tests] Tests and patch for context variables

--- 

- [patch] Find context variables within FunctionDeclarations (previously 
missing) 

- [todo] Need to fix non-allocating values / variables being DCE'd 

One approach is to label everything referenced by a lambda as context variables. 
I couldn't come up with other examples that break without this change, so I 
wonder if something lighter / hackier works just as well. (My only hesitation is 
that we may end up losing out on potential optimizations for everything aliased 
to these variables).
This commit is contained in:
Mofei Zhang
2023-06-05 15:04:46 -04:00
parent 6d1d05ff91
commit b160ee8522
3 changed files with 72 additions and 1 deletions
@@ -6,7 +6,9 @@ import { GeneratedSource } from "./HIR";
type FindContextIdentifierState = {
inLambda: number;
currentLambda: Array<
NodePath<t.FunctionExpression> | NodePath<t.ArrowFunctionExpression>
| NodePath<t.FunctionDeclaration>
| NodePath<t.FunctionExpression>
| NodePath<t.ArrowFunctionExpression>
>;
contextIdentifiers: Set<t.Identifier>;
};
@@ -22,6 +24,20 @@ export function findContextIdentifiers(
func.traverse<FindContextIdentifierState>(
{
FunctionDeclaration: {
enter(
fn: NodePath<t.FunctionDeclaration>,
state: FindContextIdentifierState
): void {
state.currentLambda.push(fn);
},
exit(
fn: NodePath<t.FunctionDeclaration>,
state: FindContextIdentifierState
): void {
state.currentLambda.pop();
},
},
FunctionExpression: {
enter(
fn: NodePath<t.FunctionExpression>,
@@ -69,6 +85,7 @@ export function findContextIdentifiers(
function handleAssignment(
currentLambda:
| NodePath<t.FunctionDeclaration>
| NodePath<t.FunctionExpression>
| NodePath<t.ArrowFunctionExpression>,
contextIdentifiers: Set<t.Identifier>,
@@ -0,0 +1,46 @@
## Input
```javascript
function Component() {
let x = null;
function foo() {
x = 9;
}
const y = bar(foo);
return <Child y={y} />;
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component() {
const $ = useMemoCache(2);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
let x;
x = null;
const foo = function foo() {
x = 9;
};
t0 = bar(foo);
$[0] = t0;
} else {
t0 = $[0];
}
const y = t0;
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <Child y={y} />;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
```
@@ -0,0 +1,8 @@
function Component() {
let x = null;
function foo() {
x = 9;
}
const y = bar(foo);
return <Child y={y} />;
}