mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[rhir] Refactor ReactiveScopeDependency, conditional dependencies (2/2)
--- See comment block in `PropagateScopeDependencies` and added test case `reduce-reactive-conditional-dependencies` for correctness properties / dependency merging logic.
This commit is contained in:
@@ -22,9 +22,7 @@ import {
|
||||
ReactiveValue,
|
||||
} from "../HIR/HIR";
|
||||
import { eachInstructionValueOperand } from "../HIR/visitors";
|
||||
import { todoInvariant } from "../Utils/todo";
|
||||
import { assertExhaustive } from "../Utils/utils";
|
||||
import { eachReactiveValueOperand } from "./visitors";
|
||||
|
||||
/**
|
||||
* Infers the dependencies of each scope to include variables whose values
|
||||
@@ -60,10 +58,10 @@ type Scopes = Array<ReactiveScope>;
|
||||
// TODO(@mofeiZ): remove once we replace Context.#dependencies, #properties with tree
|
||||
// representation
|
||||
function areDependenciesEqual(
|
||||
dep1: ReactiveScopeDependency,
|
||||
dep2: ReactiveScopeDependency
|
||||
dep1: ReactiveScopeDependencyInfo,
|
||||
dep2: ReactiveScopeDependencyInfo
|
||||
): boolean {
|
||||
if (dep1.identifier.id !== dep2.identifier.id) {
|
||||
if (dep1.identifier.id !== dep2.identifier.id || dep1.cond !== dep2.cond) {
|
||||
return false;
|
||||
}
|
||||
const dep1Path = dep1.path;
|
||||
@@ -75,7 +73,7 @@ function areDependenciesEqual(
|
||||
} else if (
|
||||
dep1Path === null ||
|
||||
dep2Path === null ||
|
||||
dep2Path.length != dep1Path.length
|
||||
dep2Path.length !== dep1Path.length
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -85,6 +83,8 @@ function areDependenciesEqual(
|
||||
});
|
||||
}
|
||||
|
||||
type ReactiveScopeDependencyInfo = ReactiveScopeDependency & { cond: boolean };
|
||||
|
||||
/**
|
||||
* Enum representing the access type of single property on a parent object.
|
||||
* We distinguish on two independent axes:
|
||||
@@ -97,23 +97,59 @@ function areDependenciesEqual(
|
||||
* - Dependency: this property is read as a dependency and we must track changes
|
||||
* to it for correctness.
|
||||
*
|
||||
* ```javascript
|
||||
* // props.a is a dependency here and must be tracked
|
||||
* deps: {props.a, props.a.b} ---> minimalDeps: {props.a}
|
||||
* // props.a is just an access here and does not need to be tracked
|
||||
* deps: {props.a.b} ---> minimalDeps: {props.a.b}
|
||||
* ```
|
||||
*/
|
||||
enum PropertyAccessType {
|
||||
ConditionalAccess = "ConditionalAccess",
|
||||
UnconditionalAccess = "UnconditionalAccess",
|
||||
ConditionalDependency = "ConditionalDependency",
|
||||
UnconditionalDependency = "UnconditionalDependency",
|
||||
}
|
||||
|
||||
function isUnconditional(access: PropertyAccessType) {
|
||||
return (
|
||||
access === PropertyAccessType.UnconditionalAccess ||
|
||||
access === PropertyAccessType.UnconditionalDependency
|
||||
);
|
||||
}
|
||||
function isDependency(access: PropertyAccessType) {
|
||||
return (
|
||||
access === PropertyAccessType.ConditionalDependency ||
|
||||
access === PropertyAccessType.UnconditionalDependency
|
||||
);
|
||||
}
|
||||
|
||||
function merge(
|
||||
access1: PropertyAccessType,
|
||||
access2: PropertyAccessType
|
||||
): PropertyAccessType {
|
||||
if (
|
||||
access1 === PropertyAccessType.UnconditionalDependency ||
|
||||
access2 === PropertyAccessType.UnconditionalDependency
|
||||
) {
|
||||
return PropertyAccessType.UnconditionalDependency;
|
||||
const resultIsUnconditional =
|
||||
isUnconditional(access1) || isUnconditional(access2);
|
||||
const resultIsDependency = isDependency(access1) || isDependency(access2);
|
||||
|
||||
// Straightforward merge.
|
||||
// This can be represented as bitwise OR, but is written out for readability
|
||||
//
|
||||
// Observe that `UnconditionalAccess | ConditionalDependency` produces an
|
||||
// unconditionally accessed conditional dependency. We currently use these
|
||||
// as we use unconditional dependencies. (i.e. to codegen change variables)
|
||||
if (resultIsUnconditional) {
|
||||
if (resultIsDependency) {
|
||||
return PropertyAccessType.UnconditionalDependency;
|
||||
} else {
|
||||
return PropertyAccessType.UnconditionalAccess;
|
||||
}
|
||||
} else {
|
||||
return PropertyAccessType.UnconditionalAccess;
|
||||
if (resultIsDependency) {
|
||||
return PropertyAccessType.ConditionalDependency;
|
||||
} else {
|
||||
return PropertyAccessType.ConditionalAccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,12 +170,24 @@ const promoteUncondResult = [
|
||||
},
|
||||
];
|
||||
|
||||
const promoteCondResult = [
|
||||
{
|
||||
relativePath: [],
|
||||
accessType: PropertyAccessType.ConditionalDependency,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Recursively calculates minimal dependencies in a subtree.
|
||||
* @param dep DependencyNode representing a dependency subtree.
|
||||
* @returns a minimal list of dependencies in this subtree.
|
||||
*/
|
||||
function deriveMinimalDependenciesInSubtree(
|
||||
dep: DependencyNode
|
||||
): Array<ReduceResultNode> {
|
||||
const results: Array<ReduceResultNode> = [];
|
||||
for (const [childName, childNode] of dep.properties) {
|
||||
const reduceResult = deriveMinimalDependenciesInSubtree(childNode).map(
|
||||
const childResult = deriveMinimalDependenciesInSubtree(childNode).map(
|
||||
({ relativePath, accessType }) => {
|
||||
return {
|
||||
relativePath: [childName, ...relativePath],
|
||||
@@ -147,7 +195,7 @@ function deriveMinimalDependenciesInSubtree(
|
||||
};
|
||||
}
|
||||
);
|
||||
results.push(...reduceResult);
|
||||
results.push(...childResult);
|
||||
}
|
||||
|
||||
switch (dep.accessType) {
|
||||
@@ -155,13 +203,42 @@ function deriveMinimalDependenciesInSubtree(
|
||||
return promoteUncondResult;
|
||||
}
|
||||
case PropertyAccessType.UnconditionalAccess: {
|
||||
// all children are unconditional dependencies, return them to preserve granularity
|
||||
return results;
|
||||
if (
|
||||
results.every(
|
||||
({ accessType }) =>
|
||||
accessType === PropertyAccessType.UnconditionalDependency
|
||||
)
|
||||
) {
|
||||
// all children are unconditional dependencies, return them to preserve granularity
|
||||
return results;
|
||||
} else {
|
||||
// at least one child is accessed conditionally, so this node needs to be promoted to
|
||||
// unconditional dependency
|
||||
return promoteUncondResult;
|
||||
}
|
||||
}
|
||||
case PropertyAccessType.ConditionalAccess:
|
||||
case PropertyAccessType.ConditionalDependency: {
|
||||
if (
|
||||
results.every(
|
||||
({ accessType }) =>
|
||||
accessType === PropertyAccessType.ConditionalDependency
|
||||
)
|
||||
) {
|
||||
// No children are accessed unconditionally, so we cannot promote this node to
|
||||
// unconditional access.
|
||||
// Truncate results of child nodes here, since we shouldn't access them anyways
|
||||
return promoteCondResult;
|
||||
} else {
|
||||
// at least one child is accessed unconditionally, so this node can be promoted to
|
||||
// unconditional dependency
|
||||
return promoteUncondResult;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
todoInvariant(
|
||||
false,
|
||||
"[PropgateScopeDependencies] Handle conditional dependencies."
|
||||
assertExhaustive(
|
||||
dep.accessType,
|
||||
"[PropgateScopeDependencies] Unhandled access type!"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -193,7 +270,7 @@ function deriveMinimalDependenciesInSubtree(
|
||||
// TODO(@mofeiZ): change once we replace Context.#dependencies, #properties with tree
|
||||
// representation
|
||||
function deriveMinimalDependencies(
|
||||
initialDeps: Set<ReactiveScopeDependency>
|
||||
initialDeps: Set<ReactiveScopeDependencyInfo>
|
||||
): Set<ReactiveScopeDependency> {
|
||||
const depRoots = new Map<IdentifierId, [Identifier, DependencyNode]>();
|
||||
|
||||
@@ -209,9 +286,13 @@ function deriveMinimalDependencies(
|
||||
depRoots.set(dep.identifier.id, [dep.identifier, root]);
|
||||
}
|
||||
let currNode: DependencyNode = root;
|
||||
// TODO(@mofeiZ) add conditional access/dependencies here
|
||||
const accessType = PropertyAccessType.UnconditionalAccess;
|
||||
const depType = PropertyAccessType.UnconditionalDependency;
|
||||
|
||||
const accessType = dep.cond
|
||||
? PropertyAccessType.ConditionalAccess
|
||||
: PropertyAccessType.UnconditionalAccess;
|
||||
const depType = dep.cond
|
||||
? PropertyAccessType.ConditionalDependency
|
||||
: PropertyAccessType.UnconditionalDependency;
|
||||
|
||||
for (const property of path) {
|
||||
// all properties read 'on the way' to a dependency are marked as 'access'
|
||||
@@ -256,20 +337,49 @@ function deriveMinimalDependencies(
|
||||
class Context {
|
||||
#declarations: DeclMap = new Map();
|
||||
#reassignments: Map<Identifier, Decl> = new Map();
|
||||
#dependencies: Set<ReactiveScopeDependency> = new Set();
|
||||
#properties: Map<Identifier, ReactiveScopeDependency> = new Map();
|
||||
#dependencies: Set<ReactiveScopeDependencyInfo> = new Set();
|
||||
#properties: Map<Identifier, ReactiveScopeDependencyInfo> = new Map();
|
||||
#temporaries: Map<Identifier, Place> = new Map();
|
||||
#inConditionalWithinScope: boolean = false;
|
||||
#scopes: Scopes = [];
|
||||
|
||||
enter(scope: ReactiveScope, fn: () => void): Set<ReactiveScopeDependency> {
|
||||
// Save context of previous scope
|
||||
const prevInConditional = this.#inConditionalWithinScope;
|
||||
const previousDependencies = this.#dependencies;
|
||||
const scopedDependencies = new Set<ReactiveScopeDependency>();
|
||||
|
||||
// Set context for new scope
|
||||
// A nested scope should add all deps it directly uses as its own
|
||||
// unconditional deps, regardless of whether the nested scope is itself
|
||||
// within a conditional
|
||||
const scopedDependencies = new Set<ReactiveScopeDependencyInfo>();
|
||||
this.#inConditionalWithinScope = false;
|
||||
this.#dependencies = scopedDependencies;
|
||||
this.#scopes.push(scope);
|
||||
|
||||
fn();
|
||||
|
||||
// Restore context of previous scope
|
||||
this.#scopes.pop();
|
||||
this.#dependencies = previousDependencies;
|
||||
return deriveMinimalDependencies(scopedDependencies);
|
||||
this.#inConditionalWithinScope = prevInConditional;
|
||||
|
||||
const minScopeDependencies = deriveMinimalDependencies(scopedDependencies);
|
||||
// propagate dependencies upward using the same rules as normal dependency
|
||||
// collection. child scopes may have dependencies on values created within
|
||||
// the outer scope, which necessarily cannot be dependencies of the outer
|
||||
// scope
|
||||
for (const dep of minScopeDependencies) {
|
||||
this.visitDependency({ ...dep, cond: this.#inConditionalWithinScope });
|
||||
}
|
||||
return minScopeDependencies;
|
||||
}
|
||||
|
||||
enterConditional(fn: () => void): void {
|
||||
const prevInConditional = this.#inConditionalWithinScope;
|
||||
this.#inConditionalWithinScope = true;
|
||||
fn();
|
||||
this.#inConditionalWithinScope = prevInConditional;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,16 +402,18 @@ class Context {
|
||||
declareProperty(lvalue: Place, object: Place, property: string): void {
|
||||
const resolvedObject = this.#temporaries.get(object.identifier) ?? object;
|
||||
const objectDependency = this.#properties.get(resolvedObject.identifier);
|
||||
let nextDependency: ReactiveScopeDependency;
|
||||
let nextDependency: ReactiveScopeDependencyInfo;
|
||||
if (objectDependency === undefined) {
|
||||
nextDependency = {
|
||||
identifier: resolvedObject.identifier,
|
||||
path: [property],
|
||||
cond: this.#inConditionalWithinScope,
|
||||
};
|
||||
} else {
|
||||
nextDependency = {
|
||||
identifier: objectDependency.identifier,
|
||||
path: [...(objectDependency.path ?? []), property],
|
||||
cond: this.#inConditionalWithinScope,
|
||||
};
|
||||
}
|
||||
this.#properties.set(lvalue.identifier, nextDependency);
|
||||
@@ -317,29 +429,35 @@ class Context {
|
||||
|
||||
visitOperand(place: Place): void {
|
||||
const resolved = this.#temporaries.get(place.identifier) ?? place;
|
||||
this.visitDependency({ identifier: resolved.identifier, path: null });
|
||||
this.visitDependency({
|
||||
identifier: resolved.identifier,
|
||||
path: null,
|
||||
cond: this.#inConditionalWithinScope,
|
||||
});
|
||||
}
|
||||
|
||||
visitProperty(object: Place, property: string): void {
|
||||
const resolvedObject = this.#temporaries.get(object.identifier) ?? object;
|
||||
const objectDependency = this.#properties.get(resolvedObject.identifier);
|
||||
let nextDependency: ReactiveScopeDependency;
|
||||
let nextDependency: ReactiveScopeDependencyInfo;
|
||||
if (objectDependency === undefined) {
|
||||
nextDependency = {
|
||||
identifier: resolvedObject.identifier,
|
||||
path: [property],
|
||||
cond: this.#inConditionalWithinScope,
|
||||
};
|
||||
} else {
|
||||
nextDependency = {
|
||||
identifier: objectDependency.identifier,
|
||||
path: [...(objectDependency.path ?? []), property],
|
||||
cond: this.#inConditionalWithinScope,
|
||||
};
|
||||
}
|
||||
this.visitDependency(nextDependency);
|
||||
}
|
||||
|
||||
visitDependency(dependency: ReactiveScopeDependency): void {
|
||||
let maybeDependency: ReactiveScopeDependency;
|
||||
visitDependency(dependency: ReactiveScopeDependencyInfo): void {
|
||||
let maybeDependency: ReactiveScopeDependencyInfo;
|
||||
if (dependency.path !== null) {
|
||||
// Operands may have memberPaths when propagating depenencies of an inner scope upward
|
||||
// In this case we use the dependency as-is
|
||||
@@ -349,12 +467,11 @@ class Context {
|
||||
// the expanded Place. Fall back to using the operand as-is.
|
||||
let propDep = this.#properties.get(dependency.identifier);
|
||||
if (dependency.identifier.name === null && propDep !== undefined) {
|
||||
maybeDependency = propDep;
|
||||
maybeDependency = { ...propDep, cond: dependency.cond };
|
||||
} else {
|
||||
maybeDependency = dependency;
|
||||
}
|
||||
}
|
||||
|
||||
// Any value used after its originally defining scope has concluded must be added as an
|
||||
// output of its defining scope. Regardless of whether its a const or not,
|
||||
// some later code needs access to the value. If the current
|
||||
@@ -429,13 +546,6 @@ function visit(context: Context, block: ReactiveBlock): void {
|
||||
visit(context, item.instructions);
|
||||
});
|
||||
item.scope.dependencies = scopeDependencies;
|
||||
for (const dep of scopeDependencies) {
|
||||
// propagate dependencies upward using the same rules as
|
||||
// normal dependency collection. child scopes may have dependencies
|
||||
// on values created within the outer scope, which necessarily cannot
|
||||
// be dependencies of the outer scope
|
||||
context.visitDependency(dep);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "instruction": {
|
||||
@@ -462,30 +572,53 @@ function visit(context: Context, block: ReactiveBlock): void {
|
||||
case "for": {
|
||||
visitReactiveValue(context, terminal.init);
|
||||
visitReactiveValue(context, terminal.test);
|
||||
visitReactiveValue(context, terminal.update);
|
||||
visit(context, terminal.loop);
|
||||
context.enterConditional(() => {
|
||||
visitReactiveValue(context, terminal.update);
|
||||
visit(context, terminal.loop);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "while": {
|
||||
visitReactiveValue(context, terminal.test);
|
||||
visit(context, terminal.loop);
|
||||
context.enterConditional(() => {
|
||||
visit(context, terminal.loop);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "if": {
|
||||
context.visitOperand(terminal.test);
|
||||
visit(context, terminal.consequent);
|
||||
if (terminal.alternate !== null) {
|
||||
visit(context, terminal.alternate);
|
||||
}
|
||||
/**
|
||||
* TODO: Track dependencies always accessed within consequent and ones
|
||||
* always accessed within alternate. If a dependency is always accessed in
|
||||
* both, we can promote it to an unconditional dependency.
|
||||
*
|
||||
* e.g. props.a.b is unconditionally accessed here.
|
||||
* if (foo(...)) {
|
||||
* access(props.a.b);
|
||||
* } else {
|
||||
* access(props.a.b);
|
||||
* }
|
||||
*
|
||||
* To deal with nested if-branches, enterConditional should return a list
|
||||
* of dependencies unconditionally accessed within the callback.
|
||||
*/
|
||||
context.enterConditional(() => {
|
||||
visit(context, terminal.consequent);
|
||||
if (terminal.alternate !== null) {
|
||||
visit(context, terminal.alternate);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "switch": {
|
||||
context.visitOperand(terminal.test);
|
||||
for (const case_ of terminal.cases) {
|
||||
if (case_.block !== undefined) {
|
||||
visit(context, case_.block);
|
||||
context.enterConditional(() => {
|
||||
for (const case_ of terminal.cases) {
|
||||
if (case_.block !== undefined) {
|
||||
visit(context, case_.block);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -508,13 +641,19 @@ function visitReactiveValue(context: Context, value: ReactiveValue): void {
|
||||
switch (value.kind) {
|
||||
case "LogicalExpression": {
|
||||
visitReactiveValue(context, value.left);
|
||||
visitReactiveValue(context, value.right);
|
||||
|
||||
context.enterConditional(() => {
|
||||
visitReactiveValue(context, value.right);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "ConditionalExpression": {
|
||||
visitReactiveValue(context, value.test);
|
||||
visitReactiveValue(context, value.consequent);
|
||||
visitReactiveValue(context, value.alternate);
|
||||
|
||||
context.enterConditional(() => {
|
||||
visitReactiveValue(context, value.consequent);
|
||||
visitReactiveValue(context, value.alternate);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "SequenceExpression": {
|
||||
@@ -553,9 +692,7 @@ function visitInstructionValue(
|
||||
context.visitProperty(value.object, value.property);
|
||||
}
|
||||
} else {
|
||||
for (const operand of eachReactiveValueOperand(value)) {
|
||||
context.visitOperand(operand);
|
||||
}
|
||||
visitReactiveValue(context, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,13 +92,10 @@ function ComponentA(props) {
|
||||
* props.b *does* influence `a`
|
||||
*/
|
||||
function ComponentB(props) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== props.b;
|
||||
const c_2 = $[2] !== props.c;
|
||||
const c_3 = $[3] !== props.d;
|
||||
const $ = React.unstable_useMemoCache(2);
|
||||
const c_0 = $[0] !== props;
|
||||
let a;
|
||||
if (c_0 || c_1 || c_2 || c_3) {
|
||||
if (c_0) {
|
||||
a = [];
|
||||
a.push(props.a);
|
||||
if (props.b) {
|
||||
@@ -106,13 +103,10 @@ function ComponentB(props) {
|
||||
}
|
||||
|
||||
a.push(props.d);
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = props.c;
|
||||
$[3] = props.d;
|
||||
$[4] = a;
|
||||
$[0] = props;
|
||||
$[1] = a;
|
||||
} else {
|
||||
a = $[4];
|
||||
a = $[1];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -121,13 +115,10 @@ function ComponentB(props) {
|
||||
* props.b *does* influence `a`, but only in a way that is never observable
|
||||
*/
|
||||
function ComponentC(props) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== props.b;
|
||||
const c_2 = $[2] !== props.c;
|
||||
const c_3 = $[3] !== props.d;
|
||||
const $ = React.unstable_useMemoCache(2);
|
||||
const c_0 = $[0] !== props;
|
||||
let a;
|
||||
if (c_0 || c_1 || c_2 || c_3) {
|
||||
if (c_0) {
|
||||
a = [];
|
||||
a.push(props.a);
|
||||
if (props.b) {
|
||||
@@ -136,13 +127,10 @@ function ComponentC(props) {
|
||||
}
|
||||
|
||||
a.push(props.d);
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = props.c;
|
||||
$[3] = props.d;
|
||||
$[4] = a;
|
||||
$[0] = props;
|
||||
$[1] = a;
|
||||
} else {
|
||||
a = $[4];
|
||||
a = $[1];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -151,13 +139,10 @@ function ComponentC(props) {
|
||||
* props.b *does* influence `a`
|
||||
*/
|
||||
function ComponentD(props) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== props.b;
|
||||
const c_2 = $[2] !== props.c;
|
||||
const c_3 = $[3] !== props.d;
|
||||
const $ = React.unstable_useMemoCache(2);
|
||||
const c_0 = $[0] !== props;
|
||||
let a;
|
||||
if (c_0 || c_1 || c_2 || c_3) {
|
||||
if (c_0) {
|
||||
a = [];
|
||||
a.push(props.a);
|
||||
if (props.b) {
|
||||
@@ -166,13 +151,10 @@ function ComponentD(props) {
|
||||
}
|
||||
|
||||
a.push(props.d);
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = props.c;
|
||||
$[3] = props.d;
|
||||
$[4] = a;
|
||||
$[0] = props;
|
||||
$[1] = a;
|
||||
} else {
|
||||
a = $[4];
|
||||
a = $[1];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -35,13 +35,11 @@ function mayMutate() {}
|
||||
|
||||
```javascript
|
||||
function ComponentA(props) {
|
||||
const $ = React.unstable_useMemoCache(8);
|
||||
const c_0 = $[0] !== props.p0;
|
||||
const c_1 = $[1] !== props.p1;
|
||||
const c_2 = $[2] !== props.p2;
|
||||
const $ = React.unstable_useMemoCache(6);
|
||||
const c_0 = $[0] !== props;
|
||||
let a;
|
||||
let b;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
if (c_0) {
|
||||
a = [];
|
||||
b = [];
|
||||
if (b) {
|
||||
@@ -50,37 +48,33 @@ function ComponentA(props) {
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p1;
|
||||
$[2] = props.p2;
|
||||
$[0] = props;
|
||||
$[1] = a;
|
||||
$[2] = b;
|
||||
} else {
|
||||
a = $[1];
|
||||
b = $[2];
|
||||
}
|
||||
const c_3 = $[3] !== a;
|
||||
const c_4 = $[4] !== b;
|
||||
let t0;
|
||||
if (c_3 || c_4) {
|
||||
t0 = <Foo a={a} b={b}></Foo>;
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
$[5] = t0;
|
||||
} else {
|
||||
a = $[3];
|
||||
b = $[4];
|
||||
}
|
||||
const c_5 = $[5] !== a;
|
||||
const c_6 = $[6] !== b;
|
||||
let t0;
|
||||
if (c_5 || c_6) {
|
||||
t0 = <Foo a={a} b={b}></Foo>;
|
||||
$[5] = a;
|
||||
$[6] = b;
|
||||
$[7] = t0;
|
||||
} else {
|
||||
t0 = $[7];
|
||||
t0 = $[5];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
function ComponentB(props) {
|
||||
const $ = React.unstable_useMemoCache(8);
|
||||
const c_0 = $[0] !== props.p0;
|
||||
const c_1 = $[1] !== props.p1;
|
||||
const c_2 = $[2] !== props.p2;
|
||||
const $ = React.unstable_useMemoCache(6);
|
||||
const c_0 = $[0] !== props;
|
||||
let a;
|
||||
let b;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
if (c_0) {
|
||||
a = [];
|
||||
b = [];
|
||||
if (mayMutate(b)) {
|
||||
@@ -89,25 +83,23 @@ function ComponentB(props) {
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p1;
|
||||
$[2] = props.p2;
|
||||
$[0] = props;
|
||||
$[1] = a;
|
||||
$[2] = b;
|
||||
} else {
|
||||
a = $[1];
|
||||
b = $[2];
|
||||
}
|
||||
const c_3 = $[3] !== a;
|
||||
const c_4 = $[4] !== b;
|
||||
let t0;
|
||||
if (c_3 || c_4) {
|
||||
t0 = <Foo a={a} b={b}></Foo>;
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
$[5] = t0;
|
||||
} else {
|
||||
a = $[3];
|
||||
b = $[4];
|
||||
}
|
||||
const c_5 = $[5] !== a;
|
||||
const c_6 = $[6] !== b;
|
||||
let t0;
|
||||
if (c_5 || c_6) {
|
||||
t0 = <Foo a={a} b={b}></Foo>;
|
||||
$[5] = a;
|
||||
$[6] = b;
|
||||
$[7] = t0;
|
||||
} else {
|
||||
t0 = $[7];
|
||||
t0 = $[5];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// When an object's properties are only read conditionally, we should
|
||||
// track the base object as a dependency.
|
||||
function TestOnlyConditionalDependencies(props, other) {
|
||||
const x = {};
|
||||
if (foo(other)) {
|
||||
x.b = props.a.b;
|
||||
x.c = props.a.b.c;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// When an object's properties are only read conditionally, we should
|
||||
// track the base object as a dependency.
|
||||
function TestOnlyConditionalDependencies(props, other) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== other;
|
||||
const c_1 = $[1] !== props;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = {};
|
||||
const c_3 = $[3] !== other;
|
||||
let t0;
|
||||
if (c_3) {
|
||||
t0 = foo(other);
|
||||
$[3] = other;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
}
|
||||
if (t0) {
|
||||
x.b = props.a.b;
|
||||
x.c = props.a.b.c;
|
||||
}
|
||||
$[0] = other;
|
||||
$[1] = props;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// When an object's properties are only read conditionally, we should
|
||||
// track the base object as a dependency.
|
||||
function TestOnlyConditionalDependencies(props, other) {
|
||||
const x = {};
|
||||
if (foo(other)) {
|
||||
x.b = props.a.b;
|
||||
x.c = props.a.b.c;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// When a conditional dependency `props.a.b.c` has no unconditional dependency
|
||||
// in its subpath or superpath, we should find the nearest unconditional access
|
||||
// and promote it to an unconditional dependency.
|
||||
function TestPromoteUnconditionalAccessToDependency(props, other) {
|
||||
const x = {};
|
||||
x.a = props.a.a.a;
|
||||
if (foo(other)) {
|
||||
x.c = props.a.b.c;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// When a conditional dependency `props.a.b.c` has no unconditional dependency
|
||||
// in its subpath or superpath, we should find the nearest unconditional access
|
||||
// and promote it to an unconditional dependency.
|
||||
function TestPromoteUnconditionalAccessToDependency(props, other) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== other;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = {};
|
||||
x.a = props.a.a.a;
|
||||
const c_3 = $[3] !== other;
|
||||
let t0;
|
||||
if (c_3) {
|
||||
t0 = foo(other);
|
||||
$[3] = other;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
}
|
||||
if (t0) {
|
||||
x.c = props.a.b.c;
|
||||
}
|
||||
$[0] = props.a;
|
||||
$[1] = other;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// When a conditional dependency `props.a.b.c` has no unconditional dependency
|
||||
// in its subpath or superpath, we should find the nearest unconditional access
|
||||
// and promote it to an unconditional dependency.
|
||||
function TestPromoteUnconditionalAccessToDependency(props, other) {
|
||||
const x = {};
|
||||
x.a = props.a.a.a;
|
||||
if (foo(other)) {
|
||||
x.c = props.a.b.c;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// When a conditional dependency `props.a` is a subpath of an unconditional
|
||||
// dependency `props.a.b`, we can access `props.a` while preserving program
|
||||
// semantics (with respect to nullthrows).
|
||||
// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a`
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSubpath1(props, other) {
|
||||
const x = {};
|
||||
x.b = props.a.b;
|
||||
if (foo(other)) {
|
||||
x.a = props.a;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// When a conditional dependency `props.a` is a subpath of an unconditional
|
||||
// dependency `props.a.b`, we can access `props.a` while preserving program
|
||||
// semantics (with respect to nullthrows).
|
||||
// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a`
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSubpath1(props, other) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== other;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = {};
|
||||
x.b = props.a.b;
|
||||
const c_3 = $[3] !== other;
|
||||
let t0;
|
||||
if (c_3) {
|
||||
t0 = foo(other);
|
||||
$[3] = other;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
}
|
||||
if (t0) {
|
||||
x.a = props.a;
|
||||
}
|
||||
$[0] = props.a;
|
||||
$[1] = other;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// When a conditional dependency `props.a` is a subpath of an unconditional
|
||||
// dependency `props.a.b`, we can access `props.a` while preserving program
|
||||
// semantics (with respect to nullthrows).
|
||||
// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a`
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSubpath1(props, other) {
|
||||
const x = {};
|
||||
x.b = props.a.b;
|
||||
if (foo(other)) {
|
||||
x.a = props.a;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// When a conditional dependency `props.a` is a subpath of an unconditional
|
||||
// dependency `props.a.b`, we can access `props.a` while preserving program
|
||||
// semantics (with respect to nullthrows).
|
||||
// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a`
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSubpath2(props, other) {
|
||||
const x = {};
|
||||
if (foo(other)) {
|
||||
x.a = props.a;
|
||||
}
|
||||
x.b = props.a.b;
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// When a conditional dependency `props.a` is a subpath of an unconditional
|
||||
// dependency `props.a.b`, we can access `props.a` while preserving program
|
||||
// semantics (with respect to nullthrows).
|
||||
// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a`
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSubpath2(props, other) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== other;
|
||||
const c_1 = $[1] !== props.a;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = {};
|
||||
const c_3 = $[3] !== other;
|
||||
let t0;
|
||||
if (c_3) {
|
||||
t0 = foo(other);
|
||||
$[3] = other;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
}
|
||||
if (t0) {
|
||||
x.a = props.a;
|
||||
}
|
||||
x.b = props.a.b;
|
||||
$[0] = other;
|
||||
$[1] = props.a;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// When a conditional dependency `props.a` is a subpath of an unconditional
|
||||
// dependency `props.a.b`, we can access `props.a` while preserving program
|
||||
// semantics (with respect to nullthrows).
|
||||
// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a`
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSubpath2(props, other) {
|
||||
const x = {};
|
||||
if (foo(other)) {
|
||||
x.a = props.a;
|
||||
}
|
||||
x.b = props.a.b;
|
||||
return x;
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// When an unconditional dependency `props.a` is the subpath of a conditional
|
||||
// dependency `props.a.b`, we can safely overestimate and only track `props.a`
|
||||
// as a dependency
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSuperpath1(props, other) {
|
||||
const x = {};
|
||||
x.a = props.a;
|
||||
if (foo(other)) {
|
||||
x.b = props.a.b;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// When an unconditional dependency `props.a` is the subpath of a conditional
|
||||
// dependency `props.a.b`, we can safely overestimate and only track `props.a`
|
||||
// as a dependency
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSuperpath1(props, other) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== other;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = {};
|
||||
x.a = props.a;
|
||||
const c_3 = $[3] !== other;
|
||||
let t0;
|
||||
if (c_3) {
|
||||
t0 = foo(other);
|
||||
$[3] = other;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
}
|
||||
if (t0) {
|
||||
x.b = props.a.b;
|
||||
}
|
||||
$[0] = props.a;
|
||||
$[1] = other;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// When an unconditional dependency `props.a` is the subpath of a conditional
|
||||
// dependency `props.a.b`, we can safely overestimate and only track `props.a`
|
||||
// as a dependency
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSuperpath1(props, other) {
|
||||
const x = {};
|
||||
x.a = props.a;
|
||||
if (foo(other)) {
|
||||
x.b = props.a.b;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// When an unconditional dependency `props.a` is the subpath of a conditional
|
||||
// dependency `props.a.b`, we can safely overestimate and only track `props.a`
|
||||
// as a dependency
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSuperpath2(props, other) {
|
||||
const x = {};
|
||||
if (foo(other)) {
|
||||
x.b = props.a.b;
|
||||
}
|
||||
x.a = props.a;
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// When an unconditional dependency `props.a` is the subpath of a conditional
|
||||
// dependency `props.a.b`, we can safely overestimate and only track `props.a`
|
||||
// as a dependency
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSuperpath2(props, other) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
const c_0 = $[0] !== other;
|
||||
const c_1 = $[1] !== props.a;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = {};
|
||||
const c_3 = $[3] !== other;
|
||||
let t0;
|
||||
if (c_3) {
|
||||
t0 = foo(other);
|
||||
$[3] = other;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
}
|
||||
if (t0) {
|
||||
x.b = props.a.b;
|
||||
}
|
||||
x.a = props.a;
|
||||
$[0] = other;
|
||||
$[1] = props.a;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// When an unconditional dependency `props.a` is the subpath of a conditional
|
||||
// dependency `props.a.b`, we can safely overestimate and only track `props.a`
|
||||
// as a dependency
|
||||
// ordering of accesses should not matter
|
||||
function TestConditionalSuperpath2(props, other) {
|
||||
const x = {};
|
||||
if (foo(other)) {
|
||||
x.b = props.a.b;
|
||||
}
|
||||
x.a = props.a;
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// Some reactive scopes are created within a conditional. If a child scope
|
||||
// is within a conditional, its reactive dependencies should be propagated
|
||||
// as conditionals
|
||||
//
|
||||
// In this test:
|
||||
// ```javascript
|
||||
// scope @0 (deps=[???] decls=[x]) {
|
||||
// const x = {};
|
||||
// if (foo) {
|
||||
// scope @1 (deps=[props.a.b] decls=[tmp]) {
|
||||
// const tmp = bar(props.a.b);
|
||||
// }
|
||||
// x.a = tmp;
|
||||
// }
|
||||
// }
|
||||
// return x;
|
||||
// ```
|
||||
|
||||
function TestReactiveDepsInCondScope(props) {
|
||||
let x = {};
|
||||
if (foo) {
|
||||
let tmp = bar(props.a.b);
|
||||
x.a = tmp;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// Some reactive scopes are created within a conditional. If a child scope
|
||||
// is within a conditional, its reactive dependencies should be propagated
|
||||
// as conditionals
|
||||
//
|
||||
// In this test:
|
||||
// ```javascript
|
||||
// scope @0 (deps=[???] decls=[x]) {
|
||||
// const x = {};
|
||||
// if (foo) {
|
||||
// scope @1 (deps=[props.a.b] decls=[tmp]) {
|
||||
// const tmp = bar(props.a.b);
|
||||
// }
|
||||
// x.a = tmp;
|
||||
// }
|
||||
// }
|
||||
// return x;
|
||||
// ```
|
||||
|
||||
function TestReactiveDepsInCondScope(props) {
|
||||
const $ = React.unstable_useMemoCache(4);
|
||||
const c_0 = $[0] !== props;
|
||||
let x;
|
||||
if (c_0) {
|
||||
x = {};
|
||||
if (foo) {
|
||||
const c_2 = $[2] !== props.a.b;
|
||||
let tmp;
|
||||
if (c_2) {
|
||||
tmp = bar(props.a.b);
|
||||
$[2] = props.a.b;
|
||||
$[3] = tmp;
|
||||
} else {
|
||||
tmp = $[3];
|
||||
}
|
||||
x.a = tmp;
|
||||
}
|
||||
$[0] = props;
|
||||
$[1] = x;
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Some reactive scopes are created within a conditional. If a child scope
|
||||
// is within a conditional, its reactive dependencies should be propagated
|
||||
// as conditionals
|
||||
//
|
||||
// In this test:
|
||||
// ```javascript
|
||||
// scope @0 (deps=[???] decls=[x]) {
|
||||
// const x = {};
|
||||
// if (foo) {
|
||||
// scope @1 (deps=[props.a.b] decls=[tmp]) {
|
||||
// const tmp = bar(props.a.b);
|
||||
// }
|
||||
// x.a = tmp;
|
||||
// }
|
||||
// }
|
||||
// return x;
|
||||
// ```
|
||||
|
||||
function TestReactiveDepsInCondScope(props) {
|
||||
let x = {};
|
||||
if (foo) {
|
||||
let tmp = bar(props.a.b);
|
||||
x.a = tmp;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
+2
-2
@@ -57,12 +57,12 @@ function foo(props) {
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
const c_2 = $[2] !== props;
|
||||
const c_2 = $[2] !== props.showHeader;
|
||||
const c_3 = $[3] !== x;
|
||||
let t0;
|
||||
if (c_2 || c_3) {
|
||||
t0 = props.showHeader ? <div>{x}</div> : null;
|
||||
$[2] = props;
|
||||
$[2] = props.showHeader;
|
||||
$[3] = x;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
|
||||
@@ -23,41 +23,39 @@ function Component(props) {
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const $ = React.unstable_useMemoCache(7);
|
||||
const c_0 = $[0] !== props.p0;
|
||||
const c_1 = $[1] !== props.p1;
|
||||
const $ = React.unstable_useMemoCache(6);
|
||||
const c_0 = $[0] !== props;
|
||||
let x;
|
||||
let y;
|
||||
if (c_0 || c_1) {
|
||||
if (c_0) {
|
||||
x = [];
|
||||
y = undefined;
|
||||
if (props.p0) {
|
||||
x.push(props.p1);
|
||||
y = x;
|
||||
}
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p1;
|
||||
$[2] = x;
|
||||
$[3] = y;
|
||||
$[0] = props;
|
||||
$[1] = x;
|
||||
$[2] = y;
|
||||
} else {
|
||||
x = $[2];
|
||||
y = $[3];
|
||||
x = $[1];
|
||||
y = $[2];
|
||||
}
|
||||
const c_4 = $[4] !== x;
|
||||
const c_5 = $[5] !== y;
|
||||
const c_3 = $[3] !== x;
|
||||
const c_4 = $[4] !== y;
|
||||
let t0;
|
||||
if (c_4 || c_5) {
|
||||
if (c_3 || c_4) {
|
||||
t0 = (
|
||||
<Component>
|
||||
{x}
|
||||
{y}
|
||||
</Component>
|
||||
);
|
||||
$[4] = x;
|
||||
$[5] = y;
|
||||
$[6] = t0;
|
||||
$[3] = x;
|
||||
$[4] = y;
|
||||
$[5] = t0;
|
||||
} else {
|
||||
t0 = $[6];
|
||||
t0 = $[5];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,10 @@ function foo(props) {
|
||||
|
||||
```javascript
|
||||
function foo(props) {
|
||||
const $ = React.unstable_useMemoCache(4);
|
||||
const c_0 = $[0] !== props.bar;
|
||||
const c_1 = $[1] !== props.cond;
|
||||
const c_2 = $[2] !== props.foo;
|
||||
const $ = React.unstable_useMemoCache(2);
|
||||
const c_0 = $[0] !== props;
|
||||
let x;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
if (c_0) {
|
||||
x = [];
|
||||
x.push(props.bar);
|
||||
if (props.cond) {
|
||||
@@ -34,12 +32,10 @@ function foo(props) {
|
||||
}
|
||||
|
||||
mut(x);
|
||||
$[0] = props.bar;
|
||||
$[1] = props.cond;
|
||||
$[2] = props.foo;
|
||||
$[3] = x;
|
||||
$[0] = props;
|
||||
$[1] = x;
|
||||
} else {
|
||||
x = $[3];
|
||||
x = $[1];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,11 @@ function Component(props) {
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const $ = React.unstable_useMemoCache(10);
|
||||
const c_0 = $[0] !== props.p0;
|
||||
const c_1 = $[1] !== props.p2;
|
||||
const $ = React.unstable_useMemoCache(9);
|
||||
const c_0 = $[0] !== props;
|
||||
let x;
|
||||
let y;
|
||||
if (c_0 || c_1) {
|
||||
if (c_0) {
|
||||
x = [];
|
||||
y = undefined;
|
||||
bb1: switch (props.p0) {
|
||||
@@ -47,11 +46,11 @@ function Component(props) {
|
||||
case true: {
|
||||
x.push(props.p2);
|
||||
let t0;
|
||||
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = [];
|
||||
$[4] = t0;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
t0 = $[3];
|
||||
}
|
||||
y = t0;
|
||||
break bb1;
|
||||
@@ -63,34 +62,33 @@ function Component(props) {
|
||||
y = x;
|
||||
}
|
||||
}
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p2;
|
||||
$[2] = x;
|
||||
$[3] = y;
|
||||
$[0] = props;
|
||||
$[1] = x;
|
||||
$[2] = y;
|
||||
} else {
|
||||
x = $[2];
|
||||
y = $[3];
|
||||
x = $[1];
|
||||
y = $[2];
|
||||
}
|
||||
const c_5 = $[5] !== x;
|
||||
const c_4 = $[4] !== x;
|
||||
let child;
|
||||
if (c_5) {
|
||||
if (c_4) {
|
||||
child = <Component data={x}></Component>;
|
||||
$[5] = x;
|
||||
$[6] = child;
|
||||
$[4] = x;
|
||||
$[5] = child;
|
||||
} else {
|
||||
child = $[6];
|
||||
child = $[5];
|
||||
}
|
||||
y.push(props.p4);
|
||||
const c_7 = $[7] !== y;
|
||||
const c_8 = $[8] !== child;
|
||||
const c_6 = $[6] !== y;
|
||||
const c_7 = $[7] !== child;
|
||||
let t1;
|
||||
if (c_7 || c_8) {
|
||||
if (c_6 || c_7) {
|
||||
t1 = <Component data={y}>{child}</Component>;
|
||||
$[7] = y;
|
||||
$[8] = child;
|
||||
$[9] = t1;
|
||||
$[6] = y;
|
||||
$[7] = child;
|
||||
$[8] = t1;
|
||||
} else {
|
||||
t1 = $[9];
|
||||
t1 = $[8];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,11 @@ function Component(props) {
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const $ = React.unstable_useMemoCache(10);
|
||||
const c_0 = $[0] !== props.p0;
|
||||
const c_1 = $[1] !== props.p2;
|
||||
const c_2 = $[2] !== props.p3;
|
||||
const $ = React.unstable_useMemoCache(8);
|
||||
const c_0 = $[0] !== props;
|
||||
let x;
|
||||
let y;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
if (c_0) {
|
||||
x = [];
|
||||
y = undefined;
|
||||
switch (props.p0) {
|
||||
@@ -45,35 +43,33 @@ function Component(props) {
|
||||
y = x;
|
||||
}
|
||||
}
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p2;
|
||||
$[2] = props.p3;
|
||||
$[3] = x;
|
||||
$[4] = y;
|
||||
$[0] = props;
|
||||
$[1] = x;
|
||||
$[2] = y;
|
||||
} else {
|
||||
x = $[3];
|
||||
y = $[4];
|
||||
x = $[1];
|
||||
y = $[2];
|
||||
}
|
||||
const c_5 = $[5] !== x;
|
||||
const c_3 = $[3] !== x;
|
||||
let child;
|
||||
if (c_5) {
|
||||
if (c_3) {
|
||||
child = <Component data={x}></Component>;
|
||||
$[5] = x;
|
||||
$[6] = child;
|
||||
$[3] = x;
|
||||
$[4] = child;
|
||||
} else {
|
||||
child = $[6];
|
||||
child = $[4];
|
||||
}
|
||||
y.push(props.p4);
|
||||
const c_7 = $[7] !== y;
|
||||
const c_8 = $[8] !== child;
|
||||
const c_5 = $[5] !== y;
|
||||
const c_6 = $[6] !== child;
|
||||
let t0;
|
||||
if (c_7 || c_8) {
|
||||
if (c_5 || c_6) {
|
||||
t0 = <Component data={y}>{child}</Component>;
|
||||
$[7] = y;
|
||||
$[8] = child;
|
||||
$[9] = t0;
|
||||
$[5] = y;
|
||||
$[6] = child;
|
||||
$[7] = t0;
|
||||
} else {
|
||||
t0 = $[9];
|
||||
t0 = $[7];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user