mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[patch][contextvars] Patch for variables reassigned after objectmethod
definitions
This commit is contained in:
@@ -11,71 +11,44 @@ import { CompilerError } from "../CompilerError";
|
||||
import { Set_union } from "../Utils/utils";
|
||||
import { GeneratedSource } from "./HIR";
|
||||
|
||||
type BabelFunction =
|
||||
| NodePath<t.FunctionDeclaration>
|
||||
| NodePath<t.FunctionExpression>
|
||||
| NodePath<t.ArrowFunctionExpression>
|
||||
| NodePath<t.ObjectMethod>;
|
||||
type FindContextIdentifierState = {
|
||||
currentLambda: Array<
|
||||
| NodePath<t.FunctionDeclaration>
|
||||
| NodePath<t.FunctionExpression>
|
||||
| NodePath<t.ArrowFunctionExpression>
|
||||
| NodePath<t.ObjectMethod>
|
||||
>;
|
||||
currentFn: Array<BabelFunction>;
|
||||
reassigned: Set<t.Identifier>;
|
||||
referenced: Set<t.Identifier>;
|
||||
};
|
||||
|
||||
const withFunctionScope = {
|
||||
enter: function (
|
||||
path: BabelFunction,
|
||||
state: FindContextIdentifierState
|
||||
): void {
|
||||
state.currentFn.push(path);
|
||||
},
|
||||
exit: function (_: BabelFunction, state: FindContextIdentifierState): void {
|
||||
state.currentFn.pop();
|
||||
},
|
||||
};
|
||||
|
||||
export function findContextIdentifiers(
|
||||
func: NodePath<t.Function>
|
||||
): Set<t.Identifier> {
|
||||
const state: FindContextIdentifierState = {
|
||||
currentLambda: [],
|
||||
currentFn: [],
|
||||
reassigned: new Set(),
|
||||
referenced: new Set(),
|
||||
};
|
||||
|
||||
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>,
|
||||
state: FindContextIdentifierState
|
||||
): void {
|
||||
state.currentLambda.push(fn);
|
||||
},
|
||||
exit(
|
||||
_fn: NodePath<t.FunctionExpression>,
|
||||
state: FindContextIdentifierState
|
||||
): void {
|
||||
state.currentLambda.pop();
|
||||
},
|
||||
},
|
||||
|
||||
ArrowFunctionExpression: {
|
||||
enter(
|
||||
fn: NodePath<t.ArrowFunctionExpression>,
|
||||
state: FindContextIdentifierState
|
||||
): void {
|
||||
state.currentLambda.push(fn);
|
||||
},
|
||||
exit(
|
||||
_fn: NodePath<t.ArrowFunctionExpression>,
|
||||
state: FindContextIdentifierState
|
||||
): void {
|
||||
state.currentLambda.pop();
|
||||
},
|
||||
},
|
||||
FunctionDeclaration: withFunctionScope,
|
||||
FunctionExpression: withFunctionScope,
|
||||
ArrowFunctionExpression: withFunctionScope,
|
||||
ObjectMethod: withFunctionScope,
|
||||
AssignmentExpression(
|
||||
path: NodePath<t.AssignmentExpression>,
|
||||
state: FindContextIdentifierState
|
||||
@@ -83,19 +56,13 @@ export function findContextIdentifiers(
|
||||
const left = path.get("left");
|
||||
handleAssignment(state.reassigned, left);
|
||||
},
|
||||
ObjectMethod(
|
||||
fn: NodePath<t.ObjectMethod>,
|
||||
state: FindContextIdentifierState
|
||||
): void {
|
||||
state.currentLambda.push(fn);
|
||||
},
|
||||
Identifier(
|
||||
path: NodePath<t.Identifier>,
|
||||
state: FindContextIdentifierState
|
||||
): void {
|
||||
const currentLambda = state.currentLambda.at(-1);
|
||||
if (currentLambda !== undefined)
|
||||
handleIdentifier(currentLambda, state.referenced, path);
|
||||
const currentFn = state.currentFn.at(-1);
|
||||
if (currentFn !== undefined)
|
||||
handleIdentifier(currentFn, state.referenced, path);
|
||||
},
|
||||
},
|
||||
state
|
||||
@@ -104,17 +71,13 @@ export function findContextIdentifiers(
|
||||
}
|
||||
|
||||
function handleIdentifier(
|
||||
currentLambda:
|
||||
| NodePath<t.FunctionDeclaration>
|
||||
| NodePath<t.FunctionExpression>
|
||||
| NodePath<t.ArrowFunctionExpression>
|
||||
| NodePath<t.ObjectMethod>,
|
||||
currentFn: BabelFunction,
|
||||
referenced: Set<t.Identifier>,
|
||||
path: NodePath<t.Identifier>
|
||||
): void {
|
||||
const name = path.node.name;
|
||||
const binding = path.scope.getBinding(name);
|
||||
const bindingAboveLambdaScope = currentLambda.scope.parent.getBinding(name);
|
||||
const bindingAboveLambdaScope = currentFn.scope.parent.getBinding(name);
|
||||
|
||||
if (binding != null && binding === bindingAboveLambdaScope) {
|
||||
referenced.add(binding.identifier);
|
||||
@@ -126,7 +89,7 @@ function handleAssignment(
|
||||
lvalPath: NodePath<t.LVal>
|
||||
): void {
|
||||
/*
|
||||
* Find all reassignments to identifiers declared outside of currentLambda
|
||||
* Find all reassignments to identifiers declared outside of currentFn
|
||||
* This closely follows destructuring assignment assumptions and logic in BuildHIR
|
||||
*/
|
||||
const lvalNode = lvalPath.node;
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import { identity } from "shared-runtime";
|
||||
|
||||
// repro for context identifier scoping bug, in which x was
|
||||
// inferred as a context variable.
|
||||
|
||||
function Component() {
|
||||
let x = 2;
|
||||
const obj = {
|
||||
method() {},
|
||||
};
|
||||
x = 4;
|
||||
identity(obj);
|
||||
// constant propagation should return 4 here
|
||||
return x;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { identity } from "shared-runtime";
|
||||
|
||||
// repro for context identifier scoping bug, in which x was
|
||||
// inferred as a context variable.
|
||||
|
||||
function Component() {
|
||||
const obj = { method() {} };
|
||||
|
||||
identity(obj);
|
||||
return 4;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) 4
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { identity } from "shared-runtime";
|
||||
|
||||
// repro for context identifier scoping bug, in which x was
|
||||
// inferred as a context variable.
|
||||
|
||||
function Component() {
|
||||
let x = 2;
|
||||
const obj = {
|
||||
method() {},
|
||||
};
|
||||
x = 4;
|
||||
identity(obj);
|
||||
// constant propagation should return 4 here
|
||||
return x;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{}],
|
||||
};
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import { invoke } from "shared-runtime";
|
||||
|
||||
function Component({ cond }) {
|
||||
let x = 2;
|
||||
const obj = {
|
||||
method(cond) {
|
||||
if (cond) {
|
||||
x = 4;
|
||||
}
|
||||
},
|
||||
};
|
||||
invoke(obj.method, cond);
|
||||
return x;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ cond: true }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
import { invoke } from "shared-runtime";
|
||||
|
||||
function Component(t24) {
|
||||
const $ = useMemoCache(2);
|
||||
const { cond } = t24;
|
||||
let x;
|
||||
if ($[0] !== cond) {
|
||||
x = 2;
|
||||
const obj = {
|
||||
method(cond_0) {
|
||||
if (cond_0) {
|
||||
x = 4;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
invoke(obj.method, cond);
|
||||
$[0] = cond;
|
||||
$[1] = x;
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ cond: true }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) 4
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { invoke } from "shared-runtime";
|
||||
|
||||
function Component({ cond }) {
|
||||
let x = 2;
|
||||
const obj = {
|
||||
method(cond) {
|
||||
if (cond) {
|
||||
x = 4;
|
||||
}
|
||||
},
|
||||
};
|
||||
invoke(obj.method, cond);
|
||||
return x;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ cond: true }],
|
||||
};
|
||||
Reference in New Issue
Block a user