[compiler][autodeps/fire] Do not include fire functions in autodep arrays (#32532)
Summary: We landed on not including fire functions in dep arrays. They aren't needed because all values returned from the useFire hook call will read from the same ref. The linter will error if you include a fired function in an explicit dep array. Test Plan: yarn snap --watch --
Jordan Brown committed
Apr 17, 2025 at 13:03 UTC
b8bedc267f79db375f3147db4d766e09de599b68
6 files changed
+31
-5
compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts
+7
-1
@@ -9,6 +9,7 @@ import {Effect, ValueKind, ValueReason} from './HIR';
9
import {
10
BUILTIN_SHAPES,
11
BuiltInArrayId,
12
+ BuiltInFireFunctionId,
13
BuiltInFireId,
14
BuiltInMapId,
15
BuiltInMixedReadonlyId,
@@ -674,7 +675,12 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
675
{
676
positionalParams: [],
677
restParam: null,
677
- returnType: {kind: 'Primitive'},
678
+ returnType: {
679
+ kind: 'Function',
680
+ return: {kind: 'Poly'},
681
+ shapeId: BuiltInFireFunctionId,
682
+ isConstructor: false,
683
+ },
684
calleeEffect: Effect.Read,
685
returnValueKind: ValueKind.Frozen,
686
},
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
+6
@@ -1722,6 +1722,12 @@ export function isDispatcherType(id: Identifier): boolean {
1722
return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInDispatch';
1723
}
1724
1725
+export function isFireFunctionType(id: Identifier): boolean {
1726
+ return (
1727
+ id.type.kind === 'Function' && id.type.shapeId === 'BuiltInFireFunction'
1728
+ );
1729
+}
1730
+
1731
export function isStableType(id: Identifier): boolean {
1732
return (
1733
isSetStateType(id) ||
compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
+1
@@ -223,6 +223,7 @@ export const BuiltInUseContextHookId = 'BuiltInUseContextHook';
223
export const BuiltInUseTransitionId = 'BuiltInUseTransition';
224
export const BuiltInStartTransitionId = 'BuiltInStartTransition';
225
export const BuiltInFireId = 'BuiltInFire';
226
+export const BuiltInFireFunctionId = 'BuiltInFireFunction';
227
228
// ShapeRegistry with default definitions for built-ins.
229
export const BUILTIN_SHAPES: ShapeRegistry = new Map();
compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts
+4
-2
@@ -17,6 +17,7 @@ import {
17
ReactiveScopeDependencies,
18
isUseRefType,
19
isSetStateType,
20
+ isFireFunctionType,
21
} from '../HIR';
22
import {DEFAULT_EXPORT} from '../HIR/Environment';
23
import {
@@ -189,9 +190,10 @@ export function inferEffectDependencies(fn: HIRFunction): void {
190
*/
191
for (const dep of scopeInfo.deps) {
192
if (
192
- (isUseRefType(dep.identifier) ||
193
+ ((isUseRefType(dep.identifier) ||
194
isSetStateType(dep.identifier)) &&
194
- !reactiveIds.has(dep.identifier.id)
195
+ !reactiveIds.has(dep.identifier.id)) ||
196
+ isFireFunctionType(dep.identifier)
197
) {
198
// exclude non-reactive hook results, which will never be in a memo block
199
continue;
compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts
+12
-1
@@ -34,7 +34,11 @@ import {
34
} from '../HIR';
35
import {createTemporaryPlace, markInstructionIds} from '../HIR/HIRBuilder';
36
import {getOrInsertWith} from '../Utils/utils';
37
-import {BuiltInFireId, DefaultNonmutatingHook} from '../HIR/ObjectShape';
37
+import {
38
+ BuiltInFireFunctionId,
39
+ BuiltInFireId,
40
+ DefaultNonmutatingHook,
41
+} from '../HIR/ObjectShape';
42
import {eachInstructionOperand} from '../HIR/visitors';
43
import {printSourceLocationLine} from '../HIR/PrintHIR';
44
import {USE_FIRE_FUNCTION_NAME} from '../HIR/Environment';
@@ -633,6 +637,13 @@ class Context {
637
() => createTemporaryPlace(this.#env, GeneratedSource),
638
);
639
640
+ fireFunctionBinding.identifier.type = {
641
+ kind: 'Function',
642
+ shapeId: BuiltInFireFunctionId,
643
+ return: {kind: 'Poly'},
644
+ isConstructor: false,
645
+ };
646
+
647
this.#capturedCalleeIdentifierIds.set(callee.identifier.id, {
648
fireFunctionBinding,
649
capturedCalleeIdentifier: callee.identifier,
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/fire-and-autodeps.expect.md
+1
-1
@@ -49,7 +49,7 @@ function Component(props) {
49
} else {
50
t2 = $[4];
51
}
52
- useEffect(t2, [t1, props]);
52
+ useEffect(t2, [props]);
53
return null;
54
}
55