Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a7e8557da | ||
|
|
4a3ff8eed6 | ||
|
|
ec4374c387 | ||
|
|
60b5271a9a | ||
|
|
033edca721 | ||
|
|
e6dc25daea | ||
|
|
150f022444 | ||
|
|
49ded1d12a | ||
|
|
3a43e72d66 | ||
|
|
8ba3501cd9 | ||
|
|
956d770adf | ||
|
|
d35fef9e21 | ||
|
|
a7a116577d | ||
|
|
777264b4ef | ||
|
|
befc1246b0 | ||
|
|
bbea677b77 | ||
|
|
f1ecf82bfb | ||
|
|
b44a99bf58 | ||
|
|
e4314a0a0f | ||
|
|
e43986f1f3 | ||
|
|
c932e45780 | ||
|
|
223f81d877 | ||
|
|
8a6c589be7 | ||
|
|
7cafeff340 | ||
|
|
0378b46e7e | ||
|
|
bb402876f7 | ||
|
|
9a645e1d10 | ||
|
|
2d7f0c4259 | ||
|
|
4aad5e45ba | ||
|
|
453a19a107 | ||
|
|
5d87cd2244 | ||
|
|
5f71eed2eb | ||
|
|
455424dbf3 | ||
|
|
9fd4c09d68 | ||
|
|
d45db667d4 | ||
|
|
3fc1bc6f28 | ||
|
|
ef8b6fa257 | ||
|
|
0b78161d7d | ||
|
|
dcf83f7c2d | ||
|
|
94fce500bc | ||
|
|
508f7aa78f | ||
|
|
e104795f63 | ||
|
|
c0d151ce7e | ||
|
|
fc41c24aa6 | ||
|
|
73aa744b70 | ||
|
|
602917c8cb | ||
|
|
91d097b2c5 | ||
|
|
7216c0f002 | ||
|
|
6a3d16ca74 | ||
|
|
65c4decb56 | ||
|
|
1e0d12b6f2 | ||
|
|
e9cab42ece | ||
|
|
3cfcdfb307 | ||
|
|
9c2a8dd5f8 | ||
|
|
811e203ed4 | ||
|
|
d92056efb3 | ||
|
|
58ac15cdc9 | ||
|
|
bfc8801e0f | ||
|
|
d2a288febf | ||
|
|
4db4b21c63 | ||
|
|
31d91651e0 | ||
|
|
9406162bc9 | ||
|
|
9b2a545b32 | ||
|
|
bb6c9d521e | ||
|
|
123ff13b19 | ||
|
|
e130c08b06 | ||
|
|
9894c488e0 | ||
|
|
cee7939b00 | ||
|
|
b42341ddc7 | ||
|
|
7a3ffef703 | ||
|
|
e67b4fe22e | ||
|
|
4a523489b7 | ||
|
|
94cf60bede | ||
|
|
bbc13fa17b | ||
|
|
12eaef7ef5 | ||
|
|
c80c69fa96 | ||
|
|
aab72cb1cb | ||
|
|
fa3feba672 | ||
|
|
2a911f27dd | ||
|
|
18ee505e77 | ||
|
|
1d1b26c701 | ||
|
|
fe3f0ec037 | ||
|
|
d70ee32b88 | ||
|
|
6c7b1a1d98 | ||
|
|
ed077194b5 | ||
|
|
643257ca52 | ||
|
|
06e89951be | ||
|
|
79d9aed7ed | ||
|
|
c8822e926b | ||
|
|
a947eba4f2 | ||
|
|
374dfe8edf | ||
|
|
2bee34867d | ||
|
|
d37faa041b | ||
|
|
3a2ff8b51b |
@@ -622,6 +622,7 @@ module.exports = {
|
||||
ScrollTimeline: 'readonly',
|
||||
EventListenerOptionsOrUseCapture: 'readonly',
|
||||
FocusOptions: 'readonly',
|
||||
OptionalEffectTiming: 'readonly',
|
||||
|
||||
spyOnDev: 'readonly',
|
||||
spyOnDevAndProd: 'readonly',
|
||||
|
||||
10
.github/workflows/runtime_build_and_test.yml
vendored
10
.github/workflows/runtime_build_and_test.yml
vendored
@@ -301,10 +301,12 @@ jobs:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Install runtime dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Install compiler dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: compiler
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: ./scripts/react-compiler/build-compiler.sh && ./scripts/react-compiler/link-compiler.sh
|
||||
- run: yarn workspace eslint-plugin-react-hooks test
|
||||
|
||||
8
.github/workflows/runtime_prereleases.yml
vendored
8
.github/workflows/runtime_prereleases.yml
vendored
@@ -85,7 +85,7 @@ jobs:
|
||||
--skipTests \
|
||||
--tags=${{ inputs.dist_tag }} \
|
||||
--onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}}
|
||||
${{ inputs.dry && '--dry'}}
|
||||
${{ inputs.dry && '--dry' || '' }}
|
||||
- if: '${{ inputs.skip_packages }}'
|
||||
name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}'
|
||||
run: |
|
||||
@@ -94,19 +94,19 @@ jobs:
|
||||
--skipTests \
|
||||
--tags=${{ inputs.dist_tag }} \
|
||||
--skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}}
|
||||
${{ inputs.dry && '--dry'}}
|
||||
${{ inputs.dry && '--dry' || '' }}
|
||||
- if: '${{ !(inputs.skip_packages && inputs.only_packages) }}'
|
||||
name: 'Publish all packages'
|
||||
run: |
|
||||
scripts/release/publish.js \
|
||||
--ci \
|
||||
--tags=${{ inputs.dist_tag }} ${{ (inputs.dry && '') || '\'}}
|
||||
${{ inputs.dry && '--dry'}}
|
||||
${{ inputs.dry && '--dry' || '' }}
|
||||
- name: Notify Discord on failure
|
||||
if: failure() && inputs.enableFailureNotification == true
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: "GitHub Actions"
|
||||
embed-title: 'Publish of $${{ inputs.release_channel }} release failed'
|
||||
embed-title: '[Runtime] Publish of ${{ inputs.release_channel }}@${{ inputs.dist_tag}} release failed'
|
||||
embed-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}
|
||||
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
--tags=${{ inputs.tags }} \
|
||||
--publishVersion=${{ inputs.version_to_publish }} \
|
||||
--onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}}
|
||||
${{ inputs.dry && '--dry'}}
|
||||
${{ inputs.dry && '--dry' || '' }}
|
||||
- if: '${{ inputs.skip_packages }}'
|
||||
name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}'
|
||||
run: |
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
--tags=${{ inputs.tags }} \
|
||||
--publishVersion=${{ inputs.version_to_publish }} \
|
||||
--skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}}
|
||||
${{ inputs.dry && '--dry'}}
|
||||
${{ inputs.dry && '--dry' || '' }}
|
||||
- name: Archive released package for debugging
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -19,11 +19,11 @@ An Owner Stack is a string representing the components that are directly respons
|
||||
* Updated `useId` to use valid CSS selectors, changing format from `:r123:` to `«r123»`. [#32001](https://github.com/facebook/react/pull/32001)
|
||||
* Added a dev-only warning for null/undefined created in useEffect, useInsertionEffect, and useLayoutEffect. [#32355](https://github.com/facebook/react/pull/32355)
|
||||
* Fixed a bug where dev-only methods were exported in production builds. React.act is no longer available in production builds. [#32200](https://github.com/facebook/react/pull/32200)
|
||||
* Improved consistency across prod and dev to improve compatibility with Google Closure Complier and bindings [#31808](https://github.com/facebook/react/pull/31808)
|
||||
* Improved consistency across prod and dev to improve compatibility with Google Closure Compiler and bindings [#31808](https://github.com/facebook/react/pull/31808)
|
||||
* Improve passive effect scheduling for consistent task yielding. [#31785](https://github.com/facebook/react/pull/31785)
|
||||
* Fixed asserts in React Native when passChildrenWhenCloningPersistedNodes is enabled for OffscreenComponent rendering. [#32528](https://github.com/facebook/react/pull/32528)
|
||||
* Fixed component name resolution for Portal [#32640](https://github.com/facebook/react/pull/32640)
|
||||
* Added support for beforetoggle and toggle events on the dialog element. #32479 [#32479](https://github.com/facebook/react/pull/32479)
|
||||
* Added support for beforetoggle and toggle events on the dialog element. [#32479](https://github.com/facebook/react/pull/32479)
|
||||
|
||||
### React DOM
|
||||
* Fixed double warning when the `href` attribute is an empty string [#31783](https://github.com/facebook/react/pull/31783)
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
PrintedCompilerPipelineValue,
|
||||
} from './Output';
|
||||
import {transformFromAstSync} from '@babel/core';
|
||||
import {LoggerEvent} from 'babel-plugin-react-compiler/dist/Entrypoint';
|
||||
|
||||
function parseInput(
|
||||
input: string,
|
||||
@@ -143,6 +144,7 @@ const COMMON_HOOKS: Array<[string, Hook]> = [
|
||||
function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
||||
const results = new Map<string, Array<PrintedCompilerPipelineValue>>();
|
||||
const error = new CompilerError();
|
||||
const otherErrors: Array<CompilerErrorDetail> = [];
|
||||
const upsert: (result: PrintedCompilerPipelineValue) => void = result => {
|
||||
const entry = results.get(result.name);
|
||||
if (Array.isArray(entry)) {
|
||||
@@ -210,7 +212,11 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
||||
},
|
||||
logger: {
|
||||
debugLogIRs: logIR,
|
||||
logEvent: () => {},
|
||||
logEvent: (_filename: string | null, event: LoggerEvent) => {
|
||||
if (event.kind === 'CompileError') {
|
||||
otherErrors.push(new CompilerErrorDetail(event.detail));
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
transformOutput = invokeCompiler(source, language, opts);
|
||||
@@ -237,6 +243,10 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Only include logger errors if there weren't other errors
|
||||
if (!error.hasErrors() && otherErrors.length !== 0) {
|
||||
otherErrors.forEach(e => error.push(e));
|
||||
}
|
||||
if (error.hasErrors()) {
|
||||
return [{kind: 'err', results, error: error}, language];
|
||||
}
|
||||
|
||||
@@ -221,7 +221,6 @@ export function lower(
|
||||
params,
|
||||
fnType: bindings == null ? env.fnType : 'Other',
|
||||
returnTypeAnnotation: null, // TODO: extract the actual return type node if present
|
||||
returnType: makeType(),
|
||||
returns: createTemporaryPlace(env, func.node.loc ?? GeneratedSource),
|
||||
body: builder.build(),
|
||||
context,
|
||||
@@ -1356,13 +1355,48 @@ function lowerStatement(
|
||||
|
||||
return;
|
||||
}
|
||||
case 'TypeAlias':
|
||||
case 'TSInterfaceDeclaration':
|
||||
case 'TSTypeAliasDeclaration': {
|
||||
// We do not preserve type annotations/syntax through transformation
|
||||
case 'WithStatement': {
|
||||
builder.errors.push({
|
||||
reason: `JavaScript 'with' syntax is not supported`,
|
||||
description: `'with' syntax is considered deprecated and removed from JavaScript standards, consider alternatives`,
|
||||
severity: ErrorSeverity.InvalidJS,
|
||||
loc: stmtPath.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
lowerValueToTemporary(builder, {
|
||||
kind: 'UnsupportedNode',
|
||||
loc: stmtPath.node.loc ?? GeneratedSource,
|
||||
node: stmtPath.node,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case 'ClassDeclaration': {
|
||||
/*
|
||||
* We can in theory support nested classes, similarly to functions where we track values
|
||||
* captured by the class and consider mutations of the instances to mutate the class itself
|
||||
*/
|
||||
builder.errors.push({
|
||||
reason: `Support nested class declarations`,
|
||||
severity: ErrorSeverity.Todo,
|
||||
loc: stmtPath.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
lowerValueToTemporary(builder, {
|
||||
kind: 'UnsupportedNode',
|
||||
loc: stmtPath.node.loc ?? GeneratedSource,
|
||||
node: stmtPath.node,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case 'EnumDeclaration':
|
||||
case 'TSEnumDeclaration': {
|
||||
lowerValueToTemporary(builder, {
|
||||
kind: 'UnsupportedNode',
|
||||
loc: stmtPath.node.loc ?? GeneratedSource,
|
||||
node: stmtPath.node,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case 'ClassDeclaration':
|
||||
case 'DeclareClass':
|
||||
case 'DeclareExportAllDeclaration':
|
||||
case 'DeclareExportDeclaration':
|
||||
@@ -1373,20 +1407,23 @@ function lowerStatement(
|
||||
case 'DeclareOpaqueType':
|
||||
case 'DeclareTypeAlias':
|
||||
case 'DeclareVariable':
|
||||
case 'EnumDeclaration':
|
||||
case 'InterfaceDeclaration':
|
||||
case 'OpaqueType':
|
||||
case 'TSDeclareFunction':
|
||||
case 'TSInterfaceDeclaration':
|
||||
case 'TSTypeAliasDeclaration':
|
||||
case 'TypeAlias': {
|
||||
// We do not preserve type annotations/syntax through transformation
|
||||
return;
|
||||
}
|
||||
case 'ExportAllDeclaration':
|
||||
case 'ExportDefaultDeclaration':
|
||||
case 'ExportNamedDeclaration':
|
||||
case 'ImportDeclaration':
|
||||
case 'InterfaceDeclaration':
|
||||
case 'OpaqueType':
|
||||
case 'TSDeclareFunction':
|
||||
case 'TSEnumDeclaration':
|
||||
case 'TSExportAssignment':
|
||||
case 'TSImportEqualsDeclaration':
|
||||
case 'TSModuleDeclaration':
|
||||
case 'TSNamespaceExportDeclaration':
|
||||
case 'WithStatement': {
|
||||
case 'TSNamespaceExportDeclaration': {
|
||||
builder.errors.push({
|
||||
reason: `(BuildHIR::lowerStatement) Handle ${stmtPath.type} statements`,
|
||||
severity: ErrorSeverity.Todo,
|
||||
@@ -3503,6 +3540,16 @@ function lowerIdentifier(
|
||||
return place;
|
||||
}
|
||||
default: {
|
||||
if (binding.kind === 'Global' && binding.name === 'eval') {
|
||||
builder.errors.push({
|
||||
reason: `The 'eval' function is not supported`,
|
||||
description:
|
||||
'Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler',
|
||||
severity: ErrorSeverity.InvalidJS,
|
||||
loc: exprPath.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
}
|
||||
return lowerValueToTemporary(builder, {
|
||||
kind: 'LoadGlobal',
|
||||
binding,
|
||||
|
||||
@@ -279,7 +279,6 @@ export type HIRFunction = {
|
||||
env: Environment;
|
||||
params: Array<Place | SpreadPattern>;
|
||||
returnTypeAnnotation: t.FlowType | t.TSType | null;
|
||||
returnType: Type;
|
||||
returns: Place;
|
||||
context: Array<Place>;
|
||||
effects: Array<FunctionEffect> | null;
|
||||
@@ -1770,6 +1769,10 @@ export function isUseStateType(id: Identifier): boolean {
|
||||
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseState';
|
||||
}
|
||||
|
||||
export function isJsxType(type: Type): boolean {
|
||||
return type.kind === 'Object' && type.shapeId === 'BuiltInJsx';
|
||||
}
|
||||
|
||||
export function isRefOrRefValue(id: Identifier): boolean {
|
||||
return isUseRefType(id) || isRefValueType(id);
|
||||
}
|
||||
|
||||
@@ -107,6 +107,17 @@ export function mergeConsecutiveBlocks(fn: HIRFunction): void {
|
||||
merged.merge(block.id, predecessorId);
|
||||
fn.body.blocks.delete(block.id);
|
||||
}
|
||||
for (const [, block] of fn.body.blocks) {
|
||||
for (const phi of block.phis) {
|
||||
for (const [predecessorId, operand] of phi.operands) {
|
||||
const mapped = merged.get(predecessorId);
|
||||
if (mapped !== predecessorId) {
|
||||
phi.operands.delete(predecessorId);
|
||||
phi.operands.set(mapped, operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
markPredecessors(fn.body);
|
||||
for (const [, {terminal}] of fn.body.blocks) {
|
||||
if (terminalHasFallthrough(terminal)) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import generate from '@babel/generator';
|
||||
import {CompilerError} from '../CompilerError';
|
||||
import {printReactiveScopeSummary} from '../ReactiveScopes/PrintReactiveFunction';
|
||||
import DisjointSet from '../Utils/DisjointSet';
|
||||
@@ -54,6 +53,8 @@ export function printFunction(fn: HIRFunction): string {
|
||||
let definition = '';
|
||||
if (fn.id !== null) {
|
||||
definition += fn.id;
|
||||
} else {
|
||||
definition += '<<anonymous>>';
|
||||
}
|
||||
if (fn.params.length !== 0) {
|
||||
definition +=
|
||||
@@ -71,10 +72,8 @@ export function printFunction(fn: HIRFunction): string {
|
||||
} else {
|
||||
definition += '()';
|
||||
}
|
||||
if (definition.length !== 0) {
|
||||
output.push(definition);
|
||||
}
|
||||
output.push(`: ${printType(fn.returnType)} @ ${printPlace(fn.returns)}`);
|
||||
definition += `: ${printPlace(fn.returns)}`;
|
||||
output.push(definition);
|
||||
output.push(...fn.directives);
|
||||
output.push(printHIR(fn.body));
|
||||
return output.join('\n');
|
||||
@@ -466,7 +465,7 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
|
||||
break;
|
||||
}
|
||||
case 'UnsupportedNode': {
|
||||
value = `UnsupportedNode(${generate(instrValue.node).code})`;
|
||||
value = `UnsupportedNode ${instrValue.node.type}`;
|
||||
break;
|
||||
}
|
||||
case 'LoadLocal': {
|
||||
@@ -715,7 +714,7 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
|
||||
break;
|
||||
}
|
||||
case 'FinishMemoize': {
|
||||
value = `FinishMemoize decl=${printPlace(instrValue.decl)}`;
|
||||
value = `FinishMemoize decl=${printPlace(instrValue.decl)}${instrValue.pruned ? ' pruned' : ''}`;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
@@ -20,11 +20,9 @@ import {inferReactiveScopeVariables} from '../ReactiveScopes';
|
||||
import {rewriteInstructionKindsBasedOnReassignment} from '../SSA';
|
||||
import {inferMutableRanges} from './InferMutableRanges';
|
||||
import inferReferenceEffects from './InferReferenceEffects';
|
||||
import {assertExhaustive, retainWhere} from '../Utils/utils';
|
||||
import {assertExhaustive} from '../Utils/utils';
|
||||
import {inferMutationAliasingEffects} from './InferMutationAliasingEffects';
|
||||
import {inferFunctionExpressionAliasingEffectsSignature} from './InferFunctionExpressionAliasingEffectsSignature';
|
||||
import {inferMutationAliasingRanges} from './InferMutationAliasingRanges';
|
||||
import {hashEffect} from './AliasingEffects';
|
||||
|
||||
export default function analyseFunctions(func: HIRFunction): void {
|
||||
for (const [_, block] of func.body.blocks) {
|
||||
@@ -69,30 +67,12 @@ function lowerWithMutationAliasing(fn: HIRFunction): void {
|
||||
analyseFunctions(fn);
|
||||
inferMutationAliasingEffects(fn, {isFunctionExpression: true});
|
||||
deadCodeElimination(fn);
|
||||
inferMutationAliasingRanges(fn, {isFunctionExpression: true});
|
||||
const functionEffects = inferMutationAliasingRanges(fn, {
|
||||
isFunctionExpression: true,
|
||||
}).unwrap();
|
||||
rewriteInstructionKindsBasedOnReassignment(fn);
|
||||
inferReactiveScopeVariables(fn);
|
||||
const effects = inferFunctionExpressionAliasingEffectsSignature(fn);
|
||||
fn.env.logger?.debugLogIRs?.({
|
||||
kind: 'hir',
|
||||
name: 'AnalyseFunction (inner)',
|
||||
value: fn,
|
||||
});
|
||||
if (effects != null) {
|
||||
fn.aliasingEffects ??= [];
|
||||
fn.aliasingEffects?.push(...effects);
|
||||
}
|
||||
if (fn.aliasingEffects != null) {
|
||||
const seen = new Set<string>();
|
||||
retainWhere(fn.aliasingEffects, effect => {
|
||||
const hash = hashEffect(effect);
|
||||
if (seen.has(hash)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(hash);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
fn.aliasingEffects = functionEffects;
|
||||
|
||||
/**
|
||||
* Phase 2: populate the Effect of each context variable to use in inferring
|
||||
@@ -100,7 +80,7 @@ function lowerWithMutationAliasing(fn: HIRFunction): void {
|
||||
* effects to decide if the function may be mutable or not.
|
||||
*/
|
||||
const capturedOrMutated = new Set<IdentifierId>();
|
||||
for (const effect of effects ?? []) {
|
||||
for (const effect of functionEffects) {
|
||||
switch (effect.kind) {
|
||||
case 'Assign':
|
||||
case 'Alias':
|
||||
@@ -152,6 +132,12 @@ function lowerWithMutationAliasing(fn: HIRFunction): void {
|
||||
operand.effect = Effect.Read;
|
||||
}
|
||||
}
|
||||
|
||||
fn.env.logger?.debugLogIRs?.({
|
||||
kind: 'hir',
|
||||
name: 'AnalyseFunction (inner)',
|
||||
value: fn,
|
||||
});
|
||||
}
|
||||
|
||||
function lower(func: HIRFunction): void {
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {HIRFunction, IdentifierId, Place, ValueKind, ValueReason} from '../HIR';
|
||||
import {getOrInsertDefault} from '../Utils/utils';
|
||||
import {AliasingEffect} from './AliasingEffects';
|
||||
|
||||
/**
|
||||
* This function tracks data flow within an inner function expression in order to
|
||||
* compute a set of data-flow aliasing effects describing data flow between the function's
|
||||
* params, context variables, and return value.
|
||||
*
|
||||
* For example, consider the following function expression:
|
||||
*
|
||||
* ```
|
||||
* (x) => { return [x, y] }
|
||||
* ```
|
||||
*
|
||||
* This function captures both param `x` and context variable `y` into the return value.
|
||||
* Unlike our previous inference which counted this as a mutation of x and y, we want to
|
||||
* build a signature for the function that describes the data flow. We would infer
|
||||
* `Capture x -> return, Capture y -> return` effects for this function.
|
||||
*
|
||||
* This function *also* propagates more ambient-style effects (MutateFrozen, MutateGlobal, Impure, Render)
|
||||
* from instructions within the function up to the function itself.
|
||||
*/
|
||||
export function inferFunctionExpressionAliasingEffectsSignature(
|
||||
fn: HIRFunction,
|
||||
): Array<AliasingEffect> | null {
|
||||
const effects: Array<AliasingEffect> = [];
|
||||
|
||||
/**
|
||||
* Map used to identify tracked variables: params, context vars, return value
|
||||
* This is used to detect mutation/capturing/aliasing of params/context vars
|
||||
*/
|
||||
const tracked = new Map<IdentifierId, Place>();
|
||||
tracked.set(fn.returns.identifier.id, fn.returns);
|
||||
for (const operand of [...fn.context, ...fn.params]) {
|
||||
const place = operand.kind === 'Identifier' ? operand : operand.place;
|
||||
tracked.set(place.identifier.id, place);
|
||||
}
|
||||
|
||||
/**
|
||||
* Track capturing/aliasing of context vars and params into each other and into the return.
|
||||
* We don't need to track locals and intermediate values, since we're only concerned with effects
|
||||
* as they relate to arguments visible outside the function.
|
||||
*
|
||||
* For each aliased identifier we track capture/alias/createfrom and then merge this with how
|
||||
* the value is used. Eg capturing an alias => capture. See joinEffects() helper.
|
||||
*/
|
||||
type AliasedIdentifier = {
|
||||
kind: AliasingKind;
|
||||
place: Place;
|
||||
};
|
||||
const dataFlow = new Map<IdentifierId, Array<AliasedIdentifier>>();
|
||||
|
||||
/*
|
||||
* Check for aliasing of tracked values. Also joins the effects of how the value is
|
||||
* used (@param kind) with the aliasing type of each value
|
||||
*/
|
||||
function lookup(
|
||||
place: Place,
|
||||
kind: AliasedIdentifier['kind'],
|
||||
): Array<AliasedIdentifier> | null {
|
||||
if (tracked.has(place.identifier.id)) {
|
||||
return [{kind, place}];
|
||||
}
|
||||
return (
|
||||
dataFlow.get(place.identifier.id)?.map(aliased => ({
|
||||
kind: joinEffects(aliased.kind, kind),
|
||||
place: aliased.place,
|
||||
})) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
// todo: fixpoint
|
||||
for (const block of fn.body.blocks.values()) {
|
||||
for (const phi of block.phis) {
|
||||
const operands: Array<AliasedIdentifier> = [];
|
||||
for (const operand of phi.operands.values()) {
|
||||
const inputs = lookup(operand, 'Alias');
|
||||
if (inputs != null) {
|
||||
operands.push(...inputs);
|
||||
}
|
||||
}
|
||||
if (operands.length !== 0) {
|
||||
dataFlow.set(phi.place.identifier.id, operands);
|
||||
}
|
||||
}
|
||||
for (const instr of block.instructions) {
|
||||
if (instr.effects == null) continue;
|
||||
for (const effect of instr.effects) {
|
||||
if (
|
||||
effect.kind === 'Assign' ||
|
||||
effect.kind === 'Capture' ||
|
||||
effect.kind === 'Alias' ||
|
||||
effect.kind === 'CreateFrom'
|
||||
) {
|
||||
const from = lookup(effect.from, effect.kind);
|
||||
if (from == null) {
|
||||
continue;
|
||||
}
|
||||
const into = lookup(effect.into, 'Alias');
|
||||
if (into == null) {
|
||||
getOrInsertDefault(dataFlow, effect.into.identifier.id, []).push(
|
||||
...from,
|
||||
);
|
||||
} else {
|
||||
for (const aliased of into) {
|
||||
getOrInsertDefault(
|
||||
dataFlow,
|
||||
aliased.place.identifier.id,
|
||||
[],
|
||||
).push(...from);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
effect.kind === 'Create' ||
|
||||
effect.kind === 'CreateFunction'
|
||||
) {
|
||||
getOrInsertDefault(dataFlow, effect.into.identifier.id, [
|
||||
{kind: 'Alias', place: effect.into},
|
||||
]);
|
||||
} else if (
|
||||
effect.kind === 'MutateFrozen' ||
|
||||
effect.kind === 'MutateGlobal' ||
|
||||
effect.kind === 'Impure' ||
|
||||
effect.kind === 'Render'
|
||||
) {
|
||||
effects.push(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (block.terminal.kind === 'return') {
|
||||
const from = lookup(block.terminal.value, 'Alias');
|
||||
if (from != null) {
|
||||
getOrInsertDefault(dataFlow, fn.returns.identifier.id, []).push(
|
||||
...from,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create aliasing effects based on observed data flow
|
||||
let hasReturn = false;
|
||||
for (const [into, from] of dataFlow) {
|
||||
const input = tracked.get(into);
|
||||
if (input == null) {
|
||||
continue;
|
||||
}
|
||||
for (const aliased of from) {
|
||||
if (
|
||||
aliased.place.identifier.id === input.identifier.id ||
|
||||
!tracked.has(aliased.place.identifier.id)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const effect = {kind: aliased.kind, from: aliased.place, into: input};
|
||||
effects.push(effect);
|
||||
if (
|
||||
into === fn.returns.identifier.id &&
|
||||
(aliased.kind === 'Assign' || aliased.kind === 'CreateFrom')
|
||||
) {
|
||||
hasReturn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: more precise return effect inference
|
||||
if (!hasReturn) {
|
||||
effects.unshift({
|
||||
kind: 'Create',
|
||||
into: fn.returns,
|
||||
value:
|
||||
fn.returnType.kind === 'Primitive'
|
||||
? ValueKind.Primitive
|
||||
: ValueKind.Mutable,
|
||||
reason: ValueReason.KnownReturnSignature,
|
||||
});
|
||||
}
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
||||
export enum MutationKind {
|
||||
None = 0,
|
||||
Conditional = 1,
|
||||
Definite = 2,
|
||||
}
|
||||
|
||||
type AliasingKind = 'Alias' | 'Capture' | 'CreateFrom' | 'Assign';
|
||||
function joinEffects(
|
||||
effect1: AliasingKind,
|
||||
effect2: AliasingKind,
|
||||
): AliasingKind {
|
||||
if (effect1 === 'Capture' || effect2 === 'Capture') {
|
||||
return 'Capture';
|
||||
} else if (effect1 === 'Assign' || effect2 === 'Assign') {
|
||||
return 'Assign';
|
||||
} else {
|
||||
return 'Alias';
|
||||
}
|
||||
}
|
||||
@@ -822,7 +822,8 @@ function applyEffect(
|
||||
const functionValues = state.values(effect.function);
|
||||
if (
|
||||
functionValues.length === 1 &&
|
||||
functionValues[0].kind === 'FunctionExpression'
|
||||
functionValues[0].kind === 'FunctionExpression' &&
|
||||
functionValues[0].loweredFunc.func.aliasingEffects != null
|
||||
) {
|
||||
/*
|
||||
* We're calling a locally declared function, we already know it's effects!
|
||||
@@ -2126,8 +2127,6 @@ function computeEffectsForLegacySignature(
|
||||
const mutateIterator = conditionallyMutateIterator(place);
|
||||
if (mutateIterator != null) {
|
||||
effects.push(mutateIterator);
|
||||
// TODO: should we always push to captures?
|
||||
captures.push(place);
|
||||
}
|
||||
effects.push({
|
||||
kind: 'Capture',
|
||||
|
||||
@@ -13,8 +13,12 @@ import {
|
||||
Identifier,
|
||||
IdentifierId,
|
||||
InstructionId,
|
||||
isJsxType,
|
||||
makeInstructionId,
|
||||
ValueKind,
|
||||
ValueReason,
|
||||
Place,
|
||||
isPrimitiveType,
|
||||
} from '../HIR/HIR';
|
||||
import {
|
||||
eachInstructionLValue,
|
||||
@@ -22,34 +26,58 @@ import {
|
||||
eachTerminalOperand,
|
||||
} from '../HIR/visitors';
|
||||
import {assertExhaustive, getOrInsertWith} from '../Utils/utils';
|
||||
import {MutationKind} from './InferFunctionExpressionAliasingEffectsSignature';
|
||||
import {Result} from '../Utils/Result';
|
||||
import {Err, Ok, Result} from '../Utils/Result';
|
||||
import {AliasingEffect} from './AliasingEffects';
|
||||
|
||||
/**
|
||||
* Infers mutable ranges for all values in the program, using previously inferred
|
||||
* mutation/aliasing effects. This pass builds a data flow graph using the effects,
|
||||
* tracking an abstract notion of "when" each effect occurs relative to the others.
|
||||
* It then walks each mutation effect against the graph, updating the range of each
|
||||
* node that would be reachable at the "time" that the effect occurred.
|
||||
* This pass builds an abstract model of the heap and interprets the effects of the
|
||||
* given function in order to determine the following:
|
||||
* - The mutable ranges of all identifiers in the function
|
||||
* - The externally-visible effects of the function, such as mutations of params and
|
||||
* context-vars, aliasing between params/context-vars/return-value, and impure side
|
||||
* effects.
|
||||
* - The legacy `Effect` to store on each Place.
|
||||
*
|
||||
* This pass builds a data flow graph using the effects, tracking an abstract notion
|
||||
* of "when" each effect occurs relative to the others. It then walks each mutation
|
||||
* effect against the graph, updating the range of each node that would be reachable
|
||||
* at the "time" that the effect occurred.
|
||||
*
|
||||
* This pass also validates against invalid effects: any function that is reachable
|
||||
* by being called, or via a Render effect, is validated against mutating globals
|
||||
* or calling impure code.
|
||||
*
|
||||
* Note that this function also populates the outer function's aliasing effects with
|
||||
* any mutations that apply to its params or context variables. For example, a
|
||||
* function expression such as the following:
|
||||
* any mutations that apply to its params or context variables.
|
||||
*
|
||||
* ## Example
|
||||
* A function expression such as the following:
|
||||
*
|
||||
* ```
|
||||
* (x) => { x.y = true }
|
||||
* ```
|
||||
*
|
||||
* Would populate a `Mutate x` aliasing effect on the outer function.
|
||||
*
|
||||
* ## Returned Function Effects
|
||||
*
|
||||
* The function returns (if successful) a list of externally-visible effects.
|
||||
* This is determined by simulating a conditional, transitive mutation against
|
||||
* each param, context variable, and return value in turn, and seeing which other
|
||||
* such values are affected. If they're affected, they must be captured, so we
|
||||
* record a Capture.
|
||||
*
|
||||
* The only tricky bit is the return value, which could _alias_ (or even assign)
|
||||
* one or more of the params/context-vars rather than just capturing. So we have
|
||||
* to do a bit more tracking for returns.
|
||||
*/
|
||||
export function inferMutationAliasingRanges(
|
||||
fn: HIRFunction,
|
||||
{isFunctionExpression}: {isFunctionExpression: boolean},
|
||||
): Result<void, CompilerError> {
|
||||
): Result<Array<AliasingEffect>, CompilerError> {
|
||||
// The set of externally-visible effects
|
||||
const functionEffects: Array<AliasingEffect> = [];
|
||||
|
||||
/**
|
||||
* Part 1: Infer mutable ranges for values. We build an abstract model of
|
||||
* values, the alias/capture edges between them, and the set of mutations.
|
||||
@@ -168,8 +196,10 @@ export function inferMutationAliasingRanges(
|
||||
effect.kind === 'Impure'
|
||||
) {
|
||||
errors.push(effect.error);
|
||||
functionEffects.push(effect);
|
||||
} else if (effect.kind === 'Render') {
|
||||
renders.push({index: index++, place: effect.place});
|
||||
functionEffects.push(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,7 +245,6 @@ export function inferMutationAliasingRanges(
|
||||
for (const render of renders) {
|
||||
state.render(render.index, render.place.identifier, errors);
|
||||
}
|
||||
fn.aliasingEffects ??= [];
|
||||
for (const param of [...fn.context, ...fn.params]) {
|
||||
const place = param.kind === 'Identifier' ? param : param.place;
|
||||
const node = state.nodes.get(place.identifier);
|
||||
@@ -226,13 +255,13 @@ export function inferMutationAliasingRanges(
|
||||
if (node.local != null) {
|
||||
if (node.local.kind === MutationKind.Conditional) {
|
||||
mutated = true;
|
||||
fn.aliasingEffects.push({
|
||||
functionEffects.push({
|
||||
kind: 'MutateConditionally',
|
||||
value: {...place, loc: node.local.loc},
|
||||
});
|
||||
} else if (node.local.kind === MutationKind.Definite) {
|
||||
mutated = true;
|
||||
fn.aliasingEffects.push({
|
||||
functionEffects.push({
|
||||
kind: 'Mutate',
|
||||
value: {...place, loc: node.local.loc},
|
||||
});
|
||||
@@ -241,13 +270,13 @@ export function inferMutationAliasingRanges(
|
||||
if (node.transitive != null) {
|
||||
if (node.transitive.kind === MutationKind.Conditional) {
|
||||
mutated = true;
|
||||
fn.aliasingEffects.push({
|
||||
functionEffects.push({
|
||||
kind: 'MutateTransitiveConditionally',
|
||||
value: {...place, loc: node.transitive.loc},
|
||||
});
|
||||
} else if (node.transitive.kind === MutationKind.Definite) {
|
||||
mutated = true;
|
||||
fn.aliasingEffects.push({
|
||||
functionEffects.push({
|
||||
kind: 'MutateTransitive',
|
||||
value: {...place, loc: node.transitive.loc},
|
||||
});
|
||||
@@ -436,7 +465,82 @@ export function inferMutationAliasingRanges(
|
||||
}
|
||||
}
|
||||
|
||||
return errors.asResult();
|
||||
/**
|
||||
* Part 3
|
||||
* Finish populating the externally visible effects. Above we bubble-up the side effects
|
||||
* (MutateFrozen/MutableGlobal/Impure/Render) as well as mutations of context variables.
|
||||
* Here we populate an effect to create the return value as well as populating alias/capture
|
||||
* effects for how data flows between the params, context vars, and return.
|
||||
*/
|
||||
const returns = fn.returns.identifier;
|
||||
functionEffects.push({
|
||||
kind: 'Create',
|
||||
into: fn.returns,
|
||||
value: isPrimitiveType(returns)
|
||||
? ValueKind.Primitive
|
||||
: isJsxType(returns.type)
|
||||
? ValueKind.Frozen
|
||||
: ValueKind.Mutable,
|
||||
reason: ValueReason.KnownReturnSignature,
|
||||
});
|
||||
/**
|
||||
* Determine precise data-flow effects by simulating transitive mutations of the params/
|
||||
* captures and seeing what other params/context variables are affected. Anything that
|
||||
* would be transitively mutated needs a capture relationship.
|
||||
*/
|
||||
const tracked: Array<Place> = [];
|
||||
const ignoredErrors = new CompilerError();
|
||||
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
||||
const place = param.kind === 'Identifier' ? param : param.place;
|
||||
tracked.push(place);
|
||||
}
|
||||
for (const into of tracked) {
|
||||
const mutationIndex = index++;
|
||||
state.mutate(
|
||||
mutationIndex,
|
||||
into.identifier,
|
||||
null,
|
||||
true,
|
||||
MutationKind.Conditional,
|
||||
into.loc,
|
||||
ignoredErrors,
|
||||
);
|
||||
for (const from of tracked) {
|
||||
if (
|
||||
from.identifier.id === into.identifier.id ||
|
||||
from.identifier.id === fn.returns.identifier.id
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const fromNode = state.nodes.get(from.identifier);
|
||||
CompilerError.invariant(fromNode != null, {
|
||||
reason: `Expected a node to exist for all parameters and context variables`,
|
||||
loc: into.loc,
|
||||
});
|
||||
if (fromNode.lastMutated === mutationIndex) {
|
||||
if (into.identifier.id === fn.returns.identifier.id) {
|
||||
// The return value could be any of the params/context variables
|
||||
functionEffects.push({
|
||||
kind: 'Alias',
|
||||
from,
|
||||
into,
|
||||
});
|
||||
} else {
|
||||
// Otherwise params/context-vars can only capture each other
|
||||
functionEffects.push({
|
||||
kind: 'Capture',
|
||||
from,
|
||||
into,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.hasErrors() && !isFunctionExpression) {
|
||||
return Err(errors);
|
||||
}
|
||||
return Ok(functionEffects);
|
||||
}
|
||||
|
||||
function appendFunctionErrors(errors: CompilerError, fn: HIRFunction): void {
|
||||
@@ -452,6 +556,12 @@ function appendFunctionErrors(errors: CompilerError, fn: HIRFunction): void {
|
||||
}
|
||||
}
|
||||
|
||||
export enum MutationKind {
|
||||
None = 0,
|
||||
Conditional = 1,
|
||||
Definite = 2,
|
||||
}
|
||||
|
||||
type Node = {
|
||||
id: Identifier;
|
||||
createdFrom: Map<Identifier, number>;
|
||||
@@ -460,6 +570,7 @@ type Node = {
|
||||
edges: Array<{index: number; node: Identifier; kind: 'capture' | 'alias'}>;
|
||||
transitive: {kind: MutationKind; loc: SourceLocation} | null;
|
||||
local: {kind: MutationKind; loc: SourceLocation} | null;
|
||||
lastMutated: number;
|
||||
value:
|
||||
| {kind: 'Object'}
|
||||
| {kind: 'Phi'}
|
||||
@@ -477,6 +588,7 @@ class AliasingState {
|
||||
edges: [],
|
||||
transitive: null,
|
||||
local: null,
|
||||
lastMutated: 0,
|
||||
value,
|
||||
});
|
||||
}
|
||||
@@ -558,7 +670,8 @@ class AliasingState {
|
||||
mutate(
|
||||
index: number,
|
||||
start: Identifier,
|
||||
end: InstructionId,
|
||||
// Null is used for simulated mutations
|
||||
end: InstructionId | null,
|
||||
transitive: boolean,
|
||||
kind: MutationKind,
|
||||
loc: SourceLocation,
|
||||
@@ -580,9 +693,12 @@ class AliasingState {
|
||||
if (node == null) {
|
||||
continue;
|
||||
}
|
||||
node.id.mutableRange.end = makeInstructionId(
|
||||
Math.max(node.id.mutableRange.end, end),
|
||||
);
|
||||
node.lastMutated = Math.max(node.lastMutated, index);
|
||||
if (end != null) {
|
||||
node.id.mutableRange.end = makeInstructionId(
|
||||
Math.max(node.id.mutableRange.end, end),
|
||||
);
|
||||
}
|
||||
if (
|
||||
node.value.kind === 'Function' &&
|
||||
node.transitive == null &&
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Environment,
|
||||
FunctionExpression,
|
||||
GeneratedSource,
|
||||
GotoTerminal,
|
||||
GotoVariant,
|
||||
HIRFunction,
|
||||
IdentifierId,
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
Place,
|
||||
isStatementBlockKind,
|
||||
makeInstructionId,
|
||||
mergeConsecutiveBlocks,
|
||||
promoteTemporary,
|
||||
reversePostorderBlocks,
|
||||
} from '../HIR';
|
||||
@@ -73,6 +75,10 @@ import {retainWhere} from '../Utils/utils';
|
||||
* - All return statements in the original function expression are replaced with a
|
||||
* StoreLocal to the temporary we allocated before plus a Goto to the fallthrough
|
||||
* block (code following the CallExpression).
|
||||
*
|
||||
* Note that if the inliined function has only one return, we avoid the labeled block
|
||||
* and fully inline the code. The original return is replaced with an assignmen to the
|
||||
* IIFE's call expression lvalue.
|
||||
*/
|
||||
export function inlineImmediatelyInvokedFunctionExpressions(
|
||||
fn: HIRFunction,
|
||||
@@ -146,37 +152,75 @@ export function inlineImmediatelyInvokedFunctionExpressions(
|
||||
*/
|
||||
block.instructions.length = ii;
|
||||
|
||||
/*
|
||||
* To account for complex control flow within the lambda, we treat the lambda
|
||||
* as if it were a single labeled statement, and replace all returns with gotos
|
||||
* to the label fallthrough.
|
||||
*/
|
||||
const newTerminal: LabelTerminal = {
|
||||
block: body.loweredFunc.func.body.entry,
|
||||
id: makeInstructionId(0),
|
||||
kind: 'label',
|
||||
fallthrough: continuationBlockId,
|
||||
loc: block.terminal.loc,
|
||||
};
|
||||
block.terminal = newTerminal;
|
||||
if (hasSingleExitReturnTerminal(body.loweredFunc.func)) {
|
||||
block.terminal = {
|
||||
kind: 'goto',
|
||||
block: body.loweredFunc.func.body.entry,
|
||||
id: block.terminal.id,
|
||||
loc: block.terminal.loc,
|
||||
variant: GotoVariant.Break,
|
||||
} as GotoTerminal;
|
||||
for (const block of body.loweredFunc.func.body.blocks.values()) {
|
||||
if (block.terminal.kind === 'return') {
|
||||
block.instructions.push({
|
||||
id: makeInstructionId(0),
|
||||
loc: block.terminal.loc,
|
||||
lvalue: instr.lvalue,
|
||||
value: {
|
||||
kind: 'LoadLocal',
|
||||
loc: block.terminal.loc,
|
||||
place: block.terminal.value,
|
||||
},
|
||||
effects: null,
|
||||
});
|
||||
block.terminal = {
|
||||
kind: 'goto',
|
||||
block: continuationBlockId,
|
||||
id: block.terminal.id,
|
||||
loc: block.terminal.loc,
|
||||
variant: GotoVariant.Break,
|
||||
} as GotoTerminal;
|
||||
}
|
||||
}
|
||||
for (const [id, block] of body.loweredFunc.func.body.blocks) {
|
||||
block.preds.clear();
|
||||
fn.body.blocks.set(id, block);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* To account for multiple returns within the lambda, we treat the lambda
|
||||
* as if it were a single labeled statement, and replace all returns with gotos
|
||||
* to the label fallthrough.
|
||||
*/
|
||||
const newTerminal: LabelTerminal = {
|
||||
block: body.loweredFunc.func.body.entry,
|
||||
id: makeInstructionId(0),
|
||||
kind: 'label',
|
||||
fallthrough: continuationBlockId,
|
||||
loc: block.terminal.loc,
|
||||
};
|
||||
block.terminal = newTerminal;
|
||||
|
||||
// We store the result in the IIFE temporary
|
||||
const result = instr.lvalue;
|
||||
// We store the result in the IIFE temporary
|
||||
const result = instr.lvalue;
|
||||
|
||||
// Declare the IIFE temporary
|
||||
declareTemporary(fn.env, block, result);
|
||||
// Declare the IIFE temporary
|
||||
declareTemporary(fn.env, block, result);
|
||||
|
||||
// Promote the temporary with a name as we require this to persist
|
||||
promoteTemporary(result.identifier);
|
||||
// Promote the temporary with a name as we require this to persist
|
||||
if (result.identifier.name == null) {
|
||||
promoteTemporary(result.identifier);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrite blocks from the lambda to replace any `return` with a
|
||||
* store to the result and `goto` the continuation block
|
||||
*/
|
||||
for (const [id, block] of body.loweredFunc.func.body.blocks) {
|
||||
block.preds.clear();
|
||||
rewriteBlock(fn.env, block, continuationBlockId, result);
|
||||
fn.body.blocks.set(id, block);
|
||||
/*
|
||||
* Rewrite blocks from the lambda to replace any `return` with a
|
||||
* store to the result and `goto` the continuation block
|
||||
*/
|
||||
for (const [id, block] of body.loweredFunc.func.body.blocks) {
|
||||
block.preds.clear();
|
||||
rewriteBlock(fn.env, block, continuationBlockId, result);
|
||||
fn.body.blocks.set(id, block);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -199,7 +243,7 @@ export function inlineImmediatelyInvokedFunctionExpressions(
|
||||
|
||||
if (inlinedFunctions.size !== 0) {
|
||||
// Remove instructions that define lambdas which we inlined
|
||||
for (const [, block] of fn.body.blocks) {
|
||||
for (const block of fn.body.blocks.values()) {
|
||||
retainWhere(
|
||||
block.instructions,
|
||||
instr => !inlinedFunctions.has(instr.lvalue.identifier.id),
|
||||
@@ -213,9 +257,25 @@ export function inlineImmediatelyInvokedFunctionExpressions(
|
||||
reversePostorderBlocks(fn.body);
|
||||
markInstructionIds(fn.body);
|
||||
markPredecessors(fn.body);
|
||||
mergeConsecutiveBlocks(fn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the function has a single exit terminal (throw/return) which is a return
|
||||
*/
|
||||
function hasSingleExitReturnTerminal(fn: HIRFunction): boolean {
|
||||
let hasReturn = false;
|
||||
let exitCount = 0;
|
||||
for (const [, block] of fn.body.blocks) {
|
||||
if (block.terminal.kind === 'return' || block.terminal.kind === 'throw') {
|
||||
hasReturn ||= block.terminal.kind === 'return';
|
||||
exitCount++;
|
||||
}
|
||||
}
|
||||
return exitCount === 1 && hasReturn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrites the block so that all `return` terminals are replaced:
|
||||
* * Add a StoreLocal <returnValue> = <terminal.value>
|
||||
|
||||
@@ -514,9 +514,9 @@ Intuition: these effects are inverses of each other (capturing into an object, e
|
||||
Capture then CreatFrom is equivalent to Alias: we have to assume that the result _is_ the original value and that a local mutation of the result could mutate the original.
|
||||
|
||||
```js
|
||||
const y = [x]; // capture
|
||||
const z = y[0]; // createfrom
|
||||
mutate(z); // this clearly can mutate x, so the result must be one of Assign/Alias/CreateFrom
|
||||
const b = [a]; // capture
|
||||
const c = b[0]; // createfrom
|
||||
mutate(c); // this clearly can mutate a, so the result must be one of Assign/Alias/CreateFrom
|
||||
```
|
||||
|
||||
We use Alias as the return type because the mutability kind of the result is not derived from the source value (there's a fresh object in between due to the capture), so the full set of effects in practice would be a Create+Alias.
|
||||
@@ -528,17 +528,17 @@ CreateFrom c <- b
|
||||
Alias c <- a
|
||||
```
|
||||
|
||||
Meanwhile the opposite direction preservers the capture, because the result is not the same as the source:
|
||||
Meanwhile the opposite direction preserves the capture, because the result is not the same as the source:
|
||||
|
||||
```js
|
||||
const y = x[0]; // createfrom
|
||||
const z = [y]; // capture
|
||||
mutate(z); // does not mutate x, so the result must be Capture
|
||||
const b = a[0]; // createfrom
|
||||
const c = [b]; // capture
|
||||
mutate(c); // does not mutate a, so the result must be Capture
|
||||
```
|
||||
|
||||
```
|
||||
Capture b <- a
|
||||
CreateFrom c <- b
|
||||
CreateFrom b <- a
|
||||
Capture c <- b
|
||||
=>
|
||||
Capture b <- a
|
||||
Capture c <- a
|
||||
```
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
makeBlockId,
|
||||
makeInstructionId,
|
||||
makePropertyLiteral,
|
||||
makeType,
|
||||
markInstructionIds,
|
||||
promoteTemporary,
|
||||
reversePostorderBlocks,
|
||||
@@ -253,7 +252,6 @@ function emitSelectorFn(env: Environment, keys: Array<string>): Instruction {
|
||||
env,
|
||||
params: [obj],
|
||||
returnTypeAnnotation: null,
|
||||
returnType: makeType(),
|
||||
returns: createTemporaryPlace(env, GeneratedSource),
|
||||
context: [],
|
||||
effects: null,
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
makeBlockId,
|
||||
makeIdentifierName,
|
||||
makeInstructionId,
|
||||
makeType,
|
||||
ObjectProperty,
|
||||
Place,
|
||||
promoteTemporary,
|
||||
@@ -368,7 +367,6 @@ function emitOutlinedFn(
|
||||
env,
|
||||
params: [propsObj],
|
||||
returnTypeAnnotation: null,
|
||||
returnType: makeType(),
|
||||
returns: createTemporaryPlace(env, GeneratedSource),
|
||||
context: [],
|
||||
effects: null,
|
||||
|
||||
@@ -349,11 +349,9 @@ function codegenReactiveFunction(
|
||||
fn: ReactiveFunction,
|
||||
): Result<CodegenFunction, CompilerError> {
|
||||
for (const param of fn.params) {
|
||||
if (param.kind === 'Identifier') {
|
||||
cx.temp.set(param.identifier.declarationId, null);
|
||||
} else {
|
||||
cx.temp.set(param.place.identifier.declarationId, null);
|
||||
}
|
||||
const place = param.kind === 'Identifier' ? param : param.place;
|
||||
cx.temp.set(place.identifier.declarationId, null);
|
||||
cx.declare(place.identifier);
|
||||
}
|
||||
|
||||
const params = fn.params.map(param => convertParameter(param));
|
||||
@@ -1183,7 +1181,7 @@ function codegenTerminal(
|
||||
? codegenPlaceToExpression(cx, case_.test)
|
||||
: null;
|
||||
const block = codegenBlock(cx, case_.block!);
|
||||
return t.switchCase(test, [block]);
|
||||
return t.switchCase(test, block.body.length === 0 ? [] : [block]);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,10 @@ export function extractScopeDeclarationsFromDestructuring(
|
||||
fn: ReactiveFunction,
|
||||
): void {
|
||||
const state = new State(fn.env);
|
||||
for (const param of fn.params) {
|
||||
const place = param.kind === 'Identifier' ? param : param.place;
|
||||
state.declared.add(place.identifier.declarationId);
|
||||
}
|
||||
visitReactiveFunction(fn, new Visitor(), state);
|
||||
}
|
||||
|
||||
|
||||
@@ -829,12 +829,14 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
|
||||
};
|
||||
}
|
||||
case 'UnsupportedNode': {
|
||||
CompilerError.invariant(false, {
|
||||
reason: `Unexpected unsupported node`,
|
||||
description: null,
|
||||
loc: value.loc,
|
||||
suggestions: null,
|
||||
});
|
||||
const lvalues = [];
|
||||
if (lvalue !== null) {
|
||||
lvalues.push({place: lvalue, level: MemoizationLevel.Never});
|
||||
}
|
||||
return {
|
||||
lvalues,
|
||||
rvalues: [],
|
||||
};
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(
|
||||
@@ -1064,12 +1066,29 @@ class PruneScopesTransform extends ReactiveFunctionTransform<
|
||||
|
||||
const value = instruction.value;
|
||||
if (value.kind === 'StoreLocal' && value.lvalue.kind === 'Reassign') {
|
||||
// Complex cases of useMemo inlining result in a temporary that is reassigned
|
||||
const ids = getOrInsertDefault(
|
||||
this.reassignments,
|
||||
value.lvalue.place.identifier.declarationId,
|
||||
new Set(),
|
||||
);
|
||||
ids.add(value.value.identifier);
|
||||
} else if (
|
||||
value.kind === 'LoadLocal' &&
|
||||
value.place.identifier.scope != null &&
|
||||
instruction.lvalue != null &&
|
||||
instruction.lvalue.identifier.scope == null
|
||||
) {
|
||||
/*
|
||||
* Simpler cases result in a direct assignment to the original lvalue, with a
|
||||
* LoadLocal
|
||||
*/
|
||||
const ids = getOrInsertDefault(
|
||||
this.reassignments,
|
||||
instruction.lvalue.identifier.declarationId,
|
||||
new Set(),
|
||||
);
|
||||
ids.add(value.place.identifier);
|
||||
} else if (value.kind === 'FinishMemoize') {
|
||||
let decls;
|
||||
if (value.decl.identifier.scope == null) {
|
||||
|
||||
@@ -90,7 +90,8 @@ function apply(func: HIRFunction, unifier: Unifier): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
func.returnType = unifier.get(func.returnType);
|
||||
const returns = func.returns.identifier;
|
||||
returns.type = unifier.get(returns.type);
|
||||
}
|
||||
|
||||
type TypeEquation = {
|
||||
@@ -143,12 +144,12 @@ function* generate(
|
||||
}
|
||||
}
|
||||
if (returnTypes.length > 1) {
|
||||
yield equation(func.returnType, {
|
||||
yield equation(func.returns.identifier.type, {
|
||||
kind: 'Phi',
|
||||
operands: returnTypes,
|
||||
});
|
||||
} else if (returnTypes.length === 1) {
|
||||
yield equation(func.returnType, returnTypes[0]!);
|
||||
yield equation(func.returns.identifier.type, returnTypes[0]!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +408,7 @@ function* generateInstructionTypes(
|
||||
yield equation(left, {
|
||||
kind: 'Function',
|
||||
shapeId: BuiltInFunctionId,
|
||||
return: value.loweredFunc.func.returnType,
|
||||
return: value.loweredFunc.func.returns.identifier.type,
|
||||
isConstructor: false,
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -445,11 +445,13 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
||||
*/
|
||||
this.recordTemporaries(instruction, state);
|
||||
const value = instruction.value;
|
||||
// Track reassignments from inlining of manual memo
|
||||
if (
|
||||
value.kind === 'StoreLocal' &&
|
||||
value.lvalue.kind === 'Reassign' &&
|
||||
state.manualMemoState != null
|
||||
) {
|
||||
// Complex cases of inlining end up with a temporary that is reassigned
|
||||
const ids = getOrInsertDefault(
|
||||
state.manualMemoState.reassignments,
|
||||
value.lvalue.place.identifier.declarationId,
|
||||
@@ -457,6 +459,21 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
||||
);
|
||||
ids.add(value.value.identifier);
|
||||
}
|
||||
if (
|
||||
value.kind === 'LoadLocal' &&
|
||||
value.place.identifier.scope != null &&
|
||||
instruction.lvalue != null &&
|
||||
instruction.lvalue.identifier.scope == null &&
|
||||
state.manualMemoState != null
|
||||
) {
|
||||
// Simpler cases of inlining assign to the original IIFE lvalue
|
||||
const ids = getOrInsertDefault(
|
||||
state.manualMemoState.reassignments,
|
||||
instruction.lvalue.identifier.declarationId,
|
||||
new Set(),
|
||||
);
|
||||
ids.add(value.place.identifier);
|
||||
}
|
||||
if (value.kind === 'StartMemoize') {
|
||||
let depsFromSource: Array<ManualMemoDependency> | null = null;
|
||||
if (value.deps != null) {
|
||||
|
||||
@@ -26,20 +26,16 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { getNull } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(3);
|
||||
let t0;
|
||||
const $ = _c(2);
|
||||
let items;
|
||||
if ($[0] !== props.a) {
|
||||
t0 = getNull() ?? [];
|
||||
items = t0;
|
||||
items = getNull() ?? [];
|
||||
|
||||
items.push(props.a);
|
||||
$[0] = props.a;
|
||||
$[1] = items;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
items = $[1];
|
||||
t0 = $[2];
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -52,15 +52,13 @@ function Component(t0) {
|
||||
}
|
||||
const onClick = t1;
|
||||
let t2;
|
||||
let t3;
|
||||
if ($[2] !== onClick) {
|
||||
t3 = <div onClick={onClick}>{someGlobal.value}</div>;
|
||||
t2 = <div onClick={onClick}>{someGlobal.value}</div>;
|
||||
$[2] = onClick;
|
||||
$[3] = t3;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
t2 = $[3];
|
||||
}
|
||||
t2 = t3;
|
||||
return t2;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,50 +30,46 @@ function Component(props) {
|
||||
const $ = _c(4);
|
||||
const [x] = useState(0);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== x) {
|
||||
t1 = calculateExpensiveNumber(x);
|
||||
t0 = calculateExpensiveNumber(x);
|
||||
$[0] = x;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const expensiveNumber = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] !== expensiveNumber) {
|
||||
t2 = <div>{expensiveNumber}</div>;
|
||||
t1 = <div>{expensiveNumber}</div>;
|
||||
$[2] = expensiveNumber;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Component2(props) {
|
||||
const $ = _c(4);
|
||||
const [x] = useState(0);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== x) {
|
||||
t1 = calculateExpensiveNumber(x);
|
||||
t0 = calculateExpensiveNumber(x);
|
||||
$[0] = x;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const expensiveNumber = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] !== expensiveNumber) {
|
||||
t2 = <div>{expensiveNumber}</div>;
|
||||
t1 = <div>{expensiveNumber}</div>;
|
||||
$[2] = expensiveNumber;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -32,50 +32,46 @@ function Component(props) {
|
||||
const $ = _c(4);
|
||||
const [x] = useState(0);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== x) {
|
||||
t1 = calculateExpensiveNumber(x);
|
||||
t0 = calculateExpensiveNumber(x);
|
||||
$[0] = x;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const expensiveNumber = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] !== expensiveNumber) {
|
||||
t2 = <div>{expensiveNumber}</div>;
|
||||
t1 = <div>{expensiveNumber}</div>;
|
||||
$[2] = expensiveNumber;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Component2(props) {
|
||||
const $ = _c(4);
|
||||
const [x] = useState(0);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== x) {
|
||||
t1 = calculateExpensiveNumber(x);
|
||||
t0 = calculateExpensiveNumber(x);
|
||||
$[0] = x;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const expensiveNumber = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] !== expensiveNumber) {
|
||||
t2 = <div>{expensiveNumber}</div>;
|
||||
t1 = <div>{expensiveNumber}</div>;
|
||||
$[2] = expensiveNumber;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -30,25 +30,23 @@ function Component(props) {
|
||||
const $ = _c(4);
|
||||
const [x] = React.useState(0);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== x) {
|
||||
t1 = calculateExpensiveNumber(x);
|
||||
t0 = calculateExpensiveNumber(x);
|
||||
$[0] = x;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const expensiveNumber = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] !== expensiveNumber) {
|
||||
t2 = <div>{expensiveNumber}</div>;
|
||||
t1 = <div>{expensiveNumber}</div>;
|
||||
$[2] = expensiveNumber;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -36,30 +36,28 @@ function Component(props) {
|
||||
const $ = _c(4);
|
||||
const [x] = React.useState(0);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== x) {
|
||||
t1 = calculateExpensiveNumber(x);
|
||||
t0 = calculateExpensiveNumber(x);
|
||||
$[0] = x;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const expensiveNumber = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] !== expensiveNumber) {
|
||||
t2 = (
|
||||
t1 = (
|
||||
<div>
|
||||
{expensiveNumber}
|
||||
{`${someImport}`}
|
||||
</div>
|
||||
);
|
||||
$[2] = expensiveNumber;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -36,26 +36,22 @@ import { useMemo } from "react";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== props.value) {
|
||||
t1 = { value: props.value };
|
||||
t0 = { value: props.value };
|
||||
$[0] = props.value;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
const handlers = t1;
|
||||
const handlers = t0;
|
||||
bb0: switch (props.test) {
|
||||
case true: {
|
||||
console.log(handlers.value);
|
||||
break bb0;
|
||||
}
|
||||
default: {
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
t0 = handlers;
|
||||
const outerHandlers = t0;
|
||||
const outerHandlers = handlers;
|
||||
return outerHandlers;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,9 @@ function useTest() {
|
||||
|
||||
const t1 = (w = 42);
|
||||
const t2 = w;
|
||||
let t3;
|
||||
|
||||
w = 999;
|
||||
t3 = 2;
|
||||
t0 = makeArray(t1, t2, t3);
|
||||
t0 = makeArray(t1, t2, 2);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
|
||||
@@ -37,11 +37,9 @@ function useTest() {
|
||||
|
||||
const t1 = (w.x = 42);
|
||||
const t2 = w.x;
|
||||
let t3;
|
||||
|
||||
w.x = 999;
|
||||
t3 = 2;
|
||||
t0 = makeArray(t1, t2, t3);
|
||||
t0 = makeArray(t1, t2, 2);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
|
||||
@@ -32,11 +32,9 @@ function useTest() {
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const t1 = print(1);
|
||||
let t2;
|
||||
|
||||
print(2);
|
||||
t2 = 2;
|
||||
t0 = makeArray(t1, t2);
|
||||
t0 = makeArray(t1, 2);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
|
||||
@@ -29,37 +29,33 @@ function useHook(t0) {
|
||||
const $ = _c(7);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== a) {
|
||||
t2 = identity({ a });
|
||||
t1 = identity({ a });
|
||||
$[0] = a;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const valA = t1;
|
||||
let t3;
|
||||
let t4;
|
||||
let t2;
|
||||
if ($[2] !== b) {
|
||||
t4 = identity([b]);
|
||||
t2 = identity([b]);
|
||||
$[2] = b;
|
||||
$[3] = t4;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t4 = $[3];
|
||||
t2 = $[3];
|
||||
}
|
||||
t3 = t4;
|
||||
const valB = t3;
|
||||
let t5;
|
||||
const valB = t2;
|
||||
let t3;
|
||||
if ($[4] !== valA || $[5] !== valB) {
|
||||
t5 = [valA, valB];
|
||||
t3 = [valA, valB];
|
||||
$[4] = valA;
|
||||
$[5] = valB;
|
||||
$[6] = t5;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t5 = $[6];
|
||||
t3 = $[6];
|
||||
}
|
||||
return t5;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -34,10 +34,8 @@ function Component(props) {
|
||||
let Component;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
Component = Stringify;
|
||||
let t0;
|
||||
|
||||
t0 = Component;
|
||||
Component = t0;
|
||||
Component = Component;
|
||||
$[0] = Component;
|
||||
} else {
|
||||
Component = $[0];
|
||||
|
||||
@@ -28,20 +28,18 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function Foo() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = function a(t2) {
|
||||
const x_0 = t2 === undefined ? _temp : t2;
|
||||
return (function b(t3) {
|
||||
const y_0 = t3 === undefined ? [] : t3;
|
||||
t0 = function a(t1) {
|
||||
const x_0 = t1 === undefined ? _temp : t1;
|
||||
return (function b(t2) {
|
||||
const y_0 = t2 === undefined ? [] : t2;
|
||||
return [x_0, y_0];
|
||||
})();
|
||||
};
|
||||
$[0] = t1;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
t0 = $[0];
|
||||
}
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
function _temp() {}
|
||||
|
||||
@@ -67,8 +67,7 @@ function Component(props) {
|
||||
case "b": {
|
||||
break bb1;
|
||||
}
|
||||
case "c": {
|
||||
}
|
||||
case "c":
|
||||
default: {
|
||||
x = 6;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import * as React from "react";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
let x;
|
||||
if ($[0] !== props.value) {
|
||||
x = [];
|
||||
@@ -38,8 +37,7 @@ function Component(props) {
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
t0 = x;
|
||||
const x_0 = t0;
|
||||
const x_0 = x;
|
||||
return x_0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
eval('props.x = true');
|
||||
return <div />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
1 | function Component(props) {
|
||||
> 2 | eval('props.x = true');
|
||||
| ^^^^ InvalidJS: The 'eval' function is not supported. Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler (2:2)
|
||||
3 | return <div />;
|
||||
4 | }
|
||||
5 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
function Component(props) {
|
||||
eval('props.x = true');
|
||||
return <div />;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ let moduleLocal = false;
|
||||
> 3 | var x = [];
|
||||
| ^^^^^^^^^^^ Todo: (BuildHIR::lowerStatement) Handle var kinds in VariableDeclaration (3:3)
|
||||
|
||||
Todo: (BuildHIR::lowerStatement) Handle ClassDeclaration statements (5:10)
|
||||
Todo: Support nested class declarations (5:10)
|
||||
|
||||
Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (20:22)
|
||||
|
||||
|
||||
@@ -42,34 +42,32 @@ function Component(props) {
|
||||
const c1 = __c;
|
||||
const $c = c1;
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== $c) {
|
||||
t1 = [$c];
|
||||
t0 = [$c];
|
||||
$[0] = $c;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const array = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] !== state) {
|
||||
t2 = [state];
|
||||
t1 = [state];
|
||||
$[2] = state;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
let t3;
|
||||
if ($[4] !== array || $[5] !== t2) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={array} />;
|
||||
let t2;
|
||||
if ($[4] !== array || $[5] !== t1) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={array} />;
|
||||
$[4] = array;
|
||||
$[5] = t2;
|
||||
$[6] = t3;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
t2 = $[6];
|
||||
}
|
||||
return t3;
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -63,23 +63,21 @@ function Component() {
|
||||
|
||||
unsafeUpdateConst();
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [{ pretendConst }];
|
||||
$[0] = t1;
|
||||
t0 = [{ pretendConst }];
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
t0 = $[0];
|
||||
}
|
||||
t0 = t1;
|
||||
const value = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = <ValidateMemoization inputs={[]} output={value} />;
|
||||
$[1] = t2;
|
||||
t1 = <ValidateMemoization inputs={[]} output={value} />;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
function _temp() {
|
||||
unsafeResetConst();
|
||||
|
||||
@@ -74,23 +74,21 @@ function Component() {
|
||||
|
||||
unsafeUpdateConst();
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [{ pretendConst }];
|
||||
$[1] = t1;
|
||||
t0 = [{ pretendConst }];
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
const value = t0;
|
||||
let t2;
|
||||
let t1;
|
||||
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = <ValidateMemoization inputs={[pretendConst]} output={value} />;
|
||||
$[2] = t2;
|
||||
t1 = <ValidateMemoization inputs={[pretendConst]} output={value} />;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
t1 = $[2];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
function _temp() {
|
||||
unsafeResetConst();
|
||||
|
||||
@@ -38,36 +38,34 @@ function Component(props) {
|
||||
$[0] = "20945b0193e529df490847c66111b38d7b02485d5b53d0829ff3b23af87b105c";
|
||||
}
|
||||
const [state] = useState(0);
|
||||
let t0;
|
||||
const t1 = state * 2;
|
||||
const t0 = state * 2;
|
||||
let t1;
|
||||
if ($[1] !== t0) {
|
||||
t1 = [t0];
|
||||
$[1] = t0;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
const doubled = t1;
|
||||
let t2;
|
||||
if ($[1] !== t1) {
|
||||
t2 = [t1];
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
t0 = t2;
|
||||
const doubled = t0;
|
||||
let t3;
|
||||
if ($[3] !== state) {
|
||||
t3 = [state];
|
||||
t2 = [state];
|
||||
$[3] = state;
|
||||
$[4] = t3;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
t2 = $[4];
|
||||
}
|
||||
let t4;
|
||||
if ($[5] !== doubled || $[6] !== t3) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={doubled} />;
|
||||
let t3;
|
||||
if ($[5] !== doubled || $[6] !== t2) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={doubled} />;
|
||||
$[5] = doubled;
|
||||
$[6] = t3;
|
||||
$[7] = t4;
|
||||
$[6] = t2;
|
||||
$[7] = t3;
|
||||
} else {
|
||||
t4 = $[7];
|
||||
t3 = $[7];
|
||||
}
|
||||
return t4;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -40,36 +40,34 @@ function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { data } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== data.name) {
|
||||
t2 = fbt._("{name}", [fbt._param("name", data.name ?? "")], {
|
||||
t1 = fbt._("{name}", [fbt._param("name", data.name ?? "")], {
|
||||
hk: "csQUH",
|
||||
});
|
||||
$[0] = data.name;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const el = t1;
|
||||
let t3;
|
||||
let t2;
|
||||
if ($[2] !== data.name) {
|
||||
t3 = [data.name];
|
||||
t2 = [data.name];
|
||||
$[2] = data.name;
|
||||
$[3] = t3;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
t2 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[4] !== el || $[5] !== t3) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={el} />;
|
||||
let t3;
|
||||
if ($[4] !== el || $[5] !== t2) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={el} />;
|
||||
$[4] = el;
|
||||
$[5] = t3;
|
||||
$[6] = t4;
|
||||
$[5] = t2;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
t3 = $[6];
|
||||
}
|
||||
return t4;
|
||||
return t3;
|
||||
}
|
||||
|
||||
const props1 = { data: { name: "Mike" } };
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow
|
||||
function Component(props) {
|
||||
enum Bool {
|
||||
True = 'true',
|
||||
False = 'false',
|
||||
}
|
||||
|
||||
let bool: Bool = Bool.False;
|
||||
if (props.value) {
|
||||
bool = Bool.True;
|
||||
}
|
||||
return <div>{bool}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: true}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
enum Bool {
|
||||
True = "true",
|
||||
False = "false",
|
||||
}
|
||||
|
||||
let bool = Bool.False;
|
||||
if (props.value) {
|
||||
bool = Bool.True;
|
||||
}
|
||||
let t0;
|
||||
if ($[0] !== bool) {
|
||||
t0 = <div>{bool}</div>;
|
||||
$[0] = bool;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ value: true }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Bool is not defined
|
||||
@@ -0,0 +1,18 @@
|
||||
// @flow
|
||||
function Component(props) {
|
||||
enum Bool {
|
||||
True = 'true',
|
||||
False = 'false',
|
||||
}
|
||||
|
||||
let bool: Bool = Bool.False;
|
||||
if (props.value) {
|
||||
bool = Bool.True;
|
||||
}
|
||||
return <div>{bool}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: true}],
|
||||
};
|
||||
@@ -47,17 +47,14 @@ function Component(t0) {
|
||||
const $ = _c(19);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== a) {
|
||||
t2 = [a];
|
||||
t1 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const x = t1;
|
||||
let t3;
|
||||
let items;
|
||||
if ($[2] !== b || $[3] !== x) {
|
||||
items = [b];
|
||||
@@ -70,59 +67,57 @@ function Component(t0) {
|
||||
} else {
|
||||
items = $[4];
|
||||
}
|
||||
|
||||
t3 = items;
|
||||
const y = t3;
|
||||
let t4;
|
||||
const y = items;
|
||||
let t2;
|
||||
if ($[5] !== a) {
|
||||
t4 = [a];
|
||||
t2 = [a];
|
||||
$[5] = a;
|
||||
$[6] = t4;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
t2 = $[6];
|
||||
}
|
||||
let t5;
|
||||
if ($[7] !== t4 || $[8] !== x) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={x} />;
|
||||
$[7] = t4;
|
||||
let t3;
|
||||
if ($[7] !== t2 || $[8] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[7] = t2;
|
||||
$[8] = x;
|
||||
$[9] = t5;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t5 = $[9];
|
||||
t3 = $[9];
|
||||
}
|
||||
let t6;
|
||||
let t4;
|
||||
if ($[10] !== b || $[11] !== x) {
|
||||
t6 = [x, b];
|
||||
t4 = [x, b];
|
||||
$[10] = b;
|
||||
$[11] = x;
|
||||
$[12] = t6;
|
||||
$[12] = t4;
|
||||
} else {
|
||||
t6 = $[12];
|
||||
t4 = $[12];
|
||||
}
|
||||
let t7;
|
||||
if ($[13] !== t6 || $[14] !== y) {
|
||||
t7 = <ValidateMemoization inputs={t6} output={y} />;
|
||||
$[13] = t6;
|
||||
let t5;
|
||||
if ($[13] !== t4 || $[14] !== y) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={y} />;
|
||||
$[13] = t4;
|
||||
$[14] = y;
|
||||
$[15] = t7;
|
||||
$[15] = t5;
|
||||
} else {
|
||||
t7 = $[15];
|
||||
t5 = $[15];
|
||||
}
|
||||
let t8;
|
||||
if ($[16] !== t5 || $[17] !== t7) {
|
||||
t8 = (
|
||||
let t6;
|
||||
if ($[16] !== t3 || $[17] !== t5) {
|
||||
t6 = (
|
||||
<>
|
||||
{t3}
|
||||
{t5}
|
||||
{t7}
|
||||
</>
|
||||
);
|
||||
$[16] = t5;
|
||||
$[17] = t7;
|
||||
$[18] = t8;
|
||||
$[16] = t3;
|
||||
$[17] = t5;
|
||||
$[18] = t6;
|
||||
} else {
|
||||
t8 = $[18];
|
||||
t6 = $[18];
|
||||
}
|
||||
return t8;
|
||||
return t6;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -34,7 +34,6 @@ import { ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
let a;
|
||||
if ($[0] !== props.name) {
|
||||
a = [];
|
||||
@@ -48,26 +47,25 @@ function Component(props) {
|
||||
} else {
|
||||
a = $[1];
|
||||
}
|
||||
t0 = a;
|
||||
const a_0 = t0;
|
||||
let t1;
|
||||
const a_0 = a;
|
||||
let t0;
|
||||
if ($[2] !== props.name) {
|
||||
t1 = [props.name];
|
||||
t0 = [props.name];
|
||||
$[2] = props.name;
|
||||
$[3] = t1;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
t0 = $[3];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== a_0 || $[5] !== t1) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={a_0} />;
|
||||
let t1;
|
||||
if ($[4] !== a_0 || $[5] !== t0) {
|
||||
t1 = <ValidateMemoization inputs={t0} output={a_0} />;
|
||||
$[4] = a_0;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
$[5] = t0;
|
||||
$[6] = t1;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t1 = $[6];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -46,7 +46,7 @@ const React$useMemo = React.useMemo;
|
||||
const Internal$Reassigned$useHook = useHook;
|
||||
|
||||
function Component() {
|
||||
const $ = _c(8);
|
||||
const $ = _c(7);
|
||||
const [state] = React$useState(0);
|
||||
const object = Internal$Reassigned$useHook();
|
||||
let t0;
|
||||
@@ -59,34 +59,30 @@ function Component() {
|
||||
}
|
||||
const json = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[2] !== state) {
|
||||
t1 = makeArray(state);
|
||||
const doubledArray = t1;
|
||||
const doubledArray = makeArray(state);
|
||||
|
||||
t2 = doubledArray.join("");
|
||||
t1 = doubledArray.join("");
|
||||
$[2] = state;
|
||||
$[3] = t2;
|
||||
$[4] = t1;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[4];
|
||||
t1 = $[3];
|
||||
}
|
||||
let t3;
|
||||
if ($[5] !== json || $[6] !== t2) {
|
||||
t3 = (
|
||||
let t2;
|
||||
if ($[4] !== json || $[5] !== t1) {
|
||||
t2 = (
|
||||
<div>
|
||||
{t2}
|
||||
{t1}
|
||||
{json}
|
||||
</div>
|
||||
);
|
||||
$[5] = json;
|
||||
$[4] = json;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
$[7] = t3;
|
||||
} else {
|
||||
t3 = $[7];
|
||||
t2 = $[6];
|
||||
}
|
||||
return t3;
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -22,20 +22,16 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(3);
|
||||
let t0;
|
||||
const $ = _c(2);
|
||||
let items;
|
||||
if ($[0] !== props.a) {
|
||||
t0 = [];
|
||||
items = t0;
|
||||
items = [];
|
||||
|
||||
items.push(props.a);
|
||||
$[0] = props.a;
|
||||
$[1] = items;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
items = $[1];
|
||||
t0 = $[2];
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -50,19 +50,17 @@ function useMakeCallback(t0) {
|
||||
|
||||
const [, setState] = useState(0);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== obj.value) {
|
||||
t2 = () => {
|
||||
t1 = () => {
|
||||
if (obj.value !== 0) {
|
||||
setState(obj.value);
|
||||
}
|
||||
};
|
||||
$[0] = obj.value;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const cb = t1;
|
||||
|
||||
useIdentity(null);
|
||||
|
||||
@@ -26,17 +26,15 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function Foo() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = function a(t2) {
|
||||
const x_0 = t2 === undefined ? _temp : t2;
|
||||
t0 = function a(t1) {
|
||||
const x_0 = t1 === undefined ? _temp : t1;
|
||||
return x_0;
|
||||
};
|
||||
$[0] = t1;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
t0 = $[0];
|
||||
}
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
function _temp() {}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {Stringify, mutate} from 'shared-runtime';
|
||||
|
||||
function Component({foo, bar}) {
|
||||
let x = {foo};
|
||||
let y = {bar};
|
||||
const f0 = function () {
|
||||
let a = {y};
|
||||
let b = {x};
|
||||
a.y.x = b;
|
||||
};
|
||||
f0();
|
||||
mutate(y);
|
||||
return <Stringify x={y} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{foo: 2, bar: 3}],
|
||||
sequentialRenders: [
|
||||
{foo: 2, bar: 3},
|
||||
{foo: 2, bar: 3},
|
||||
{foo: 2, bar: 4},
|
||||
{foo: 3, bar: 4},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { Stringify, mutate } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(3);
|
||||
const { foo, bar } = t0;
|
||||
let t1;
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
const x = { foo };
|
||||
const y = { bar };
|
||||
const f0 = function () {
|
||||
const a = { y };
|
||||
const b = { x };
|
||||
a.y.x = b;
|
||||
};
|
||||
|
||||
f0();
|
||||
mutate(y);
|
||||
t1 = <Stringify x={y} />;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ foo: 2, bar: 3 }],
|
||||
sequentialRenders: [
|
||||
{ foo: 2, bar: 3 },
|
||||
{ foo: 2, bar: 3 },
|
||||
{ foo: 2, bar: 4 },
|
||||
{ foo: 3, bar: 4 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"x":{"bar":3,"x":{"x":{"foo":2}},"wat0":"joe"}}</div>
|
||||
<div>{"x":{"bar":3,"x":{"x":{"foo":2}},"wat0":"joe"}}</div>
|
||||
<div>{"x":{"bar":4,"x":{"x":{"foo":2}},"wat0":"joe"}}</div>
|
||||
<div>{"x":{"bar":4,"x":{"x":{"foo":3}},"wat0":"joe"}}</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
import {Stringify, mutate} from 'shared-runtime';
|
||||
|
||||
function Component({foo, bar}) {
|
||||
let x = {foo};
|
||||
let y = {bar};
|
||||
const f0 = function () {
|
||||
let a = {y};
|
||||
let b = {x};
|
||||
a.y.x = b;
|
||||
};
|
||||
f0();
|
||||
mutate(y);
|
||||
return <Stringify x={y} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{foo: 2, bar: 3}],
|
||||
sequentialRenders: [
|
||||
{foo: 2, bar: 3},
|
||||
{foo: 2, bar: 3},
|
||||
{foo: 2, bar: 4},
|
||||
{foo: 3, bar: 4},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useMemo} from 'react';
|
||||
import {identity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b}) {
|
||||
const x = useMemo(() => ({a}), [a, b]);
|
||||
const f = () => {
|
||||
return identity(x);
|
||||
};
|
||||
const x2 = f();
|
||||
x2.b = b;
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{a: 0, b: 0}],
|
||||
sequentialRenders: [
|
||||
{a: 0, b: 0},
|
||||
{a: 0, b: 1},
|
||||
{a: 1, b: 1},
|
||||
{a: 0, b: 0},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useMemo } from "react";
|
||||
import { identity, ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(9);
|
||||
const { a, b } = t0;
|
||||
let x;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
x = { a };
|
||||
const f = () => identity(x);
|
||||
|
||||
const x2 = f();
|
||||
x2.b = b;
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
let t1;
|
||||
if ($[3] !== a || $[4] !== b) {
|
||||
t1 = [a, b];
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
t1 = $[5];
|
||||
}
|
||||
let t2;
|
||||
if ($[6] !== t1 || $[7] !== x) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={x} />;
|
||||
$[6] = t1;
|
||||
$[7] = x;
|
||||
$[8] = t2;
|
||||
} else {
|
||||
t2 = $[8];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ a: 0, b: 0 }],
|
||||
sequentialRenders: [
|
||||
{ a: 0, b: 0 },
|
||||
{ a: 0, b: 1 },
|
||||
{ a: 1, b: 1 },
|
||||
{ a: 0, b: 0 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"inputs":[0,0],"output":{"a":0,"b":0}}</div>
|
||||
<div>{"inputs":[0,1],"output":{"a":0,"b":1}}</div>
|
||||
<div>{"inputs":[1,1],"output":{"a":1,"b":1}}</div>
|
||||
<div>{"inputs":[0,0],"output":{"a":0,"b":0}}</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
import {useMemo} from 'react';
|
||||
import {identity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b}) {
|
||||
const x = useMemo(() => ({a}), [a, b]);
|
||||
const f = () => {
|
||||
return identity(x);
|
||||
};
|
||||
const x2 = f();
|
||||
x2.b = b;
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{a: 0, b: 0}],
|
||||
sequentialRenders: [
|
||||
{a: 0, b: 0},
|
||||
{a: 0, b: 1},
|
||||
{a: 1, b: 1},
|
||||
{a: 0, b: 0},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useMemo} from 'react';
|
||||
import {identity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b}) {
|
||||
const x = useMemo(() => ({a}), [a, b]);
|
||||
const x2 = identity(x);
|
||||
x2.b = b;
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{a: 0, b: 0}],
|
||||
sequentialRenders: [
|
||||
{a: 0, b: 0},
|
||||
{a: 0, b: 1},
|
||||
{a: 1, b: 1},
|
||||
{a: 0, b: 0},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useMemo } from "react";
|
||||
import { identity, ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(9);
|
||||
const { a, b } = t0;
|
||||
let x;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
x = { a };
|
||||
const x2 = identity(x);
|
||||
x2.b = b;
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
let t1;
|
||||
if ($[3] !== a || $[4] !== b) {
|
||||
t1 = [a, b];
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
t1 = $[5];
|
||||
}
|
||||
let t2;
|
||||
if ($[6] !== t1 || $[7] !== x) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={x} />;
|
||||
$[6] = t1;
|
||||
$[7] = x;
|
||||
$[8] = t2;
|
||||
} else {
|
||||
t2 = $[8];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ a: 0, b: 0 }],
|
||||
sequentialRenders: [
|
||||
{ a: 0, b: 0 },
|
||||
{ a: 0, b: 1 },
|
||||
{ a: 1, b: 1 },
|
||||
{ a: 0, b: 0 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"inputs":[0,0],"output":{"a":0,"b":0}}</div>
|
||||
<div>{"inputs":[0,1],"output":{"a":0,"b":1}}</div>
|
||||
<div>{"inputs":[1,1],"output":{"a":1,"b":1}}</div>
|
||||
<div>{"inputs":[0,0],"output":{"a":0,"b":0}}</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
import {useMemo} from 'react';
|
||||
import {identity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b}) {
|
||||
const x = useMemo(() => ({a}), [a, b]);
|
||||
const x2 = identity(x);
|
||||
x2.b = b;
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{a: 0, b: 0}],
|
||||
sequentialRenders: [
|
||||
{a: 0, b: 0},
|
||||
{a: 0, b: 1},
|
||||
{a: 1, b: 1},
|
||||
{a: 0, b: 0},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component() {
|
||||
const x = {};
|
||||
const fn = () => {
|
||||
new Object()
|
||||
.build(x)
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({});
|
||||
};
|
||||
return <Stringify x={x} fn={fn} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component() {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = {};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const x = t0;
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const fn = () => {
|
||||
new Object()
|
||||
.build(x)
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({});
|
||||
};
|
||||
|
||||
t1 = <Stringify x={x} fn={fn} />;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -0,0 +1,14 @@
|
||||
function Component() {
|
||||
const x = {};
|
||||
const fn = () => {
|
||||
new Object()
|
||||
.build(x)
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({})
|
||||
.build({});
|
||||
};
|
||||
return <Stringify x={x} fn={fn} />;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component({a, b}) {
|
||||
const y = {a};
|
||||
const x = {b};
|
||||
const f = () => {
|
||||
let z = null;
|
||||
while (z == null) {
|
||||
z = x;
|
||||
}
|
||||
// z is a phi with a backedge, and we don't realize it could be x,
|
||||
// and therefore fail to record a Capture x <- y effect for this
|
||||
// function expression
|
||||
z.y = y;
|
||||
};
|
||||
f();
|
||||
mutate(x);
|
||||
return <div>{x}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(t0) {
|
||||
const $ = _c(3);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
const y = { a };
|
||||
const x = { b };
|
||||
const f = () => {
|
||||
let z = null;
|
||||
while (z == null) {
|
||||
z = x;
|
||||
}
|
||||
|
||||
z.y = y;
|
||||
};
|
||||
|
||||
f();
|
||||
mutate(x);
|
||||
t1 = <div>{x}</div>;
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -0,0 +1,17 @@
|
||||
function Component({a, b}) {
|
||||
const y = {a};
|
||||
const x = {b};
|
||||
const f = () => {
|
||||
let z = null;
|
||||
while (z == null) {
|
||||
z = x;
|
||||
}
|
||||
// z is a phi with a backedge, and we don't realize it could be x,
|
||||
// and therefore fail to record a Capture x <- y effect for this
|
||||
// function expression
|
||||
z.y = y;
|
||||
};
|
||||
f();
|
||||
mutate(x);
|
||||
return <div>{x}</div>;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel:true
|
||||
|
||||
export const App = () => {
|
||||
const [selected, setSelected] = useState(new Set<string>());
|
||||
const onSelectedChange = (value: string) => {
|
||||
const newSelected = new Set(selected);
|
||||
if (newSelected.has(value)) {
|
||||
// This should not count as a mutation of `selected`
|
||||
newSelected.delete(value);
|
||||
} else {
|
||||
// This should not count as a mutation of `selected`
|
||||
newSelected.add(value);
|
||||
}
|
||||
setSelected(newSelected);
|
||||
};
|
||||
|
||||
return <Stringify selected={selected} onSelectedChange={onSelectedChange} />;
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel:true
|
||||
|
||||
export const App = () => {
|
||||
const $ = _c(6);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = new Set();
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const [selected, setSelected] = useState(t0);
|
||||
let t1;
|
||||
if ($[1] !== selected) {
|
||||
t1 = (value) => {
|
||||
const newSelected = new Set(selected);
|
||||
if (newSelected.has(value)) {
|
||||
newSelected.delete(value);
|
||||
} else {
|
||||
newSelected.add(value);
|
||||
}
|
||||
|
||||
setSelected(newSelected);
|
||||
};
|
||||
$[1] = selected;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
const onSelectedChange = t1;
|
||||
let t2;
|
||||
if ($[3] !== onSelectedChange || $[4] !== selected) {
|
||||
t2 = <Stringify selected={selected} onSelectedChange={onSelectedChange} />;
|
||||
$[3] = onSelectedChange;
|
||||
$[4] = selected;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
return t2;
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -0,0 +1,18 @@
|
||||
// @enableNewMutationAliasingModel:true
|
||||
|
||||
export const App = () => {
|
||||
const [selected, setSelected] = useState(new Set<string>());
|
||||
const onSelectedChange = (value: string) => {
|
||||
const newSelected = new Set(selected);
|
||||
if (newSelected.has(value)) {
|
||||
// This should not count as a mutation of `selected`
|
||||
newSelected.delete(value);
|
||||
} else {
|
||||
// This should not count as a mutation of `selected`
|
||||
newSelected.add(value);
|
||||
}
|
||||
setSelected(newSelected);
|
||||
};
|
||||
|
||||
return <Stringify selected={selected} onSelectedChange={onSelectedChange} />;
|
||||
};
|
||||
@@ -60,13 +60,11 @@ import {
|
||||
} from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(22);
|
||||
const $ = _c(21);
|
||||
const { a, b, c } = t0;
|
||||
let t1;
|
||||
let x;
|
||||
if ($[0] !== a || $[1] !== b || $[2] !== c) {
|
||||
t1 = [{ value: a }];
|
||||
x = t1;
|
||||
x = [{ value: a }];
|
||||
if (b === 0) {
|
||||
x.push({ value: c });
|
||||
} else {
|
||||
@@ -76,63 +74,61 @@ function Component(t0) {
|
||||
$[1] = b;
|
||||
$[2] = c;
|
||||
$[3] = x;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
x = $[3];
|
||||
t1 = $[4];
|
||||
}
|
||||
let t1;
|
||||
if ($[4] !== a || $[5] !== b || $[6] !== c) {
|
||||
t1 = [a, b, c];
|
||||
$[4] = a;
|
||||
$[5] = b;
|
||||
$[6] = c;
|
||||
$[7] = t1;
|
||||
} else {
|
||||
t1 = $[7];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== a || $[6] !== b || $[7] !== c) {
|
||||
t2 = [a, b, c];
|
||||
$[5] = a;
|
||||
$[6] = b;
|
||||
$[7] = c;
|
||||
$[8] = t2;
|
||||
if ($[8] !== t1 || $[9] !== x) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={x} />;
|
||||
$[8] = t1;
|
||||
$[9] = x;
|
||||
$[10] = t2;
|
||||
} else {
|
||||
t2 = $[8];
|
||||
t2 = $[10];
|
||||
}
|
||||
let t3;
|
||||
if ($[9] !== t2 || $[10] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[9] = t2;
|
||||
$[10] = x;
|
||||
$[11] = t3;
|
||||
if ($[11] !== a || $[12] !== b || $[13] !== c) {
|
||||
t3 = [a, b, c];
|
||||
$[11] = a;
|
||||
$[12] = b;
|
||||
$[13] = c;
|
||||
$[14] = t3;
|
||||
} else {
|
||||
t3 = $[11];
|
||||
t3 = $[14];
|
||||
}
|
||||
let t4;
|
||||
if ($[12] !== a || $[13] !== b || $[14] !== c) {
|
||||
t4 = [a, b, c];
|
||||
$[12] = a;
|
||||
$[13] = b;
|
||||
$[14] = c;
|
||||
$[15] = t4;
|
||||
if ($[15] !== t3 || $[16] !== x[0]) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={x[0]} />;
|
||||
$[15] = t3;
|
||||
$[16] = x[0];
|
||||
$[17] = t4;
|
||||
} else {
|
||||
t4 = $[15];
|
||||
t4 = $[17];
|
||||
}
|
||||
let t5;
|
||||
if ($[16] !== t4 || $[17] !== x[0]) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={x[0]} />;
|
||||
$[16] = t4;
|
||||
$[17] = x[0];
|
||||
$[18] = t5;
|
||||
} else {
|
||||
t5 = $[18];
|
||||
}
|
||||
let t6;
|
||||
if ($[19] !== t3 || $[20] !== t5) {
|
||||
t6 = (
|
||||
if ($[18] !== t2 || $[19] !== t4) {
|
||||
t5 = (
|
||||
<>
|
||||
{t3};{t5};
|
||||
{t2};{t4};
|
||||
</>
|
||||
);
|
||||
$[19] = t3;
|
||||
$[18] = t2;
|
||||
$[19] = t4;
|
||||
$[20] = t5;
|
||||
$[21] = t6;
|
||||
} else {
|
||||
t6 = $[21];
|
||||
t5 = $[20];
|
||||
}
|
||||
return t6;
|
||||
return t5;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -51,13 +51,11 @@ import {
|
||||
} from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(10);
|
||||
const $ = _c(9);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let x;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
t1 = [{ a }];
|
||||
x = t1;
|
||||
x = [{ a }];
|
||||
const f = () => {
|
||||
const y = typedCreateFrom(x);
|
||||
const z = typedCapture(y);
|
||||
@@ -70,30 +68,28 @@ function Component(t0) {
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
x = $[2];
|
||||
t1 = $[3];
|
||||
}
|
||||
let t1;
|
||||
if ($[3] !== a || $[4] !== b) {
|
||||
t1 = [a, b];
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
t1 = $[5];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== a || $[5] !== b) {
|
||||
t2 = [a, b];
|
||||
$[4] = a;
|
||||
$[5] = b;
|
||||
$[6] = t2;
|
||||
if ($[6] !== t1 || $[7] !== x) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={x} />;
|
||||
$[6] = t1;
|
||||
$[7] = x;
|
||||
$[8] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t2 = $[8];
|
||||
}
|
||||
let t3;
|
||||
if ($[7] !== t2 || $[8] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[7] = t2;
|
||||
$[8] = x;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t3 = $[9];
|
||||
}
|
||||
return t3;
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -52,24 +52,20 @@ import {
|
||||
} from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(20);
|
||||
const $ = _c(19);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== a) {
|
||||
t2 = { a };
|
||||
t1 = { a };
|
||||
$[0] = a;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const o = t1;
|
||||
let t3;
|
||||
let x;
|
||||
if ($[2] !== b || $[3] !== o) {
|
||||
t3 = [o];
|
||||
x = t3;
|
||||
x = [o];
|
||||
const y = typedCapture(x);
|
||||
const z = typedCapture(y);
|
||||
x.push(z);
|
||||
@@ -77,60 +73,58 @@ function Component(t0) {
|
||||
$[2] = b;
|
||||
$[3] = o;
|
||||
$[4] = x;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
x = $[4];
|
||||
t3 = $[5];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== a) {
|
||||
t2 = [a];
|
||||
$[5] = a;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
let t3;
|
||||
if ($[7] !== o || $[8] !== t2) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={o} />;
|
||||
$[7] = o;
|
||||
$[8] = t2;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t3 = $[9];
|
||||
}
|
||||
let t4;
|
||||
if ($[6] !== a) {
|
||||
t4 = [a];
|
||||
$[6] = a;
|
||||
$[7] = t4;
|
||||
if ($[10] !== a || $[11] !== b) {
|
||||
t4 = [a, b];
|
||||
$[10] = a;
|
||||
$[11] = b;
|
||||
$[12] = t4;
|
||||
} else {
|
||||
t4 = $[7];
|
||||
t4 = $[12];
|
||||
}
|
||||
let t5;
|
||||
if ($[8] !== o || $[9] !== t4) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={o} />;
|
||||
$[8] = o;
|
||||
$[9] = t4;
|
||||
$[10] = t5;
|
||||
if ($[13] !== t4 || $[14] !== x) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={x} />;
|
||||
$[13] = t4;
|
||||
$[14] = x;
|
||||
$[15] = t5;
|
||||
} else {
|
||||
t5 = $[10];
|
||||
t5 = $[15];
|
||||
}
|
||||
let t6;
|
||||
if ($[11] !== a || $[12] !== b) {
|
||||
t6 = [a, b];
|
||||
$[11] = a;
|
||||
$[12] = b;
|
||||
$[13] = t6;
|
||||
} else {
|
||||
t6 = $[13];
|
||||
}
|
||||
let t7;
|
||||
if ($[14] !== t6 || $[15] !== x) {
|
||||
t7 = <ValidateMemoization inputs={t6} output={x} />;
|
||||
$[14] = t6;
|
||||
$[15] = x;
|
||||
$[16] = t7;
|
||||
} else {
|
||||
t7 = $[16];
|
||||
}
|
||||
let t8;
|
||||
if ($[17] !== t5 || $[18] !== t7) {
|
||||
t8 = (
|
||||
if ($[16] !== t3 || $[17] !== t5) {
|
||||
t6 = (
|
||||
<>
|
||||
{t5};{t7};
|
||||
{t3};{t5};
|
||||
</>
|
||||
);
|
||||
$[16] = t3;
|
||||
$[17] = t5;
|
||||
$[18] = t7;
|
||||
$[19] = t8;
|
||||
$[18] = t6;
|
||||
} else {
|
||||
t8 = $[19];
|
||||
t6 = $[18];
|
||||
}
|
||||
return t8;
|
||||
return t6;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -50,13 +50,11 @@ import {
|
||||
} from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(10);
|
||||
const $ = _c(9);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let x;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
t1 = { a };
|
||||
x = t1;
|
||||
x = { a };
|
||||
const f = () => {
|
||||
const y = typedCapture(x);
|
||||
const z = typedCreateFrom(y);
|
||||
@@ -69,30 +67,28 @@ function Component(t0) {
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
x = $[2];
|
||||
t1 = $[3];
|
||||
}
|
||||
let t1;
|
||||
if ($[3] !== a || $[4] !== b) {
|
||||
t1 = [a, b];
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
t1 = $[5];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== a || $[5] !== b) {
|
||||
t2 = [a, b];
|
||||
$[4] = a;
|
||||
$[5] = b;
|
||||
$[6] = t2;
|
||||
if ($[6] !== t1 || $[7] !== x) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={x} />;
|
||||
$[6] = t1;
|
||||
$[7] = x;
|
||||
$[8] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t2 = $[8];
|
||||
}
|
||||
let t3;
|
||||
if ($[7] !== t2 || $[8] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[7] = t2;
|
||||
$[8] = x;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t3 = $[9];
|
||||
}
|
||||
return t3;
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -46,13 +46,11 @@ import {
|
||||
} from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(10);
|
||||
const $ = _c(9);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let x;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
t1 = { a };
|
||||
x = t1;
|
||||
x = { a };
|
||||
const y = typedCapture(x);
|
||||
const z = typedCreateFrom(y);
|
||||
|
||||
@@ -60,30 +58,28 @@ function Component(t0) {
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
x = $[2];
|
||||
t1 = $[3];
|
||||
}
|
||||
let t1;
|
||||
if ($[3] !== a || $[4] !== b) {
|
||||
t1 = [a, b];
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
t1 = $[5];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== a || $[5] !== b) {
|
||||
t2 = [a, b];
|
||||
$[4] = a;
|
||||
$[5] = b;
|
||||
$[6] = t2;
|
||||
if ($[6] !== t1 || $[7] !== x) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={x} />;
|
||||
$[6] = t1;
|
||||
$[7] = x;
|
||||
$[8] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t2 = $[8];
|
||||
}
|
||||
let t3;
|
||||
if ($[7] !== t2 || $[8] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[7] = t2;
|
||||
$[8] = x;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t3 = $[9];
|
||||
}
|
||||
return t3;
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -49,38 +49,36 @@ function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== a) {
|
||||
t2 = [{ a }];
|
||||
t1 = [{ a }];
|
||||
$[0] = a;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const x = t1;
|
||||
const y = typedCreateFrom(x);
|
||||
const z = typedCapture(y);
|
||||
|
||||
typedMutate(z, b);
|
||||
let t3;
|
||||
let t2;
|
||||
if ($[2] !== a) {
|
||||
t3 = [a];
|
||||
t2 = [a];
|
||||
$[2] = a;
|
||||
$[3] = t3;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
t2 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[4] !== t3 || $[5] !== x) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} />;
|
||||
$[4] = t3;
|
||||
let t3;
|
||||
if ($[4] !== t2 || $[5] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[4] = t2;
|
||||
$[5] = x;
|
||||
$[6] = t4;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
t3 = $[6];
|
||||
}
|
||||
return t4;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -50,21 +50,19 @@ import {
|
||||
} from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(12);
|
||||
const $ = _c(11);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== a) {
|
||||
t2 = { a };
|
||||
t1 = { a };
|
||||
$[0] = a;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
let x;
|
||||
if ($[2] !== b || $[3] !== t2) {
|
||||
t1 = [t2];
|
||||
x = t1;
|
||||
if ($[2] !== b || $[3] !== t1) {
|
||||
x = [t1];
|
||||
let z;
|
||||
if (b) {
|
||||
z = x;
|
||||
@@ -74,32 +72,30 @@ function Component(t0) {
|
||||
|
||||
typedMutate(z, b);
|
||||
$[2] = b;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
$[4] = x;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
x = $[4];
|
||||
t1 = $[5];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== a || $[6] !== b) {
|
||||
t2 = [a, b];
|
||||
$[5] = a;
|
||||
$[6] = b;
|
||||
$[7] = t2;
|
||||
} else {
|
||||
t2 = $[7];
|
||||
}
|
||||
let t3;
|
||||
if ($[6] !== a || $[7] !== b) {
|
||||
t3 = [a, b];
|
||||
$[6] = a;
|
||||
$[7] = b;
|
||||
$[8] = t3;
|
||||
if ($[8] !== t2 || $[9] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[8] = t2;
|
||||
$[9] = x;
|
||||
$[10] = t3;
|
||||
} else {
|
||||
t3 = $[8];
|
||||
t3 = $[10];
|
||||
}
|
||||
let t4;
|
||||
if ($[9] !== t3 || $[10] !== x) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} />;
|
||||
$[9] = t3;
|
||||
$[10] = x;
|
||||
$[11] = t4;
|
||||
} else {
|
||||
t4 = $[11];
|
||||
}
|
||||
return t4;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -63,15 +63,13 @@ function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== a) {
|
||||
t2 = makeObject_Primitives(a);
|
||||
t1 = makeObject_Primitives(a);
|
||||
$[0] = a;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const x = t1;
|
||||
|
||||
useIdentity(x);
|
||||
@@ -79,24 +77,24 @@ function Component(t0) {
|
||||
const x2 = typedIdentity(x);
|
||||
|
||||
identity(x2, b);
|
||||
let t3;
|
||||
let t2;
|
||||
if ($[2] !== a) {
|
||||
t3 = [a];
|
||||
t2 = [a];
|
||||
$[2] = a;
|
||||
$[3] = t3;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
t2 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[4] !== t3 || $[5] !== x) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} />;
|
||||
$[4] = t3;
|
||||
let t3;
|
||||
if ($[4] !== t2 || $[5] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[4] = t2;
|
||||
$[5] = x;
|
||||
$[6] = t4;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
t3 = $[6];
|
||||
}
|
||||
return t4;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -51,15 +51,13 @@ function useFoo(arr1, arr2) {
|
||||
y = $[4];
|
||||
}
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[5] !== y) {
|
||||
t2 = { y };
|
||||
t1 = { y };
|
||||
$[5] = y;
|
||||
$[6] = t2;
|
||||
$[6] = t1;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t1 = $[6];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,36 +42,34 @@ function Component(t0) {
|
||||
|
||||
arg?.items.edges?.nodes;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== arg?.items.edges?.nodes) {
|
||||
t2 = arg?.items.edges?.nodes.map(identity);
|
||||
t1 = arg?.items.edges?.nodes.map(identity);
|
||||
$[0] = arg?.items.edges?.nodes;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const data = t1;
|
||||
|
||||
const t3 = arg?.items.edges?.nodes;
|
||||
const t2 = arg?.items.edges?.nodes;
|
||||
let t3;
|
||||
if ($[2] !== t2) {
|
||||
t3 = [t2];
|
||||
$[2] = t2;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[2] !== t3) {
|
||||
t4 = [t3];
|
||||
$[2] = t3;
|
||||
$[3] = t4;
|
||||
} else {
|
||||
t4 = $[3];
|
||||
}
|
||||
let t5;
|
||||
if ($[4] !== data || $[5] !== t4) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={data} />;
|
||||
if ($[4] !== data || $[5] !== t3) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={data} />;
|
||||
$[4] = data;
|
||||
$[5] = t4;
|
||||
$[6] = t5;
|
||||
$[5] = t3;
|
||||
$[6] = t4;
|
||||
} else {
|
||||
t5 = $[6];
|
||||
t4 = $[6];
|
||||
}
|
||||
return t5;
|
||||
return t4;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -23,21 +23,19 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe
|
||||
import { ValidateMemoization } from "shared-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
|
||||
const x$0 = [];
|
||||
x$0.push(props?.a.b?.c.d?.e);
|
||||
x$0.push(props.a?.b.c?.d.e);
|
||||
t0 = x$0;
|
||||
let t1;
|
||||
let t0;
|
||||
if ($[0] !== props.a.b.c.d.e) {
|
||||
t1 = <ValidateMemoization inputs={[props.a.b.c.d.e]} output={x} />;
|
||||
t0 = <ValidateMemoization inputs={[props.a.b.c.d.e]} output={x} />;
|
||||
$[0] = props.a.b.c.d.e;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
return t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -23,7 +23,6 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe
|
||||
import { ValidateMemoization } from "shared-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
let x;
|
||||
if ($[0] !== props.items) {
|
||||
x = [];
|
||||
@@ -34,26 +33,25 @@ function Component(props) {
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
t0 = x;
|
||||
const data = t0;
|
||||
let t1;
|
||||
const data = x;
|
||||
let t0;
|
||||
if ($[2] !== props.items) {
|
||||
t1 = [props.items];
|
||||
t0 = [props.items];
|
||||
$[2] = props.items;
|
||||
$[3] = t1;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
t0 = $[3];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== data || $[5] !== t1) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={data} />;
|
||||
let t1;
|
||||
if ($[4] !== data || $[5] !== t0) {
|
||||
t1 = <ValidateMemoization inputs={t0} output={data} />;
|
||||
$[4] = data;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
$[5] = t0;
|
||||
$[6] = t1;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t1 = $[6];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -38,7 +38,6 @@ function Component(t0) {
|
||||
const { arg } = t0;
|
||||
|
||||
arg?.items;
|
||||
let t1;
|
||||
let x;
|
||||
if ($[0] !== arg?.items) {
|
||||
x = [];
|
||||
@@ -48,27 +47,26 @@ function Component(t0) {
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
t1 = x;
|
||||
const data = t1;
|
||||
const t2 = arg?.items;
|
||||
const data = x;
|
||||
const t1 = arg?.items;
|
||||
let t2;
|
||||
if ($[2] !== t1) {
|
||||
t2 = [t1];
|
||||
$[2] = t1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
let t3;
|
||||
if ($[2] !== t2) {
|
||||
t3 = [t2];
|
||||
$[2] = t2;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[4] !== data || $[5] !== t3) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={data} />;
|
||||
if ($[4] !== data || $[5] !== t2) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={data} />;
|
||||
$[4] = data;
|
||||
$[5] = t3;
|
||||
$[6] = t4;
|
||||
$[5] = t2;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
t3 = $[6];
|
||||
}
|
||||
return t4;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -36,11 +36,9 @@ 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;
|
||||
let t1;
|
||||
if (styles.width > minWidth) {
|
||||
setStyles(styles);
|
||||
}
|
||||
t1 = undefined;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -34,10 +34,7 @@ import { identity } from "shared-runtime";
|
||||
* This is technically a false positive, although it makes sense
|
||||
* to bailout as source code might be doing something sketchy.
|
||||
*/
|
||||
function useFoo(x) {
|
||||
let t0;
|
||||
t0 = identity(x);
|
||||
}
|
||||
function useFoo(x) {}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
|
||||
@@ -40,14 +40,12 @@ function useFoo() {
|
||||
const $ = _c(1);
|
||||
const constVal = 0;
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [0];
|
||||
$[0] = t1;
|
||||
t0 = [0];
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
t0 = $[0];
|
||||
}
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,16 +32,14 @@ function Component(t0) {
|
||||
const { propA, propB } = t0;
|
||||
const x = propB.x.y;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== propA.x || $[1] !== x) {
|
||||
t2 = sum(propA.x, x);
|
||||
t1 = sum(propA.x, x);
|
||||
$[0] = propA.x;
|
||||
$[1] = x;
|
||||
$[2] = t2;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
t1 = $[2];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,28 +32,26 @@ import { identity } from "shared-runtime";
|
||||
function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { propA, propB } = t0;
|
||||
let t1;
|
||||
|
||||
const t2 = propB?.x.y;
|
||||
const t1 = propB?.x.y;
|
||||
let t2;
|
||||
if ($[0] !== t1) {
|
||||
t2 = identity(t1);
|
||||
$[0] = t1;
|
||||
$[1] = t2;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
}
|
||||
let t3;
|
||||
if ($[0] !== t2) {
|
||||
t3 = identity(t2);
|
||||
$[0] = t2;
|
||||
$[1] = t3;
|
||||
} else {
|
||||
t3 = $[1];
|
||||
}
|
||||
let t4;
|
||||
if ($[2] !== propA || $[3] !== t3) {
|
||||
t4 = { value: t3, other: propA };
|
||||
if ($[2] !== propA || $[3] !== t2) {
|
||||
t3 = { value: t2, other: propA };
|
||||
$[2] = propA;
|
||||
$[3] = t3;
|
||||
$[4] = t4;
|
||||
$[3] = t2;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t4 = $[4];
|
||||
t3 = $[4];
|
||||
}
|
||||
t1 = t4;
|
||||
return t1;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -30,20 +30,18 @@ import { useMemo } from "react";
|
||||
function Component(t0) {
|
||||
const $ = _c(3);
|
||||
const { propA, propB } = t0;
|
||||
let t1;
|
||||
|
||||
const t2 = propB?.x.y;
|
||||
let t3;
|
||||
if ($[0] !== propA || $[1] !== t2) {
|
||||
t3 = { value: t2, other: propA };
|
||||
const t1 = propB?.x.y;
|
||||
let t2;
|
||||
if ($[0] !== propA || $[1] !== t1) {
|
||||
t2 = { value: t1, other: propA };
|
||||
$[0] = propA;
|
||||
$[1] = t2;
|
||||
$[2] = t3;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t3 = $[2];
|
||||
t2 = $[2];
|
||||
}
|
||||
t1 = t3;
|
||||
return t1;
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -37,39 +37,35 @@ function useFoo(cond) {
|
||||
const $ = _c(5);
|
||||
const sourceDep = 0;
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = identity(0);
|
||||
$[0] = t1;
|
||||
t0 = identity(0);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
t0 = $[0];
|
||||
}
|
||||
t0 = t1;
|
||||
const derived1 = t0;
|
||||
|
||||
const derived2 = (cond ?? Math.min(0, 1)) ? 1 : 2;
|
||||
let t2;
|
||||
let t3;
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = identity(0);
|
||||
$[1] = t3;
|
||||
t1 = identity(0);
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t3 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t2 = t3;
|
||||
const derived3 = t2;
|
||||
const derived3 = t1;
|
||||
|
||||
const derived4 = (Math.min(0, -1) ?? cond) ? 1 : 2;
|
||||
let t4;
|
||||
let t2;
|
||||
if ($[2] !== derived2 || $[3] !== derived4) {
|
||||
t4 = [derived1, derived2, derived3, derived4];
|
||||
t2 = [derived1, derived2, derived3, derived4];
|
||||
$[2] = derived2;
|
||||
$[3] = derived4;
|
||||
$[4] = t4;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t4 = $[4];
|
||||
t2 = $[4];
|
||||
}
|
||||
return t4;
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -48,15 +48,13 @@ function Foo(props) {
|
||||
}
|
||||
const x = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[2] !== x[0]) {
|
||||
t2 = [x[0]];
|
||||
t1 = [x[0]];
|
||||
$[2] = x[0];
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,19 +42,17 @@ function useFoo(minWidth, otherProp) {
|
||||
let t0;
|
||||
if ($[0] !== minWidth || $[1] !== otherProp || $[2] !== width) {
|
||||
const x = [];
|
||||
let t1;
|
||||
|
||||
const t2 = Math.max(minWidth, width);
|
||||
let t3;
|
||||
if ($[4] !== t2) {
|
||||
t3 = { width: t2 };
|
||||
$[4] = t2;
|
||||
$[5] = t3;
|
||||
const t1 = Math.max(minWidth, width);
|
||||
let t2;
|
||||
if ($[4] !== t1) {
|
||||
t2 = { width: t1 };
|
||||
$[4] = t1;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
t2 = $[5];
|
||||
}
|
||||
t1 = t3;
|
||||
const style = t1;
|
||||
const style = t2;
|
||||
|
||||
arrayPush(x, otherProp);
|
||||
t0 = [style, x];
|
||||
|
||||
@@ -29,15 +29,13 @@ import { useMemo } from "react";
|
||||
function useFoo(a, b) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== a) {
|
||||
t1 = [a];
|
||||
t0 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,15 +37,13 @@ import { useMemo } from "react";
|
||||
function useHook(x) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== x.y.z) {
|
||||
t1 = [x.y.z];
|
||||
t0 = [x.y.z];
|
||||
$[0] = x.y.z;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,7 @@ import { useMemo } from "react";
|
||||
// It's correct to infer a useMemo value is non-allocating
|
||||
// and not provide it with a reactive scope
|
||||
function useFoo(num1, num2) {
|
||||
let t0;
|
||||
t0 = Math.min(num1, num2);
|
||||
return t0;
|
||||
return Math.min(num1, num2);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -31,14 +31,12 @@ import { CONST_STRING0 } from "shared-runtime";
|
||||
function useFoo() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [CONST_STRING0];
|
||||
$[0] = t1;
|
||||
t0 = [CONST_STRING0];
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
t0 = $[0];
|
||||
}
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,25 +30,23 @@ import { identity } from "shared-runtime";
|
||||
function useFoo(data) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== data.a) {
|
||||
t1 = identity(data.a);
|
||||
t0 = identity(data.a);
|
||||
$[0] = data.a;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
const temp = t1;
|
||||
let t2;
|
||||
const temp = t0;
|
||||
let t1;
|
||||
if ($[2] !== temp) {
|
||||
t2 = { temp };
|
||||
t1 = { temp };
|
||||
$[2] = temp;
|
||||
$[3] = t2;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t1 = $[3];
|
||||
}
|
||||
t0 = t2;
|
||||
return t0;
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -35,15 +35,13 @@ function useFoo(t0) {
|
||||
const $ = _c(2);
|
||||
const { callback } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== callback) {
|
||||
t2 = new Array(callback());
|
||||
t1 = new Array(callback());
|
||||
$[0] = callback;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,15 +50,13 @@ function useFoo(arr1, arr2) {
|
||||
y = $[4];
|
||||
}
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[5] !== y) {
|
||||
t2 = { y };
|
||||
t1 = { y };
|
||||
$[5] = y;
|
||||
$[6] = t2;
|
||||
$[6] = t1;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t1 = $[6];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,14 +49,12 @@ function Foo(t0) {
|
||||
|
||||
let y = [];
|
||||
let t2;
|
||||
let t3;
|
||||
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = { x: 2 };
|
||||
$[5] = t3;
|
||||
t2 = { x: 2 };
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
t2 = $[5];
|
||||
}
|
||||
t2 = t3;
|
||||
val1 = t2;
|
||||
|
||||
foo ? (y = x.concat(arr2)) : y;
|
||||
|
||||
@@ -33,15 +33,13 @@ function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const { propA } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== propA) {
|
||||
t2 = [propA];
|
||||
t1 = [propA];
|
||||
$[0] = propA;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,36 +42,34 @@ function Component(t0) {
|
||||
|
||||
arg?.items.edges?.nodes;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== arg?.items.edges?.nodes) {
|
||||
t2 = arg?.items.edges?.nodes.map(identity);
|
||||
t1 = arg?.items.edges?.nodes.map(identity);
|
||||
$[0] = arg?.items.edges?.nodes;
|
||||
$[1] = t2;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t1 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const data = t1;
|
||||
|
||||
const t3 = arg?.items.edges?.nodes;
|
||||
const t2 = arg?.items.edges?.nodes;
|
||||
let t3;
|
||||
if ($[2] !== t2) {
|
||||
t3 = [t2];
|
||||
$[2] = t2;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[2] !== t3) {
|
||||
t4 = [t3];
|
||||
$[2] = t3;
|
||||
$[3] = t4;
|
||||
} else {
|
||||
t4 = $[3];
|
||||
}
|
||||
let t5;
|
||||
if ($[4] !== data || $[5] !== t4) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={data} />;
|
||||
if ($[4] !== data || $[5] !== t3) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={data} />;
|
||||
$[4] = data;
|
||||
$[5] = t4;
|
||||
$[6] = t5;
|
||||
$[5] = t3;
|
||||
$[6] = t4;
|
||||
} else {
|
||||
t5 = $[6];
|
||||
t4 = $[6];
|
||||
}
|
||||
return t5;
|
||||
return t4;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -23,21 +23,19 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe
|
||||
import { ValidateMemoization } from "shared-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
|
||||
const x$0 = [];
|
||||
x$0.push(props?.a.b?.c.d?.e);
|
||||
x$0.push(props.a?.b.c?.d.e);
|
||||
t0 = x$0;
|
||||
let t1;
|
||||
let t0;
|
||||
if ($[0] !== props.a.b.c.d.e) {
|
||||
t1 = <ValidateMemoization inputs={[props.a.b.c.d.e]} output={x} />;
|
||||
t0 = <ValidateMemoization inputs={[props.a.b.c.d.e]} output={x} />;
|
||||
$[0] = props.a.b.c.d.e;
|
||||
$[1] = t1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
return t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -23,7 +23,6 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe
|
||||
import { ValidateMemoization } from "shared-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
let x;
|
||||
if ($[0] !== props.items) {
|
||||
x = [];
|
||||
@@ -34,26 +33,25 @@ function Component(props) {
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
t0 = x;
|
||||
const data = t0;
|
||||
let t1;
|
||||
const data = x;
|
||||
let t0;
|
||||
if ($[2] !== props.items) {
|
||||
t1 = [props.items];
|
||||
t0 = [props.items];
|
||||
$[2] = props.items;
|
||||
$[3] = t1;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
t0 = $[3];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== data || $[5] !== t1) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={data} />;
|
||||
let t1;
|
||||
if ($[4] !== data || $[5] !== t0) {
|
||||
t1 = <ValidateMemoization inputs={t0} output={data} />;
|
||||
$[4] = data;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
$[5] = t0;
|
||||
$[6] = t1;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t1 = $[6];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user