Compare commits

...

2 Commits

Author SHA1 Message Date
Joe Savona
2142d829cd [compiler] Add missing source locations to statements, expressions
Adds missing locations to all the statement kinds that we produce in codegenInstruction(), and adds generic handling of source locations for the nodes produced by codegenInstructionValue(). There are definitely some places where we are still missing a location, but this should address some of the known issues we've seen such as missing location on `throw`.
2025-09-05 19:37:17 -07:00
Joe Savona
0fba073934 [compiler] Cleanup for @enablePreserveExistingMemoizationGuarantees
I tried turning on `@enablePreserveExistingMemoizationGuarantees` by default and cleaned up a couple small things:

* We emit freeze calls for StartMemoize deps but these had ValueReason.Other so the message wasn't great. We now treat these like other hook arguments.
* PruneNonEscapingScopes was being too aggressive in this mode and memoizing even loads of globals. Switching to MemoizationLevel.Conditional ensures we build a graph that connects through to primitive-returning function calls, but doesn't unnecessarily force memoization otherwise.
2025-09-03 17:48:48 -07:00
100 changed files with 303 additions and 83 deletions

View File

@@ -2089,7 +2089,7 @@ function computeSignatureForInstruction(
effects.push({
kind: 'Freeze',
value: operand,
reason: ValueReason.Other,
reason: ValueReason.HookCaptured,
});
}
}

View File

