mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[compiler][rfc] Hacky retry pipeline for fire (#32164)
Hacky retry pipeline for when transforming `fire(...)` calls encounters validation, todo, or memoization invariant bailouts. Would love feedback on how we implement this to be extensible to other compiler non-memoization features (e.g. inlineJSX) Some observations: - Compiler "front-end" passes (e.g. lower, type, effect, and mutability inferences) should be shared for all compiler features -- memo and otherwise - Many passes (anything dealing with reactive scope ranges, scope blocks / dependencies, and optimizations such as ReactiveIR #31974) can be left out of the retry pipeline. This PR hackily skips memoization features by removing reactive scope creation, but we probably should restructure the pipeline to skip these entirely on a retry - We should maintain a canonical set of "validation flags" Note the newly added fixtures are prefixed with `bailout-...` when the retry fire pipeline is used. These fixture outputs contain correctly inserted `useFire` calls and no memoization.
This commit is contained in:
parent
19ca800caa
commit
152bfe3769
|
|
@ -162,7 +162,8 @@ function runWithEnvironment(
|
||||||
if (
|
if (
|
||||||
!env.config.enablePreserveExistingManualUseMemo &&
|
!env.config.enablePreserveExistingManualUseMemo &&
|
||||||
!env.config.disableMemoizationForDebugging &&
|
!env.config.disableMemoizationForDebugging &&
|
||||||
!env.config.enableChangeDetectionForDebugging
|
!env.config.enableChangeDetectionForDebugging &&
|
||||||
|
!env.config.enableMinimalTransformsForRetry
|
||||||
) {
|
) {
|
||||||
dropManualMemoization(hir);
|
dropManualMemoization(hir);
|
||||||
log({kind: 'hir', name: 'DropManualMemoization', value: hir});
|
log({kind: 'hir', name: 'DropManualMemoization', value: hir});
|
||||||
|
|
@ -279,8 +280,10 @@ function runWithEnvironment(
|
||||||
value: hir,
|
value: hir,
|
||||||
});
|
});
|
||||||
|
|
||||||
inferReactiveScopeVariables(hir);
|
if (!env.config.enableMinimalTransformsForRetry) {
|
||||||
log({kind: 'hir', name: 'InferReactiveScopeVariables', value: hir});
|
inferReactiveScopeVariables(hir);
|
||||||
|
log({kind: 'hir', name: 'InferReactiveScopeVariables', value: hir});
|
||||||
|
}
|
||||||
|
|
||||||
const fbtOperands = memoizeFbtAndMacroOperandsInSameScope(hir);
|
const fbtOperands = memoizeFbtAndMacroOperandsInSameScope(hir);
|
||||||
log({
|
log({
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
EnvironmentConfig,
|
EnvironmentConfig,
|
||||||
ExternalFunction,
|
ExternalFunction,
|
||||||
ReactFunctionType,
|
ReactFunctionType,
|
||||||
|
MINIMAL_RETRY_CONFIG,
|
||||||
tryParseExternalFunction,
|
tryParseExternalFunction,
|
||||||
} from '../HIR/Environment';
|
} from '../HIR/Environment';
|
||||||
import {CodegenFunction} from '../ReactiveScopes';
|
import {CodegenFunction} from '../ReactiveScopes';
|
||||||
|
|
@ -382,66 +383,92 @@ export function compileProgram(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let compiledFn: CodegenFunction;
|
/**
|
||||||
try {
|
* Note that Babel does not attach comment nodes to nodes; they are dangling off of the
|
||||||
/**
|
* Program node itself. We need to figure out whether an eslint suppression range
|
||||||
* Note that Babel does not attach comment nodes to nodes; they are dangling off of the
|
* applies to this function first.
|
||||||
* Program node itself. We need to figure out whether an eslint suppression range
|
*/
|
||||||
* applies to this function first.
|
const suppressionsInFunction = filterSuppressionsThatAffectFunction(
|
||||||
*/
|
suppressions,
|
||||||
const suppressionsInFunction = filterSuppressionsThatAffectFunction(
|
fn,
|
||||||
suppressions,
|
);
|
||||||
fn,
|
let compileResult:
|
||||||
);
|
| {kind: 'compile'; compiledFn: CodegenFunction}
|
||||||
if (suppressionsInFunction.length > 0) {
|
| {kind: 'error'; error: unknown};
|
||||||
const lintError = suppressionsToCompilerError(suppressionsInFunction);
|
if (suppressionsInFunction.length > 0) {
|
||||||
if (optOutDirectives.length > 0) {
|
compileResult = {
|
||||||
logError(lintError, pass, fn.node.loc ?? null);
|
kind: 'error',
|
||||||
} else {
|
error: suppressionsToCompilerError(suppressionsInFunction),
|
||||||
handleError(lintError, pass, fn.node.loc ?? null);
|
};
|
||||||
}
|
} else {
|
||||||
return null;
|
try {
|
||||||
|
compileResult = {
|
||||||
|
kind: 'compile',
|
||||||
|
compiledFn: compileFn(
|
||||||
|
fn,
|
||||||
|
environment,
|
||||||
|
fnType,
|
||||||
|
useMemoCacheIdentifier.name,
|
||||||
|
pass.opts.logger,
|
||||||
|
pass.filename,
|
||||||
|
pass.code,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
compileResult = {kind: 'error', error: err};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
compiledFn = compileFn(
|
// If non-memoization features are enabled, retry regardless of error kind
|
||||||
fn,
|
if (compileResult.kind === 'error' && environment.enableFire) {
|
||||||
environment,
|
try {
|
||||||
fnType,
|
compileResult = {
|
||||||
useMemoCacheIdentifier.name,
|
kind: 'compile',
|
||||||
pass.opts.logger,
|
compiledFn: compileFn(
|
||||||
pass.filename,
|
fn,
|
||||||
pass.code,
|
{
|
||||||
);
|
...environment,
|
||||||
pass.opts.logger?.logEvent(pass.filename, {
|
...MINIMAL_RETRY_CONFIG,
|
||||||
kind: 'CompileSuccess',
|
},
|
||||||
fnLoc: fn.node.loc ?? null,
|
fnType,
|
||||||
fnName: compiledFn.id?.name ?? null,
|
useMemoCacheIdentifier.name,
|
||||||
memoSlots: compiledFn.memoSlotsUsed,
|
pass.opts.logger,
|
||||||
memoBlocks: compiledFn.memoBlocks,
|
pass.filename,
|
||||||
memoValues: compiledFn.memoValues,
|
pass.code,
|
||||||
prunedMemoBlocks: compiledFn.prunedMemoBlocks,
|
),
|
||||||
prunedMemoValues: compiledFn.prunedMemoValues,
|
};
|
||||||
});
|
} catch (err) {
|
||||||
} catch (err) {
|
compileResult = {kind: 'error', error: err};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (compileResult.kind === 'error') {
|
||||||
/**
|
/**
|
||||||
* If an opt out directive is present, log only instead of throwing and don't mark as
|
* If an opt out directive is present, log only instead of throwing and don't mark as
|
||||||
* containing a critical error.
|
* containing a critical error.
|
||||||
*/
|
*/
|
||||||
if (fn.node.body.type === 'BlockStatement') {
|
if (optOutDirectives.length > 0) {
|
||||||
if (optOutDirectives.length > 0) {
|
logError(compileResult.error, pass, fn.node.loc ?? null);
|
||||||
logError(err, pass, fn.node.loc ?? null);
|
} else {
|
||||||
return null;
|
handleError(compileResult.error, pass, fn.node.loc ?? null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
handleError(err, pass, fn.node.loc ?? null);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pass.opts.logger?.logEvent(pass.filename, {
|
||||||
|
kind: 'CompileSuccess',
|
||||||
|
fnLoc: fn.node.loc ?? null,
|
||||||
|
fnName: compileResult.compiledFn.id?.name ?? null,
|
||||||
|
memoSlots: compileResult.compiledFn.memoSlotsUsed,
|
||||||
|
memoBlocks: compileResult.compiledFn.memoBlocks,
|
||||||
|
memoValues: compileResult.compiledFn.memoValues,
|
||||||
|
prunedMemoBlocks: compileResult.compiledFn.prunedMemoBlocks,
|
||||||
|
prunedMemoValues: compileResult.compiledFn.prunedMemoValues,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Always compile functions with opt in directives.
|
* Always compile functions with opt in directives.
|
||||||
*/
|
*/
|
||||||
if (optInDirectives.length > 0) {
|
if (optInDirectives.length > 0) {
|
||||||
return compiledFn;
|
return compileResult.compiledFn;
|
||||||
} else if (pass.opts.compilationMode === 'annotation') {
|
} else if (pass.opts.compilationMode === 'annotation') {
|
||||||
/**
|
/**
|
||||||
* No opt-in directive in annotation mode, so don't insert the compiled function.
|
* No opt-in directive in annotation mode, so don't insert the compiled function.
|
||||||
|
|
@ -467,7 +494,7 @@ export function compileProgram(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pass.opts.noEmit) {
|
if (!pass.opts.noEmit) {
|
||||||
return compiledFn;
|
return compileResult.compiledFn;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -552,6 +552,8 @@ const EnvironmentConfigSchema = z.object({
|
||||||
*/
|
*/
|
||||||
disableMemoizationForDebugging: z.boolean().default(false),
|
disableMemoizationForDebugging: z.boolean().default(false),
|
||||||
|
|
||||||
|
enableMinimalTransformsForRetry: z.boolean().default(false),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When true, rather using memoized values, the compiler will always re-compute
|
* When true, rather using memoized values, the compiler will always re-compute
|
||||||
* values, and then use a heuristic to compare the memoized value to the newly
|
* values, and then use a heuristic to compare the memoized value to the newly
|
||||||
|
|
@ -626,6 +628,17 @@ const EnvironmentConfigSchema = z.object({
|
||||||
|
|
||||||
export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;
|
export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;
|
||||||
|
|
||||||
|
export const MINIMAL_RETRY_CONFIG: PartialEnvironmentConfig = {
|
||||||
|
validateHooksUsage: false,
|
||||||
|
validateRefAccessDuringRender: false,
|
||||||
|
validateNoSetStateInRender: false,
|
||||||
|
validateNoSetStateInPassiveEffects: false,
|
||||||
|
validateNoJSXInTryStatements: false,
|
||||||
|
validateMemoizedEffectDependencies: false,
|
||||||
|
validateNoCapitalizedCalls: null,
|
||||||
|
validateBlocklistedImports: null,
|
||||||
|
enableMinimalTransformsForRetry: true,
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* For test fixtures and playground only.
|
* For test fixtures and playground only.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,7 @@ export default function inferReferenceEffects(
|
||||||
|
|
||||||
if (options.isFunctionExpression) {
|
if (options.isFunctionExpression) {
|
||||||
fn.effects = functionEffects;
|
fn.effects = functionEffects;
|
||||||
} else {
|
} else if (!fn.env.config.enableMinimalTransformsForRetry) {
|
||||||
raiseFunctionEffectErrors(functionEffects);
|
raiseFunctionEffectErrors(functionEffects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @validateNoCapitalizedCalls @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
const CapitalizedCall = require('shared-runtime').sum;
|
||||||
|
|
||||||
|
function Component({prop1, bar}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
return CapitalizedCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire
|
||||||
|
import { fire } from "react";
|
||||||
|
const CapitalizedCall = require("shared-runtime").sum;
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const { prop1, bar } = t0;
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
const t1 = useFire(foo);
|
||||||
|
const t2 = useFire(bar);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
t1(prop1);
|
||||||
|
t1();
|
||||||
|
t2();
|
||||||
|
});
|
||||||
|
return CapitalizedCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: exception) Fixture not implemented
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// @validateNoCapitalizedCalls @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
const CapitalizedCall = require('shared-runtime').sum;
|
||||||
|
|
||||||
|
function Component({prop1, bar}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
return CapitalizedCall();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @enableFire
|
||||||
|
import {useRef} from 'react';
|
||||||
|
|
||||||
|
function Component({props, bar}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(props);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(props));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
const ref = useRef(null);
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
ref.current = 'bad';
|
||||||
|
return <button ref={ref} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { useFire } from "react/compiler-runtime"; // @enableFire
|
||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const { props, bar } = t0;
|
||||||
|
const foo = () => {
|
||||||
|
console.log(props);
|
||||||
|
};
|
||||||
|
const t1 = useFire(foo);
|
||||||
|
const t2 = useFire(bar);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
t1(props);
|
||||||
|
t1();
|
||||||
|
t2();
|
||||||
|
});
|
||||||
|
|
||||||
|
const ref = useRef(null);
|
||||||
|
|
||||||
|
ref.current = "bad";
|
||||||
|
return <button ref={ref} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: exception) Fixture not implemented
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// @enableFire
|
||||||
|
import {useRef} from 'react';
|
||||||
|
|
||||||
|
function Component({props, bar}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(props);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(props));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
const ref = useRef(null);
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
ref.current = 'bad';
|
||||||
|
return <button ref={ref} />;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @validatePreserveExistingMemoizationGuarantees @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
import {sum} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({prop1, bar}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
return useMemo(() => sum(bar), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { useFire } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableFire
|
||||||
|
import { fire } from "react";
|
||||||
|
import { sum } from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const { prop1, bar } = t0;
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
const t1 = useFire(foo);
|
||||||
|
const t2 = useFire(bar);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
t1(prop1);
|
||||||
|
t1();
|
||||||
|
t2();
|
||||||
|
});
|
||||||
|
return useMemo(() => sum(bar), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: exception) Fixture not implemented
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// @validatePreserveExistingMemoizationGuarantees @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
import {sum} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({prop1, bar}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
return useMemo(() => sum(bar), []);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
|
||||||
|
function Component({prop1}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
});
|
||||||
|
prop1.value += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { useFire } from "react/compiler-runtime"; // @enableFire
|
||||||
|
import { fire } from "react";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const { prop1 } = t0;
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
const t1 = useFire(foo);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
t1(prop1);
|
||||||
|
});
|
||||||
|
prop1.value = prop1.value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: exception) Fixture not implemented
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
|
||||||
|
function Component({prop1}) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
});
|
||||||
|
prop1.value += 1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @flow @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
import {print} from 'shared-runtime';
|
||||||
|
|
||||||
|
component Component(prop1, ref) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
bar();
|
||||||
|
fire(foo());
|
||||||
|
});
|
||||||
|
|
||||||
|
print(ref.current);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { useFire } from "react/compiler-runtime";
|
||||||
|
import { fire } from "react";
|
||||||
|
import { print } from "shared-runtime";
|
||||||
|
|
||||||
|
const Component = React.forwardRef(Component_withRef);
|
||||||
|
function Component_withRef(t0, ref) {
|
||||||
|
const { prop1 } = t0;
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
const t1 = useFire(foo);
|
||||||
|
useEffect(() => {
|
||||||
|
t1(prop1);
|
||||||
|
bar();
|
||||||
|
t1();
|
||||||
|
});
|
||||||
|
print(ref.current);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: exception) Fixture not implemented
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// @flow @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
import {print} from 'shared-runtime';
|
||||||
|
|
||||||
|
component Component(prop1, ref) {
|
||||||
|
const foo = () => {
|
||||||
|
console.log(prop1);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(prop1));
|
||||||
|
bar();
|
||||||
|
fire(foo());
|
||||||
|
});
|
||||||
|
|
||||||
|
print(ref.current);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that a react compiler-based transform still has limitations on JS syntax.
|
||||||
|
* In practice, we expect to surface these as actionable errors to the user, in
|
||||||
|
* the same way that invalid `fire` calls error.
|
||||||
|
*/
|
||||||
|
function Component({prop1}) {
|
||||||
|
const foo = () => {
|
||||||
|
try {
|
||||||
|
console.log(prop1);
|
||||||
|
} finally {
|
||||||
|
console.log('jbrown215');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Error
|
||||||
|
|
||||||
|
```
|
||||||
|
9 | function Component({prop1}) {
|
||||||
|
10 | const foo = () => {
|
||||||
|
> 11 | try {
|
||||||
|
| ^^^^^
|
||||||
|
> 12 | console.log(prop1);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
> 13 | } finally {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
> 14 | console.log('jbrown215');
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
> 15 | }
|
||||||
|
| ^^^^^^ Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (11:15)
|
||||||
|
16 | };
|
||||||
|
17 | useEffect(() => {
|
||||||
|
18 | fire(foo());
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that a react compiler-based transform still has limitations on JS syntax.
|
||||||
|
* In practice, we expect to surface these as actionable errors to the user, in
|
||||||
|
* the same way that invalid `fire` calls error.
|
||||||
|
*/
|
||||||
|
function Component({prop1}) {
|
||||||
|
const foo = () => {
|
||||||
|
try {
|
||||||
|
console.log(prop1);
|
||||||
|
} finally {
|
||||||
|
console.log('jbrown215');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
|
||||||
|
function Component({props, bar}) {
|
||||||
|
'use no memo';
|
||||||
|
const foo = () => {
|
||||||
|
console.log(props);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(props));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @enableFire
|
||||||
|
import { fire } from "react";
|
||||||
|
|
||||||
|
function Component({ props, bar }) {
|
||||||
|
"use no memo";
|
||||||
|
const foo = () => {
|
||||||
|
console.log(props);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(props));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: exception) Fixture not implemented
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// @enableFire
|
||||||
|
import {fire} from 'react';
|
||||||
|
|
||||||
|
function Component({props, bar}) {
|
||||||
|
'use no memo';
|
||||||
|
const foo = () => {
|
||||||
|
console.log(props);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(props));
|
||||||
|
fire(foo());
|
||||||
|
fire(bar());
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// @enableFire
|
||||||
|
import {fire, useEffect} from 'react';
|
||||||
|
import {Stringify} from 'shared-runtime';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When @enableFire is specified, retry compilation with validation passes (e.g.
|
||||||
|
* hook usage) disabled
|
||||||
|
*/
|
||||||
|
function Component(props) {
|
||||||
|
const foo = props => {
|
||||||
|
console.log(props);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (props.cond) {
|
||||||
|
useEffect(() => {
|
||||||
|
fire(foo(props));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Stringify />;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { useFire } from "react/compiler-runtime"; // @enableFire
|
||||||
|
import { fire, useEffect } from "react";
|
||||||
|
import { Stringify } from "shared-runtime";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When @enableFire is specified, retry compilation with validation passes (e.g.
|
||||||
|
* hook usage) disabled
|
||||||
|
*/
|
||||||
|
function Component(props) {
|
||||||
|
const foo = _temp;
|
||||||
|
if (props.cond) {
|
||||||
|
const t0 = useFire(foo);
|
||||||
|
useEffect(() => {
|
||||||
|
t0(props);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return <Stringify />;
|
||||||
|
}
|
||||||
|
function _temp(props_0) {
|
||||||
|
console.log(props_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: exception) Fixture not implemented
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
// @enableFire
|
// @enableFire
|
||||||
import {fire, useEffect} from 'react';
|
import {fire, useEffect} from 'react';
|
||||||
|
import {Stringify} from 'shared-runtime';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When @enableFire is specified, retry compilation with validation passes (e.g.
|
||||||
|
* hook usage) disabled
|
||||||
|
*/
|
||||||
function Component(props) {
|
function Component(props) {
|
||||||
const foo = props => {
|
const foo = props => {
|
||||||
console.log(props);
|
console.log(props);
|
||||||
|
|
@ -12,5 +17,5 @@ function Component(props) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return <Stringify />;
|
||||||
}
|
}
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
|
|
||||||
## Input
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// @enableFire
|
|
||||||
import {fire, useEffect} from 'react';
|
|
||||||
|
|
||||||
function Component(props) {
|
|
||||||
const foo = props => {
|
|
||||||
console.log(props);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (props.cond) {
|
|
||||||
useEffect(() => {
|
|
||||||
fire(foo(props));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Error
|
|
||||||
|
|
||||||
```
|
|
||||||
8 |
|
|
||||||
9 | if (props.cond) {
|
|
||||||
> 10 | useEffect(() => {
|
|
||||||
| ^^^^^^^^^ InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (10:10)
|
|
||||||
11 | fire(foo(props));
|
|
||||||
12 | });
|
|
||||||
13 | }
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user