Skip to content

[pull] main from facebook:main #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {Effect, ValueKind, ValueReason} from './HIR';
import {
BUILTIN_SHAPES,
BuiltInArrayId,
BuiltInAutodepsId,
BuiltInFireFunctionId,
BuiltInFireId,
BuiltInMapId,
Expand Down Expand Up @@ -780,6 +781,7 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
BuiltInUseEffectEventId,
),
],
['AUTODEPS', addObject(DEFAULT_SHAPES, BuiltInAutodepsId, [])],
];

TYPED_GLOBALS.push(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ export const BuiltInFireId = 'BuiltInFire';
export const BuiltInFireFunctionId = 'BuiltInFireFunction';
export const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
export const BuiltinEffectEventId = 'BuiltInEffectEventFunction';
export const BuiltInAutodepsId = 'BuiltInAutoDepsId';

// See getReanimatedModuleType() in Globals.ts — this is part of supporting Reanimated's ref-like types
export const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import {
} from '../HIR/visitors';
import {empty} from '../Utils/Stack';
import {getOrInsertWith} from '../Utils/utils';
import {deadCodeElimination} from '../Optimization';
import {BuiltInAutodepsId} from '../HIR/ObjectShape';

/**
* Infers reactive dependencies captured by useEffect lambdas and adds them as
Expand Down Expand Up @@ -135,7 +137,6 @@ export function inferEffectDependencies(fn: HIRFunction): void {
}
} else if (value.kind === 'LoadGlobal') {
loadGlobals.add(lvalue.identifier.id);

/*
* TODO: Handle properties on default exports, like
* import React from 'react';
Expand Down Expand Up @@ -169,8 +170,17 @@ export function inferEffectDependencies(fn: HIRFunction): void {
) {
const callee =
value.kind === 'CallExpression' ? value.callee : value.property;

const autodepsArgIndex = value.args.findIndex(
arg =>
arg.kind === 'Identifier' &&
arg.identifier.type.kind === 'Object' &&
arg.identifier.type.shapeId === BuiltInAutodepsId,
);
if (
value.args.length === autodepFnLoads.get(callee.identifier.id) &&
value.args.length > 1 &&
autodepsArgIndex > 0 &&
autodepFnLoads.has(callee.identifier.id) &&
value.args[0].kind === 'Identifier'
) {
// We have a useEffect call with no deps array, so we need to infer the deps
Expand Down Expand Up @@ -260,7 +270,10 @@ export function inferEffectDependencies(fn: HIRFunction): void {
effects: null,
},
});
value.args.push({...depsPlace, effect: Effect.Freeze});
value.args[autodepsArgIndex] = {
...depsPlace,
effect: Effect.Freeze,
};
fn.env.inferredEffectLocations.add(callee.loc);
} else if (loadGlobals.has(value.args[0].identifier.id)) {
// Global functions have no reactive dependencies, so we can insert an empty array
Expand All @@ -275,7 +288,10 @@ export function inferEffectDependencies(fn: HIRFunction): void {
effects: null,
},
});
value.args.push({...depsPlace, effect: Effect.Freeze});
value.args[autodepsArgIndex] = {
...depsPlace,
effect: Effect.Freeze,
};
fn.env.inferredEffectLocations.add(callee.loc);
}
} else if (
Expand Down Expand Up @@ -323,6 +339,7 @@ export function inferEffectDependencies(fn: HIRFunction): void {
// Renumber instructions and fix scope ranges
markInstructionIds(fn.body);
fixScopeAndIdentifierRanges(fn.body);
deadCodeElimination(fn);

fn.env.hasInferredEffect = true;
}
Expand Down Expand Up @@ -408,6 +425,7 @@ function rewriteSplices(
rewriteBlocks.push(currBlock);

let cursor = 0;

for (const rewrite of splices) {
while (originalInstrs[cursor].id < rewrite.___location) {
CompilerError.invariant(
Expand All @@ -429,7 +447,7 @@ function rewriteSplices(

if (rewrite.kind === 'instr') {
currBlock.instructions.push(rewrite.value);
} else {
} else if (rewrite.kind === 'block') {
const {entry, blocks} = rewrite.value;
const entryBlock = blocks.get(entry)!;
// splice in all instructions from the entry block
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

```javascript
// @inferEffectDependencies @panicThreshold:"none"
import {useEffect} from 'react';
import {useEffect, AUTODEPS} from 'react';
import {print} from 'shared-runtime';

function Component({foo}) {
const arr = [];
// Taking either arr[0].value or arr as a dependency is reasonable
// as long as developers know what to expect.
useEffect(() => print(arr[0].value));
useEffect(() => print(arr[0].value), AUTODEPS);
arr.push({value: foo});
return arr;
}
Expand All @@ -21,7 +21,7 @@ function Component({foo}) {

```javascript
// @inferEffectDependencies @panicThreshold:"none"
import { useEffect } from "react";
import { useEffect, AUTODEPS } from "react";
import { print } from "shared-runtime";

function Component(t0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// @inferEffectDependencies @panicThreshold:"none"
import {useEffect} from 'react';
import {useEffect, AUTODEPS} from 'react';
import {print} from 'shared-runtime';

function Component({foo}) {
const arr = [];
// Taking either arr[0].value or arr as a dependency is reasonable
// as long as developers know what to expect.
useEffect(() => print(arr[0].value));
useEffect(() => print(arr[0].value), AUTODEPS);
arr.push({value: foo});
return arr;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

```javascript
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
import {useEffect} from 'react';
import {useEffect, AUTODEPS} from 'react';
import {print} from 'shared-runtime';

function Component({foo}) {
const arr = [];
// Taking either arr[0].value or arr as a dependency is reasonable
// as long as developers know what to expect.
useEffect(() => print(arr[0]?.value));
useEffect(() => print(arr[0]?.value), AUTODEPS);
arr.push({value: foo});
return arr;
}
Expand All @@ -26,7 +26,7 @@ export const FIXTURE_ENTRYPOINT = {

```javascript
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
import { useEffect } from "react";
import { useEffect, AUTODEPS } from "react";
import { print } from "shared-runtime";

function Component(t0) {
Expand All @@ -48,9 +48,9 @@ export const FIXTURE_ENTRYPOINT = {
## Logs

```
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":10,"column":2,"index":345},"end":{"line":10,"column":5,"index":348},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":304},"end":{"line":9,"column":39,"index":341},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":326},"end":{"line":9,"column":27,"index":329},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":10,"column":2,"index":365},"end":{"line":10,"column":5,"index":368},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":314},"end":{"line":9,"column":49,"index":361},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":336},"end":{"line":9,"column":27,"index":339},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
```

### Eval output
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
import {useEffect} from 'react';
import {useEffect, AUTODEPS} from 'react';
import {print} from 'shared-runtime';

function Component({foo}) {
const arr = [];
// Taking either arr[0].value or arr as a dependency is reasonable
// as long as developers know what to expect.
useEffect(() => print(arr[0]?.value));
useEffect(() => print(arr[0]?.value), AUTODEPS);
arr.push({value: foo});
return arr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
```javascript
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly

import {useEffect, useRef} from 'react';
import {useEffect, useRef, AUTODEPS} from 'react';
import {print} from 'shared-runtime';

function Component({arrRef}) {
// Avoid taking arr.current as a dependency
useEffect(() => print(arrRef.current));
useEffect(() => print(arrRef.current), AUTODEPS);
arrRef.current.val = 2;
return arrRef;
}
Expand All @@ -26,7 +26,7 @@ export const FIXTURE_ENTRYPOINT = {
```javascript
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly

import { useEffect, useRef } from "react";
import { useEffect, useRef, AUTODEPS } from "react";
import { print } from "shared-runtime";

function Component(t0) {
Expand All @@ -47,9 +47,9 @@ export const FIXTURE_ENTRYPOINT = {
## Logs

```
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":269},"end":{"line":9,"column":16,"index":283},"filename":"mutate-after-useeffect-ref-access.ts"}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":227},"end":{"line":8,"column":40,"index":265},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":249},"end":{"line":8,"column":30,"index":255},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":237},"end":{"line":8,"column":50,"index":285},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":259},"end":{"line":8,"column":30,"index":265},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
```

### Eval output
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly

import {useEffect, useRef} from 'react';
import {useEffect, useRef, AUTODEPS} from 'react';
import {print} from 'shared-runtime';

function Component({arrRef}) {
// Avoid taking arr.current as a dependency
useEffect(() => print(arrRef.current));
useEffect(() => print(arrRef.current), AUTODEPS);
arrRef.current.val = 2;
return arrRef;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

```javascript
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
import {useEffect} from 'react';
import {useEffect, AUTODEPS} from 'react';

function Component({foo}) {
const arr = [];
useEffect(() => {
arr.push(foo);
});
}, AUTODEPS);
arr.push(2);
return arr;
}
Expand All @@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPOINT = {

```javascript
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
import { useEffect } from "react";
import { useEffect, AUTODEPS } from "react";

function Component(t0) {
const { foo } = t0;
Expand All @@ -47,9 +47,9 @@ export const FIXTURE_ENTRYPOINT = {
## Logs

```
{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":194},"end":{"line":9,"column":5,"index":197},"filename":"mutate-after-useeffect.ts","identifierName":"arr"}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":149},"end":{"line":8,"column":4,"index":190},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":180},"end":{"line":7,"column":16,"index":183},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":214},"end":{"line":9,"column":5,"index":217},"filename":"mutate-after-useeffect.ts","identifierName":"arr"}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":159},"end":{"line":8,"column":14,"index":210},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":181},"end":{"line":7,"column":7,"index":184},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":181},"end":{"line":7,"column":7,"index":184},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":190},"end":{"line":7,"column":16,"index":193},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
```

### Eval output
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
import {useEffect} from 'react';
import {useEffect, AUTODEPS} from 'react';

function Component({foo}) {
const arr = [];
useEffect(() => {
arr.push(foo);
});
}, AUTODEPS);
arr.push(2);
return arr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

```javascript
// @inferEffectDependencies
import {useEffect, useRef} from 'react';
import {useEffect, useRef, AUTODEPS} from 'react';
function useCustomRef() {
const ref = useRef();
return ref;
Expand All @@ -12,7 +12,7 @@ function NonReactiveWrapper() {
const ref = useCustomRef();
useEffect(() => {
print(ref);
});
}, AUTODEPS);
}

```
Expand All @@ -21,7 +21,7 @@ function NonReactiveWrapper() {

```javascript
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
import { useEffect, useRef } from "react";
import { useEffect, useRef, AUTODEPS } from "react";
function useCustomRef() {
const ref = useRef();
return ref;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @inferEffectDependencies
import {useEffect, useRef} from 'react';
import {useEffect, useRef, AUTODEPS} from 'react';
function useCustomRef() {
const ref = useRef();
return ref;
Expand All @@ -8,5 +8,5 @@ function NonReactiveWrapper() {
const ref = useCustomRef();
useEffect(() => {
print(ref);
});
}, AUTODEPS);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import * as SharedRuntime from 'shared-runtime';

function NonReactiveDepInEffect() {
const obj = makeObject_Primitives();
React.useEffect(() => print(obj));
SharedRuntime.useSpecialEffect(() => print(obj), [obj]);
React.useEffect(() => print(obj), React.AUTODEPS);
SharedRuntime.useSpecialEffect(() => print(obj), [obj], React.AUTODEPS);
}

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import * as SharedRuntime from 'shared-runtime';

function NonReactiveDepInEffect() {
const obj = makeObject_Primitives();
React.useEffect(() => print(obj));
SharedRuntime.useSpecialEffect(() => print(obj), [obj]);
React.useEffect(() => print(obj), React.AUTODEPS);
SharedRuntime.useSpecialEffect(() => print(obj), [obj], React.AUTODEPS);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
```javascript
// @inferEffectDependencies
import {print, useSpecialEffect} from 'shared-runtime';
import {AUTODEPS} from 'react';

function CustomConfig({propVal}) {
// Insertion
useSpecialEffect(() => print(propVal), [propVal]);
useSpecialEffect(() => print(propVal), [propVal], AUTODEPS);
// No insertion
useSpecialEffect(() => print(propVal), [propVal], [propVal]);
}
Expand All @@ -19,6 +20,7 @@ function CustomConfig({propVal}) {
```javascript
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
import { print, useSpecialEffect } from "shared-runtime";
import { AUTODEPS } from "react";

function CustomConfig(t0) {
const $ = _c(7);
Expand Down
Loading
Loading