@@ -945,7 +945,8 @@ function codegenTerminal(
if (terminal.targetKind === 'implicit') {
return null;
}
return t.breakStatement(
return createBreakStatement(
terminal.loc,
terminal.targetKind === 'labeled'
? t.identifier(codegenLabel(terminal.target))
: null,
@@ -955,14 +956,16 @@ function codegenTerminal(
if (terminal.targetKind === 'implicit') {
return null;
}
return t.continueStatement(
return createContinueStatement(
terminal.loc,
terminal.targetKind === 'labeled'
? t.identifier(codegenLabel(terminal.target))
: null,
);
}
case 'for': {
return t.forStatement(
return createForStatement(
terminal.loc,
codegenForInit(cx, terminal.init),
codegenInstructionValueToExpression(cx, terminal.test),
terminal.update !== null
@@ -1047,7 +1050,8 @@ function codegenTerminal(
`Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`,
);
}
return t.forInStatement(
return createForInStatement(
terminal.loc,
/*
* Special handling here since we only want the VariableDeclarators without any inits
* This needs to be updated when we handle non-trivial ForOf inits
@@ -1140,7 +1144,8 @@ function codegenTerminal(
`Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`,
);
}
return t.forOfStatement(
return createForOfStatement(
terminal.loc,
/*
* Special handling here since we only want the VariableDeclarators without any inits
* This needs to be updated when we handle non-trivial ForOf inits
@@ -1162,7 +1167,7 @@ function codegenTerminal(
alternate = block;
}
}
return t.ifStatement(test, consequent, alternate);
return createIfStatement(terminal.loc, test, consequent, alternate);
}
case 'return': {
const value = codegenPlaceToExpression(cx, terminal.value);
@@ -1173,7 +1178,8 @@ function codegenTerminal(
return t.returnStatement(value);
}
case 'switch': {
return t.switchStatement(
return createSwitchStatement(
terminal.loc,
codegenPlaceToExpression(cx, terminal.test),
terminal.cases.map(case_ => {
const test =
@@ -1186,15 +1192,26 @@ function codegenTerminal(
);
}
case 'throw': {
return t.throwStatement(codegenPlaceToExpression(cx, terminal.value));
return createThrowStatement(
terminal.loc,
codegenPlaceToExpression(cx, terminal.value),
);
}
case 'do-while': {
const test = codegenInstructionValueToExpression(cx, terminal.test);
return t.doWhileStatement(test, codegenBlock(cx, terminal.loop));
return createDoWhileStatement(
terminal.loc,
test,
codegenBlock(cx, terminal.loop),
);
}
case 'while': {
const test = codegenInstructionValueToExpression(cx, terminal.test);
return t.whileStatement(test, codegenBlock(cx, terminal.loop));
return createWhileStatement(
terminal.loc,
test,
codegenBlock(cx, terminal.loop),
);
}
case 'label': {
return codegenBlock(cx, terminal.block);
@@ -1205,7 +1222,8 @@ function codegenTerminal(
catchParam = convertIdentifier(terminal.handlerBinding.identifier);
cx.temp.set(terminal.handlerBinding.identifier.declarationId, null);
}
return t.tryStatement(
return createTryStatement(
terminal.loc,
codegenBlock(cx, terminal.block),
t.catchClause(catchParam, codegenBlock(cx, terminal.handler)),
);
@@ -1543,7 +1561,13 @@ const createExpressionStatement = withLoc(t.expressionStatement);
const _createLabelledStatement = withLoc(t.labeledStatement);
const createVariableDeclaration = withLoc(t.variableDeclaration);
const createFunctionDeclaration = withLoc(t.functionDeclaration);
const _createWhileStatement = withLoc(t.whileStatement);
const createWhileStatement = withLoc(t.whileStatement);
const createDoWhileStatement = withLoc(t.doWhileStatement);
const createSwitchStatement = withLoc(t.switchStatement);
const createIfStatement = withLoc(t.ifStatement);
const createForStatement = withLoc(t.forStatement);
const createForOfStatement = withLoc(t.forOfStatement);
const createForInStatement = withLoc(t.forInStatement);
const createTaggedTemplateExpression = withLoc(t.taggedTemplateExpression);
const createLogicalExpression = withLoc(t.logicalExpression);
const createSequenceExpression = withLoc(t.sequenceExpression);
@@ -1558,6 +1582,10 @@ const createJsxText = withLoc(t.jsxText);
const createJsxClosingElement = withLoc(t.jsxClosingElement);
const createJsxOpeningElement = withLoc(t.jsxOpeningElement);
const createStringLiteral = withLoc(t.stringLiteral);
const createThrowStatement = withLoc(t.throwStatement);
const createTryStatement = withLoc(t.tryStatement);
const createBreakStatement = withLoc(t.breakStatement);
const createContinueStatement = withLoc(t.continueStatement);
function createHookGuard(
guard: ExternalFunction,
@@ -2314,6 +2342,9 @@ function codegenInstructionValue(
);
}
}
if (instrValue.loc != null && instrValue.loc != GeneratedSource) {
value.loc = instrValue.loc;
}
return value;
}

View File

@@ -546,7 +546,7 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
* memoization. Note: we may still prune primitive-producing scopes if
* they don't ultimately escape at all.
*/
const level = MemoizationLevel.Memoized;
const level = MemoizationLevel.Conditional;
return {
lvalues: lvalue !== null ? [{place: lvalue, level}] : [],
rvalues: [...eachReactiveValueOperand(value)],
@@ -701,9 +701,7 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
}
case 'ComputedLoad':
case 'PropertyLoad': {
const level = options.forceMemoizePrimitives
? MemoizationLevel.Memoized
: MemoizationLevel.Conditional;
const level = MemoizationLevel.Conditional;
return {
// Indirection for the inner value, memoized if the value is
lvalues: lvalue !== null ? [{place: lvalue, level}] : [],

View File

@@ -129,6 +129,7 @@ function useFoo(t0) {
t1 = null;
break bb0;
}
if (cond2) {
mutate(s);
}

View File

@@ -43,6 +43,7 @@ function useFoo(t0) {
if ($[0] !== cond || $[1] !== value) {
bb0: {
items = [];
if (cond) {
break bb0;
}

View File

@@ -39,6 +39,7 @@ function Foo() {
if (cond) {
thing = makeObject_Primitives();
}
if (CONST_TRUE) {
mutate(thing);
}

View File

@@ -23,6 +23,7 @@ import { c as _c } from "react/compiler-runtime";
function useBar(props) {
const $ = _c(1);
let z;
if (props.a) {
if (props.b) {
let t0;

View File

@@ -67,6 +67,7 @@ function getNativeLogFunction(level) {
) {
logLevel = LOG_LEVELS.warn;
}
if (global.__inspectorLog) {
global.__inspectorLog(
INSPECTOR_LEVELS[logLevel],
@@ -75,6 +76,7 @@ function getNativeLogFunction(level) {
INSPECTOR_FRAMES_TO_SKIP,
);
}
if (groupStack.length) {
str = groupFormat("", str);
}

View File

@@ -47,9 +47,7 @@ function useKeyCommand() {
};
const moveLeft = { handler: handleKey("left") };
const moveRight = { handler: handleKey("right") };
t0 = [moveLeft, moveRight];
$[0] = t0;
} else {

View File

@@ -33,7 +33,6 @@ function Component() {
let y;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
y = x = {};
const foo = () => {
x = makeArray();
};

View File

@@ -44,6 +44,7 @@ function ComponentA(props) {
if (b) {
a.push(props.p0);
}
if (props.p1) {
b.push(props.p2);
}
@@ -68,6 +69,7 @@ function ComponentB(props) {
if (mayMutate(b)) {
a.push(props.p0);
}
if (props.p1) {
b.push(props.p2);
}

View File

@@ -34,6 +34,7 @@ function Component(props) {
const foo = () => {
setX(1);
};
if (props.cond) {
setX(2);
foo();

View File

@@ -36,7 +36,6 @@ function Foo() {
return identity(1);
},
};
t0 = x.foo();
$[0] = t0;
} else {

View File

@@ -79,7 +79,6 @@ function foo() {
value={[
true,
true,
"a\nb",
"\n",
"a1b",

View File

@@ -48,7 +48,6 @@ function foo() {
true,
-Infinity,
-NaN,
-1 * NaN,
-1 * Infinity,
-1 * -Infinity,

View File

@@ -28,6 +28,7 @@ function Component(props) {
const a = [];
const b = {};
new Foo(a, b);
new Foo(b);
t0 = <div a={a} b={b} />;
$[0] = t0;

View File

@@ -43,7 +43,6 @@ function Component(t0) {
}
},
};
invoke(obj.method, cond);
$[0] = cond;
$[1] = x;

View File

@@ -27,6 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
```javascript
function Component(props) {
debugger;
if (props.cond) {
debugger;
} else {

View File

@@ -26,6 +26,7 @@ function Component(props) {
let x;
if ($[0] !== props.a || $[1] !== props.b) {
x = { a: props.a, b: props.b };
delete x["b"];
$[0] = props.a;
$[1] = props.b;

View File

@@ -46,6 +46,7 @@ function foo(a, b) {
if (x.length) {
y.push(x);
}
if (b) {
y.push(b);
}

View File

@@ -46,6 +46,7 @@ function foo(x, y, z) {
} else {
items2 = $[2];
}
if (y) {
items.push(x);
}

View File

@@ -57,6 +57,7 @@ function Component(t0) {
let y;
if ($[0] !== a || $[1] !== b || $[2] !== c) {
x = [];
if (a) {
let t1;
if ($[5] !== b) {

View File

@@ -48,6 +48,7 @@ function foo(a, b, c) {
} else {
x = $[3];
}
if (x.length) {
return x;
}

View File

@@ -28,6 +28,7 @@ function Component(props) {
let items;
if ($[0] !== props.items) {
items = [];
for (let i = 0, length = props.items.length; i < length; i++) {
items.push(props.items[i]);
}

View File

@@ -39,6 +39,7 @@ function Component(props) {
for (const x of items) {
lastItem = x;
}
if (lastItem != null) {
lastItem.a = lastItem.a + 1;
}

View File

@@ -39,6 +39,7 @@ function Component(props) {
for (const x of items) {
lastItem = x;
}
if (lastItem != null) {
lastItem.a = lastItem.a + 1;
}

View File

@@ -41,6 +41,7 @@ function Component(props) {
t1 = $[1];
}
const onChange = t1;
if (props.cond) {
}
let t2;

View File

@@ -69,6 +69,7 @@ const Foo = isForgetEnabled_Fixtures()
if (DEV && shouldInstrument)
useRenderCounter("Foo", "/codegen-instrument-forget-gating-test.ts");
const $ = _c(3);
if (props.bar < 0) {
return props.children;
}

View File

@@ -63,6 +63,7 @@ const Foo = isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
const $ = _c(3);
if (props.bar < 0) {
return props.children;
}

View File

@@ -35,7 +35,6 @@ function hoisting() {
return bar();
},
};
const bar = _temp;
t0 = x.foo();

View File

@@ -30,6 +30,7 @@ function Component(props) {
let items;
if ($[0] !== props.a || $[1] !== props.cond) {
let t0;
if (props.cond) {
t0 = [];
} else {

View File

@@ -390,6 +390,7 @@ function ConditionalJsx(t0) {
t1 = $[0];
}
let content = t1;
if (shouldWrap) {
const t2 = content;
let t3;

View File

@@ -27,6 +27,7 @@ import * as SharedRuntime from "shared-runtime";
function useFoo(t0) {
const $ = _c(1);
const { cond } = t0;
if (cond) {
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {

View File

@@ -30,6 +30,7 @@ const { getNumber } = require("shared-runtime");
function Component(props) {
const $ = _c(1);
let x;
if (props.cond) {
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {

View File

@@ -2,6 +2,7 @@
## Input
```javascript
// @compilationMode:"infer"
import {makeArray} from 'shared-runtime';
function Component() {
@@ -30,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @compilationMode:"infer"
import { makeArray } from "shared-runtime";
function Component() {

View File

@@ -1,3 +1,4 @@
// @compilationMode:"infer"
import {makeArray} from 'shared-runtime';
function Component() {

View File

@@ -75,7 +75,6 @@ function Component() {
if ($[0] !== state) {
t0 = [
React,
state,
CONST,
NON_REASSIGNED_LET,

View File

@@ -94,12 +94,16 @@ function testFunction(props) {
break;
}
}
if (a) {
}
if (b) {
}
if (c) {
}
if (d) {
}

View File

@@ -78,14 +78,19 @@ function Component(props) {
x = {};
x.b = b;
const y = mutate(x, d);
if (a) {
}
if (b) {
}
if (c) {
}
if (d) {
}
if (y) {
}

View File

@@ -51,12 +51,16 @@ function Component(props) {
break;
}
}
if (a) {
}
if (b) {
}
if (c) {
}
if (d) {
}

View File

@@ -53,8 +53,10 @@ function Component(t0) {
let z;
if ($[0] !== prop1 || $[1] !== prop2) {
let x = [{ value: prop1 }];
while (x.length < 2) {
arrayPush(x, { value: prop2 });
if (x[0].value === prop1) {
x = [{ value: prop2 }];
const y = x;

View File

@@ -30,6 +30,7 @@ function Component(props) {
let items;
if ($[0] !== props.a || $[1] !== props.cond) {
let t0;
if (props.cond) {
t0 = [];
} else {

View File

@@ -33,7 +33,6 @@ function Component(props) {
if ($[0] !== props.value) {
const key = {};
context = { [key]: identity([props.value]) };
mutate(key);
$[0] = props.value;
$[1] = context;

View File

@@ -44,7 +44,6 @@ function Component(props) {
t2 = $[3];
}
context = t2;
mutate(key);
$[0] = props.value;
$[1] = context;

View File

@@ -32,6 +32,7 @@ import fbt from "fbt";
function Component() {
const $ = _c(1);
const sections = Object.keys(items);
for (let i = 0; i < sections.length; i = i + 3, i) {
chunks.push(sections.slice(i, i + 3).map(_temp));
}

View File

@@ -51,7 +51,6 @@ function useFoo(arr1, arr2) {
if ($[2] !== arr2 || $[3] !== x) {
let y;
t1 = () => ({ y });
(y = x.concat(arr2)), y;
$[2] = arr2;
$[3] = x;

View File

@@ -89,6 +89,7 @@ function useFoo(t0) {
y = $[2];
z = $[3];
}
if (z[0] !== y) {
throw new Error("oh no!");
}

View File

@@ -32,7 +32,6 @@ function Component(props) {
if ($[0] !== props.value) {
const key = {};
context = { [key]: identity([props.value]) };
mutate(key);
$[0] = props.value;
$[1] = context;

View File

@@ -43,7 +43,6 @@ function Component(props) {
t2 = $[3];
}
context = t2;
mutate(key);
$[0] = props.value;
$[1] = context;

View File

@@ -38,13 +38,11 @@ function useHook(props) {
return props;
},
};
const y = {
getY() {
return "y";
},
};
t0 = setProperty(x, y);
$[0] = props;
$[1] = t0;

View File

@@ -39,7 +39,6 @@ function useHook(a) {
return x;
},
};
t0 = obj.method();
$[0] = a;
$[1] = t0;

View File

@@ -37,7 +37,6 @@ function useHook(t0) {
return value;
},
};
mutate(x);
$[0] = value;
$[1] = obj;

View File

@@ -37,7 +37,6 @@ function useHook(t0) {
return x;
},
};
mutate(obj);
$[0] = value;
$[1] = obj;

View File

@@ -31,7 +31,6 @@ function Component() {
return 1;
},
};
t0 = obj.method();
$[0] = t0;
} else {

View File

@@ -48,9 +48,7 @@ function useKeyCommand() {
};
const moveLeft = { handler: handleKey("left") };
const moveRight = { handler: handleKey("right") };
t0 = [moveLeft, moveRight];
$[0] = t0;
} else {

View File

@@ -27,6 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
function foo(a, b, c) {
const x = [];
const y = [];
if (x) {
}

View File

@@ -0,0 +1,86 @@
## Input
```javascript
// @enablePreserveExistingMemoizationGuarantees
import {fbt} from 'fbt';
function Component() {
const buttonLabel = () => {
if (!someCondition) {
return <fbt desc="My label">{'Purchase as a gift'}</fbt>;
} else if (
!iconOnly &&
showPrice &&
item?.current_gift_offer?.price?.formatted != null
) {
return (
<fbt desc="Gift button's label">
{'Gift | '}
<fbt:param name="price">
{item?.current_gift_offer?.price?.formatted}
</fbt:param>
</fbt>
);
} else if (!iconOnly && !showPrice) {
return <fbt desc="Gift button's label">{'Gift'}</fbt>;
}
};
return (
<View>
<Button text={buttonLabel()} />
</View>
);
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees
import { fbt } from "fbt";
function Component() {
const $ = _c(1);
const buttonLabel = _temp;
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<View>
<Button text={buttonLabel()} />
</View>
);
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
function _temp() {
if (!someCondition) {
return fbt._("Purchase as a gift", null, { hk: "1gHj4g" });
} else {
if (
!iconOnly &&
showPrice &&
item?.current_gift_offer?.price?.formatted != null
) {
return fbt._(
"Gift | {price}",
[fbt._param("price", item?.current_gift_offer?.price?.formatted)],
{ hk: "3GTnGE" },
);
} else {
if (!iconOnly && !showPrice) {
return fbt._("Gift", null, { hk: "3fqfrk" });
}
}
}
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -0,0 +1,31 @@
// @enablePreserveExistingMemoizationGuarantees
import {fbt} from 'fbt';
function Component() {
const buttonLabel = () => {
if (!someCondition) {
return <fbt desc="My label">{'Purchase as a gift'}</fbt>;
} else if (
!iconOnly &&
showPrice &&
item?.current_gift_offer?.price?.formatted != null
) {
return (
<fbt desc="Gift button's label">
{'Gift | '}
<fbt:param name="price">
{item?.current_gift_offer?.price?.formatted}
</fbt:param>
</fbt>
);
} else if (!iconOnly && !showPrice) {
return <fbt desc="Gift button's label">{'Gift'}</fbt>;
}
};
return (
<View>
<Button text={buttonLabel()} />
</View>
);
}

View File

@@ -36,6 +36,7 @@ import { useMemo } from "react";
// (i.e. inferred non-mutable or non-escaping values don't get memoized)
function useFoo(t0) {
const { minWidth, styles, setStyles } = t0;
if (styles.width > minWidth) {
setStyles(styles);
}

View File

@@ -34,6 +34,7 @@ import { identity } from "shared-runtime";
function useFoo(cond) {
let t0;
if (cond) {
t0 = 2;
} else {

View File

@@ -34,6 +34,7 @@ import { identity } from "shared-runtime";
function useFoo(cond) {
let t0;
if (cond) {
t0 = identity(10);
} else {

View File

@@ -41,6 +41,7 @@ function Component(t0) {
const { entity, children } = t0;
const showMessage = () => entity != null;
if (!showMessage()) {
return children;
}

View File

@@ -50,7 +50,6 @@ function useFoo(arr1, arr2) {
if ($[2] !== arr2 || $[3] !== x) {
let y;
t1 = () => ({ y });
(y = x.concat(arr2)), y;
$[2] = arr2;
$[3] = x;

View File

@@ -2,7 +2,7 @@
## Input
```javascript
// @enableForest
// @enablePreserveExistingMemoizationGuarantees
function Component({base, start, increment, test}) {
let value = base;
for (let i = start; i < test; i += increment) {
@@ -27,25 +27,23 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @enableForest
import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees
function Component(t0) {
const $ = _c(5);
const $ = _c(2);
const { base, start, increment, test } = t0;
let value;
if ($[0] !== base || $[1] !== increment || $[2] !== start || $[3] !== test) {
value = base;
for (let i = start; i < test; i = i + increment, i) {
value = value + i;
}
$[0] = base;
$[1] = increment;
$[2] = start;
$[3] = test;
$[4] = value;
} else {
value = $[4];
let value = base;
for (let i = start; i < test; i = i + increment, i) {
value = value + i;
}
return <div>{value}</div>;
let t1;
if ($[0] !== value) {
t1 = <div>{value}</div>;
$[0] = value;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {

View File

@@ -1,4 +1,4 @@
// @enableForest
// @enablePreserveExistingMemoizationGuarantees
function Component({base, start, increment, test}) {
let value = base;
for (let i = start; i < test; i += increment) {

View File

@@ -45,6 +45,7 @@ function ComponentA(props) {
if (b) {
a.push(props.p0);
}
if (props.p1) {
b.push(props.p2);
}
@@ -69,6 +70,7 @@ function ComponentB(props) {
if (mayMutate(b)) {
a.push(props.p0);
}
if (props.p1) {
b.push(props.p2);
}

View File

@@ -31,6 +31,7 @@ function Component(props) {
let items;
if ($[0] !== props.a || $[1] !== props.cond) {
let t0;
if (props.cond) {
t0 = [];
} else {

View File

@@ -40,7 +40,6 @@ function useFoo(t0) {
return identity(a.b.c);
},
};
t1 = <Stringify x={x} shouldInvokeFns={true} />;
$[0] = a;
$[1] = t1;

View File

@@ -61,7 +61,6 @@ function Component(props) {
y = x;
}
}
t0 = <Component data={x} />;
$[0] = props.p0;
$[1] = props.p2;

View File

@@ -34,6 +34,7 @@ function Component(props) {
let y;
if ($[0] !== props.p0 || $[1] !== props.p2 || $[2] !== props.p3) {
const x = [];
switch (props.p0) {
case true: {
x.push(props.p2);
@@ -43,7 +44,6 @@ function Component(props) {
y = x;
}
}
t0 = <Component data={x} />;
$[0] = props.p0;
$[1] = props.p2;

View File

@@ -47,6 +47,7 @@ function Component(props) {
if (props.cond) {
y.push(props.a);
}
if (props.cond2) {
t0 = y;
break bb0;

View File

@@ -33,6 +33,7 @@ function Component(props) {
const $ = _c(2);
let x = 0;
let y = 0;
while (x === 0) {
x = y;
y = props.value;

View File

@@ -29,6 +29,7 @@ function Component(props) {
let x = [];
x.push(props.p0);
const y = x;
if (props.p1) {
let t1;
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {

View File

@@ -59,7 +59,6 @@ function useFoo(props) {
return b;
},
};
t1 = a.foo().bar();
$0[0] = props;
$0[1] = t1;

View File

@@ -43,6 +43,7 @@ function Foo(t0) {
<Stringify
fn={() => {
const arr = [];
for (const selectedUser of userIds) {
arr.push(selectedUser);
}

View File

@@ -49,7 +49,6 @@ function Component() {
if ($[0] !== params) {
t0 = (partialParams) => {
const nextParams = { ...params, ...partialParams };
nextParams.param = "value";
console.log(nextParams);
};

View File

@@ -82,6 +82,7 @@ function Foo() {
const result = t1;
useNoAlias(result, obj);
if (shouldCaptureObj && result[0] !== obj) {
throw new Error("Unexpected");
}

View File

@@ -52,6 +52,7 @@ function Example() {
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = function updateStyles() {
const foo = fooRef.current;
if (barRef.current == null || foo == null) {
return;
}

View File

@@ -67,7 +67,6 @@ function Component(props) {
const key = {};
const tmp = (mutate(key), key);
const context = { [tmp]: identity([props.value]) };
mutate(key);
t0 = [context, key];
$[0] = props.value;

View File

@@ -72,7 +72,6 @@ function Component(props) {
let t2;
if ($[3] !== t0) {
const linkProps = { url: t0 };
const x = {};
let t3;
let t4;

View File

@@ -40,11 +40,7 @@ function useTest(t0) {
t1 = Builder.makeBuilder(isNull, "hello world")
?.push("1", 2)
?.push(3, { a: 4, b: 5, c: data })
?.push(
6,
data,
)
?.push(6, data)
?.push(7, "8")
?.push("8", Builder.makeBuilder(!isNull)?.push(9).vals)?.vals;
$[0] = data;

View File

@@ -53,6 +53,7 @@ function Component(t0) {
t1 = null;
break bb0;
}
try {
let t3;
if ($[0] !== value) {

View File

@@ -44,6 +44,7 @@ function Foo(t0) {
t1 = $[0];
}
const s = t1;
if (cond) {
let t2;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {

View File

@@ -20,6 +20,7 @@ function RegressionTest() {
// Valid because the loop doesn't change the order of hooks calls.
function RegressionTest() {
const res = [];
for (let i = 0; i !== 10 && true; ++i) {
res.push(i);
}

View File

@@ -148,82 +148,121 @@ function MyComponent() {
function MyComponent() {
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}
if (c) {
}

View File

@@ -97,6 +97,7 @@ const SomeName = () => {
(FILLER ?? FILLER, FILLER) ?? FILLER;
useSomeHook();
if (anyConditionCanEvenBeFalse) {
return null;
}

View File

@@ -60,7 +60,6 @@ function Component(props) {
y = x;
}
}
t0 = <Component data={x} />;
$[0] = props.p0;
$[1] = props.p2;

View File

@@ -33,6 +33,7 @@ function Component(props) {
let y;
if ($[0] !== props.p0 || $[1] !== props.p2 || $[2] !== props.p3) {
const x = [];
switch (props.p0) {
case true: {
x.push(props.p2);
@@ -42,7 +43,6 @@ function Component(props) {
y = x;
}
}
t0 = <Component data={x} />;
$[0] = props.p0;
$[1] = props.p2;

View File

@@ -32,6 +32,7 @@ function Component(props) {
const onChange = (e) => {
maybeMutate(x, e.target.value);
};
if (props.cond) {
}

View File

@@ -46,6 +46,7 @@ function useFoo(t0) {
() => {
log(derived);
},
[derived],
[derived],
);

View File

@@ -39,6 +39,7 @@ import { Stringify } from "shared-runtime";
*/
function Component(props) {
const foo = _temp;
if (props.cond) {
const t0 = useFire(foo);
useEffect(() => {

View File

@@ -44,7 +44,6 @@ function Component(props) {
}
},
};
t0 = object.foo();
$[0] = props;
$[1] = t0;

View File

@@ -39,7 +39,6 @@ function Component(props) {
}
},
};
t0 = object.foo();
$[0] = t0;
} else {

View File

@@ -35,6 +35,7 @@ function useHook(end) {
log = [];
for (let i = 0; i < end + 1; i++) {
log.push(`${i} @A`);
if (i === end) {
break;
}

View File

@@ -41,6 +41,7 @@ function useHook(cond) {
bb0: switch (CONST_STRING0) {
case CONST_STRING0: {
log.push("@A");
if (cond) {
break bb0;
}

View File

@@ -65,12 +65,16 @@ function Component(t0) {
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = () => {
let cleanedUp = false;
setTimeout(() => {
if (!cleanedUp) {
cleanedUp = true;
setCleanupCount(_temp);
}
}, 0);
setTimeout(
() => {
if (!cleanedUp) {
cleanedUp = true;
setCleanupCount(_temp);
}
},
0,
);
return () => {
if (!cleanedUp) {
cleanedUp = true;

View File

@@ -43,7 +43,6 @@ function Component(t0) {
const precomputed = prop + ref2.current;
return { foo: () => prop + ref2.current + precomputed };
};
t2 = [prop];
$[0] = prop;
$[1] = t1;

View File

@@ -46,6 +46,7 @@ function Component(props) {
if (props.cond) {
y.push(props.a);
}
if (props.cond2) {
t0 = y;
break bb0;

View File

@@ -50,7 +50,6 @@ function Component(props) {
y = props.y;
}
}
t0 = y;
}
const x = t0;

View File

@@ -50,6 +50,7 @@ function Component(props) {
t0 = $[1];
}
const onSubmit = t0;
switch (currentStep) {
case 0: {
let t1;