[compiler] patch: retain UpdateExpression for globals

ghstack-source-id: aff6606f85
Pull Request resolved: https://github.com/facebook/react/pull/30471
This commit is contained in:
Mofei Zhang
2024-07-26 17:36:04 -04:00
parent 2a9274a73e
commit a8f5c4e16d
7 changed files with 67 additions and 56 deletions

View File

@@ -1934,7 +1934,6 @@ function lowerExpression(
switch (leftNode.type) {
case 'Identifier': {
const leftExpr = left as NodePath<t.Identifier>;
const identifier = lowerIdentifier(builder, leftExpr);
const leftPlace = lowerExpressionToTemporary(builder, leftExpr);
const right = lowerExpressionToTemporary(builder, expr.get('right'));
const binaryPlace = lowerValueToTemporary(builder, {
@@ -1944,30 +1943,42 @@ function lowerExpression(
right,
loc: exprLoc,
});
const kind = getStoreKind(builder, leftExpr);
if (kind === 'StoreLocal') {
lowerValueToTemporary(builder, {
kind: 'StoreLocal',
lvalue: {
place: {...identifier},
kind: InstructionKind.Reassign,
},
value: {...binaryPlace},
type: null,
loc: exprLoc,
});
return {kind: 'LoadLocal', place: identifier, loc: exprLoc};
const binding = builder.resolveIdentifier(leftExpr);
if (binding.kind === 'Identifier') {
const identifier = lowerIdentifier(builder, leftExpr);
const kind = getStoreKind(builder, leftExpr);
if (kind === 'StoreLocal') {
lowerValueToTemporary(builder, {
kind: 'StoreLocal',
lvalue: {
place: {...identifier},
kind: InstructionKind.Reassign,
},
value: {...binaryPlace},
type: null,
loc: exprLoc,
});
return {kind: 'LoadLocal', place: identifier, loc: exprLoc};
} else {
lowerValueToTemporary(builder, {
kind: 'StoreContext',
lvalue: {
place: {...identifier},
kind: InstructionKind.Reassign,
},
value: {...binaryPlace},
loc: exprLoc,
});
return {kind: 'LoadContext', place: identifier, loc: exprLoc};
}
} else {
lowerValueToTemporary(builder, {
kind: 'StoreContext',
lvalue: {
place: {...identifier},
kind: InstructionKind.Reassign,
},
const temporary = lowerValueToTemporary(builder, {
kind: 'StoreGlobal',
name: leftExpr.node.name,
value: {...binaryPlace},
loc: exprLoc,
});
return {kind: 'LoadContext', place: identifier, loc: exprLoc};
return {kind: 'LoadLocal', place: temporary, loc: temporary.loc};
}
}
case 'MemberExpression': {

View File

@@ -1,32 +0,0 @@
## Input
```javascript
let renderCount = 0;
function useFoo() {
renderCount += 1;
return renderCount;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [],
};
```
## Code
```javascript
let renderCount = 0;
function useFoo() {
return renderCount;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [],
};
```

View File

@@ -0,0 +1,31 @@
## Input
```javascript
let renderCount = 0;
function useFoo() {
renderCount += 1;
return renderCount;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [],
};
```
## Error
```
1 | let renderCount = 0;
2 | function useFoo() {
> 3 | renderCount += 1;
| ^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (3:3)
4 | return renderCount;
5 | }
6 |
```

View File

@@ -40,6 +40,7 @@ function Foo() {
return t0;
}
function _temp() {
renderCount = renderCount + 1;
return renderCount;
}
@@ -49,4 +50,6 @@ export const FIXTURE_ENTRYPOINT = {
};
```
### Eval output
(kind: ok) <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>

View File

@@ -484,8 +484,6 @@ const skipFilter = new Set([
'rules-of-hooks/rules-of-hooks-69521d94fa03',
// bugs
'bug-invalid-update-global-should-bailout',
'bug-update-global-in-callback',
'bug-invalid-hoisting-functionexpr',
'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block',
'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope',