mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fix promotion of locals referenced outside of scopes
This commit is contained in:
+8
-5
@@ -23,6 +23,7 @@ import {
|
||||
ReactiveScopeDependency,
|
||||
ReactiveTerminalStatement,
|
||||
ReactiveValue,
|
||||
ScopeId,
|
||||
} from "../HIR/HIR";
|
||||
import {
|
||||
eachInstructionValueOperand,
|
||||
@@ -75,18 +76,18 @@ type TemporariesUsedOutsideDefiningScope = {
|
||||
* tracks all relevant temporary declarations (currently LoadLocal and PropertyLoad)
|
||||
* and the scope where they are defined
|
||||
*/
|
||||
declarations: Map<IdentifierId, ReactiveScope>;
|
||||
declarations: Map<IdentifierId, ScopeId>;
|
||||
// temporaries used outside of their defining scope
|
||||
usedOutsideDeclaringScope: Set<IdentifierId>;
|
||||
};
|
||||
class FindPromotedTemporaries extends ReactiveFunctionVisitor<TemporariesUsedOutsideDefiningScope> {
|
||||
scopes: Array<ReactiveScope> = [];
|
||||
scopes: Array<ScopeId> = [];
|
||||
|
||||
override visitScope(
|
||||
scope: ReactiveScopeBlock,
|
||||
state: TemporariesUsedOutsideDefiningScope
|
||||
): void {
|
||||
this.scopes.push(scope.scope);
|
||||
this.scopes.push(scope.scope.id);
|
||||
this.traverseScope(scope, state);
|
||||
this.scopes.pop();
|
||||
}
|
||||
@@ -95,6 +96,9 @@ class FindPromotedTemporaries extends ReactiveFunctionVisitor<TemporariesUsedOut
|
||||
instruction: ReactiveInstruction,
|
||||
state: TemporariesUsedOutsideDefiningScope
|
||||
): void {
|
||||
// Visit all places first, then record temporaries which may need to be promoted
|
||||
this.traverseInstruction(instruction, state);
|
||||
|
||||
const scope = this.scopes.at(-1);
|
||||
if (instruction.lvalue === null || scope === undefined) {
|
||||
return;
|
||||
@@ -110,7 +114,6 @@ class FindPromotedTemporaries extends ReactiveFunctionVisitor<TemporariesUsedOut
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.traverseInstruction(instruction, state);
|
||||
}
|
||||
|
||||
override visitPlace(
|
||||
@@ -119,7 +122,7 @@ class FindPromotedTemporaries extends ReactiveFunctionVisitor<TemporariesUsedOut
|
||||
state: TemporariesUsedOutsideDefiningScope
|
||||
): void {
|
||||
const declaringScope = state.declarations.get(place.identifier.id);
|
||||
if (this.scopes.length === 0 || declaringScope === undefined) {
|
||||
if (declaringScope === undefined) {
|
||||
return;
|
||||
}
|
||||
if (this.scopes.indexOf(declaringScope) === -1) {
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
|
||||
function Component(listItem, thread) {
|
||||
const isFoo = isFooThread(thread.threadType);
|
||||
const body = useBar(listItem, [getBadgeText(listItem, isFoo)]);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
function Component(listItem, thread) {
|
||||
const $ = useMemoCache(7);
|
||||
let t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== thread.threadType || $[1] !== listItem) {
|
||||
const isFoo = isFooThread(thread.threadType);
|
||||
t1 = useBar;
|
||||
t2 = listItem;
|
||||
t0 = getBadgeText(listItem, isFoo);
|
||||
$[0] = thread.threadType;
|
||||
$[1] = listItem;
|
||||
$[2] = t0;
|
||||
$[3] = t1;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
t1 = $[3];
|
||||
t2 = $[4];
|
||||
}
|
||||
let t3;
|
||||
if ($[5] !== t0) {
|
||||
t3 = [t0];
|
||||
$[5] = t0;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
const body = t1(t2, t3);
|
||||
return body;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented!
|
||||
logs: ['The above error occurred in the <WrapperTestComponent> component:\n' +
|
||||
'\n' +
|
||||
' at WrapperTestComponent (<project_root>/packages/snap/dist/sprout/evaluator.js:54:26)\n' +
|
||||
'\n' +
|
||||
'Consider adding an error boundary to your tree to customize error handling behavior.\n' +
|
||||
'Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.']
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// @flow @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
|
||||
function Component(listItem, thread) {
|
||||
const isFoo = isFooThread(thread.threadType);
|
||||
const body = useBar(listItem, [getBadgeText(listItem, isFoo)]);
|
||||
|
||||
return body;
|
||||
}
|
||||
Reference in New Issue
Block a user