diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
index a354acf69274e8..0953289c1950ed 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
@@ -162,7 +162,8 @@ function runWithEnvironment(
if (
!env.config.enablePreserveExistingManualUseMemo &&
!env.config.disableMemoizationForDebugging &&
- !env.config.enableChangeDetectionForDebugging
+ !env.config.enableChangeDetectionForDebugging &&
+ !env.config.enableMinimalTransformsForRetry
) {
dropManualMemoization(hir);
log({kind: 'hir', name: 'DropManualMemoization', value: hir});
@@ -279,8 +280,10 @@ function runWithEnvironment(
value: hir,
});
- inferReactiveScopeVariables(hir);
- log({kind: 'hir', name: 'InferReactiveScopeVariables', value: hir});
+ if (!env.config.enableMinimalTransformsForRetry) {
+ inferReactiveScopeVariables(hir);
+ log({kind: 'hir', name: 'InferReactiveScopeVariables', value: hir});
+ }
const fbtOperands = memoizeFbtAndMacroOperandsInSameScope(hir);
log({
diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
index 6ab9ee79c7412e..b732e7a40151ae 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
@@ -333,6 +333,35 @@ export function compileProgram(
queue.push({kind: 'original', fn, fnType});
};
+ const runMinimalCompilePipeline = (
+ fn: NodePath<
+ t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
+ >,
+ fnType: ReactFunctionType,
+ ) => {
+ const retryEnvironment = {
+ ...environment,
+ validateHooksUsage: false,
+ validateRefAccessDuringRender: false,
+ validateNoSetStateInRender: false,
+ validateNoSetStateInPassiveEffects: false,
+ validateNoJSXInTryStatements: false,
+ validateMemoizedEffectDependencies: false,
+ validateNoCapitalizedCalls: null,
+ validateBlocklistedImports: null,
+ enableMinimalTransformsForRetry: true,
+ };
+ return compileFn(
+ fn,
+ retryEnvironment,
+ fnType,
+ useMemoCacheIdentifier.name,
+ pass.opts.logger,
+ pass.filename,
+ pass.code,
+ );
+ };
+
// Main traversal to compile with Forget
program.traverse(
{
@@ -382,66 +411,81 @@ 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
- * applies to this function first.
- */
- const suppressionsInFunction = filterSuppressionsThatAffectFunction(
- suppressions,
- fn,
- );
- if (suppressionsInFunction.length > 0) {
- const lintError = suppressionsToCompilerError(suppressionsInFunction);
- if (optOutDirectives.length > 0) {
- logError(lintError, pass, fn.node.loc ?? null);
- } else {
- handleError(lintError, pass, fn.node.loc ?? null);
- }
- return null;
+ /**
+ * 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
+ * applies to this function first.
+ */
+ const suppressionsInFunction = filterSuppressionsThatAffectFunction(
+ suppressions,
+ fn,
+ );
+ let compileResult:
+ | {kind: 'compile'; compiledFn: CodegenFunction}
+ | {kind: 'error'; error: unknown};
+ if (suppressionsInFunction.length > 0) {
+ compileResult = {
+ kind: 'error',
+ error: suppressionsToCompilerError(suppressionsInFunction),
+ };
+ } else {
+ 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(
- fn,
- environment,
- fnType,
- useMemoCacheIdentifier.name,
- pass.opts.logger,
- pass.filename,
- pass.code,
- );
- pass.opts.logger?.logEvent(pass.filename, {
- kind: 'CompileSuccess',
- fnLoc: fn.node.loc ?? null,
- fnName: compiledFn.id?.name ?? null,
- memoSlots: compiledFn.memoSlotsUsed,
- memoBlocks: compiledFn.memoBlocks,
- memoValues: compiledFn.memoValues,
- prunedMemoBlocks: compiledFn.prunedMemoBlocks,
- prunedMemoValues: compiledFn.prunedMemoValues,
- });
- } catch (err) {
+ }
+ // If non-memoization features are enabled, retry regardless of error kind
+ if (compileResult.kind === 'error' && environment.enableFire) {
+ try {
+ compileResult = {
+ kind: 'compile',
+ compiledFn: runMinimalCompilePipeline(fn, fnType),
+ };
+ } 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
* containing a critical error.
*/
- if (fn.node.body.type === 'BlockStatement') {
- if (optOutDirectives.length > 0) {
- logError(err, pass, fn.node.loc ?? null);
- return null;
- }
+ if (optOutDirectives.length > 0) {
+ logError(compileResult.error, pass, fn.node.loc ?? null);
+ } else {
+ handleError(compileResult.error, pass, fn.node.loc ?? null);
}
- handleError(err, pass, fn.node.loc ?? 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.
*/
if (optInDirectives.length > 0) {
- return compiledFn;
+ return compileResult.compiledFn;
} else if (pass.opts.compilationMode === 'annotation') {
/**
* No opt-in directive in annotation mode, so don't insert the compiled function.
@@ -467,7 +511,7 @@ export function compileProgram(
}
if (!pass.opts.noEmit) {
- return compiledFn;
+ return compileResult.compiledFn;
}
return null;
};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
index 9df34242ec0890..b2df97be993deb 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
@@ -552,6 +552,8 @@ const EnvironmentConfigSchema = z.object({
*/
disableMemoizationForDebugging: z.boolean().default(false),
+ enableMinimalTransformsForRetry: z.boolean().default(false),
+
/**
* 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
diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts
index 8cf30a9666e252..58aaf50ed06a74 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts
@@ -241,7 +241,7 @@ export default function inferReferenceEffects(
if (options.isFunctionExpression) {
fn.effects = functionEffects;
- } else {
+ } else if (!fn.env.config.enableMinimalTransformsForRetry) {
raiseFunctionEffectErrors(functionEffects);
}
}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.insert-fire.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.insert-fire.expect.md
new file mode 100644
index 00000000000000..9927d2792a4688
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.insert-fire.expect.md
@@ -0,0 +1,43 @@
+
+## Input
+
+```javascript
+// @enableFire
+import {fire} from 'react';
+
+function Component({props, bar}) {
+ const foo = () => {
+ console.log(props);
+ };
+ useEffect(() => {
+ fire(foo(props), bar);
+ fire(...foo);
+ fire(bar);
+ fire(props.foo());
+ });
+
+ return null;
+}
+
+```
+
+
+## Error
+
+```
+ 7 | };
+ 8 | useEffect(() => {
+> 9 | fire(foo(props), bar);
+ | ^^^^^^^^^^^^^^^^^^^^^ InvalidReact: Cannot compile `fire`. fire() can only take in a single call expression as an argument but received multiple arguments (9:9)
+
+InvalidReact: Cannot compile `fire`. fire() can only take in a single call expression as an argument but received a spread argument (10:10)
+
+InvalidReact: Cannot compile `fire`. `fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed (11:11)
+
+InvalidReact: Cannot compile `fire`. `fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed (12:12)
+ 10 | fire(...foo);
+ 11 | fire(bar);
+ 12 | fire(props.foo());
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.insert-fire.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.insert-fire.js
new file mode 100644
index 00000000000000..24b1eec2bd8a47
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.insert-fire.js
@@ -0,0 +1,16 @@
+// @enableFire
+import {fire} from 'react';
+
+function Component({props, bar}) {
+ const foo = () => {
+ console.log(props);
+ };
+ useEffect(() => {
+ fire(foo(props), bar);
+ fire(...foo);
+ fire(bar);
+ fire(props.foo());
+ });
+
+ return null;
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-capitalized-fn-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-capitalized-fn-call.expect.md
new file mode 100644
index 00000000000000..f7f413dedf906d
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-capitalized-fn-call.expect.md
@@ -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
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-capitalized-fn-call.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-capitalized-fn-call.js
new file mode 100644
index 00000000000000..b872fd8670e8ed
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-capitalized-fn-call.js
@@ -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();
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-eslint-suppressions.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-eslint-suppressions.expect.md
new file mode 100644
index 00000000000000..ad7f0ab467b001
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-eslint-suppressions.expect.md
@@ -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 ;
+}
+
+```
+
+## 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 ;
+}
+
+```
+
+### Eval output
+(kind: exception) Fixture not implemented
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-eslint-suppressions.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-eslint-suppressions.js
new file mode 100644
index 00000000000000..7145fef03b1d47
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-eslint-suppressions.js
@@ -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 ;
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-preserve-memo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-preserve-memo.expect.md
new file mode 100644
index 00000000000000..9f8db6265f064a
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-preserve-memo.expect.md
@@ -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
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-preserve-memo.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-preserve-memo.js
new file mode 100644
index 00000000000000..b7c01e40ac2a50
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-preserve-memo.js
@@ -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), []);
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-prop-write.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-prop-write.expect.md
new file mode 100644
index 00000000000000..74d9f679c4ffde
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-prop-write.expect.md
@@ -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
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-prop-write.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-prop-write.js
new file mode 100644
index 00000000000000..4fac46f78e81cc
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-prop-write.js
@@ -0,0 +1,12 @@
+// @enableFire
+import {fire} from 'react';
+
+function Component({prop1}) {
+ const foo = () => {
+ console.log(prop1);
+ };
+ useEffect(() => {
+ fire(foo(prop1));
+ });
+ prop1.value += 1;
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-ref-current-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-ref-current-access.expect.md
new file mode 100644
index 00000000000000..af0fc7b5a2f26a
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-ref-current-access.expect.md
@@ -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
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-ref-current-access.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-ref-current-access.js
new file mode 100644
index 00000000000000..96ccf0b161e931
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/bailout-validate-ref-current-access.js
@@ -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;
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/error.todo-syntax.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/error.todo-syntax.expect.md
new file mode 100644
index 00000000000000..86836d86b60922
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/error.todo-syntax.expect.md
@@ -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());
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/error.todo-syntax.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/error.todo-syntax.js
new file mode 100644
index 00000000000000..ec50ed84c5780c
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/error.todo-syntax.js
@@ -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());
+ });
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/todo-use-no-memo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/todo-use-no-memo.expect.md
new file mode 100644
index 00000000000000..907501228b10b9
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/todo-use-no-memo.expect.md
@@ -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
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/todo-use-no-memo.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/todo-use-no-memo.js
new file mode 100644
index 00000000000000..2587e24ee11707
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fire/bailout-retry/todo-use-no-memo.js
@@ -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;
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/insert-fire.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/insert-fire.expect.md
new file mode 100644
index 00000000000000..fcfeab6180546f
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/insert-fire.expect.md
@@ -0,0 +1,67 @@
+
+## Input
+
+```javascript
+// @enableFire
+import {fire} from 'react';
+
+function Component({props, bar}) {
+ const foo = () => {
+ console.log(props);
+ };
+ useEffect(() => {
+ fire(foo(props));
+ fire(foo());
+ fire(bar());
+ });
+
+ return null;
+}
+
+```
+
+## Code
+
+```javascript
+import { useFire } from "react/compiler-runtime";
+import { c as _c } from "react/compiler-runtime"; // @enableFire
+import { fire } from "react";
+
+function Component(t0) {
+ const $ = _c(6);
+ const { props, bar } = t0;
+ let t1;
+ if ($[0] !== props) {
+ t1 = () => {
+ console.log(props);
+ };
+ $[0] = props;
+ $[1] = t1;
+ } else {
+ t1 = $[1];
+ }
+ const foo = t1;
+ const t2 = useFire(foo);
+ const t3 = useFire(bar);
+ let t4;
+ if ($[2] !== props || $[3] !== t2 || $[4] !== t3) {
+ t4 = () => {
+ t2(props);
+ t2();
+ t3();
+ };
+ $[2] = props;
+ $[3] = t2;
+ $[4] = t3;
+ $[5] = t4;
+ } else {
+ t4 = $[5];
+ }
+ useEffect(t4);
+ return null;
+}
+
+```
+
+### Eval output
+(kind: exception) Fixture not implemented
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/insert-fire.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/insert-fire.js
new file mode 100644
index 00000000000000..4fdc3da73ee5a3
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/insert-fire.js
@@ -0,0 +1,15 @@
+// @enableFire
+import {fire} from 'react';
+
+function Component({props, bar}) {
+ const foo = () => {
+ console.log(props);
+ };
+ useEffect(() => {
+ fire(foo(props));
+ fire(foo());
+ fire(bar());
+ });
+
+ return null;
+}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md
new file mode 100644
index 00000000000000..c20f89d3af8d24
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md
@@ -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 ;
+}
+
+```
+
+## 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 ;
+}
+function _temp(props_0) {
+ console.log(props_0);
+}
+
+```
+
+### Eval output
+(kind: exception) Fixture not implemented
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-conditional-use-effect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.js
similarity index 55%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-conditional-use-effect.js
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.js
index 30ae8e59b986e6..0a29fd852c0307 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-conditional-use-effect.js
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.js
@@ -1,6 +1,11 @@
// @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);
@@ -12,5 +17,5 @@ function Component(props) {
});
}
- return null;
+ return ;
}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-conditional-use-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-conditional-use-effect.expect.md
deleted file mode 100644
index a24f27a695f54c..00000000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-conditional-use-effect.expect.md
+++ /dev/null
@@ -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 | }
-```
-
-
\ No newline at end of file