@samitouri / QOS-React-2 / commits / b16b768fbd

[compiler] Feature flag cleanup (#35825)

Cleans up feature flags that do not have an active experiment and which we don't currently plan to ship, one commit per flag. Notable removals: * Automatic (inferred) effect dependencies / Fire: abandoned due to early feedback. Shipped useEffectEvent which addresses some of the use-cases. * Inline JSX transform (experimented, not a consistent win) * Context selectors (experimented, not a sufficient/consistent win given the benefit the compiler already provides) * Instruction Reordering (will try a different approach) To decide which features to remove, I looked at Meta's internal repos as well as eslint-pugin-react-hooks to see which flags were never overridden anywhere. That gave a longer list of flags, from which I then removed some features that I know are used in OSS.

Joseph Savona committed Feb 20, 2026 at 12:29 UTC b16b768fbd95fff334b15d36b8f141010d68869e
310 files changed +88 -15255
compiler/CLAUDE.md
+2 -2
@@ -215,12 +215,12 @@ const UseEffectEventHook = addHook(
215 Feature flags are configured in `src/HIR/Environment.ts`, for example `enableJsxOutlining`. Test fixtures can override the active feature flags used for that fixture via a comment pragma on the first line of the fixture input, for example:
216
217 ```javascript
218 -// enableJsxOutlining @enableChangeVariableCodegen:false
218 +// enableJsxOutlining @enableNameAnonymousFunctions:false
219
220 ...code...
221 ```
222
223 -Would enable the `enableJsxOutlining` feature and disable the `enableChangeVariableCodegen` feature.
223 +Would enable the `enableJsxOutlining` feature and disable the `enableNameAnonymousFunctions` feature.
224
225 ## Debugging Tips
226
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/disableMemoizationForDebugging-output.txt deleted
-14
@@ -1,14 +0,0 @@
1 -import { c as _c } from "react/compiler-runtime";
2 -export default function TestComponent(t0) {
3 - const $ = _c(2);
4 - const { x } = t0;
5 - let t1;
6 - if ($[0] !== x || true) {
7 - t1 = <Button>{x}</Button>;
8 - $[0] = x;
9 - $[1] = t1;
10 - } else {
11 - t1 = $[1];
12 - }
13 - return t1;
14 -}
compiler/apps/playground/__tests__/e2e/page.spec.ts
-31
@@ -283,37 +283,6 @@ test('error is displayed when config has validation error', async ({page}) => {
283 expect(output.replace(/\s+/g, ' ')).toContain('Unexpected compilationMode');
284 });
285
286 -test('disableMemoizationForDebugging flag works as expected', async ({
287 - page,
288 -}) => {
289 - const store: Store = {
290 - source: TEST_SOURCE,
291 - config: `import type { PluginOptions } from 'babel-plugin-react-compiler/dist';
292 -
293 -({
294 - environment: {
295 - disableMemoizationForDebugging: true
296 - }
297 -} satisfies PluginOptions);`,
298 - showInternals: false,
299 - };
300 - const hash = encodeStore(store);
301 - await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
302 - await page.waitForFunction(isMonacoLoaded);
303 - await expandConfigs(page);
304 - await page.screenshot({
305 - fullPage: true,
306 - path: 'test-results/07-config-disableMemoizationForDebugging-flag.png',
307 - });
308 -
309 - const text =
310 - (await page.locator('.monaco-editor-output').allInnerTexts()) ?? [];
311 - const output = await formatPrint(text);
312 -
313 - expect(output).not.toEqual('');
314 - expect(output).toMatchSnapshot('disableMemoizationForDebugging-output.txt');
315 -});
316 -
286 test('error is displayed when source has syntax error', async ({page}) => {
287 const syntaxErrorSource = `function TestComponent(props) {
288 const oops = props.
compiler/packages/babel-plugin-react-compiler/docs/passes/06-inferTypes.md
-3
@@ -70,9 +70,6 @@ The `occursCheck` method prevents infinite types by detecting when a type variab
70 - `DeclareContext` and `LoadContext` generate no type equations (intentionally untyped)
71 - `StoreContext` with `Const` kind does propagate the rvalue type to enable ref inference through context variables
72
73 -### Event Handler Inference
74 -When `enableInferEventHandlers` is enabled, JSX props starting with "on" (e.g., `onClick`) on built-in DOM elements (excluding web components with hyphens) are inferred as `Function<BuiltInEventHandlerId>`.
75 -
73 ## TODOs
74 1. **Hook vs Function type ambiguity**:
75 > "TODO: callee could be a hook or a function, so this type equation isn't correct. We should change Hook to a subtype of Function or change unifier logic."
compiler/packages/babel-plugin-react-compiler/docs/passes/31-codegenReactiveFunction.md
-3
@@ -205,8 +205,6 @@ if ($[0] !== "source_hash_abc123") {
205 }
206 ```
207
208 -### Change Detection for Debugging
209 -When `enableChangeDetectionForDebugging` is configured, additional code is generated to detect when cached values unexpectedly change.
208
209 ### Labeled Breaks
210 Control flow with labeled breaks (for early returns or loop exits) uses `codegenLabel` to generate consistent label names:
@@ -231,7 +229,6 @@ type CodegenFunction = {
229 prunedMemoBlocks: number; // Scopes that were pruned
230 prunedMemoValues: number; // Values in pruned scopes
231 hasInferredEffect: boolean;
234 - hasFireRewrite: boolean;
232 };
233 ```
234
compiler/packages/babel-plugin-react-compiler/docs/passes/32-transformFire.md deleted
-203
@@ -1,203 +0,0 @@
1 -# transformFire
2 -
3 -## File
4 -`src/Transform/TransformFire.ts`
5 -
6 -## Purpose
7 -This pass transforms `fire(fn())` calls inside `useEffect` lambdas into calls to a `useFire` hook that provides stable function references. The `fire()` function is a React API that allows effect callbacks to call functions with their current values while maintaining stable effect dependencies.
8 -
9 -Without this transform, if an effect depends on a function that changes every render, the effect would re-run on every render. The `useFire` hook provides a stable wrapper that always calls the latest version of the function.
10 -
11 -## Input Invariants
12 -- The `enableFire` feature flag must be enabled
13 -- `fire()` calls must only appear inside `useEffect` lambdas
14 -- Each `fire()` call must have exactly one argument (a function call expression)
15 -- The function being fired must be consistent across all `fire()` calls in the same effect
16 -
17 -## Output Guarantees
18 -- All `fire(fn(...args))` calls are replaced with direct calls `fired_fn(...args)`
19 -- A `useFire(fn)` hook call is inserted before the `useEffect`
20 -- The fired function is stored in a temporary and captured by the effect
21 -- The original function `fn` is removed from the effect's captured context
22 -
23 -## Algorithm
24 -
25 -### Phase 1: Find Fire Calls
26 -```typescript
27 -function replaceFireFunctions(fn: HIRFunction, context: Context): void {
28 - // For each useEffect call instruction:
29 - // 1. Find all fire() calls in the effect lambda
30 - // 2. Validate they have proper arguments
31 - // 3. Track which functions are being fired
32 -
33 - for (const [, block] of fn.body.blocks) {
34 - for (const instr of block.instructions) {
35 - if (isUseEffectCall(instr)) {
36 - const lambda = getEffectLambda(instr);
37 - findAndReplaceFireCalls(lambda, fireFunctions);
38 - }
39 - }
40 - }
41 -}
42 -```
43 -
44 -### Phase 2: Insert useFire Hooks
45 -For each function being fired, insert a `useFire` call:
46 -```typescript
47 -// Before:
48 -useEffect(() => {
49 - fire(foo(props));
50 -}, [foo, props]);
51 -
52 -// After:
53 -const t0 = useFire(foo);
54 -useEffect(() => {
55 - t0(props);
56 -}, [t0, props]);
57 -```
58 -
59 -### Phase 3: Replace Fire Calls
60 -Transform `fire(fn(...args))` to `firedFn(...args)`:
61 -```typescript
62 -// The fire() wrapper is removed
63 -// The inner function call uses the useFire'd version
64 -fire(foo(x, y)) → t0(x, y) // where t0 = useFire(foo)
65 -```
66 -
67 -### Phase 4: Validate No Remaining Fire Uses
68 -```typescript
69 -function ensureNoMoreFireUses(fn: HIRFunction, context: Context): void {
70 - // Ensure all fire() uses have been transformed
71 - // Report errors for any remaining fire() calls
72 -}
73 -```
74 -
75 -## Edge Cases
76 -
77 -### Fire Outside Effect
78 -`fire()` calls outside `useEffect` lambdas cause a validation error:
79 -```javascript
80 -// ERROR: fire() can only be used inside useEffect
81 -function Component() {
82 - fire(callback());
83 -}
84 -```
85 -
86 -### Mixed Fire and Non-Fire Calls
87 -All calls to the same function must either all use `fire()` or none:
88 -```javascript
89 -// ERROR: Cannot mix fire() and non-fire calls
90 -useEffect(() => {
91 - fire(foo(x));
92 - foo(y); // Error: foo is used with and without fire()
93 -});
94 -```
95 -
96 -### Multiple Arguments to Fire
97 -`fire()` accepts exactly one argument (the function call):
98 -```javascript
99 -// ERROR: fire() takes exactly one argument
100 -fire(foo, bar) // Invalid
101 -fire() // Invalid
102 -```
103 -
104 -### Nested Effects
105 -Fire calls in nested effects are validated separately:
106 -```javascript
107 -useEffect(() => {
108 - useEffect(() => { // Error: nested effects not allowed
109 - fire(foo());
110 - });
111 -});
112 -```
113 -
114 -### Deep Scope Handling
115 -The pass handles fire calls within deeply nested scopes inside effects:
116 -```javascript
117 -useEffect(() => {
118 - if (cond) {
119 - while (x) {
120 - fire(foo(x)); // Still transformed correctly
121 - }
122 - }
123 -});
124 -```
125 -
126 -## TODOs
127 -None in the source file.
128 -
129 -## Example
130 -
131 -### Fixture: `transform-fire/basic.js`
132 -
133 -**Input:**
134 -```javascript
135 -// @enableFire
136 -function Component(props) {
137 - const foo = (props_0) => {
138 - console.log(props_0);
139 - };
140 - useEffect(() => {
141 - fire(foo(props));
142 - });
143 - return null;
144 -}
145 -```
146 -
147 -**After TransformFire:**
148 -```
149 -bb0 (block):
150 - [1] $25 = Function @context[] ... // foo definition
151 - [2] StoreLocal Const foo$32 = $25
152 - [3] $45 = LoadGlobal import { useFire } from 'react/compiler-runtime'
153 - [4] $46 = LoadLocal foo$32
154 - [5] $47 = Call $45($46) // useFire(foo)
155 - [6] StoreLocal Const #t44$44 = $47
156 - [7] $34 = LoadGlobal(global) useEffect
157 - [8] $35 = Function @context[#t44$44, props$24] ...
158 - <<anonymous>>():
159 - [1] $37 = LoadLocal #t44$44 // Load the fired function
160 - [2] $38 = LoadLocal props$24
161 - [3] $39 = Call $37($38) // Call it directly (no fire wrapper)
162 - [4] Return Void
163 - [9] Call $34($35) // useEffect(lambda)
164 - [10] Return null
165 -```
166 -
167 -**Generated Code:**
168 -```javascript
169 -import { useFire as _useFire } from "react/compiler-runtime";
170 -function Component(props) {
171 - const $ = _c(4);
172 - let t0;
173 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
174 - t0 = (props_0) => {
175 - console.log(props_0);
176 - };
177 - $[0] = t0;
178 - } else {
179 - t0 = $[0];
180 - }
181 - const foo = t0;
182 - const t1 = _useFire(foo);
183 - let t2;
184 - if ($[1] !== props || $[2] !== t1) {
185 - t2 = () => {
186 - t1(props);
187 - };
188 - $[1] = props;
189 - $[2] = t1;
190 - $[3] = t2;
191 - } else {
192 - t2 = $[3];
193 - }
194 - useEffect(t2);
195 - return null;
196 -}
197 -```
198 -
199 -Key observations:
200 -- `useFire` is imported from `react/compiler-runtime`
201 -- `fire(foo(props))` becomes `t1(props)` where `t1 = _useFire(foo)`
202 -- The effect now depends on `t1` (stable) and `props` (reactive)
203 -- The original `foo` function is memoized and passed to `useFire`
compiler/packages/babel-plugin-react-compiler/docs/passes/33-lowerContextAccess.md deleted
-174
@@ -1,174 +0,0 @@
1 -# lowerContextAccess
2 -
3 -## File
4 -`src/Optimization/LowerContextAccess.ts`
5 -
6 -## Purpose
7 -This pass optimizes `useContext` calls by generating selector functions that extract only the needed properties from the context. Instead of subscribing to the entire context object, components can subscribe to specific slices, enabling more granular re-rendering.
8 -
9 -When a component destructures specific properties from a context, this pass transforms the `useContext` call to use a selector-based API that only triggers re-renders when the selected properties change.
10 -
11 -## Input Invariants
12 -- The `lowerContextAccess` configuration must be set with:
13 - - `source`: The module to import the lowered context hook from
14 - - `importSpecifierName`: The name of the hook function
15 -- The function must use `useContext` with destructuring patterns
16 -- Only object destructuring patterns with identifier values are supported
17 -
18 -## Output Guarantees
19 -- `useContext(Ctx)` calls with destructuring are replaced with selector calls
20 -- A selector function is generated that extracts the needed properties
21 -- The return type is changed from object to array for positional access
22 -- Unused original `useContext` calls are removed by dead code elimination
23 -
24 -## Algorithm
25 -
26 -### Phase 1: Collect Context Access Patterns
27 -```typescript
28 -function lowerContextAccess(fn: HIRFunction, config: ExternalFunction): void {
29 - const contextAccess: Map<IdentifierId, CallExpression> = new Map();
30 - const contextKeys: Map<IdentifierId, Array<string>> = new Map();
31 -
32 - for (const [, block] of fn.body.blocks) {
33 - for (const instr of block.instructions) {
34 - // Find useContext calls
35 - if (isUseContextCall(instr)) {
36 - contextAccess.set(instr.lvalue.identifier.id, instr.value);
37 - }
38 -
39 - // Find destructuring patterns that access context results
40 - if (isDestructure(instr) && contextAccess.has(instr.value.value.id)) {
41 - const keys = extractPropertyKeys(instr.value.pattern);
42 - contextKeys.set(instr.value.value.id, keys);
43 - }
44 - }
45 - }
46 -}
47 -```
48 -
49 -### Phase 2: Generate Selector Functions
50 -For each context access with known keys:
51 -```typescript
52 -// Original:
53 -const {foo, bar} = useContext(MyContext);
54 -
55 -// Selector function generated:
56 -(ctx) => [ctx.foo, ctx.bar]
57 -```
58 -
59 -### Phase 3: Transform Context Calls
60 -```typescript
61 -// Before:
62 -$0 = useContext(MyContext)
63 -{foo, bar} = $0
64 -
65 -// After:
66 -$0 = useContext_withSelector(MyContext, (ctx) => [ctx.foo, ctx.bar])
67 -[foo, bar] = $0
68 -```
69 -
70 -### Phase 4: Update Destructuring
71 -Change object destructuring to array destructuring to match selector return:
72 -```typescript
73 -// Before: { foo: foo$15, bar: bar$16 } = $14
74 -// After: [ foo$15, bar$16 ] = $14
75 -```
76 -
77 -## Edge Cases
78 -
79 -### Dynamic Property Access
80 -If context properties are accessed dynamically (not through destructuring), the optimization is skipped:
81 -```javascript
82 -const ctx = useContext(MyContext);
83 -const x = ctx[dynamicKey]; // Cannot optimize
84 -```
85 -
86 -### Spread in Destructuring
87 -Spread patterns prevent optimization:
88 -```javascript
89 -const {foo, ...rest} = useContext(MyContext); // Cannot optimize
90 -```
91 -
92 -### Non-Identifier Values
93 -Only simple identifier destructuring is supported:
94 -```javascript
95 -const {foo: bar} = useContext(MyContext); // Supported (rename)
96 -const {foo = defaultVal} = useContext(MyContext); // Not supported
97 -```
98 -
99 -### Multiple Context Accesses
100 -Each `useContext` call is transformed independently:
101 -```javascript
102 -const {a} = useContext(CtxA); // Transformed
103 -const {b} = useContext(CtxB); // Transformed separately
104 -```
105 -
106 -### Hook Guards
107 -When `enableEmitHookGuards` is enabled, the selector function includes proper hook guard annotations.
108 -
109 -## TODOs
110 -None in the source file.
111 -
112 -## Example
113 -
114 -### Fixture: `lower-context-selector-simple.js`
115 -
116 -**Input:**
117 -```javascript
118 -// @lowerContextAccess
119 -function App() {
120 - const {foo, bar} = useContext(MyContext);
121 - return <Bar foo={foo} bar={bar} />;
122 -}
123 -```
124 -
125 -**After OptimizePropsMethodCalls (where lowering happens):**
126 -```
127 -bb0 (block):
128 - [1] $12 = LoadGlobal(global) useContext // Original (now unused)
129 - [2] $13 = LoadGlobal(global) MyContext
130 - [3] $22 = LoadGlobal import { useContext_withSelector } from 'react-compiler-runtime'
131 - [4] $36 = Function @context[]
132 - <<anonymous>>(#t23$30):
133 - [1] $31 = LoadLocal #t23$30
134 - [2] $32 = PropertyLoad $31.foo
135 - [3] $33 = LoadLocal #t23$30
136 - [4] $34 = PropertyLoad $33.bar
137 - [5] $35 = Array [$32, $34] // Return [foo, bar]
138 - [6] Return $35
139 - [5] $14 = Call $22($13, $36) // useContext_withSelector(MyContext, selector)
140 - [6] $17 = Destructure Const { foo: foo$15, bar: bar$16 } = $14
141 - ...
142 -```
143 -
144 -**Generated Code:**
145 -```javascript
146 -import { c as _c } from "react/compiler-runtime";
147 -import { useContext_withSelector } from "react-compiler-runtime";
148 -function App() {
149 - const $ = _c(2);
150 - let t0;
151 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
152 - t0 = (ctx) => [ctx.foo, ctx.bar];
153 - $[0] = t0;
154 - } else {
155 - t0 = $[0];
156 - }
157 - const { foo, bar } = useContext_withSelector(MyContext, t0);
158 - let t1;
159 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
160 - t1 = <Bar foo={foo} bar={bar} />;
161 - $[1] = t1;
162 - } else {
163 - t1 = $[1];
164 - }
165 - return t1;
166 -}
167 -```
168 -
169 -Key observations:
170 -- `useContext` is replaced with `useContext_withSelector`
171 -- A selector function `(ctx) => [ctx.foo, ctx.bar]` is generated
172 -- The selector function is memoized (first cache slot)
173 -- Only `foo` and `bar` properties are extracted, enabling granular subscriptions
174 -- The selector return type changes from object to array
compiler/packages/babel-plugin-react-compiler/docs/passes/42-validateNoCapitalizedCalls.md
+1 -13
@@ -49,13 +49,8 @@ const ALLOW_LIST = new Set([
49 ...(envConfig.validateNoCapitalizedCalls ?? []), // User-configured allowlist
50 ]);
51
52 -const hookPattern = envConfig.hookPattern != null
53 - ? new RegExp(envConfig.hookPattern)
54 - : null;
55 -
52 const isAllowed = (name: string): boolean => {
57 - return ALLOW_LIST.has(name) ||
58 - (hookPattern != null && hookPattern.test(name));
53 + return ALLOW_LIST.has(name);
54 };
55 ```
56
@@ -137,13 +132,6 @@ Users can allowlist specific functions via configuration:
132 validateNoCapitalizedCalls: ['MyUtility', 'SomeFactory']
133 ```
134
140 -### Hook Patterns
141 -Functions matching the configured hook pattern are allowed even if capitalized:
142 -```typescript
143 -// With hookPattern: 'React\\$use.*'
144 -const x = React$useState(); // Allowed if it matches the hook pattern
145 -```
146 -
135 ### Method Calls vs Function Calls
136 Both direct function calls and method calls on objects are checked:
137 ```javascript
compiler/packages/babel-plugin-react-compiler/docs/passes/52-validateMemoizedEffectDependencies.md deleted
-93
@@ -1,93 +0,0 @@
1 -# validateMemoizedEffectDependencies
2 -
3 -## File
4 -`src/Validation/ValidateMemoizedEffectDependencies.ts`
5 -
6 -## Purpose
7 -Validates that all known effect dependencies (for `useEffect`, `useLayoutEffect`, and `useInsertionEffect`) are properly memoized. This prevents a common bug where unmemoized effect dependencies can cause infinite re-render loops or other unexpected behavior.
8 -
9 -## Input Invariants
10 -- Operates on ReactiveFunction (post-reactive scope inference)
11 -- Reactive scopes have been assigned to values that need memoization
12 -- Must run after scope inference but before codegen
13 -
14 -## Validation Rules
15 -This pass checks two conditions:
16 -
17 -1. **Unmemoized dependencies with assigned scopes**: Disallows effect dependencies that should be memoized (have a reactive scope assigned) but where that reactive scope does not exist in the output. This catches cases where a reactive scope was pruned, such as when it spans a hook call.
18 -
19 -2. **Mutable dependencies at effect call site**: Disallows effect dependencies whose mutable range encompasses the effect call. This catches values that the compiler knows may be mutated after the effect is set up.
20 -
21 -When either condition is violated, the pass produces:
22 -```
23 -Compilation Skipped: React Compiler has skipped optimizing this component because
24 -the effect dependencies could not be memoized. Unmemoized effect dependencies can
25 -trigger an infinite loop or other unexpected behavior
26 -```
27 -
28 -## Algorithm
29 -1. Traverse the reactive function using a visitor pattern
30 -2. Track all scopes that exist in the AST by adding them to a `Set<ScopeId>` during `visitScope`
31 -3. Only record a scope if its dependencies are also memoized (transitive memoization check)
32 -4. When visiting an instruction that is an effect hook call (`useEffect`, `useLayoutEffect`, `useInsertionEffect`) with at least 2 arguments (function + deps array):
33 - - Check if the dependency array is mutable at the call site using `isMutable()`
34 - - Check if the dependency array's scope exists using `isUnmemoized()`
35 - - If either check fails, push an error
36 -
37 -### Key Helper Functions
38 -
39 -**isEffectHook(identifier)**: Returns true if the identifier is `useEffect`, `useLayoutEffect`, or `useInsertionEffect`.
40 -
41 -**isUnmemoized(operand, scopes)**: Returns true if the operand has a scope assigned (`operand.scope != null`) but that scope doesn't exist in the set of valid scopes.
42 -
43 -## Edge Cases
44 -- Only validates effects with 2+ arguments (ignores effects without dependency arrays)
45 -- Transitive memoization: A scope is only considered valid if all its dependencies are also memoized
46 -- Merged scopes are tracked together with their primary scope
47 -
48 -## TODOs
49 -From the source code:
50 -```typescript
51 -// TODO: isMutable is not safe to call here as it relies on identifier mutableRange
52 -// which is no longer valid at this point in the pipeline
53 -```
54 -
55 -## Example
56 -
57 -### Fixture: `error.invalid-useEffect-dep-not-memoized.js`
58 -
59 -**Input:**
60 -```javascript
61 -// @validateMemoizedEffectDependencies
62 -import {useEffect} from 'react';
63 -
64 -function Component(props) {
65 - const data = {};
66 - useEffect(() => {
67 - console.log(props.value);
68 - }, [data]);
69 - mutate(data);
70 - return data;
71 -}
72 -```
73 -
74 -**Error:**
75 -```
76 -Found 1 error:
77 -
78 -Compilation Skipped: React Compiler has skipped optimizing this component because
79 -the effect dependencies could not be memoized. Unmemoized effect dependencies can
80 -trigger an infinite loop or other unexpected behavior
81 -
82 -error.invalid-useEffect-dep-not-memoized.ts:6:2
83 - 4 | function Component(props) {
84 - 5 | const data = {};
85 -> 6 | useEffect(() => {
86 - | ^^^^^^^^^^^^^^^^^
87 -> 7 | console.log(props.value);
88 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89 -> 8 | }, [data]);
90 - | ^^^^^^^^^^^^^
91 -```
92 -
93 -**Why it fails:** The `data` object is mutated after the `useEffect` call, which extends its mutable range past the effect. This means `data` cannot be safely memoized as an effect dependency because it might change after the effect is set up.
compiler/packages/babel-plugin-react-compiler/docs/passes/README.md
+1 -6
@@ -25,7 +25,7 @@ This directory contains detailed documentation for each pass in the React Compil
25 ┌─────────────────────────────────────────────────────────────────────────────────────┐
26 │ PHASE 2: OPTIMIZATION │
27 │ │
28 -│ constantPropagation ──▶ deadCodeElimination ──▶ instructionReordering │
28 +│ constantPropagation ──▶ deadCodeElimination │
29 │ │
30 └─────────────────────────────────────────────────────────────────────────────────────┘
31
@@ -195,8 +195,6 @@ This directory contains detailed documentation for each pass in the React Compil
195
196 | # | Pass | File | Description |
197 |---|------|------|-------------|
198 -| 32 | [transformFire](32-transformFire.md) | `Transform/TransformFire.ts` | Transform `fire()` calls in effects |
199 -| 33 | [lowerContextAccess](33-lowerContextAccess.md) | `Optimization/LowerContextAccess.ts` | Optimize context access with selectors |
198 | 34 | [optimizePropsMethodCalls](34-optimizePropsMethodCalls.md) | `Optimization/OptimizePropsMethodCalls.ts` | Normalize props method calls |
199 | 35 | [optimizeForSSR](35-optimizeForSSR.md) | `Optimization/OptimizeForSSR.ts` | SSR-specific optimizations |
200 | 36 | [outlineJSX](36-outlineJSX.md) | `Optimization/OutlineJsx.ts` | Outline JSX to components |
@@ -220,7 +218,6 @@ This directory contains detailed documentation for each pass in the React Compil
218 | 49 | [validateNoRefAccessInRender](49-validateNoRefAccessInRender.md) | `Validation/ValidateNoRefAccessInRender.ts` | Ref access constraints |
219 | 50 | [validateNoFreezingKnownMutableFunctions](50-validateNoFreezingKnownMutableFunctions.md) | `Validation/ValidateNoFreezingKnownMutableFunctions.ts` | Mutable function isolation |
220 | 51 | [validateExhaustiveDependencies](51-validateExhaustiveDependencies.md) | `Validation/ValidateExhaustiveDependencies.ts` | Dependency array completeness |
223 -| 52 | [validateMemoizedEffectDependencies](52-validateMemoizedEffectDependencies.md) | `Validation/ValidateMemoizedEffectDependencies.ts` | Effect scope memoization |
221 | 53 | [validatePreservedManualMemoization](53-validatePreservedManualMemoization.md) | `Validation/ValidatePreservedManualMemoization.ts` | Manual memo preservation |
222 | 54 | [validateStaticComponents](54-validateStaticComponents.md) | `Validation/ValidateStaticComponents.ts` | Component identity stability |
223 | 55 | [validateSourceLocations](55-validateSourceLocations.md) | `Validation/ValidateSourceLocations.ts` | Source location preservation |
@@ -275,8 +272,6 @@ Many passes are controlled by feature flags in `Environment.ts`:
272
273 | Flag | Enables Pass |
274 |------|--------------|
278 -| `enableFire` | transformFire |
279 -| `lowerContextAccess` | lowerContextAccess |
275 | `enableJsxOutlining` | outlineJSX |
276 | `enableFunctionOutlining` | outlineFunctions |
277 | `validateNoSetStateInRender` | validateNoSetStateInRender |
compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts
-45
@@ -565,15 +565,12 @@ function printCodeFrame(
565 function printErrorSummary(category: ErrorCategory, message: string): string {
566 let heading: string;
567 switch (category) {
568 - case ErrorCategory.AutomaticEffectDependencies:
568 case ErrorCategory.CapitalizedCalls:
569 case ErrorCategory.Config:
570 case ErrorCategory.EffectDerivationsOfState:
571 case ErrorCategory.EffectSetState:
572 case ErrorCategory.ErrorBoundaries:
574 - case ErrorCategory.Factories:
573 case ErrorCategory.FBT:
576 - case ErrorCategory.Fire:
574 case ErrorCategory.Gating:
575 case ErrorCategory.Globals:
576 case ErrorCategory.Hooks:
@@ -637,10 +634,6 @@ export enum ErrorCategory {
634 * Checking that useMemos always return a value
635 */
636 VoidUseMemo = 'VoidUseMemo',
640 - /**
641 - * Checking for higher order functions acting as factories for components/hooks
642 - */
643 - Factories = 'Factories',
637 /**
638 * Checks that manual memoization is preserved
639 */
@@ -718,14 +711,6 @@ export enum ErrorCategory {
711 * Suppressions
712 */
713 Suppression = 'Suppression',
721 - /**
722 - * Issues with auto deps
723 - */
724 - AutomaticEffectDependencies = 'AutomaticEffectDependencies',
725 - /**
726 - * Issues with `fire`
727 - */
728 - Fire = 'Fire',
714 /**
715 * fbt-specific issues
716 */
@@ -790,16 +775,6 @@ export function getRuleForCategory(category: ErrorCategory): LintRule {
775
776 function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
777 switch (category) {
793 - case ErrorCategory.AutomaticEffectDependencies: {
794 - return {
795 - category,
796 - severity: ErrorSeverity.Error,
797 - name: 'automatic-effect-dependencies',
798 - description:
799 - 'Verifies that automatic effect dependencies are compiled if opted-in',
800 - preset: LintRulePreset.Off,
801 - };
802 - }
778 case ErrorCategory.CapitalizedCalls: {
779 return {
780 category,
@@ -870,17 +845,6 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
845 preset: LintRulePreset.Recommended,
846 };
847 }
873 - case ErrorCategory.Factories: {
874 - return {
875 - category,
876 - severity: ErrorSeverity.Error,
877 - name: 'component-hook-factories',
878 - description:
879 - 'Validates against higher order functions defining nested components or hooks. ' +
880 - 'Components and hooks should be defined at the module level',
881 - preset: LintRulePreset.Recommended,
882 - };
883 - }
848 case ErrorCategory.FBT: {
849 return {
850 category,
@@ -890,15 +854,6 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
854 preset: LintRulePreset.Off,
855 };
856 }
893 - case ErrorCategory.Fire: {
894 - return {
895 - category,
896 - severity: ErrorSeverity.Error,
897 - name: 'fire',
898 - description: 'Validates usage of `fire`',
899 - preset: LintRulePreset.Off,
900 - };
901 - }
857 case ErrorCategory.Gating: {
858 return {
859 category,
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts
+1 -9
@@ -88,7 +88,6 @@ export class ProgramContext {
88 * Metadata from compilation
89 */
90 retryErrors: Array<{fn: BabelFn; error: CompilerError}> = [];
91 - inferredEffectLocations: Set<t.SourceLocation> = new Set();
91
92 constructor({
93 program,
@@ -108,14 +107,7 @@ export class ProgramContext {
107 }
108
109 isHookName(name: string): boolean {
111 - if (this.opts.environment.hookPattern == null) {
112 - return isHookName(name);
113 - } else {
114 - const match = new RegExp(this.opts.environment.hookPattern).exec(name);
115 - return (
116 - match != null && typeof match[1] === 'string' && isHookName(match[1])
117 - );
118 - }
110 + return isHookName(name);
111 }
112
113 hasReference(name: string): boolean {
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts
+1 -14
@@ -255,9 +255,7 @@ export type LoggerEvent =
255 | CompileDiagnosticEvent
256 | CompileSkipEvent
257 | PipelineErrorEvent
258 - | TimingEvent
259 - | AutoDepsDecorationsEvent
260 - | AutoDepsEligibleEvent;
258 + | TimingEvent;
259
260 export type CompileErrorEvent = {
261 kind: 'CompileError';
@@ -294,17 +292,6 @@ export type TimingEvent = {
292 kind: 'Timing';
293 measurement: PerformanceMeasure;
294 };
297 -export type AutoDepsDecorationsEvent = {
298 - kind: 'AutoDepsDecorations';
299 - fnLoc: t.SourceLocation;
300 - decorations: Array<t.SourceLocation>;
301 -};
302 -export type AutoDepsEligibleEvent = {
303 - kind: 'AutoDepsEligible';
304 - fnLoc: t.SourceLocation;
305 - depArrayLoc: t.SourceLocation;
306 -};
307 -
295 export type Logger = {
296 logEvent: (filename: string | null, event: LoggerEvent) => void;
297 debugLogIRs?: (value: CompilerPipelineValue) => void;
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+1 -59
@@ -34,15 +34,12 @@ import {
34 dropManualMemoization,
35 inferReactivePlaces,
36 inlineImmediatelyInvokedFunctionExpressions,
37 - inferEffectDependencies,
37 } from '../Inference';
38 import {
39 constantPropagation,
40 deadCodeElimination,
41 pruneMaybeThrows,
43 - inlineJsxTransform,
42 } from '../Optimization';
45 -import {instructionReordering} from '../Optimization/InstructionReordering';
43 import {
44 CodegenFunction,
45 alignObjectMethodScopes,
@@ -69,7 +66,6 @@ import {alignReactiveScopesToBlockScopesHIR} from '../ReactiveScopes/AlignReacti
66 import {flattenReactiveLoopsHIR} from '../ReactiveScopes/FlattenReactiveLoopsHIR';
67 import {flattenScopesWithHooksOrUseHIR} from '../ReactiveScopes/FlattenScopesWithHooksOrUseHIR';
68 import {pruneAlwaysInvalidatingScopes} from '../ReactiveScopes/PruneAlwaysInvalidatingScopes';
72 -import pruneInitializationDependencies from '../ReactiveScopes/PruneInitializationDependencies';
69 import {stabilizeBlockIds} from '../ReactiveScopes/StabilizeBlockIds';
70 import {
71 eliminateRedundantPhi,
@@ -80,7 +76,6 @@ import {inferTypes} from '../TypeInference';
76 import {
77 validateContextVariableLValues,
78 validateHooksUsage,
83 - validateMemoizedEffectDependencies,
79 validateNoCapitalizedCalls,
80 validateNoRefAccessInRender,
81 validateNoSetStateInRender,
@@ -89,13 +84,11 @@ import {
84 } from '../Validation';
85 import {validateLocalsNotReassignedAfterRender} from '../Validation/ValidateLocalsNotReassignedAfterRender';
86 import {outlineFunctions} from '../Optimization/OutlineFunctions';
92 -import {lowerContextAccess} from '../Optimization/LowerContextAccess';
87 import {validateNoSetStateInEffects} from '../Validation/ValidateNoSetStateInEffects';
88 import {validateNoJSXInTryStatement} from '../Validation/ValidateNoJSXInTryStatement';
89 import {propagateScopeDependenciesHIR} from '../HIR/PropagateScopeDependenciesHIR';
90 import {outlineJSX} from '../Optimization/OutlineJsx';
91 import {optimizePropsMethodCalls} from '../Optimization/OptimizePropsMethodCalls';
98 -import {transformFire} from '../Transform';
92 import {validateNoImpureFunctionsInRender} from '../Validation/ValidateNoImpureFunctionsInRender';
93 import {validateStaticComponents} from '../Validation/ValidateStaticComponents';
94 import {validateNoFreezingKnownMutableFunctions} from '../Validation/ValidateNoFreezingKnownMutableFunctions';
@@ -169,12 +162,7 @@ function runWithEnvironment(
162 validateContextVariableLValues(hir);
163 validateUseMemo(hir).unwrap();
164
172 - if (
173 - env.enableDropManualMemoization &&
174 - !env.config.enablePreserveExistingManualUseMemo &&
175 - !env.config.disableMemoizationForDebugging &&
176 - !env.config.enableChangeDetectionForDebugging
177 - ) {
165 + if (env.enableDropManualMemoization) {
166 dropManualMemoization(hir).unwrap();
167 log({kind: 'hir', name: 'DropManualMemoization', value: hir});
168 }
@@ -215,15 +203,6 @@ function runWithEnvironment(
203 }
204 }
205
218 - if (env.config.enableFire) {
219 - transformFire(hir);
220 - log({kind: 'hir', name: 'TransformFire', value: hir});
221 - }
222 -
223 - if (env.config.lowerContextAccess) {
224 - lowerContextAccess(hir, env.config.lowerContextAccess);
225 - }
226 -
206 optimizePropsMethodCalls(hir);
207 log({kind: 'hir', name: 'OptimizePropsMethodCalls', value: hir});
208
@@ -246,12 +225,6 @@ function runWithEnvironment(
225 // Note: Has to come after infer reference effects because "dead" code may still affect inference
226 deadCodeElimination(hir);
227 log({kind: 'hir', name: 'DeadCodeElimination', value: hir});
249 -
250 - if (env.config.enableInstructionReordering) {
251 - instructionReordering(hir);
252 - log({kind: 'hir', name: 'InstructionReordering', value: hir});
253 - }
254 -
228 pruneMaybeThrows(hir);
229 log({kind: 'hir', name: 'PruneMaybeThrows', value: hir});
230
@@ -433,24 +406,6 @@ function runWithEnvironment(
406 value: hir,
407 });
408
436 - if (env.config.inferEffectDependencies) {
437 - inferEffectDependencies(hir);
438 - log({
439 - kind: 'hir',
440 - name: 'InferEffectDependencies',
441 - value: hir,
442 - });
443 - }
444 -
445 - if (env.config.inlineJsxTransform) {
446 - inlineJsxTransform(hir, env.config.inlineJsxTransform);
447 - log({
448 - kind: 'hir',
449 - name: 'inlineJsxTransform',
450 - value: hir,
451 - });
452 - }
453 -
409 const reactiveFunction = buildReactiveFunction(hir);
410 log({
411 kind: 'reactive',
@@ -503,15 +458,6 @@ function runWithEnvironment(
458 value: reactiveFunction,
459 });
460
506 - if (env.config.enableChangeDetectionForDebugging != null) {
507 - pruneInitializationDependencies(reactiveFunction);
508 - log({
509 - kind: 'reactive',
510 - name: 'PruneInitializationDependencies',
511 - value: reactiveFunction,
512 - });
513 - }
514 -
461 propagateEarlyReturns(reactiveFunction);
462 log({
463 kind: 'reactive',
@@ -561,10 +507,6 @@ function runWithEnvironment(
507 value: reactiveFunction,
508 });
509
564 - if (env.config.validateMemoizedEffectDependencies) {
565 - validateMemoizedEffectDependencies(reactiveFunction).unwrap();
566 - }
567 -
510 if (
511 env.config.enablePreserveExistingMemoizationGuarantees ||
512 env.config.validatePreserveExistingMemoizationGuarantees
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
+13 -158
@@ -352,7 +352,6 @@ function isFilePartOfSources(
352
353 export type CompileProgramMetadata = {
354 retryErrors: Array<{fn: BabelFn; error: CompilerError}>;
355 - inferredEffectLocations: Set<t.SourceLocation>;
355 };
356 /**
357 * Main entrypoint for React Compiler.
@@ -487,7 +486,6 @@ export function compileProgram(
486
487 return {
488 retryErrors: programContext.retryErrors,
490 - inferredEffectLocations: programContext.inferredEffectLocations,
489 };
490 }
491
@@ -518,10 +516,6 @@ function findFunctionsToCompile(
516
517 const fnType = getReactFunctionType(fn, pass);
518
521 - if (pass.opts.environment.validateNoDynamicallyCreatedComponentsOrHooks) {
522 - validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext);
523 - }
524 -
519 if (fnType === null || programContext.alreadyCompiled.has(fn.node)) {
520 return;
521 }
@@ -633,15 +627,7 @@ function processFn(
627 } else {
628 handleError(compileResult.error, programContext, fn.node.loc ?? null);
629 }
636 - if (outputMode === 'client') {
637 - const retryResult = retryCompileFunction(fn, fnType, programContext);
638 - if (retryResult == null) {
639 - return null;
640 - }
641 - compiledFn = retryResult;
642 - } else {
643 - return null;
644 - }
630 + return null;
631 } else {
632 compiledFn = compileResult.compiledFn;
633 }
@@ -678,16 +664,6 @@ function processFn(
664 if (programContext.hasModuleScopeOptOut) {
665 return null;
666 } else if (programContext.opts.outputMode === 'lint') {
681 - /**
682 - * inferEffectDependencies + noEmit is currently only used for linting. In
683 - * this mode, add source locations for where the compiler *can* infer effect
684 - * dependencies.
685 - */
686 - for (const loc of compiledFn.inferredEffectLocations) {
687 - if (loc !== GeneratedSource) {
688 - programContext.inferredEffectLocations.add(loc);
689 - }
690 - }
667 return null;
668 } else if (
669 programContext.opts.compilationMode === 'annotation' &&
@@ -746,52 +722,6 @@ function tryCompileFunction(
722 }
723 }
724
749 -/**
750 - * If non-memo feature flags are enabled, retry compilation with a more minimal
751 - * feature set.
752 - *
753 - * @returns a CodegenFunction if retry was successful
754 - */
755 -function retryCompileFunction(
756 - fn: BabelFn,
757 - fnType: ReactFunctionType,
758 - programContext: ProgramContext,
759 -): CodegenFunction | null {
760 - const environment = programContext.opts.environment;
761 - if (
762 - !(environment.enableFire || environment.inferEffectDependencies != null)
763 - ) {
764 - return null;
765 - }
766 - /**
767 - * Note that function suppressions are not checked in the retry pipeline, as
768 - * they only affect auto-memoization features.
769 - */
770 - try {
771 - const retryResult = compileFn(
772 - fn,
773 - environment,
774 - fnType,
775 - 'client-no-memo',
776 - programContext,
777 - programContext.opts.logger,
778 - programContext.filename,
779 - programContext.code,
780 - );
781 -
782 - if (!retryResult.hasFireRewrite && !retryResult.hasInferredEffect) {
783 - return null;
784 - }
785 - return retryResult;
786 - } catch (err) {
787 - // TODO: we might want to log error here, but this will also result in duplicate logging
788 - if (err instanceof CompilerError) {
789 - programContext.retryErrors.push({fn, error: err});
790 - }
791 - return null;
792 - }
793 -}
794 -
725 /**
726 * Applies React Compiler generated functions to the babel AST by replacing
727 * existing functions in place or inserting new declarations.
@@ -876,84 +806,17 @@ function shouldSkipCompilation(
806 return false;
807 }
808
879 -/**
880 - * Validates that Components/Hooks are always defined at module level. This prevents scope reference
881 - * errors that occur when the compiler attempts to optimize the nested component/hook while its
882 - * parent function remains uncompiled.
883 - */
884 -function validateNoDynamicallyCreatedComponentsOrHooks(
885 - fn: BabelFn,
886 - pass: CompilerPass,
887 - programContext: ProgramContext,
888 -): void {
889 - const parentNameExpr = getFunctionName(fn);
890 - const parentName =
891 - parentNameExpr !== null && parentNameExpr.isIdentifier()
892 - ? parentNameExpr.node.name
893 - : '<anonymous>';
894 -
895 - const validateNestedFunction = (
896 - nestedFn: NodePath<
897 - t.FunctionDeclaration | t.FunctionExpression | t.ArrowFunctionExpression
898 - >,
899 - ): void => {
900 - if (
901 - nestedFn.node === fn.node ||
902 - programContext.alreadyCompiled.has(nestedFn.node)
903 - ) {
904 - return;
905 - }
906 -
907 - if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
908 - const nestedFnType = getReactFunctionType(nestedFn as BabelFn, pass);
909 - const nestedFnNameExpr = getFunctionName(nestedFn as BabelFn);
910 - const nestedName =
911 - nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
912 - ? nestedFnNameExpr.node.name
913 - : '<anonymous>';
914 - if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
915 - CompilerError.throwDiagnostic({
916 - category: ErrorCategory.Factories,
917 - reason: `Components and hooks cannot be created dynamically`,
918 - description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
919 - details: [
920 - {
921 - kind: 'error',
922 - message: 'this function dynamically created a component/hook',
923 - loc: parentNameExpr?.node.loc ?? fn.node.loc ?? null,
924 - },
925 - {
926 - kind: 'error',
927 - message: 'the component is created here',
928 - loc: nestedFnNameExpr?.node.loc ?? nestedFn.node.loc ?? null,
929 - },
930 - ],
931 - });
932 - }
933 - }
934 -
935 - nestedFn.skip();
936 - };
937 -
938 - fn.traverse({
939 - FunctionDeclaration: validateNestedFunction,
940 - FunctionExpression: validateNestedFunction,
941 - ArrowFunctionExpression: validateNestedFunction,
942 - });
943 -}
944 -
809 function getReactFunctionType(
810 fn: BabelFn,
811 pass: CompilerPass,
812 ): ReactFunctionType | null {
949 - const hookPattern = pass.opts.environment.hookPattern;
813 if (fn.node.body.type === 'BlockStatement') {
814 const optInDirectives = tryFindDirectiveEnablingMemoization(
815 fn.node.body.directives,
816 pass.opts,
817 );
818 if (optInDirectives.unwrapOr(null) != null) {
956 - return getComponentOrHookLike(fn, hookPattern) ?? 'Other';
819 + return getComponentOrHookLike(fn) ?? 'Other';
820 }
821 }
822
@@ -974,13 +837,13 @@ function getReactFunctionType(
837 }
838 case 'infer': {
839 // Check if this is a component or hook-like function
977 - return componentSyntaxType ?? getComponentOrHookLike(fn, hookPattern);
840 + return componentSyntaxType ?? getComponentOrHookLike(fn);
841 }
842 case 'syntax': {
843 return componentSyntaxType;
844 }
845 case 'all': {
983 - return getComponentOrHookLike(fn, hookPattern) ?? 'Other';
846 + return getComponentOrHookLike(fn) ?? 'Other';
847 }
848 default: {
849 assertExhaustive(
@@ -1022,10 +885,7 @@ function hasMemoCacheFunctionImport(
885 return hasUseMemoCache;
886 }
887
1025 -function isHookName(s: string, hookPattern: string | null): boolean {
1026 - if (hookPattern !== null) {
1027 - return new RegExp(hookPattern).test(s);
1028 - }
888 +function isHookName(s: string): boolean {
889 return /^use[A-Z0-9]/.test(s);
890 }
891
@@ -1034,16 +894,13 @@ function isHookName(s: string, hookPattern: string | null): boolean {
894 * containing a hook name.
895 */
896
1037 -function isHook(
1038 - path: NodePath<t.Expression | t.PrivateName>,
1039 - hookPattern: string | null,
1040 -): boolean {
897 +function isHook(path: NodePath<t.Expression | t.PrivateName>): boolean {
898 if (path.isIdentifier()) {
1042 - return isHookName(path.node.name, hookPattern);
899 + return isHookName(path.node.name);
900 } else if (
901 path.isMemberExpression() &&
902 !path.node.computed &&
1046 - isHook(path.get('property'), hookPattern)
903 + isHook(path.get('property'))
904 ) {
905 const obj = path.get('object').node;
906 const isPascalCaseNameSpace = /^[A-Z].*/;
@@ -1184,19 +1041,18 @@ function getComponentOrHookLike(
1041 node: NodePath<
1042 t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
1043 >,
1187 - hookPattern: string | null,
1044 ): ReactFunctionType | null {
1045 const functionName = getFunctionName(node);
1046 // Check if the name is component or hook like:
1047 if (functionName !== null && isComponentName(functionName)) {
1048 let isComponent =
1193 - callsHooksOrCreatesJsx(node, hookPattern) &&
1049 + callsHooksOrCreatesJsx(node) &&
1050 isValidComponentParams(node.get('params')) &&
1051 !returnsNonNode(node);
1052 return isComponent ? 'Component' : null;
1197 - } else if (functionName !== null && isHook(functionName, hookPattern)) {
1053 + } else if (functionName !== null && isHook(functionName)) {
1054 // Hooks have hook invocations or JSX, but can take any # of arguments
1199 - return callsHooksOrCreatesJsx(node, hookPattern) ? 'Hook' : null;
1055 + return callsHooksOrCreatesJsx(node) ? 'Hook' : null;
1056 }
1057
1058 /*
@@ -1206,7 +1062,7 @@ function getComponentOrHookLike(
1062 if (node.isFunctionExpression() || node.isArrowFunctionExpression()) {
1063 if (isForwardRefCallback(node) || isMemoCallback(node)) {
1064 // As an added check we also look for hook invocations or JSX
1209 - return callsHooksOrCreatesJsx(node, hookPattern) ? 'Component' : null;
1065 + return callsHooksOrCreatesJsx(node) ? 'Component' : null;
1066 }
1067 }
1068 return null;
@@ -1232,7 +1088,6 @@ function callsHooksOrCreatesJsx(
1088 node: NodePath<
1089 t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
1090 >,
1235 - hookPattern: string | null,
1091 ): boolean {
1092 let invokesHooks = false;
1093 let createsJsx = false;
@@ -1243,7 +1098,7 @@ function callsHooksOrCreatesJsx(
1098 },
1099 CallExpression(call) {
1100 const callee = call.get('callee');
1246 - if (callee.isExpression() && isHook(callee, hookPattern)) {
1101 + if (callee.isExpression() && isHook(callee)) {
1102 invokesHooks = true;
1103 }
1104 },
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts
+1 -166
@@ -10,137 +10,9 @@ import * as t from '@babel/types';
10
11 import {CompilerError, EnvironmentConfig, Logger} from '..';
12 import {getOrInsertWith} from '../Utils/utils';
13 -import {Environment, GeneratedSource} from '../HIR';
13 +import {GeneratedSource} from '../HIR';
14 import {DEFAULT_EXPORT} from '../HIR/Environment';
15 import {CompileProgramMetadata} from './Program';
16 -import {
17 - CompilerDiagnostic,
18 - CompilerDiagnosticOptions,
19 - ErrorCategory,
20 -} from '../CompilerError';
21 -
22 -function throwInvalidReact(
23 - options: CompilerDiagnosticOptions,
24 - {logger, filename}: TraversalState,
25 -): never {
26 - logger?.logEvent(filename, {
27 - kind: 'CompileError',
28 - fnLoc: null,
29 - detail: new CompilerDiagnostic(options),
30 - });
31 - CompilerError.throwDiagnostic(options);
32 -}
33 -
34 -function isAutodepsSigil(
35 - arg: NodePath<t.ArgumentPlaceholder | t.SpreadElement | t.Expression>,
36 -): boolean {
37 - // Check for AUTODEPS identifier imported from React
38 - if (arg.isIdentifier() && arg.node.name === 'AUTODEPS') {
39 - const binding = arg.scope.getBinding(arg.node.name);
40 - if (binding && binding.path.isImportSpecifier()) {
41 - const importSpecifier = binding.path.node as t.ImportSpecifier;
42 - if (importSpecifier.imported.type === 'Identifier') {
43 - return (importSpecifier.imported as t.Identifier).name === 'AUTODEPS';
44 - }
45 - }
46 - return false;
47 - }
48 -
49 - // Check for React.AUTODEPS member expression
50 - if (arg.isMemberExpression() && !arg.node.computed) {
51 - const object = arg.get('object');
52 - const property = arg.get('property');
53 -
54 - if (
55 - object.isIdentifier() &&
56 - object.node.name === 'React' &&
57 - property.isIdentifier() &&
58 - property.node.name === 'AUTODEPS'
59 - ) {
60 - return true;
61 - }
62 - }
63 -
64 - return false;
65 -}
66 -function assertValidEffectImportReference(
67 - autodepsIndex: number,
68 - paths: Array<NodePath<t.Node>>,
69 - context: TraversalState,
70 -): void {
71 - for (const path of paths) {
72 - const parent = path.parentPath;
73 - if (parent != null && parent.isCallExpression()) {
74 - const args = parent.get('arguments');
75 - const maybeCalleeLoc = path.node.loc;
76 - const hasInferredEffect =
77 - maybeCalleeLoc != null &&
78 - context.inferredEffectLocations.has(maybeCalleeLoc);
79 - /**
80 - * Error on effect calls that still have AUTODEPS in their args
81 - */
82 - const hasAutodepsArg = args.some(isAutodepsSigil);
83 - if (hasAutodepsArg && !hasInferredEffect) {
84 - const maybeErrorDiagnostic = matchCompilerDiagnostic(
85 - path,
86 - context.transformErrors,
87 - );
88 - /**
89 - * Note that we cannot easily check the type of the first argument here,
90 - * as it may have already been transformed by the compiler (and not
91 - * memoized).
92 - */
93 - throwInvalidReact(
94 - {
95 - category: ErrorCategory.AutomaticEffectDependencies,
96 - reason:
97 - 'Cannot infer dependencies of this effect. This will break your build!',
98 - description:
99 - 'To resolve, either pass a dependency array or fix reported compiler bailout diagnostics' +
100 - (maybeErrorDiagnostic ? ` ${maybeErrorDiagnostic}` : ''),
101 - details: [
102 - {
103 - kind: 'error',
104 - message: 'Cannot infer dependencies',
105 - loc: parent.node.loc ?? GeneratedSource,
106 - },
107 - ],
108 - },
109 - context,
110 - );
111 - }
112 - }
113 - }
114 -}
115 -
116 -function assertValidFireImportReference(
117 - paths: Array<NodePath<t.Node>>,
118 - context: TraversalState,
119 -): void {
120 - if (paths.length > 0) {
121 - const maybeErrorDiagnostic = matchCompilerDiagnostic(
122 - paths[0],
123 - context.transformErrors,
124 - );
125 - throwInvalidReact(
126 - {
127 - category: ErrorCategory.Fire,
128 - reason: '[Fire] Untransformed reference to compiler-required feature.',
129 - description:
130 - 'Either remove this `fire` call or ensure it is successfully transformed by the compiler' +
131 - (maybeErrorDiagnostic != null ? ` ${maybeErrorDiagnostic}` : ''),
132 - details: [
133 - {
134 - kind: 'error',
135 - message: 'Untransformed `fire` call',
136 - loc: paths[0].node.loc ?? GeneratedSource,
137 - },
138 - ],
139 - },
140 - context,
141 - );
142 - }
143 -}
16 export default function validateNoUntransformedReferences(
17 path: NodePath<t.Program>,
18 filename: string | null,
@@ -152,28 +24,6 @@ export default function validateNoUntransformedReferences(
24 string,
25 Map<string, CheckInvalidReferenceFn>
26 >();
155 - if (env.enableFire) {
156 - /**
157 - * Error on any untransformed references to `fire` (e.g. including non-call
158 - * expressions)
159 - */
160 - for (const module of Environment.knownReactModules) {
161 - const react = getOrInsertWith(moduleLoadChecks, module, () => new Map());
162 - react.set('fire', assertValidFireImportReference);
163 - }
164 - }
165 - if (env.inferEffectDependencies) {
166 - for (const {
167 - function: {source, importSpecifierName},
168 - autodepsIndex,
169 - } of env.inferEffectDependencies) {
170 - const module = getOrInsertWith(moduleLoadChecks, source, () => new Map());
171 - module.set(
172 - importSpecifierName,
173 - assertValidEffectImportReference.bind(null, autodepsIndex),
174 - );
175 - }
176 - }
27 if (moduleLoadChecks.size > 0) {
28 transformProgram(path, moduleLoadChecks, filename, logger, compileResult);
29 }
@@ -185,7 +35,6 @@ type TraversalState = {
35 logger: Logger | null;
36 filename: string | null;
37 transformErrors: Array<{fn: NodePath<t.Node>; error: CompilerError}>;
188 - inferredEffectLocations: Set<t.SourceLocation>;
38 };
39 type CheckInvalidReferenceFn = (
40 paths: Array<NodePath<t.Node>>,
@@ -281,8 +130,6 @@ function transformProgram(
130 filename,
131 logger,
132 transformErrors: compileResult?.retryErrors ?? [],
284 - inferredEffectLocations:
285 - compileResult?.inferredEffectLocations ?? new Set(),
133 };
134 path.traverse({
135 ImportDeclaration(path: NodePath<t.ImportDeclaration>) {
@@ -313,15 +160,3 @@ function transformProgram(
160 },
161 });
162 }
316 -
317 -function matchCompilerDiagnostic(
318 - badReference: NodePath<t.Node>,
319 - transformErrors: Array<{fn: NodePath<t.Node>; error: CompilerError}>,
320 -): string | null {
321 - for (const {fn, error} of transformErrors) {
322 - if (fn.isAncestor(badReference)) {
323 - return error.toString();
324 - }
325 - }
326 - return null;
327 -}
compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts
+2 -6
@@ -124,9 +124,7 @@ export function collectHoistablePropertyLoads(
124 hoistableFromOptionals,
125 registry,
126 nestedFnImmutableContext: null,
127 - assumedInvokedFns: fn.env.config.enableTreatFunctionDepsAsConditional
128 - ? new Set()
129 - : getAssumedInvokedFunctions(fn),
127 + assumedInvokedFns: getAssumedInvokedFunctions(fn),
128 });
129 }
130
@@ -142,9 +140,7 @@ export function collectHoistablePropertyLoadsInInnerFn(
140 hoistableFromOptionals,
141 registry: new PropertyPathRegistry(),
142 nestedFnImmutableContext: null,
145 - assumedInvokedFns: fn.env.config.enableTreatFunctionDepsAsConditional
146 - ? new Set()
147 - : getAssumedInvokedFunctions(fn),
143 + assumedInvokedFns: getAssumedInvokedFunctions(fn),
144 };
145 const nestedFnImmutableContext = new Set(
146 fn.context
compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
-258
@@ -54,14 +54,6 @@ import {FlowTypeEnv} from '../Flood/Types';
54 import {defaultModuleTypeProvider} from './DefaultModuleTypeProvider';
55 import {assertExhaustive} from '../Utils/utils';
56
57 -export const ReactElementSymbolSchema = z.object({
58 - elementSymbol: z.union([
59 - z.literal('react.element'),
60 - z.literal('react.transitional.element'),
61 - ]),
62 - globalDevVar: z.string(),
63 -});
64 -
57 export const ExternalFunctionSchema = z.object({
58 // Source for the imported module that exports the `importSpecifierName` functions
59 source: z.string(),
@@ -82,8 +74,6 @@ export const InstrumentationSchema = z
74 );
75
76 export type ExternalFunction = z.infer<typeof ExternalFunctionSchema>;
85 -export const USE_FIRE_FUNCTION_NAME = 'useFire';
86 -export const EMIT_FREEZE_GLOBAL_GATING = '__DEV__';
77
78 export const MacroSchema = z.string();
79
@@ -236,24 +226,9 @@ export const EnvironmentConfigSchema = z.object({
226 .enum(['off', 'all', 'missing-only', 'extra-only'])
227 .default('off'),
228
239 - /**
240 - * When this is true, rather than pruning existing manual memoization but ensuring or validating
241 - * that the memoized values remain memoized, the compiler will simply not prune existing calls to
242 - * useMemo/useCallback.
243 - */
244 - enablePreserveExistingManualUseMemo: z.boolean().default(false),
245 -
229 // 🌲
230 enableForest: z.boolean().default(false),
231
249 - /**
250 - * Enable use of type annotations in the source to drive type inference. By default
251 - * Forget attemps to infer types using only information that is guaranteed correct
252 - * given the source, and does not trust user-supplied type annotations. This mode
253 - * enables trusting user type annotations.
254 - */
255 - enableUseTypeAnnotations: z.boolean().default(false),
256 -
232 /**
233 * Allows specifying a function that can populate HIR with type information from
234 * Flow
@@ -268,53 +243,8 @@ export const EnvironmentConfigSchema = z.object({
243 */
244 enableOptionalDependencies: z.boolean().default(true),
245
271 - enableFire: z.boolean().default(false),
272 -
246 enableNameAnonymousFunctions: z.boolean().default(false),
247
275 - /**
276 - * Enables inference and auto-insertion of effect dependencies. Takes in an array of
277 - * configurable module and import pairs to allow for user-land experimentation. For example,
278 - * [
279 - * {
280 - * module: 'react',
281 - * imported: 'useEffect',
282 - * autodepsIndex: 1,
283 - * },{
284 - * module: 'MyExperimentalEffectHooks',
285 - * imported: 'useExperimentalEffect',
286 - * autodepsIndex: 2,
287 - * },
288 - * ]
289 - * would insert dependencies for calls of `useEffect` imported from `react` and calls of
290 - * useExperimentalEffect` from `MyExperimentalEffectHooks`.
291 - *
292 - * `autodepsIndex` tells the compiler which index we expect the AUTODEPS to appear in.
293 - * With the configuration above, we'd insert dependencies for `useEffect` if it has two
294 - * arguments, and the second is AUTODEPS.
295 - *
296 - * Still experimental.
297 - */
298 - inferEffectDependencies: z
299 - .nullable(
300 - z.array(
301 - z.object({
302 - function: ExternalFunctionSchema,
303 - autodepsIndex: z.number().min(1, 'autodepsIndex must be > 0'),
304 - }),
305 - ),
306 - )
307 - .default(null),
308 -
309 - /**
310 - * Enables inlining ReactElement object literals in place of JSX
311 - * An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime
312 - * Currently a prod-only optimization, requiring Fast JSX dependencies
313 - *
314 - * The symbol configuration is set for backwards compatability with pre-React 19 transforms
315 - */
316 - inlineJsxTransform: ReactElementSymbolSchema.nullable().default(null),
317 -
248 /*
249 * Enable validation of hooks to partially check that the component honors the rules of hooks.
250 * When disabled, the component is assumed to follow the rules (though the Babel plugin looks
@@ -366,16 +296,6 @@ export const EnvironmentConfigSchema = z.object({
296 */
297 validateStaticComponents: z.boolean().default(false),
298
369 - /**
370 - * Validates that the dependencies of all effect hooks are memoized. This helps ensure
371 - * that Forget does not introduce infinite renders caused by a dependency changing,
372 - * triggering an effect, which triggers re-rendering, which causes a dependency to change,
373 - * triggering the effect, etc.
374 - *
375 - * Covers useEffect, useLayoutEffect, useInsertionEffect.
376 - */
377 - validateMemoizedEffectDependencies: z.boolean().default(false),
378 -
299 /**
300 * Validates that there are no capitalized calls other than those allowed by the allowlist.
301 * Calls to capitalized functions are often functions that used to be components and may
@@ -422,38 +342,8 @@ export const EnvironmentConfigSchema = z.object({
342 * then this flag will assume that `x` is not subusequently modified.
343 */
344 enableTransitivelyFreezeFunctionExpressions: z.boolean().default(true),
425 -
426 - /*
427 - * Enables codegen mutability debugging. This emits a dev-mode only to log mutations
428 - * to values that Forget assumes are immutable (for Forget compiled code).
429 - * For example:
430 - * emitFreeze: {
431 - * source: 'ReactForgetRuntime',
432 - * importSpecifierName: 'makeReadOnly',
433 - * }
434 - *
435 - * produces:
436 - * import {makeReadOnly} from 'ReactForgetRuntime';
437 - *
438 - * function Component(props) {
439 - * if (c_0) {
440 - * // ...
441 - * $[0] = __DEV__ ? makeReadOnly(x) : x;
442 - * } else {
443 - * x = $[0];
444 - * }
445 - * }
446 - */
447 - enableEmitFreeze: ExternalFunctionSchema.nullable().default(null),
448 -
345 enableEmitHookGuards: ExternalFunctionSchema.nullable().default(null),
346
451 - /**
452 - * Enable instruction reordering. See InstructionReordering.ts for the details
453 - * of the approach.
454 - */
455 - enableInstructionReordering: z.boolean().default(false),
456 -
347 /**
348 * Enables function outlinining, where anonymous functions that do not close over
349 * local variables can be extracted into top-level helper functions.
@@ -535,80 +425,12 @@ export const EnvironmentConfigSchema = z.object({
425 // Enable validation of mutable ranges
426 assertValidMutableRanges: z.boolean().default(false),
427
538 - /*
539 - * Enable emitting "change variables" which store the result of whether a particular
540 - * reactive scope dependency has changed since the scope was last executed.
541 - *
542 - * Ex:
543 - * ```
544 - * const c_0 = $[0] !== input; // change variable
545 - * let output;
546 - * if (c_0) ...
547 - * ```
548 - *
549 - * Defaults to false, where the comparison is inlined:
550 - *
551 - * ```
552 - * let output;
553 - * if ($[0] !== input) ...
554 - * ```
555 - */
556 - enableChangeVariableCodegen: z.boolean().default(false),
557 -
558 - /**
559 - * Enable emitting comments that explain Forget's output, and which
560 - * values are being checked and which values produced by each memo block.
561 - *
562 - * Intended for use in demo purposes (incl playground)
563 - */
564 - enableMemoizationComments: z.boolean().default(false),
565 -
428 /**
429 * [TESTING ONLY] Throw an unknown exception during compilation to
430 * simulate unexpected exceptions e.g. errors from babel functions.
431 */
432 throwUnknownException__testonly: z.boolean().default(false),
433
572 - /**
573 - * Enables deps of a function epxression to be treated as conditional. This
574 - * makes sure we don't load a dep when it's a property (to check if it has
575 - * changed) and instead check the receiver.
576 - *
577 - * This makes sure we don't end up throwing when the reciver is null. Consider
578 - * this code:
579 - *
580 - * ```
581 - * function getLength() {
582 - * return props.bar.length;
583 - * }
584 - * ```
585 - *
586 - * It's only safe to memoize `getLength` against props, not props.bar, as
587 - * props.bar could be null when this `getLength` function is created.
588 - *
589 - * This does cause the memoization to now be coarse grained, which is
590 - * non-ideal.
591 - */
592 - enableTreatFunctionDepsAsConditional: z.boolean().default(false),
593 -
594 - /**
595 - * When true, always act as though the dependencies of a memoized value
596 - * have changed. This makes the compiler not actually perform any optimizations,
597 - * but is useful for debugging. Implicitly also sets
598 - * @enablePreserveExistingManualUseMemo, because otherwise memoization in the
599 - * original source will be disabled as well.
600 - */
601 - disableMemoizationForDebugging: z.boolean().default(false),
602 -
603 - /**
604 - * When true, rather using memoized values, the compiler will always re-compute
605 - * values, and then use a heuristic to compare the memoized value to the newly
606 - * computed one. This detects cases where rules of react violations may cause the
607 - * compiled code to behave differently than the original.
608 - */
609 - enableChangeDetectionForDebugging:
610 - ExternalFunctionSchema.nullable().default(null),
611 -
434 /**
435 * The react native re-animated library uses custom Babel transforms that
436 * requires the calls to library API remain unmodified.
@@ -619,19 +441,6 @@ export const EnvironmentConfigSchema = z.object({
441 */
442 enableCustomTypeDefinitionForReanimated: z.boolean().default(false),
443
622 - /**
623 - * If specified, this value is used as a pattern for determing which global values should be
624 - * treated as hooks. The pattern should have a single capture group, which will be used as
625 - * the hook name for the purposes of resolving hook definitions (for builtin hooks)_.
626 - *
627 - * For example, by default `React$useState` would not be treated as a hook. By specifying
628 - * `hookPattern: 'React$(\w+)'`, the compiler will treat this value equivalently to `useState()`.
629 - *
630 - * This setting is intended for cases where Forget is compiling code that has been prebundled
631 - * and identifiers have been changed.
632 - */
633 - hookPattern: z.string().nullable().default(null),
634 -
444 /**
445 * If enabled, this will treat objects named as `ref` or if their names end with the substring `Ref`,
446 * and contain a property named `current`, as React refs.
@@ -656,28 +465,6 @@ export const EnvironmentConfigSchema = z.object({
465 */
466 enableTreatSetIdentifiersAsStateSetters: z.boolean().default(false),
467
659 - /*
660 - * If specified a value, the compiler lowers any calls to `useContext` to use
661 - * this value as the callee.
662 - *
663 - * A selector function is compiled and passed as an argument along with the
664 - * context to this function call.
665 - *
666 - * The compiler automatically figures out the keys by looking for the immediate
667 - * destructuring of the return value from the useContext call. In the future,
668 - * this can be extended to different kinds of context access like property
669 - * loads and accesses over multiple statements as well.
670 - *
671 - * ```
672 - * // input
673 - * const {foo, bar} = useContext(MyContext);
674 - *
675 - * // output
676 - * const {foo, bar} = useCompiledContext(MyContext, (c) => [c.foo, c.bar]);
677 - * ```
678 - */
679 - lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
680 -
468 /**
469 * If enabled, will validate useMemos that don't return any values:
470 *
@@ -689,13 +476,6 @@ export const EnvironmentConfigSchema = z.object({
476 */
477 validateNoVoidUseMemo: z.boolean().default(true),
478
692 - /**
693 - * Validates that Components/Hooks are always defined at module level. This prevents scope
694 - * reference errors that occur when the compiler attempts to optimize the nested component/hook
695 - * while its parent function remains uncompiled.
696 - */
697 - validateNoDynamicallyCreatedComponentsOrHooks: z.boolean().default(false),
698 -
479 /**
480 * When enabled, allows setState calls in effects based on valid patterns involving refs:
481 * - Allow setState where the value being set is derived from a ref. This is useful where
@@ -717,15 +497,6 @@ export const EnvironmentConfigSchema = z.object({
497 * 3. Force update / external sync - should use useSyncExternalStore
498 */
499 enableVerboseNoSetStateInEffect: z.boolean().default(false),
720 -
721 - /**
722 - * Enables inference of event handler types for JSX props on built-in DOM elements.
723 - * When enabled, functions passed to event handler props (props starting with "on")
724 - * on primitive JSX tags are inferred to have the BuiltinEventHandlerId type, which
725 - * allows ref access within those functions since DOM event handlers are guaranteed
726 - * by React to only execute in response to events, not during render.
727 - */
728 - enableInferEventHandlers: z.boolean().default(false),
500 });
501
502 export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;
@@ -767,9 +538,6 @@ export class Environment {
538 fnType: ReactFunctionType;
539 outputMode: CompilerOutputMode;
540 programContext: ProgramContext;
770 - hasFireRewrite: boolean;
771 - hasInferredEffect: boolean;
772 - inferredEffectLocations: Set<SourceLocation> = new Set();
541
542 #contextIdentifiers: Set<t.Identifier>;
543 #hoistedIdentifiers: Set<t.Identifier>;
@@ -799,20 +567,6 @@ export class Environment {
567 this.programContext = programContext;
568 this.#shapes = new Map(DEFAULT_SHAPES);
569 this.#globals = new Map(DEFAULT_GLOBALS);
802 - this.hasFireRewrite = false;
803 - this.hasInferredEffect = false;
804 -
805 - if (
806 - config.disableMemoizationForDebugging &&
807 - config.enableChangeDetectionForDebugging != null
808 - ) {
809 - CompilerError.throwInvalidConfig({
810 - reason: `Invalid environment config: the 'disableMemoizationForDebugging' and 'enableChangeDetectionForDebugging' options cannot be used together`,
811 - description: null,
812 - loc: null,
813 - suggestions: null,
814 - });
815 - }
570
571 for (const [hookName, hook] of this.config.customHooks) {
572 CompilerError.invariant(!this.#globals.has(hookName), {
@@ -1029,18 +783,6 @@ export class Environment {
783 binding: NonLocalBinding,
784 loc: SourceLocation,
785 ): Global | null {
1032 - if (this.config.hookPattern != null) {
1033 - const match = new RegExp(this.config.hookPattern).exec(binding.name);
1034 - if (
1035 - match != null &&
1036 - typeof match[1] === 'string' &&
1037 - isHookName(match[1])
1038 - ) {
1039 - const resolvedName = match[1];
1040 - return this.#globals.get(resolvedName) ?? this.#getCustomHookType();
1041 - }
1042 - }
1043 -
786 switch (binding.kind) {
787 case 'ModuleLocal': {
788 // don't resolve module locals
compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts
-24
@@ -9,9 +9,6 @@ import {Effect, ValueKind, ValueReason} from './HIR';
9 import {
10 BUILTIN_SHAPES,
11 BuiltInArrayId,
12 - BuiltInAutodepsId,
13 - BuiltInFireFunctionId,
14 - BuiltInFireId,
12 BuiltInMapId,
13 BuiltInMixedReadonlyId,
14 BuiltInObjectId,
@@ -846,26 +843,6 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
843 BuiltInUseOperatorId,
844 ),
845 ],
849 - [
850 - 'fire',
851 - addFunction(
852 - DEFAULT_SHAPES,
853 - [],
854 - {
855 - positionalParams: [],
856 - restParam: null,
857 - returnType: {
858 - kind: 'Function',
859 - return: {kind: 'Poly'},
860 - shapeId: BuiltInFireFunctionId,
861 - isConstructor: false,
862 - },
863 - calleeEffect: Effect.Read,
864 - returnValueKind: ValueKind.Frozen,
865 - },
866 - BuiltInFireId,
867 - ),
868 - ],
846 [
847 'useEffectEvent',
848 addHook(
@@ -887,7 +864,6 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
864 BuiltInUseEffectEventId,
865 ),
866 ],
890 - ['AUTODEPS', addObject(DEFAULT_SHAPES, BuiltInAutodepsId, [])],
867 ];
868
869 TYPED_GLOBALS.push(
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
-6
@@ -1888,12 +1888,6 @@ export function isDispatcherType(id: Identifier): boolean {
1888 return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInDispatch';
1889 }
1890
1891 -export function isFireFunctionType(id: Identifier): boolean {
1892 - return (
1893 - id.type.kind === 'Function' && id.type.shapeId === 'BuiltInFireFunction'
1894 - );
1895 -}
1896 -
1891 export function isEffectEventFunctionType(id: Identifier): boolean {
1892 return (
1893 id.type.kind === 'Function' &&
compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
-17
@@ -383,12 +383,8 @@ export const BuiltInUseTransitionId = 'BuiltInUseTransition';
383 export const BuiltInUseOptimisticId = 'BuiltInUseOptimistic';
384 export const BuiltInSetOptimisticId = 'BuiltInSetOptimistic';
385 export const BuiltInStartTransitionId = 'BuiltInStartTransition';
386 -export const BuiltInFireId = 'BuiltInFire';
387 -export const BuiltInFireFunctionId = 'BuiltInFireFunction';
386 export const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
387 export const BuiltInEffectEventId = 'BuiltInEffectEventFunction';
390 -export const BuiltInAutodepsId = 'BuiltInAutoDepsId';
391 -export const BuiltInEventHandlerId = 'BuiltInEventHandlerId';
388
389 // See getReanimatedModuleType() in Globals.ts — this is part of supporting Reanimated's ref-like types
390 export const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
@@ -1249,19 +1245,6 @@ addFunction(
1245 BuiltInEffectEventId,
1246 );
1247
1252 -addFunction(
1253 - BUILTIN_SHAPES,
1254 - [],
1255 - {
1256 - positionalParams: [],
1257 - restParam: Effect.ConditionallyMutate,
1258 - returnType: {kind: 'Poly'},
1259 - calleeEffect: Effect.ConditionallyMutate,
1260 - returnValueKind: ValueKind.Mutable,
1261 - },
1262 - BuiltInEventHandlerId,
1263 -);
1264 -
1248 /**
1249 * MixedReadOnly =
1250 * | primitive
compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts deleted
-675
@@ -1,675 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import * as t from '@babel/types';
9 -import {CompilerError, SourceLocation} from '..';
10 -import {
11 - ArrayExpression,
12 - Effect,
13 - FunctionExpression,
14 - GeneratedSource,
15 - HIRFunction,
16 - IdentifierId,
17 - Instruction,
18 - makeInstructionId,
19 - TInstruction,
20 - InstructionId,
21 - ScopeId,
22 - ReactiveScopeDependency,
23 - Place,
24 - ReactiveScope,
25 - ReactiveScopeDependencies,
26 - Terminal,
27 - isUseRefType,
28 - isSetStateType,
29 - isFireFunctionType,
30 - makeScopeId,
31 - HIR,
32 - BasicBlock,
33 - BlockId,
34 - isEffectEventFunctionType,
35 -} from '../HIR';
36 -import {collectHoistablePropertyLoadsInInnerFn} from '../HIR/CollectHoistablePropertyLoads';
37 -import {collectOptionalChainSidemap} from '../HIR/CollectOptionalChainDependencies';
38 -import {ReactiveScopeDependencyTreeHIR} from '../HIR/DeriveMinimalDependenciesHIR';
39 -import {DEFAULT_EXPORT} from '../HIR/Environment';
40 -import {
41 - createTemporaryPlace,
42 - fixScopeAndIdentifierRanges,
43 - markInstructionIds,
44 - markPredecessors,
45 - reversePostorderBlocks,
46 -} from '../HIR/HIRBuilder';
47 -import {
48 - collectTemporariesSidemap,
49 - DependencyCollectionContext,
50 - handleInstruction,
51 -} from '../HIR/PropagateScopeDependenciesHIR';
52 -import {buildDependencyInstructions} from '../HIR/ScopeDependencyUtils';
53 -import {
54 - eachInstructionOperand,
55 - eachTerminalOperand,
56 - terminalFallthrough,
57 -} from '../HIR/visitors';
58 -import {empty} from '../Utils/Stack';
59 -import {getOrInsertWith} from '../Utils/utils';
60 -import {deadCodeElimination} from '../Optimization';
61 -import {BuiltInAutodepsId} from '../HIR/ObjectShape';
62 -
63 -/**
64 - * Infers reactive dependencies captured by useEffect lambdas and adds them as
65 - * a second argument to the useEffect call if no dependency array is provided.
66 - */
67 -export function inferEffectDependencies(fn: HIRFunction): void {
68 - const fnExpressions = new Map<
69 - IdentifierId,
70 - TInstruction<FunctionExpression>
71 - >();
72 -
73 - const autodepFnConfigs = new Map<string, Map<string, number>>();
74 - for (const effectTarget of fn.env.config.inferEffectDependencies!) {
75 - const moduleTargets = getOrInsertWith(
76 - autodepFnConfigs,
77 - effectTarget.function.source,
78 - () => new Map<string, number>(),
79 - );
80 - moduleTargets.set(
81 - effectTarget.function.importSpecifierName,
82 - effectTarget.autodepsIndex,
83 - );
84 - }
85 - const autodepFnLoads = new Map<IdentifierId, number>();
86 - const autodepModuleLoads = new Map<IdentifierId, Map<string, number>>();
87 -
88 - const scopeInfos = new Map<ScopeId, ReactiveScopeDependencies>();
89 -
90 - const loadGlobals = new Set<IdentifierId>();
91 -
92 - /**
93 - * When inserting LoadLocals, we need to retain the reactivity of the base
94 - * identifier, as later passes e.g. PruneNonReactiveDeps take the reactivity of
95 - * a base identifier as the "maximal" reactivity of all its references.
96 - * Concretely,
97 - * reactive(Identifier i) = Union_{reference of i}(reactive(reference))
98 - */
99 - const reactiveIds = inferReactiveIdentifiers(fn);
100 - const rewriteBlocks: Array<BasicBlock> = [];
101 -
102 - for (const [, block] of fn.body.blocks) {
103 - if (block.terminal.kind === 'scope') {
104 - const scopeBlock = fn.body.blocks.get(block.terminal.block)!;
105 - if (
106 - scopeBlock.instructions.length === 1 &&
107 - scopeBlock.terminal.kind === 'goto' &&
108 - scopeBlock.terminal.block === block.terminal.fallthrough
109 - ) {
110 - scopeInfos.set(
111 - block.terminal.scope.id,
112 - block.terminal.scope.dependencies,
113 - );
114 - }
115 - }
116 - const rewriteInstrs: Array<SpliceInfo> = [];
117 - for (const instr of block.instructions) {
118 - const {value, lvalue} = instr;
119 - if (value.kind === 'FunctionExpression') {
120 - fnExpressions.set(
121 - lvalue.identifier.id,
122 - instr as TInstruction<FunctionExpression>,
123 - );
124 - } else if (value.kind === 'PropertyLoad') {
125 - if (
126 - typeof value.property === 'string' &&
127 - autodepModuleLoads.has(value.object.identifier.id)
128 - ) {
129 - const moduleTargets = autodepModuleLoads.get(
130 - value.object.identifier.id,
131 - )!;
132 - const propertyName = value.property;
133 - const numRequiredArgs = moduleTargets.get(propertyName);
134 - if (numRequiredArgs != null) {
135 - autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
136 - }
137 - }
138 - } else if (value.kind === 'LoadGlobal') {
139 - loadGlobals.add(lvalue.identifier.id);
140 - /*
141 - * TODO: Handle properties on default exports, like
142 - * import React from 'react';
143 - * React.useEffect(...);
144 - */
145 - if (value.binding.kind === 'ImportNamespace') {
146 - const moduleTargets = autodepFnConfigs.get(value.binding.module);
147 - if (moduleTargets != null) {
148 - autodepModuleLoads.set(lvalue.identifier.id, moduleTargets);
149 - }
150 - }
151 - if (
152 - value.binding.kind === 'ImportSpecifier' ||
153 - value.binding.kind === 'ImportDefault'
154 - ) {
155 - const moduleTargets = autodepFnConfigs.get(value.binding.module);
156 - if (moduleTargets != null) {
157 - const importSpecifierName =
158 - value.binding.kind === 'ImportSpecifier'
159 - ? value.binding.imported
160 - : DEFAULT_EXPORT;
161 - const numRequiredArgs = moduleTargets.get(importSpecifierName);
162 - if (numRequiredArgs != null) {
163 - autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
164 - }
165 - }
166 - }
167 - } else if (
168 - value.kind === 'CallExpression' ||
169 - value.kind === 'MethodCall'
170 - ) {
171 - const callee =
172 - value.kind === 'CallExpression' ? value.callee : value.property;
173 -
174 - const autodepsArgIndex = value.args.findIndex(
175 - arg =>
176 - arg.kind === 'Identifier' &&
177 - arg.identifier.type.kind === 'Object' &&
178 - arg.identifier.type.shapeId === BuiltInAutodepsId,
179 - );
180 - const autodepsArgExpectedIndex = autodepFnLoads.get(
181 - callee.identifier.id,
182 - );
183 -
184 - if (
185 - value.args.length > 0 &&
186 - autodepsArgExpectedIndex != null &&
187 - autodepsArgIndex === autodepsArgExpectedIndex &&
188 - autodepFnLoads.has(callee.identifier.id) &&
189 - value.args[0].kind === 'Identifier'
190 - ) {
191 - // We have a useEffect call with no deps array, so we need to infer the deps
192 - const effectDeps: Array<Place> = [];
193 - const deps: ArrayExpression = {
194 - kind: 'ArrayExpression',
195 - elements: effectDeps,
196 - loc: GeneratedSource,
197 - };
198 - const depsPlace = createTemporaryPlace(fn.env, GeneratedSource);
199 - depsPlace.effect = Effect.Read;
200 -
201 - const fnExpr = fnExpressions.get(value.args[0].identifier.id);
202 - if (fnExpr != null) {
203 - // We have a function expression, so we can infer its dependencies
204 - const scopeInfo =
205 - fnExpr.lvalue.identifier.scope != null
206 - ? scopeInfos.get(fnExpr.lvalue.identifier.scope.id)
207 - : null;
208 - let minimalDeps: Set<ReactiveScopeDependency>;
209 - if (scopeInfo != null) {
210 - minimalDeps = new Set(scopeInfo);
211 - } else {
212 - minimalDeps = inferMinimalDependencies(fnExpr);
213 - }
214 - /**
215 - * Step 1: push dependencies to the effect deps array
216 - *
217 - * Note that it's invalid to prune all non-reactive deps in this pass, see
218 - * the `infer-effect-deps/pruned-nonreactive-obj` fixture for an
219 - * explanation.
220 - */
221 -
222 - const usedDeps = [];
223 - for (const maybeDep of minimalDeps) {
224 - if (
225 - ((isUseRefType(maybeDep.identifier) ||
226 - isSetStateType(maybeDep.identifier)) &&
227 - !reactiveIds.has(maybeDep.identifier.id)) ||
228 - isFireFunctionType(maybeDep.identifier) ||
229 - isEffectEventFunctionType(maybeDep.identifier)
230 - ) {
231 - // exclude non-reactive hook results, which will never be in a memo block
232 - continue;
233 - }
234 -
235 - const dep = truncateDepAtCurrent(maybeDep);
236 - const {place, value, exitBlockId} = buildDependencyInstructions(
237 - dep,
238 - fn.env,
239 - );
240 - rewriteInstrs.push({
241 - kind: 'block',
242 - location: instr.id,
243 - value,
244 - exitBlockId: exitBlockId,
245 - });
246 - effectDeps.push(place);
247 - usedDeps.push(dep);
248 - }
249 -
250 - // For LSP autodeps feature.
251 - const decorations: Array<t.SourceLocation> = [];
252 - for (const loc of collectDepUsages(usedDeps, fnExpr.value)) {
253 - if (typeof loc === 'symbol') {
254 - continue;
255 - }
256 - decorations.push(loc);
257 - }
258 - if (typeof value.loc !== 'symbol') {
259 - fn.env.logger?.logEvent(fn.env.filename, {
260 - kind: 'AutoDepsDecorations',
261 - fnLoc: value.loc,
262 - decorations,
263 - });
264 - }
265 -
266 - // Step 2: push the inferred deps array as an argument of the useEffect
267 - rewriteInstrs.push({
268 - kind: 'instr',
269 - location: instr.id,
270 - value: {
271 - id: makeInstructionId(0),
272 - loc: GeneratedSource,
273 - lvalue: {...depsPlace, effect: Effect.Mutate},
274 - value: deps,
275 - effects: null,
276 - },
277 - });
278 - value.args[autodepsArgIndex] = {
279 - ...depsPlace,
280 - effect: Effect.Freeze,
281 - };
282 - fn.env.inferredEffectLocations.add(callee.loc);
283 - } else if (loadGlobals.has(value.args[0].identifier.id)) {
284 - // Global functions have no reactive dependencies, so we can insert an empty array
285 - rewriteInstrs.push({
286 - kind: 'instr',
287 - location: instr.id,
288 - value: {
289 - id: makeInstructionId(0),
290 - loc: GeneratedSource,
291 - lvalue: {...depsPlace, effect: Effect.Mutate},
292 - value: deps,
293 - effects: null,
294 - },
295 - });
296 - value.args[autodepsArgIndex] = {
297 - ...depsPlace,
298 - effect: Effect.Freeze,
299 - };
300 - fn.env.inferredEffectLocations.add(callee.loc);
301 - }
302 - } else if (
303 - value.args.length >= 2 &&
304 - value.args.length - 1 === autodepFnLoads.get(callee.identifier.id) &&
305 - value.args[0] != null &&
306 - value.args[0].kind === 'Identifier'
307 - ) {
308 - const penultimateArg = value.args[value.args.length - 2];
309 - const depArrayArg = value.args[value.args.length - 1];
310 - if (
311 - depArrayArg.kind !== 'Spread' &&
312 - penultimateArg.kind !== 'Spread' &&
313 - typeof depArrayArg.loc !== 'symbol' &&
314 - typeof penultimateArg.loc !== 'symbol' &&
315 - typeof value.loc !== 'symbol'
316 - ) {
317 - fn.env.logger?.logEvent(fn.env.filename, {
318 - kind: 'AutoDepsEligible',
319 - fnLoc: value.loc,
320 - depArrayLoc: {
321 - ...depArrayArg.loc,
322 - start: penultimateArg.loc.end,
323 - end: depArrayArg.loc.end,
324 - },
325 - });
326 - }
327 - }
328 - }
329 - }
330 - rewriteSplices(block, rewriteInstrs, rewriteBlocks);
331 - }
332 -
333 - if (rewriteBlocks.length > 0) {
334 - for (const block of rewriteBlocks) {
335 - fn.body.blocks.set(block.id, block);
336 - }
337 -
338 - /**
339 - * Fixup the HIR to restore RPO, ensure correct predecessors, and renumber
340 - * instructions.
341 - */
342 - reversePostorderBlocks(fn.body);
343 - markPredecessors(fn.body);
344 - // Renumber instructions and fix scope ranges
345 - markInstructionIds(fn.body);
346 - fixScopeAndIdentifierRanges(fn.body);
347 - deadCodeElimination(fn);
348 -
349 - fn.env.hasInferredEffect = true;
350 - }
351 -}
352 -
353 -function truncateDepAtCurrent(
354 - dep: ReactiveScopeDependency,
355 -): ReactiveScopeDependency {
356 - const idx = dep.path.findIndex(path => path.property === 'current');
357 - if (idx === -1) {
358 - return dep;
359 - } else {
360 - return {...dep, path: dep.path.slice(0, idx)};
361 - }
362 -}
363 -
364 -type SpliceInfo =
365 - | {kind: 'instr'; location: InstructionId; value: Instruction}
366 - | {
367 - kind: 'block';
368 - location: InstructionId;
369 - value: HIR;
370 - exitBlockId: BlockId;
371 - };
372 -
373 -function rewriteSplices(
374 - originalBlock: BasicBlock,
375 - splices: Array<SpliceInfo>,
376 - rewriteBlocks: Array<BasicBlock>,
377 -): void {
378 - if (splices.length === 0) {
379 - return;
380 - }
381 - /**
382 - * Splice instructions or value blocks into the original block.
383 - * --- original block ---
384 - * bb_original
385 - * instr1
386 - * ...
387 - * instr2 <-- splice location
388 - * instr3
389 - * ...
390 - * <original terminal>
391 - *
392 - * If there is more than one block in the splice, this means that we're
393 - * splicing in a set of value-blocks of the following structure:
394 - * --- blocks we're splicing in ---
395 - * bb_entry:
396 - * instrEntry
397 - * ...
398 - * <splice terminal> fallthrough=bb_exit
399 - *
400 - * bb1(value):
401 - * ...
402 - *
403 - * bb_exit:
404 - * instrExit
405 - * ...
406 - * <synthetic terminal>
407 - *
408 - *
409 - * --- rewritten blocks ---
410 - * bb_original
411 - * instr1
412 - * ... (original instructions)
413 - * instr2
414 - * instrEntry
415 - * ... (spliced instructions)
416 - * <splice terminal> fallthrough=bb_exit
417 - *
418 - * bb1(value):
419 - * ...
420 - *
421 - * bb_exit:
422 - * instrExit
423 - * ... (spliced instructions)
424 - * instr3
425 - * ... (original instructions)
426 - * <original terminal>
427 - */
428 - const originalInstrs = originalBlock.instructions;
429 - let currBlock: BasicBlock = {...originalBlock, instructions: []};
430 - rewriteBlocks.push(currBlock);
431 -
432 - let cursor = 0;
433 -
434 - for (const rewrite of splices) {
435 - while (originalInstrs[cursor].id < rewrite.location) {
436 - CompilerError.invariant(
437 - originalInstrs[cursor].id < originalInstrs[cursor + 1].id,
438 - {
439 - reason:
440 - '[InferEffectDependencies] Internal invariant broken: expected block instructions to be sorted',
441 - loc: originalInstrs[cursor].loc,
442 - },
443 - );
444 - currBlock.instructions.push(originalInstrs[cursor]);
445 - cursor++;
446 - }
447 - CompilerError.invariant(originalInstrs[cursor].id === rewrite.location, {
448 - reason:
449 - '[InferEffectDependencies] Internal invariant broken: splice location not found',
450 - loc: originalInstrs[cursor].loc,
451 - });
452 -
453 - if (rewrite.kind === 'instr') {
454 - currBlock.instructions.push(rewrite.value);
455 - } else if (rewrite.kind === 'block') {
456 - const {entry, blocks} = rewrite.value;
457 - const entryBlock = blocks.get(entry)!;
458 - // splice in all instructions from the entry block
459 - currBlock.instructions.push(...entryBlock.instructions);
460 - if (blocks.size > 1) {
461 - /**
462 - * We're splicing in a set of value-blocks, which means we need
463 - * to push new blocks and update terminals.
464 - */
465 - CompilerError.invariant(
466 - terminalFallthrough(entryBlock.terminal) === rewrite.exitBlockId,
467 - {
468 - reason:
469 - '[InferEffectDependencies] Internal invariant broken: expected entry block to have a fallthrough',
470 - loc: entryBlock.terminal.loc,
471 - },
472 - );
473 - const originalTerminal = currBlock.terminal;
474 - currBlock.terminal = entryBlock.terminal;
475 -
476 - for (const [id, block] of blocks) {
477 - if (id === entry) {
478 - continue;
479 - }
480 - if (id === rewrite.exitBlockId) {
481 - block.terminal = originalTerminal;
482 - currBlock = block;
483 - }
484 - rewriteBlocks.push(block);
485 - }
486 - }
487 - }
488 - }
489 - currBlock.instructions.push(...originalInstrs.slice(cursor));
490 -}
491 -
492 -function inferReactiveIdentifiers(fn: HIRFunction): Set<IdentifierId> {
493 - const reactiveIds: Set<IdentifierId> = new Set();
494 - for (const [, block] of fn.body.blocks) {
495 - for (const instr of block.instructions) {
496 - /**
497 - * No need to traverse into nested functions as
498 - * 1. their effects are recorded in `LoweredFunction.dependencies`
499 - * 2. we don't mark `reactive` in these anyways
500 - */
501 - for (const place of eachInstructionOperand(instr)) {
502 - if (place.reactive) {
503 - reactiveIds.add(place.identifier.id);
504 - }
505 - }
506 - }
507 -
508 - for (const place of eachTerminalOperand(block.terminal)) {
509 - if (place.reactive) {
510 - reactiveIds.add(place.identifier.id);
511 - }
512 - }
513 - }
514 - return reactiveIds;
515 -}
516 -
517 -function collectDepUsages(
518 - deps: Array<ReactiveScopeDependency>,
519 - fnExpr: FunctionExpression,
520 -): Array<SourceLocation> {
521 - const identifiers: Map<IdentifierId, ReactiveScopeDependency> = new Map();
522 - const loadedDeps: Set<IdentifierId> = new Set();
523 - const sourceLocations = [];
524 - for (const dep of deps) {
525 - identifiers.set(dep.identifier.id, dep);
526 - }
527 -
528 - for (const [, block] of fnExpr.loweredFunc.func.body.blocks) {
529 - for (const instr of block.instructions) {
530 - if (
531 - instr.value.kind === 'LoadLocal' &&
532 - identifiers.has(instr.value.place.identifier.id)
533 - ) {
534 - loadedDeps.add(instr.lvalue.identifier.id);
535 - }
536 - for (const place of eachInstructionOperand(instr)) {
537 - if (loadedDeps.has(place.identifier.id)) {
538 - // TODO(@jbrown215): handle member exprs!!
539 - sourceLocations.push(place.identifier.loc);
540 - }
541 - }
542 - }
543 - }
544 -
545 - return sourceLocations;
546 -}
547 -
548 -function inferMinimalDependencies(
549 - fnInstr: TInstruction<FunctionExpression>,
550 -): Set<ReactiveScopeDependency> {
551 - const fn = fnInstr.value.loweredFunc.func;
552 -
553 - const temporaries = collectTemporariesSidemap(fn, new Set());
554 - const {
555 - hoistableObjects,
556 - processedInstrsInOptional,
557 - temporariesReadInOptional,
558 - } = collectOptionalChainSidemap(fn);
559 -
560 - const hoistablePropertyLoads = collectHoistablePropertyLoadsInInnerFn(
561 - fnInstr,
562 - temporaries,
563 - hoistableObjects,
564 - );
565 - const hoistableToFnEntry = hoistablePropertyLoads.get(fn.body.entry);
566 - CompilerError.invariant(hoistableToFnEntry != null, {
567 - reason:
568 - '[InferEffectDependencies] Internal invariant broken: missing entry block',
569 - loc: fnInstr.loc,
570 - });
571 -
572 - const dependencies = inferDependencies(
573 - fnInstr,
574 - new Map([...temporaries, ...temporariesReadInOptional]),
575 - processedInstrsInOptional,
576 - );
577 -
578 - const tree = new ReactiveScopeDependencyTreeHIR(
579 - [...hoistableToFnEntry.assumedNonNullObjects].map(o => o.fullPath),
580 - );
581 - for (const dep of dependencies) {
582 - tree.addDependency({...dep});
583 - }
584 -
585 - return tree.deriveMinimalDependencies();
586 -}
587 -
588 -function inferDependencies(
589 - fnInstr: TInstruction<FunctionExpression>,
590 - temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>,
591 - processedInstrsInOptional: ReadonlySet<Instruction | Terminal>,
592 -): Set<ReactiveScopeDependency> {
593 - const fn = fnInstr.value.loweredFunc.func;
594 - const context = new DependencyCollectionContext(
595 - new Set(),
596 - temporaries,
597 - processedInstrsInOptional,
598 - );
599 - for (const dep of fn.context) {
600 - context.declare(dep.identifier, {
601 - id: makeInstructionId(0),
602 - scope: empty(),
603 - });
604 - }
605 - const placeholderScope: ReactiveScope = {
606 - id: makeScopeId(0),
607 - range: {
608 - start: fnInstr.id,
609 - end: makeInstructionId(fnInstr.id + 1),
610 - },
611 - dependencies: new Set(),
612 - reassignments: new Set(),
613 - declarations: new Map(),
614 - earlyReturnValue: null,
615 - merged: new Set(),
616 - loc: GeneratedSource,
617 - };
618 - context.enterScope(placeholderScope);
619 - inferDependenciesInFn(fn, context, temporaries);
620 - context.exitScope(placeholderScope, false);
621 - const resultUnfiltered = context.deps.get(placeholderScope);
622 - CompilerError.invariant(resultUnfiltered != null, {
623 - reason:
624 - '[InferEffectDependencies] Internal invariant broken: missing scope dependencies',
625 - loc: fn.loc,
626 - });
627 -
628 - const fnContext = new Set(fn.context.map(dep => dep.identifier.id));
629 - const result = new Set<ReactiveScopeDependency>();
630 - for (const dep of resultUnfiltered) {
631 - if (fnContext.has(dep.identifier.id)) {
632 - result.add(dep);
633 - }
634 - }
635 -
636 - return result;
637 -}
638 -
639 -function inferDependenciesInFn(
640 - fn: HIRFunction,
641 - context: DependencyCollectionContext,
642 - temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>,
643 -): void {
644 - for (const [, block] of fn.body.blocks) {
645 - // Record referenced optional chains in phis
646 - for (const phi of block.phis) {
647 - for (const operand of phi.operands) {
648 - const maybeOptionalChain = temporaries.get(operand[1].identifier.id);
649 - if (maybeOptionalChain) {
650 - context.visitDependency(maybeOptionalChain);
651 - }
652 - }
653 - }
654 - for (const instr of block.instructions) {
655 - if (
656 - instr.value.kind === 'FunctionExpression' ||
657 - instr.value.kind === 'ObjectMethod'
658 - ) {
659 - context.declare(instr.lvalue.identifier, {
660 - id: instr.id,
661 - scope: context.currentScope,
662 - });
663 - /**
664 - * Recursively visit the inner function to extract dependencies
665 - */
666 - const innerFn = instr.value.loweredFunc.func;
667 - context.enterInnerFn(instr as TInstruction<FunctionExpression>, () => {
668 - inferDependenciesInFn(innerFn, context, temporaries);
669 - });
670 - } else {
671 - handleInstruction(instr, context);
672 - }
673 - }
674 - }
675 -}
compiler/packages/babel-plugin-react-compiler/src/Inference/index.ts
-1
@@ -9,4 +9,3 @@ export {default as analyseFunctions} from './AnalyseFunctions';
9 export {dropManualMemoization} from './DropManualMemoization';
10 export {inferReactivePlaces} from './InferReactivePlaces';
11 export {inlineImmediatelyInvokedFunctionExpressions} from './InlineImmediatelyInvokedFunctionExpressions';
12 -export {inferEffectDependencies} from './InferEffectDependencies';
compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts deleted
-790
@@ -1,790 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import {
9 - BasicBlock,
10 - BlockId,
11 - BuiltinTag,
12 - DeclarationId,
13 - Effect,
14 - forkTemporaryIdentifier,
15 - GotoTerminal,
16 - GotoVariant,
17 - HIRFunction,
18 - Identifier,
19 - IfTerminal,
20 - Instruction,
21 - InstructionKind,
22 - JsxAttribute,
23 - makeInstructionId,
24 - makePropertyLiteral,
25 - ObjectProperty,
26 - Phi,
27 - Place,
28 - promoteTemporary,
29 - SpreadPattern,
30 -} from '../HIR';
31 -import {
32 - createTemporaryPlace,
33 - fixScopeAndIdentifierRanges,
34 - markInstructionIds,
35 - markPredecessors,
36 - reversePostorderBlocks,
37 -} from '../HIR/HIRBuilder';
38 -import {CompilerError, EnvironmentConfig} from '..';
39 -import {
40 - mapInstructionLValues,
41 - mapInstructionOperands,
42 - mapInstructionValueOperands,
43 - mapTerminalOperands,
44 -} from '../HIR/visitors';
45 -import {ErrorCategory} from '../CompilerError';
46 -
47 -type InlinedJsxDeclarationMap = Map<
48 - DeclarationId,
49 - {identifier: Identifier; blockIdsToIgnore: Set<BlockId>}
50 ->;
51 -
52 -/**
53 - * A prod-only, RN optimization to replace JSX with inlined ReactElement object literals
54 - *
55 - * Example:
56 - * <>foo</>
57 - * _______________
58 - * let t1;
59 - * if (__DEV__) {
60 - * t1 = <>foo</>
61 - * } else {
62 - * t1 = {...}
63 - * }
64 - *
65 - */
66 -export function inlineJsxTransform(
67 - fn: HIRFunction,
68 - inlineJsxTransformConfig: NonNullable<
69 - EnvironmentConfig['inlineJsxTransform']
70 - >,
71 -): void {
72 - const inlinedJsxDeclarations: InlinedJsxDeclarationMap = new Map();
73 - /**
74 - * Step 1: Codegen the conditional and ReactElement object literal
75 - */
76 - for (const [_, currentBlock] of [...fn.body.blocks]) {
77 - let fallthroughBlockInstructions: Array<Instruction> | null = null;
78 - const instructionCount = currentBlock.instructions.length;
79 - for (let i = 0; i < instructionCount; i++) {
80 - const instr = currentBlock.instructions[i]!;
81 - // TODO: Support value blocks
82 - if (currentBlock.kind === 'value') {
83 - fn.env.logger?.logEvent(fn.env.filename, {
84 - kind: 'CompileDiagnostic',
85 - fnLoc: null,
86 - detail: {
87 - category: ErrorCategory.Todo,
88 - reason: 'JSX Inlining is not supported on value blocks',
89 - loc: instr.loc,
90 - },
91 - });
92 - continue;
93 - }
94 - switch (instr.value.kind) {
95 - case 'JsxExpression':
96 - case 'JsxFragment': {
97 - /**
98 - * Split into blocks for new IfTerminal:
99 - * current, then, else, fallthrough
100 - */
101 - const currentBlockInstructions = currentBlock.instructions.slice(
102 - 0,
103 - i,
104 - );
105 - const thenBlockInstructions = currentBlock.instructions.slice(
106 - i,
107 - i + 1,
108 - );
109 - const elseBlockInstructions: Array<Instruction> = [];
110 - fallthroughBlockInstructions ??= currentBlock.instructions.slice(
111 - i + 1,
112 - );
113 -
114 - const fallthroughBlockId = fn.env.nextBlockId;
115 - const fallthroughBlock: BasicBlock = {
116 - kind: currentBlock.kind,
117 - id: fallthroughBlockId,
118 - instructions: fallthroughBlockInstructions,
119 - terminal: currentBlock.terminal,
120 - preds: new Set(),
121 - phis: new Set(),
122 - };
123 -
124 - /**
125 - * Complete current block
126 - * - Add instruction for variable declaration
127 - * - Add instruction for LoadGlobal used by conditional
128 - * - End block with a new IfTerminal
129 - */
130 - const varPlace = createTemporaryPlace(fn.env, instr.value.loc);
131 - promoteTemporary(varPlace.identifier);
132 - const varLValuePlace = createTemporaryPlace(fn.env, instr.value.loc);
133 - const thenVarPlace = {
134 - ...varPlace,
135 - identifier: forkTemporaryIdentifier(
136 - fn.env.nextIdentifierId,
137 - varPlace.identifier,
138 - ),
139 - };
140 - const elseVarPlace = {
141 - ...varPlace,
142 - identifier: forkTemporaryIdentifier(
143 - fn.env.nextIdentifierId,
144 - varPlace.identifier,
145 - ),
146 - };
147 - const varInstruction: Instruction = {
148 - id: makeInstructionId(0),
149 - lvalue: {...varLValuePlace},
150 - value: {
151 - kind: 'DeclareLocal',
152 - lvalue: {place: {...varPlace}, kind: InstructionKind.Let},
153 - type: null,
154 - loc: instr.value.loc,
155 - },
156 - effects: null,
157 - loc: instr.loc,
158 - };
159 - currentBlockInstructions.push(varInstruction);
160 -
161 - const devGlobalPlace = createTemporaryPlace(fn.env, instr.value.loc);
162 - const devGlobalInstruction: Instruction = {
163 - id: makeInstructionId(0),
164 - lvalue: {...devGlobalPlace, effect: Effect.Mutate},
165 - value: {
166 - kind: 'LoadGlobal',
167 - binding: {
168 - kind: 'Global',
169 - name: inlineJsxTransformConfig.globalDevVar,
170 - },
171 - loc: instr.value.loc,
172 - },
173 - effects: null,
174 - loc: instr.loc,
175 - };
176 - currentBlockInstructions.push(devGlobalInstruction);
177 - const thenBlockId = fn.env.nextBlockId;
178 - const elseBlockId = fn.env.nextBlockId;
179 - const ifTerminal: IfTerminal = {
180 - kind: 'if',
181 - test: {...devGlobalPlace, effect: Effect.Read},
182 - consequent: thenBlockId,
183 - alternate: elseBlockId,
184 - fallthrough: fallthroughBlockId,
185 - loc: instr.loc,
186 - id: makeInstructionId(0),
187 - };
188 - currentBlock.instructions = currentBlockInstructions;
189 - currentBlock.terminal = ifTerminal;
190 -
191 - /**
192 - * Set up then block where we put the original JSX return
193 - */
194 - const thenBlock: BasicBlock = {
195 - id: thenBlockId,
196 - instructions: thenBlockInstructions,
197 - kind: 'block',
198 - phis: new Set(),
199 - preds: new Set(),
200 - terminal: {
201 - kind: 'goto',
202 - block: fallthroughBlockId,
203 - variant: GotoVariant.Break,
204 - id: makeInstructionId(0),
205 - loc: instr.loc,
206 - },
207 - };
208 - fn.body.blocks.set(thenBlockId, thenBlock);
209 -
210 - const resassignElsePlace = createTemporaryPlace(
211 - fn.env,
212 - instr.value.loc,
213 - );
214 - const reassignElseInstruction: Instruction = {
215 - id: makeInstructionId(0),
216 - lvalue: {...resassignElsePlace},
217 - value: {
218 - kind: 'StoreLocal',
219 - lvalue: {
220 - place: elseVarPlace,
221 - kind: InstructionKind.Reassign,
222 - },
223 - value: {...instr.lvalue},
224 - type: null,
225 - loc: instr.value.loc,
226 - },
227 - effects: null,
228 - loc: instr.loc,
229 - };
230 - thenBlockInstructions.push(reassignElseInstruction);
231 -
232 - /**
233 - * Set up else block where we add new codegen
234 - */
235 - const elseBlockTerminal: GotoTerminal = {
236 - kind: 'goto',
237 - block: fallthroughBlockId,
238 - variant: GotoVariant.Break,
239 - id: makeInstructionId(0),
240 - loc: instr.loc,
241 - };
242 - const elseBlock: BasicBlock = {
243 - id: elseBlockId,
244 - instructions: elseBlockInstructions,
245 - kind: 'block',
246 - phis: new Set(),
247 - preds: new Set(),
248 - terminal: elseBlockTerminal,
249 - };
250 - fn.body.blocks.set(elseBlockId, elseBlock);
251 -
252 - /**
253 - * ReactElement object literal codegen
254 - */
255 - const {refProperty, keyProperty, propsProperty} =
256 - createPropsProperties(
257 - fn,
258 - instr,
259 - elseBlockInstructions,
260 - instr.value.kind === 'JsxExpression' ? instr.value.props : [],
261 - instr.value.children,
262 - );
263 - const reactElementInstructionPlace = createTemporaryPlace(
264 - fn.env,
265 - instr.value.loc,
266 - );
267 - const reactElementInstruction: Instruction = {
268 - id: makeInstructionId(0),
269 - lvalue: {...reactElementInstructionPlace, effect: Effect.Store},
270 - value: {
271 - kind: 'ObjectExpression',
272 - properties: [
273 - createSymbolProperty(
274 - fn,
275 - instr,
276 - elseBlockInstructions,
277 - '$$typeof',
278 - inlineJsxTransformConfig.elementSymbol,
279 - ),
280 - instr.value.kind === 'JsxExpression'
281 - ? createTagProperty(
282 - fn,
283 - instr,
284 - elseBlockInstructions,
285 - instr.value.tag,
286 - )
287 - : createSymbolProperty(
288 - fn,
289 - instr,
290 - elseBlockInstructions,
291 - 'type',
292 - 'react.fragment',
293 - ),
294 - refProperty,
295 - keyProperty,
296 - propsProperty,
297 - ],
298 - loc: instr.value.loc,
299 - },
300 - effects: null,
301 - loc: instr.loc,
302 - };
303 - elseBlockInstructions.push(reactElementInstruction);
304 -
305 - const reassignConditionalInstruction: Instruction = {
306 - id: makeInstructionId(0),
307 - lvalue: {...createTemporaryPlace(fn.env, instr.value.loc)},
308 - value: {
309 - kind: 'StoreLocal',
310 - lvalue: {
311 - place: {...elseVarPlace},
312 - kind: InstructionKind.Reassign,
313 - },
314 - value: {...reactElementInstruction.lvalue},
315 - type: null,
316 - loc: instr.value.loc,
317 - },
318 - effects: null,
319 - loc: instr.loc,
320 - };
321 - elseBlockInstructions.push(reassignConditionalInstruction);
322 -
323 - /**
324 - * Create phis to reassign the var
325 - */
326 - const operands: Map<BlockId, Place> = new Map();
327 - operands.set(thenBlockId, {
328 - ...elseVarPlace,
329 - });
330 - operands.set(elseBlockId, {
331 - ...thenVarPlace,
332 - });
333 -
334 - const phiIdentifier = forkTemporaryIdentifier(
335 - fn.env.nextIdentifierId,
336 - varPlace.identifier,
337 - );
338 - const phiPlace = {
339 - ...createTemporaryPlace(fn.env, instr.value.loc),
340 - identifier: phiIdentifier,
341 - };
342 - const phis: Set<Phi> = new Set([
343 - {
344 - kind: 'Phi',
345 - operands,
346 - place: phiPlace,
347 - },
348 - ]);
349 - fallthroughBlock.phis = phis;
350 - fn.body.blocks.set(fallthroughBlockId, fallthroughBlock);
351 -
352 - /**
353 - * Track this JSX instruction so we can replace references in step 2
354 - */
355 - inlinedJsxDeclarations.set(instr.lvalue.identifier.declarationId, {
356 - identifier: phiIdentifier,
357 - blockIdsToIgnore: new Set([thenBlockId, elseBlockId]),
358 - });
359 - break;
360 - }
361 - case 'FunctionExpression':
362 - case 'ObjectMethod': {
363 - inlineJsxTransform(
364 - instr.value.loweredFunc.func,
365 - inlineJsxTransformConfig,
366 - );
367 - break;
368 - }
369 - }
370 - }
371 - }
372 -
373 - /**
374 - * Step 2: Replace declarations with new phi values
375 - */
376 - for (const [blockId, block] of fn.body.blocks) {
377 - for (const instr of block.instructions) {
378 - mapInstructionOperands(instr, place =>
379 - handlePlace(place, blockId, inlinedJsxDeclarations),
380 - );
381 -
382 - mapInstructionLValues(instr, lvalue =>
383 - handlelValue(lvalue, blockId, inlinedJsxDeclarations),
384 - );
385 -
386 - mapInstructionValueOperands(instr.value, place =>
387 - handlePlace(place, blockId, inlinedJsxDeclarations),
388 - );
389 - }
390 -
391 - mapTerminalOperands(block.terminal, place =>
392 - handlePlace(place, blockId, inlinedJsxDeclarations),
393 - );
394 -
395 - if (block.terminal.kind === 'scope') {
396 - const scope = block.terminal.scope;
397 - for (const dep of scope.dependencies) {
398 - dep.identifier = handleIdentifier(
399 - dep.identifier,
400 - inlinedJsxDeclarations,
401 - );
402 - }
403 -
404 - for (const [origId, decl] of [...scope.declarations]) {
405 - const newDecl = handleIdentifier(
406 - decl.identifier,
407 - inlinedJsxDeclarations,
408 - );
409 - if (newDecl.id !== origId) {
410 - scope.declarations.delete(origId);
411 - scope.declarations.set(decl.identifier.id, {
412 - identifier: newDecl,
413 - scope: decl.scope,
414 - });
415 - }
416 - }
417 - }
418 - }
419 -
420 - /**
421 - * Step 3: Fixup the HIR
422 - * Restore RPO, ensure correct predecessors, renumber instructions, fix scope and ranges.
423 - */
424 - reversePostorderBlocks(fn.body);
425 - markPredecessors(fn.body);
426 - markInstructionIds(fn.body);
427 - fixScopeAndIdentifierRanges(fn.body);
428 -}
429 -
430 -function createSymbolProperty(
431 - fn: HIRFunction,
432 - instr: Instruction,
433 - nextInstructions: Array<Instruction>,
434 - propertyName: string,
435 - symbolName: string,
436 -): ObjectProperty {
437 - const symbolPlace = createTemporaryPlace(fn.env, instr.value.loc);
438 - const symbolInstruction: Instruction = {
439 - id: makeInstructionId(0),
440 - lvalue: {...symbolPlace, effect: Effect.Mutate},
441 - value: {
442 - kind: 'LoadGlobal',
443 - binding: {kind: 'Global', name: 'Symbol'},
444 - loc: instr.value.loc,
445 - },
446 - effects: null,
447 - loc: instr.loc,
448 - };
449 - nextInstructions.push(symbolInstruction);
450 -
451 - const symbolForPlace = createTemporaryPlace(fn.env, instr.value.loc);
452 - const symbolForInstruction: Instruction = {
453 - id: makeInstructionId(0),
454 - lvalue: {...symbolForPlace, effect: Effect.Read},
455 - value: {
456 - kind: 'PropertyLoad',
457 - object: {...symbolInstruction.lvalue},
458 - property: makePropertyLiteral('for'),
459 - loc: instr.value.loc,
460 - },
461 - effects: null,
462 - loc: instr.loc,
463 - };
464 - nextInstructions.push(symbolForInstruction);
465 -
466 - const symbolValuePlace = createTemporaryPlace(fn.env, instr.value.loc);
467 - const symbolValueInstruction: Instruction = {
468 - id: makeInstructionId(0),
469 - lvalue: {...symbolValuePlace, effect: Effect.Mutate},
470 - value: {
471 - kind: 'Primitive',
472 - value: symbolName,
473 - loc: instr.value.loc,
474 - },
475 - effects: null,
476 - loc: instr.loc,
477 - };
478 - nextInstructions.push(symbolValueInstruction);
479 -
480 - const $$typeofPlace = createTemporaryPlace(fn.env, instr.value.loc);
481 - const $$typeofInstruction: Instruction = {
482 - id: makeInstructionId(0),
483 - lvalue: {...$$typeofPlace, effect: Effect.Mutate},
484 - value: {
485 - kind: 'MethodCall',
486 - receiver: symbolInstruction.lvalue,
487 - property: symbolForInstruction.lvalue,
488 - args: [symbolValueInstruction.lvalue],
489 - loc: instr.value.loc,
490 - },
491 - effects: null,
492 - loc: instr.loc,
493 - };
494 - const $$typeofProperty: ObjectProperty = {
495 - kind: 'ObjectProperty',
496 - key: {name: propertyName, kind: 'string'},
497 - type: 'property',
498 - place: {...$$typeofPlace, effect: Effect.Capture},
499 - };
500 - nextInstructions.push($$typeofInstruction);
501 - return $$typeofProperty;
502 -}
503 -
504 -function createTagProperty(
505 - fn: HIRFunction,
506 - instr: Instruction,
507 - nextInstructions: Array<Instruction>,
508 - componentTag: BuiltinTag | Place,
509 -): ObjectProperty {
510 - let tagProperty: ObjectProperty;
511 - switch (componentTag.kind) {
512 - case 'BuiltinTag': {
513 - const tagPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
514 - const tagInstruction: Instruction = {
515 - id: makeInstructionId(0),
516 - lvalue: {...tagPropertyPlace, effect: Effect.Mutate},
517 - value: {
518 - kind: 'Primitive',
519 - value: componentTag.name,
520 - loc: instr.value.loc,
521 - },
522 - effects: null,
523 - loc: instr.loc,
524 - };
525 - tagProperty = {
526 - kind: 'ObjectProperty',
527 - key: {name: 'type', kind: 'string'},
528 - type: 'property',
529 - place: {...tagPropertyPlace, effect: Effect.Capture},
530 - };
531 - nextInstructions.push(tagInstruction);
532 - break;
533 - }
534 - case 'Identifier': {
535 - tagProperty = {
536 - kind: 'ObjectProperty',
537 - key: {name: 'type', kind: 'string'},
538 - type: 'property',
539 - place: {...componentTag, effect: Effect.Capture},
540 - };
541 - break;
542 - }
543 - }
544 -
545 - return tagProperty;
546 -}
547 -
548 -function createPropsProperties(
549 - fn: HIRFunction,
550 - instr: Instruction,
551 - nextInstructions: Array<Instruction>,
552 - propAttributes: Array<JsxAttribute>,
553 - children: Array<Place> | null,
554 -): {
555 - refProperty: ObjectProperty;
556 - keyProperty: ObjectProperty;
557 - propsProperty: ObjectProperty;
558 -} {
559 - let refProperty: ObjectProperty | undefined;
560 - let keyProperty: ObjectProperty | undefined;
561 - const props: Array<ObjectProperty | SpreadPattern> = [];
562 - const jsxAttributesWithoutKey = propAttributes.filter(
563 - p => p.kind === 'JsxAttribute' && p.name !== 'key',
564 - );
565 - const jsxSpreadAttributes = propAttributes.filter(
566 - p => p.kind === 'JsxSpreadAttribute',
567 - );
568 - const spreadPropsOnly =
569 - jsxAttributesWithoutKey.length === 0 && jsxSpreadAttributes.length === 1;
570 - propAttributes.forEach(prop => {
571 - switch (prop.kind) {
572 - case 'JsxAttribute': {
573 - switch (prop.name) {
574 - case 'key': {
575 - keyProperty = {
576 - kind: 'ObjectProperty',
577 - key: {name: 'key', kind: 'string'},
578 - type: 'property',
579 - place: {...prop.place},
580 - };
581 - break;
582 - }
583 - case 'ref': {
584 - /**
585 - * In the current JSX implementation, ref is both
586 - * a property on the element and a property on props.
587 - */
588 - refProperty = {
589 - kind: 'ObjectProperty',
590 - key: {name: 'ref', kind: 'string'},
591 - type: 'property',
592 - place: {...prop.place},
593 - };
594 - const refPropProperty: ObjectProperty = {
595 - kind: 'ObjectProperty',
596 - key: {name: 'ref', kind: 'string'},
597 - type: 'property',
598 - place: {...prop.place},
599 - };
600 - props.push(refPropProperty);
601 - break;
602 - }
603 - default: {
604 - const attributeProperty: ObjectProperty = {
605 - kind: 'ObjectProperty',
606 - key: {name: prop.name, kind: 'string'},
607 - type: 'property',
608 - place: {...prop.place},
609 - };
610 - props.push(attributeProperty);
611 - }
612 - }
613 - break;
614 - }
615 - case 'JsxSpreadAttribute': {
616 - props.push({
617 - kind: 'Spread',
618 - place: {...prop.argument},
619 - });
620 - break;
621 - }
622 - }
623 - });
624 -
625 - const propsPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
626 - if (children) {
627 - let childrenPropProperty: ObjectProperty;
628 - if (children.length === 1) {
629 - childrenPropProperty = {
630 - kind: 'ObjectProperty',
631 - key: {name: 'children', kind: 'string'},
632 - type: 'property',
633 - place: {...children[0], effect: Effect.Capture},
634 - };
635 - } else {
636 - const childrenPropPropertyPlace = createTemporaryPlace(
637 - fn.env,
638 - instr.value.loc,
639 - );
640 -
641 - const childrenPropInstruction: Instruction = {
642 - id: makeInstructionId(0),
643 - lvalue: {...childrenPropPropertyPlace, effect: Effect.Mutate},
644 - value: {
645 - kind: 'ArrayExpression',
646 - elements: [...children],
647 - loc: instr.value.loc,
648 - },
649 - effects: null,
650 - loc: instr.loc,
651 - };
652 - nextInstructions.push(childrenPropInstruction);
653 - childrenPropProperty = {
654 - kind: 'ObjectProperty',
655 - key: {name: 'children', kind: 'string'},
656 - type: 'property',
657 - place: {...childrenPropPropertyPlace, effect: Effect.Capture},
658 - };
659 - }
660 - props.push(childrenPropProperty);
661 - }
662 -
663 - if (refProperty == null) {
664 - const refPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
665 - const refInstruction: Instruction = {
666 - id: makeInstructionId(0),
667 - lvalue: {...refPropertyPlace, effect: Effect.Mutate},
668 - value: {
669 - kind: 'Primitive',
670 - value: null,
671 - loc: instr.value.loc,
672 - },
673 - effects: null,
674 - loc: instr.loc,
675 - };
676 - refProperty = {
677 - kind: 'ObjectProperty',
678 - key: {name: 'ref', kind: 'string'},
679 - type: 'property',
680 - place: {...refPropertyPlace, effect: Effect.Capture},
681 - };
682 - nextInstructions.push(refInstruction);
683 - }
684 -
685 - if (keyProperty == null) {
686 - const keyPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
687 - const keyInstruction: Instruction = {
688 - id: makeInstructionId(0),
689 - lvalue: {...keyPropertyPlace, effect: Effect.Mutate},
690 - value: {
691 - kind: 'Primitive',
692 - value: null,
693 - loc: instr.value.loc,
694 - },
695 - effects: null,
696 - loc: instr.loc,
697 - };
698 - keyProperty = {
699 - kind: 'ObjectProperty',
700 - key: {name: 'key', kind: 'string'},
701 - type: 'property',
702 - place: {...keyPropertyPlace, effect: Effect.Capture},
703 - };
704 - nextInstructions.push(keyInstruction);
705 - }
706 -
707 - let propsProperty: ObjectProperty;
708 - if (spreadPropsOnly) {
709 - const spreadProp = jsxSpreadAttributes[0];
710 - CompilerError.invariant(spreadProp.kind === 'JsxSpreadAttribute', {
711 - reason: 'Spread prop attribute must be of kind JSXSpreadAttribute',
712 - loc: instr.loc,
713 - });
714 - propsProperty = {
715 - kind: 'ObjectProperty',
716 - key: {name: 'props', kind: 'string'},
717 - type: 'property',
718 - place: {...spreadProp.argument, effect: Effect.Mutate},
719 - };
720 - } else {
721 - const propsInstruction: Instruction = {
722 - id: makeInstructionId(0),
723 - lvalue: {...propsPropertyPlace, effect: Effect.Mutate},
724 - value: {
725 - kind: 'ObjectExpression',
726 - properties: props,
727 - loc: instr.value.loc,
728 - },
729 - effects: null,
730 - loc: instr.loc,
731 - };
732 - propsProperty = {
733 - kind: 'ObjectProperty',
734 - key: {name: 'props', kind: 'string'},
735 - type: 'property',
736 - place: {...propsPropertyPlace, effect: Effect.Capture},
737 - };
738 - nextInstructions.push(propsInstruction);
739 - }
740 -
741 - return {refProperty, keyProperty, propsProperty};
742 -}
743 -
744 -function handlePlace(
745 - place: Place,
746 - blockId: BlockId,
747 - inlinedJsxDeclarations: InlinedJsxDeclarationMap,
748 -): Place {
749 - const inlinedJsxDeclaration = inlinedJsxDeclarations.get(
750 - place.identifier.declarationId,
751 - );
752 - if (
753 - inlinedJsxDeclaration == null ||
754 - inlinedJsxDeclaration.blockIdsToIgnore.has(blockId)
755 - ) {
756 - return place;
757 - }
758 -
759 - return {...place, identifier: inlinedJsxDeclaration.identifier};
760 -}
761 -
762 -function handlelValue(
763 - lvalue: Place,
764 - blockId: BlockId,
765 - inlinedJsxDeclarations: InlinedJsxDeclarationMap,
766 -): Place {
767 - const inlinedJsxDeclaration = inlinedJsxDeclarations.get(
768 - lvalue.identifier.declarationId,
769 - );
770 - if (
771 - inlinedJsxDeclaration == null ||
772 - inlinedJsxDeclaration.blockIdsToIgnore.has(blockId)
773 - ) {
774 - return lvalue;
775 - }
776 -
777 - return {...lvalue, identifier: inlinedJsxDeclaration.identifier};
778 -}
779 -
780 -function handleIdentifier(
781 - identifier: Identifier,
782 - inlinedJsxDeclarations: InlinedJsxDeclarationMap,
783 -): Identifier {
784 - const inlinedJsxDeclaration = inlinedJsxDeclarations.get(
785 - identifier.declarationId,
786 - );
787 - return inlinedJsxDeclaration == null
788 - ? identifier
789 - : inlinedJsxDeclaration.identifier;
790 -}
compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts deleted
-503
@@ -1,503 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import {CompilerError} from '..';
9 -import {
10 - BasicBlock,
11 - Environment,
12 - GeneratedSource,
13 - HIRFunction,
14 - IdentifierId,
15 - Instruction,
16 - InstructionId,
17 - Place,
18 - isExpressionBlockKind,
19 - makeInstructionId,
20 - markInstructionIds,
21 -} from '../HIR';
22 -import {printInstruction} from '../HIR/PrintHIR';
23 -import {
24 - eachInstructionLValue,
25 - eachInstructionValueLValue,
26 - eachInstructionValueOperand,
27 - eachTerminalOperand,
28 -} from '../HIR/visitors';
29 -import {getOrInsertWith} from '../Utils/utils';
30 -
31 -/**
32 - * This pass implements conservative instruction reordering to move instructions closer to
33 - * to where their produced values are consumed. The goal is to group instructions in a way that
34 - * is more optimal for future optimizations. Notably, MergeReactiveScopesThatAlwaysInvalidateTogether
35 - * can only merge two candidate scopes if there are no intervenining instructions that are used by
36 - * some later code: instruction reordering can move those intervening instructions later in many cases,
37 - * thereby allowing more scopes to merge together.
38 - *
39 - * The high-level approach is to build a dependency graph where nodes correspond either to
40 - * instructions OR to a particular lvalue assignment of another instruction. So
41 - * `Destructure [x, y] = z` creates 3 nodes: one for the instruction, and one each for x and y.
42 - * The lvalue nodes depend on the instruction node that assigns them.
43 - *
44 - * Dependency edges are added for all the lvalues and rvalues of each instruction, so for example
45 - * the node for `t$2 = CallExpression t$0 ( t$1 )` will take dependencies on the nodes for t$0 and t$1.
46 - *
47 - * Individual instructions are grouped into two categories:
48 - * - "Reorderable" instructions include a safe set of instructions that we know are fine to reorder.
49 - * This includes JSX elements/fragments/text, primitives, template literals, and globals.
50 - * These instructions are never emitted until they are referenced, and can even be moved across
51 - * basic blocks until they are used.
52 - * - All other instructions are non-reorderable, and take an explicit dependency on the last such
53 - * non-reorderable instruction in their block. This largely ensures that mutations are serialized,
54 - * since all potentially mutating instructions are in this category.
55 - *
56 - * The only remaining mutation not handled by the above is variable reassignment. To ensure that all
57 - * reads/writes of a variable access the correct version, all references (lvalues and rvalues) to
58 - * each named variable are serialized. Thus `x = 1; y = x; x = 2; z = x` will establish a chain
59 - * of dependencies and retain the correct ordering.
60 - *
61 - * The algorithm proceeds one basic block at a time, first building up the dependnecy graph and then
62 - * reordering.
63 - *
64 - * The reordering weights nodes according to their transitive dependencies, and whether a particular node
65 - * needs memoization or not. Larger dependencies go first, followed by smaller dependencies, which in
66 - * testing seems to allow scopes to merge more effectively. Over time we can likely continue to improve
67 - * the reordering heuristic.
68 - *
69 - * An obvious area for improvement is to allow reordering of LoadLocals that occur after the last write
70 - * of the named variable. We can add this in a follow-up.
71 - */
72 -export function instructionReordering(fn: HIRFunction): void {
73 - // Shared nodes are emitted when they are first used
74 - const shared: Nodes = new Map();
75 - const references = findReferencedRangeOfTemporaries(fn);
76 - for (const [, block] of fn.body.blocks) {
77 - reorderBlock(fn.env, block, shared, references);
78 - }
79 - CompilerError.invariant(shared.size === 0, {
80 - reason: `InstructionReordering: expected all reorderable nodes to have been emitted`,
81 - loc:
82 - [...shared.values()]
83 - .map(node => node.instruction?.loc)
84 - .filter(loc => loc != null)[0] ?? GeneratedSource,
85 - });
86 - markInstructionIds(fn.body);
87 -}
88 -
89 -const DEBUG = false;
90 -
91 -type Nodes = Map<IdentifierId, Node>;
92 -type Node = {
93 - instruction: Instruction | null;
94 - dependencies: Set<IdentifierId>;
95 - reorderability: Reorderability;
96 - depth: number | null;
97 -};
98 -
99 -// Inclusive start and end
100 -type References = {
101 - singleUseIdentifiers: SingleUseIdentifiers;
102 - lastAssignments: LastAssignments;
103 -};
104 -type LastAssignments = Map<string, InstructionId>;
105 -type SingleUseIdentifiers = Set<IdentifierId>;
106 -enum ReferenceKind {
107 - Read,
108 - Write,
109 -}
110 -function findReferencedRangeOfTemporaries(fn: HIRFunction): References {
111 - const singleUseIdentifiers = new Map<IdentifierId, number>();
112 - const lastAssignments: LastAssignments = new Map();
113 - function reference(
114 - instr: InstructionId,
115 - place: Place,
116 - kind: ReferenceKind,
117 - ): void {
118 - if (
119 - place.identifier.name !== null &&
120 - place.identifier.name.kind === 'named'
121 - ) {
122 - if (kind === ReferenceKind.Write) {
123 - const name = place.identifier.name.value;
124 - const previous = lastAssignments.get(name);
125 - if (previous === undefined) {
126 - lastAssignments.set(name, instr);
127 - } else {
128 - lastAssignments.set(
129 - name,
130 - makeInstructionId(Math.max(previous, instr)),
131 - );
132 - }
133 - }
134 - return;
135 - } else if (kind === ReferenceKind.Read) {
136 - const previousCount = singleUseIdentifiers.get(place.identifier.id) ?? 0;
137 - singleUseIdentifiers.set(place.identifier.id, previousCount + 1);
138 - }
139 - }
140 - for (const [, block] of fn.body.blocks) {
141 - for (const instr of block.instructions) {
142 - for (const operand of eachInstructionValueLValue(instr.value)) {
143 - reference(instr.id, operand, ReferenceKind.Read);
144 - }
145 - for (const lvalue of eachInstructionLValue(instr)) {
146 - reference(instr.id, lvalue, ReferenceKind.Write);
147 - }
148 - }
149 - for (const operand of eachTerminalOperand(block.terminal)) {
150 - reference(block.terminal.id, operand, ReferenceKind.Read);
151 - }
152 - }
153 - return {
154 - singleUseIdentifiers: new Set(
155 - [...singleUseIdentifiers]
156 - .filter(([, count]) => count === 1)
157 - .map(([id]) => id),
158 - ),
159 - lastAssignments,
160 - };
161 -}
162 -
163 -function reorderBlock(
164 - env: Environment,
165 - block: BasicBlock,
166 - shared: Nodes,
167 - references: References,
168 -): void {
169 - const locals: Nodes = new Map();
170 - const named: Map<string, IdentifierId> = new Map();
171 - let previous: IdentifierId | null = null;
172 - for (const instr of block.instructions) {
173 - const {lvalue, value} = instr;
174 - // Get or create a node for this lvalue
175 - const reorderability = getReorderability(instr, references);
176 - const node = getOrInsertWith(
177 - locals,
178 - lvalue.identifier.id,
179 - () =>
180 - ({
181 - instruction: instr,
182 - dependencies: new Set(),
183 - reorderability,
184 - depth: null,
185 - }) as Node,
186 - );
187 - /**
188 - * Ensure non-reoderable instructions have their order retained by
189 - * adding explicit dependencies to the previous such instruction.
190 - */
191 - if (reorderability === Reorderability.Nonreorderable) {
192 - if (previous !== null) {
193 - node.dependencies.add(previous);
194 - }
195 - previous = lvalue.identifier.id;
196 - }
197 - /**
198 - * Establish dependencies on operands
199 - */
200 - for (const operand of eachInstructionValueOperand(value)) {
201 - const {name, id} = operand.identifier;
202 - if (name !== null && name.kind === 'named') {
203 - // Serialize all accesses to named variables
204 - const previous = named.get(name.value);
205 - if (previous !== undefined) {
206 - node.dependencies.add(previous);
207 - }
208 - named.set(name.value, lvalue.identifier.id);
209 - } else if (locals.has(id) || shared.has(id)) {
210 - node.dependencies.add(id);
211 - }
212 - }
213 - /**
214 - * Establish nodes for lvalues, with dependencies on the node
215 - * for the instruction itself. This ensures that any consumers
216 - * of the lvalue will take a dependency through to the original
217 - * instruction.
218 - */
219 - for (const lvalueOperand of eachInstructionValueLValue(value)) {
220 - const lvalueNode = getOrInsertWith(
221 - locals,
222 - lvalueOperand.identifier.id,
223 - () =>
224 - ({
225 - instruction: null,
226 - dependencies: new Set(),
227 - depth: null,
228 - }) as Node,
229 - );
230 - lvalueNode.dependencies.add(lvalue.identifier.id);
231 - const name = lvalueOperand.identifier.name;
232 - if (name !== null && name.kind === 'named') {
233 - const previous = named.get(name.value);
234 - if (previous !== undefined) {
235 - node.dependencies.add(previous);
236 - }
237 - named.set(name.value, lvalue.identifier.id);
238 - }
239 - }
240 - }
241 -
242 - const nextInstructions: Array<Instruction> = [];
243 - const seen = new Set<IdentifierId>();
244 -
245 - DEBUG && console.log(`bb${block.id}`);
246 -
247 - /**
248 - * The ideal order for emitting instructions may change the final instruction,
249 - * but value blocks have special semantics for the final instruction of a block -
250 - * that's the expression's value!. So we choose between a less optimal strategy
251 - * for value blocks which preserves the final instruction order OR a more optimal
252 - * ordering for statement-y blocks.
253 - */
254 - if (isExpressionBlockKind(block.kind)) {
255 - // First emit everything that can't be reordered
256 - if (previous !== null) {
257 - DEBUG && console.log(`(last non-reorderable instruction)`);
258 - DEBUG && print(env, locals, shared, seen, previous);
259 - emit(env, locals, shared, nextInstructions, previous);
260 - }
261 - /*
262 - * For "value" blocks the final instruction represents its value, so we have to be
263 - * careful to not change the ordering. Emit the last instruction explicitly.
264 - * Any non-reorderable instructions will get emitted first, and any unused
265 - * reorderable instructions can be deferred to the shared node list.
266 - */
267 - if (block.instructions.length !== 0) {
268 - DEBUG && console.log(`(block value)`);
269 - DEBUG &&
270 - print(
271 - env,
272 - locals,
273 - shared,
274 - seen,
275 - block.instructions.at(-1)!.lvalue.identifier.id,
276 - );
277 - emit(
278 - env,
279 - locals,
280 - shared,
281 - nextInstructions,
282 - block.instructions.at(-1)!.lvalue.identifier.id,
283 - );
284 - }
285 - /*
286 - * Then emit the dependencies of the terminal operand. In many cases they will have
287 - * already been emitted in the previous step and this is a no-op.
288 - * TODO: sort the dependencies based on weight, like we do for other nodes. Not a big
289 - * deal though since most terminals have a single operand
290 - */
291 - for (const operand of eachTerminalOperand(block.terminal)) {
292 - DEBUG && console.log(`(terminal operand)`);
293 - DEBUG && print(env, locals, shared, seen, operand.identifier.id);
294 - emit(env, locals, shared, nextInstructions, operand.identifier.id);
295 - }
296 - // Anything not emitted yet is globally reorderable
297 - for (const [id, node] of locals) {
298 - if (node.instruction == null) {
299 - continue;
300 - }
301 - CompilerError.invariant(
302 - node.reorderability === Reorderability.Reorderable,
303 - {
304 - reason: `Expected all remaining instructions to be reorderable`,
305 - description:
306 - node.instruction != null
307 - ? `Instruction [${node.instruction.id}] was not emitted yet but is not reorderable`
308 - : `Lvalue $${id} was not emitted yet but is not reorderable`,
309 - loc: node.instruction?.loc ?? block.terminal.loc,
310 - },
311 - );
312 -
313 - DEBUG && console.log(`save shared: $${id}`);
314 - shared.set(id, node);
315 - }
316 - } else {
317 - /**
318 - * If this is not a value block, then the order within the block doesn't matter
319 - * and we can optimize more. The observation is that blocks often have instructions
320 - * such as:
321 - *
322 - * ```
323 - * t$0 = nonreorderable
324 - * t$1 = nonreorderable <-- this gets in the way of merging t$0 and t$2
325 - * t$2 = reorderable deps[ t$0 ]
326 - * return t$2
327 - * ```
328 - *
329 - * Ie where there is some pair of nonreorderable+reorderable values, with some intervening
330 - * also non-reorderable instruction. If we emit all non-reorderable instructions first,
331 - * then we'll keep the original order. But reordering instructions doesn't just mean moving
332 - * them later: we can also move them _earlier_. By starting from terminal operands we
333 - * end up emitting:
334 - *
335 - * ```
336 - * t$0 = nonreorderable // dep of t$2
337 - * t$2 = reorderable deps[ t$0 ]
338 - * t$1 = nonreorderable <-- not in the way of merging anymore!
339 - * return t$2
340 - * ```
341 - *
342 - * Ie all nonreorderable transitive deps of the terminal operands will get emitted first,
343 - * but we'll be able to intersperse the depending reorderable instructions in between
344 - * them in a way that works better with scope merging.
345 - */
346 - for (const operand of eachTerminalOperand(block.terminal)) {
347 - DEBUG && console.log(`(terminal operand)`);
348 - DEBUG && print(env, locals, shared, seen, operand.identifier.id);
349 - emit(env, locals, shared, nextInstructions, operand.identifier.id);
350 - }
351 - // Anything not emitted yet is globally reorderable
352 - for (const id of Array.from(locals.keys()).reverse()) {
353 - const node = locals.get(id);
354 - if (node === undefined) {
355 - continue;
356 - }
357 - if (node.reorderability === Reorderability.Reorderable) {
358 - DEBUG && console.log(`save shared: $${id}`);
359 - shared.set(id, node);
360 - } else {
361 - DEBUG && console.log('leftover');
362 - DEBUG && print(env, locals, shared, seen, id);
363 - emit(env, locals, shared, nextInstructions, id);
364 - }
365 - }
366 - }
367 -
368 - block.instructions = nextInstructions;
369 - DEBUG && console.log();
370 -}
371 -
372 -function getDepth(env: Environment, nodes: Nodes, id: IdentifierId): number {
373 - const node = nodes.get(id)!;
374 - if (node == null) {
375 - return 0;
376 - }
377 - if (node.depth != null) {
378 - return node.depth;
379 - }
380 - node.depth = 0; // in case of cycles
381 - let depth = node.reorderability === Reorderability.Reorderable ? 1 : 10;
382 - for (const dep of node.dependencies) {
383 - depth += getDepth(env, nodes, dep);
384 - }
385 - node.depth = depth;
386 - return depth;
387 -}
388 -
389 -function print(
390 - env: Environment,
391 - locals: Nodes,
392 - shared: Nodes,
393 - seen: Set<IdentifierId>,
394 - id: IdentifierId,
395 - depth: number = 0,
396 -): void {
397 - if (seen.has(id)) {
398 - DEBUG && console.log(`${'| '.repeat(depth)}$${id} <skipped>`);
399 - return;
400 - }
401 - seen.add(id);
402 - const node = locals.get(id) ?? shared.get(id);
403 - if (node == null) {
404 - return;
405 - }
406 - const deps = [...node.dependencies];
407 - deps.sort((a, b) => {
408 - const aDepth = getDepth(env, locals, a);
409 - const bDepth = getDepth(env, locals, b);
410 - return bDepth - aDepth;
411 - });
412 - for (const dep of deps) {
413 - print(env, locals, shared, seen, dep, depth + 1);
414 - }
415 - DEBUG &&
416 - console.log(
417 - `${'| '.repeat(depth)}$${id} ${printNode(node)} deps=[${deps
418 - .map(x => `$${x}`)
419 - .join(', ')}] depth=${node.depth}`,
420 - );
421 -}
422 -
423 -function printNode(node: Node): string {
424 - const {instruction} = node;
425 - if (instruction === null) {
426 - return '<lvalue-only>';
427 - }
428 - switch (instruction.value.kind) {
429 - case 'FunctionExpression':
430 - case 'ObjectMethod': {
431 - return `[${instruction.id}] ${instruction.value.kind}`;
432 - }
433 - default: {
434 - return printInstruction(instruction);
435 - }
436 - }
437 -}
438 -
439 -function emit(
440 - env: Environment,
441 - locals: Nodes,
442 - shared: Nodes,
443 - instructions: Array<Instruction>,
444 - id: IdentifierId,
445 -): void {
446 - const node = locals.get(id) ?? shared.get(id);
447 - if (node == null) {
448 - return;
449 - }
450 - locals.delete(id);
451 - shared.delete(id);
452 - const deps = [...node.dependencies];
453 - deps.sort((a, b) => {
454 - const aDepth = getDepth(env, locals, a);
455 - const bDepth = getDepth(env, locals, b);
456 - return bDepth - aDepth;
457 - });
458 - for (const dep of deps) {
459 - emit(env, locals, shared, instructions, dep);
460 - }
461 - if (node.instruction !== null) {
462 - instructions.push(node.instruction);
463 - }
464 -}
465 -
466 -enum Reorderability {
467 - Reorderable,
468 - Nonreorderable,
469 -}
470 -function getReorderability(
471 - instr: Instruction,
472 - references: References,
473 -): Reorderability {
474 - switch (instr.value.kind) {
475 - case 'JsxExpression':
476 - case 'JsxFragment':
477 - case 'JSXText':
478 - case 'LoadGlobal':
479 - case 'Primitive':
480 - case 'TemplateLiteral':
481 - case 'BinaryExpression':
482 - case 'UnaryExpression': {
483 - return Reorderability.Reorderable;
484 - }
485 - case 'LoadLocal': {
486 - const name = instr.value.place.identifier.name;
487 - if (name !== null && name.kind === 'named') {
488 - const lastAssignment = references.lastAssignments.get(name.value);
489 - if (
490 - lastAssignment !== undefined &&
491 - lastAssignment < instr.id &&
492 - references.singleUseIdentifiers.has(instr.lvalue.identifier.id)
493 - ) {
494 - return Reorderability.Reorderable;
495 - }
496 - }
497 - return Reorderability.Nonreorderable;
498 - }
499 - default: {
500 - return Reorderability.Nonreorderable;
501 - }
502 - }
503 -}
compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts deleted
-308
@@ -1,308 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import {
9 - ArrayExpression,
10 - BasicBlock,
11 - CallExpression,
12 - Destructure,
13 - Environment,
14 - ExternalFunction,
15 - GeneratedSource,
16 - HIRFunction,
17 - IdentifierId,
18 - Instruction,
19 - LoadGlobal,
20 - LoadLocal,
21 - NonLocalImportSpecifier,
22 - Place,
23 - PropertyLoad,
24 - isUseContextHookType,
25 - makeBlockId,
26 - makeInstructionId,
27 - makePropertyLiteral,
28 - markInstructionIds,
29 - promoteTemporary,
30 - reversePostorderBlocks,
31 -} from '../HIR';
32 -import {createTemporaryPlace} from '../HIR/HIRBuilder';
33 -import {enterSSA} from '../SSA';
34 -import {inferTypes} from '../TypeInference';
35 -
36 -export function lowerContextAccess(
37 - fn: HIRFunction,
38 - loweredContextCalleeConfig: ExternalFunction,
39 -): void {
40 - const contextAccess: Map<IdentifierId, CallExpression> = new Map();
41 - const contextKeys: Map<IdentifierId, Array<string>> = new Map();
42 -
43 - // collect context access and keys
44 - for (const [, block] of fn.body.blocks) {
45 - for (const instr of block.instructions) {
46 - const {value, lvalue} = instr;
47 -
48 - if (
49 - value.kind === 'CallExpression' &&
50 - isUseContextHookType(value.callee.identifier)
51 - ) {
52 - contextAccess.set(lvalue.identifier.id, value);
53 - continue;
54 - }
55 -
56 - if (value.kind !== 'Destructure') {
57 - continue;
58 - }
59 -
60 - const destructureId = value.value.identifier.id;
61 - if (!contextAccess.has(destructureId)) {
62 - continue;
63 - }
64 -
65 - const keys = getContextKeys(value);
66 - if (keys === null) {
67 - return;
68 - }
69 -
70 - if (contextKeys.has(destructureId)) {
71 - /*
72 - * TODO(gsn): Add support for accessing context over multiple
73 - * statements.
74 - */
75 - return;
76 - } else {
77 - contextKeys.set(destructureId, keys);
78 - }
79 - }
80 - }
81 -
82 - let importLoweredContextCallee: NonLocalImportSpecifier | null = null;
83 -
84 - if (contextAccess.size > 0 && contextKeys.size > 0) {
85 - for (const [, block] of fn.body.blocks) {
86 - let nextInstructions: Array<Instruction> | null = null;
87 -
88 - for (let i = 0; i < block.instructions.length; i++) {
89 - const instr = block.instructions[i];
90 - const {lvalue, value} = instr;
91 - if (
92 - value.kind === 'CallExpression' &&
93 - isUseContextHookType(value.callee.identifier) &&
94 - contextKeys.has(lvalue.identifier.id)
95 - ) {
96 - importLoweredContextCallee ??=
97 - fn.env.programContext.addImportSpecifier(
98 - loweredContextCalleeConfig,
99 - );
100 - const loweredContextCalleeInstr = emitLoadLoweredContextCallee(
101 - fn.env,
102 - importLoweredContextCallee,
103 - );
104 -
105 - if (nextInstructions === null) {
106 - nextInstructions = block.instructions.slice(0, i);
107 - }
108 - nextInstructions.push(loweredContextCalleeInstr);
109 -
110 - const keys = contextKeys.get(lvalue.identifier.id)!;
111 - const selectorFnInstr = emitSelectorFn(fn.env, keys);
112 - nextInstructions.push(selectorFnInstr);
113 -
114 - const lowerContextCallId = loweredContextCalleeInstr.lvalue;
115 - value.callee = lowerContextCallId;
116 -
117 - const selectorFn = selectorFnInstr.lvalue;
118 - value.args.push(selectorFn);
119 - }
120 -
121 - if (nextInstructions) {
122 - nextInstructions.push(instr);
123 - }
124 - }
125 - if (nextInstructions) {
126 - block.instructions = nextInstructions;
127 - }
128 - }
129 - markInstructionIds(fn.body);
130 - inferTypes(fn);
131 - }
132 -}
133 -
134 -function emitLoadLoweredContextCallee(
135 - env: Environment,
136 - importedLowerContextCallee: NonLocalImportSpecifier,
137 -): Instruction {
138 - const loadGlobal: LoadGlobal = {
139 - kind: 'LoadGlobal',
140 - binding: {...importedLowerContextCallee},
141 - loc: GeneratedSource,
142 - };
143 -
144 - return {
145 - id: makeInstructionId(0),
146 - loc: GeneratedSource,
147 - lvalue: createTemporaryPlace(env, GeneratedSource),
148 - effects: null,
149 - value: loadGlobal,
150 - };
151 -}
152 -
153 -function getContextKeys(value: Destructure): Array<string> | null {
154 - const keys = [];
155 - const pattern = value.lvalue.pattern;
156 -
157 - switch (pattern.kind) {
158 - case 'ArrayPattern': {
159 - return null;
160 - }
161 -
162 - case 'ObjectPattern': {
163 - for (const place of pattern.properties) {
164 - if (
165 - place.kind !== 'ObjectProperty' ||
166 - place.type !== 'property' ||
167 - place.key.kind !== 'identifier' ||
168 - place.place.identifier.name === null ||
169 - place.place.identifier.name.kind !== 'named'
170 - ) {
171 - return null;
172 - }
173 - keys.push(place.key.name);
174 - }
175 - return keys;
176 - }
177 - }
178 -}
179 -
180 -function emitPropertyLoad(
181 - env: Environment,
182 - obj: Place,
183 - property: string,
184 -): {instructions: Array<Instruction>; element: Place} {
185 - const loadObj: LoadLocal = {
186 - kind: 'LoadLocal',
187 - place: obj,
188 - loc: GeneratedSource,
189 - };
190 - const object: Place = createTemporaryPlace(env, GeneratedSource);
191 - const loadLocalInstr: Instruction = {
192 - lvalue: object,
193 - value: loadObj,
194 - id: makeInstructionId(0),
195 - effects: null,
196 - loc: GeneratedSource,
197 - };
198 -
199 - const loadProp: PropertyLoad = {
200 - kind: 'PropertyLoad',
201 - object,
202 - property: makePropertyLiteral(property),
203 - loc: GeneratedSource,
204 - };
205 - const element: Place = createTemporaryPlace(env, GeneratedSource);
206 - const loadPropInstr: Instruction = {
207 - lvalue: element,
208 - value: loadProp,
209 - id: makeInstructionId(0),
210 - effects: null,
211 - loc: GeneratedSource,
212 - };
213 - return {
214 - instructions: [loadLocalInstr, loadPropInstr],
215 - element: element,
216 - };
217 -}
218 -
219 -function emitSelectorFn(env: Environment, keys: Array<string>): Instruction {
220 - const obj: Place = createTemporaryPlace(env, GeneratedSource);
221 - promoteTemporary(obj.identifier);
222 - const instr: Array<Instruction> = [];
223 - const elements = [];
224 - for (const key of keys) {
225 - const {instructions, element: prop} = emitPropertyLoad(env, obj, key);
226 - instr.push(...instructions);
227 - elements.push(prop);
228 - }
229 -
230 - const arrayInstr = emitArrayInstr(elements, env);
231 - instr.push(arrayInstr);
232 -
233 - const block: BasicBlock = {
234 - kind: 'block',
235 - id: makeBlockId(0),
236 - instructions: instr,
237 - terminal: {
238 - id: makeInstructionId(0),
239 - kind: 'return',
240 - returnVariant: 'Explicit',
241 - loc: GeneratedSource,
242 - value: arrayInstr.lvalue,
243 - effects: null,
244 - },
245 - preds: new Set(),
246 - phis: new Set(),
247 - };
248 -
249 - const fn: HIRFunction = {
250 - loc: GeneratedSource,
251 - id: null,
252 - nameHint: null,
253 - fnType: 'Other',
254 - env,
255 - params: [obj],
256 - returnTypeAnnotation: null,
257 - returns: createTemporaryPlace(env, GeneratedSource),
258 - context: [],
259 - body: {
260 - entry: block.id,
261 - blocks: new Map([[block.id, block]]),
262 - },
263 - generator: false,
264 - async: false,
265 - directives: [],
266 - aliasingEffects: [],
267 - };
268 -
269 - reversePostorderBlocks(fn.body);
270 - markInstructionIds(fn.body);
271 - enterSSA(fn);
272 - inferTypes(fn);
273 -
274 - const fnInstr: Instruction = {
275 - id: makeInstructionId(0),
276 - value: {
277 - kind: 'FunctionExpression',
278 - name: null,
279 - nameHint: null,
280 - loweredFunc: {
281 - func: fn,
282 - },
283 - type: 'ArrowFunctionExpression',
284 - loc: GeneratedSource,
285 - },
286 - lvalue: createTemporaryPlace(env, GeneratedSource),
287 - effects: null,
288 - loc: GeneratedSource,
289 - };
290 - return fnInstr;
291 -}
292 -
293 -function emitArrayInstr(elements: Array<Place>, env: Environment): Instruction {
294 - const array: ArrayExpression = {
295 - kind: 'ArrayExpression',
296 - elements,
297 - loc: GeneratedSource,
298 - };
299 - const arrayLvalue: Place = createTemporaryPlace(env, GeneratedSource);
300 - const arrayInstr: Instruction = {
301 - id: makeInstructionId(0),
302 - value: array,
303 - lvalue: arrayLvalue,
304 - effects: null,
305 - loc: GeneratedSource,
306 - };
307 - return arrayInstr;
308 -}
compiler/packages/babel-plugin-react-compiler/src/Optimization/index.ts
-1
@@ -8,4 +8,3 @@
8 export {constantPropagation} from './ConstantPropagation';
9 export {deadCodeElimination} from './DeadCodeElimination';
10 export {pruneMaybeThrows} from './PruneMaybeThrows';
11 -export {inlineJsxTransform} from './InlineJsxTransform';
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+32 -264
@@ -52,7 +52,7 @@ import {assertExhaustive} from '../Utils/utils';
52 import {buildReactiveFunction} from './BuildReactiveFunction';
53 import {SINGLE_CHILD_FBT_TAGS} from './MemoizeFbtAndMacroOperandsInSameScope';
54 import {ReactiveFunctionVisitor, visitReactiveFunction} from './visitors';
55 -import {EMIT_FREEZE_GLOBAL_GATING, ReactFunctionType} from '../HIR/Environment';
55 +import {ReactFunctionType} from '../HIR/Environment';
56 import {ProgramContext} from '../Entrypoint';
57
58 export const MEMO_CACHE_SENTINEL = 'react.memo_cache_sentinel';
@@ -100,17 +100,6 @@ export type CodegenFunction = {
100 fn: CodegenFunction;
101 type: ReactFunctionType | null;
102 }>;
103 -
104 - /**
105 - * This is true if the compiler has compiled inferred effect dependencies
106 - */
107 - hasInferredEffect: boolean;
108 - inferredEffectLocations: Set<SourceLocation>;
109 -
110 - /**
111 - * This is true if the compiler has compiled a fire to a useFire call
112 - */
113 - hasFireRewrite: boolean;
103 };
104
105 export function codegenFunction(
@@ -387,9 +376,6 @@ function codegenReactiveFunction(
376 prunedMemoBlocks: countMemoBlockVisitor.prunedMemoBlocks,
377 prunedMemoValues: countMemoBlockVisitor.prunedMemoValues,
378 outlined: [],
390 - hasFireRewrite: fn.env.hasFireRewrite,
391 - hasInferredEffect: fn.env.hasInferredEffect,
392 - inferredEffectLocations: fn.env.inferredEffectLocations,
379 });
380 }
381
@@ -574,30 +560,6 @@ function codegenBlockNoReset(
560 return t.blockStatement(statements);
561 }
562
577 -function wrapCacheDep(cx: Context, value: t.Expression): t.Expression {
578 - if (
579 - cx.env.config.enableEmitFreeze != null &&
580 - cx.env.outputMode === 'client'
581 - ) {
582 - const emitFreezeIdentifier = cx.env.programContext.addImportSpecifier(
583 - cx.env.config.enableEmitFreeze,
584 - ).name;
585 - cx.env.programContext
586 - .assertGlobalBinding(EMIT_FREEZE_GLOBAL_GATING, cx.env.scope)
587 - .unwrap();
588 - return t.conditionalExpression(
589 - t.identifier(EMIT_FREEZE_GLOBAL_GATING),
590 - t.callExpression(t.identifier(emitFreezeIdentifier), [
591 - value,
592 - t.stringLiteral(cx.fnName),
593 - ]),
594 - value,
595 - );
596 - } else {
597 - return value;
598 - }
599 -}
600 -
563 function codegenReactiveScope(
564 cx: Context,
565 statements: Array<t.Statement>,
@@ -612,12 +574,9 @@ function codegenReactiveScope(
574 value: t.Expression;
575 }> = [];
576 const changeExpressions: Array<t.Expression> = [];
615 - const changeExpressionComments: Array<string> = [];
616 - const outputComments: Array<string> = [];
577
578 for (const dep of [...scope.dependencies].sort(compareScopeDependency)) {
579 const index = cx.nextCacheIndex;
620 - changeExpressionComments.push(printDependencyComment(dep));
580 const comparison = t.binaryExpression(
581 '!==',
582 t.memberExpression(
@@ -627,18 +586,7 @@ function codegenReactiveScope(
586 ),
587 codegenDependency(cx, dep),
588 );
630 -
631 - if (cx.env.config.enableChangeVariableCodegen) {
632 - const changeIdentifier = t.identifier(cx.synthesizeName(`c_${index}`));
633 - statements.push(
634 - t.variableDeclaration('const', [
635 - t.variableDeclarator(changeIdentifier, comparison),
636 - ]),
637 - );
638 - changeExpressions.push(changeIdentifier);
639 - } else {
640 - changeExpressions.push(comparison);
641 - }
589 + changeExpressions.push(comparison);
590 /*
591 * Adding directly to cacheStoreStatements rather than cacheLoads, because there
592 * is no corresponding cacheLoadStatement for dependencies
@@ -676,13 +624,12 @@ function codegenReactiveScope(
624 });
625
626 const name = convertIdentifier(identifier);
679 - outputComments.push(name.name);
627 if (!cx.hasDeclared(identifier)) {
628 statements.push(
629 t.variableDeclaration('let', [createVariableDeclarator(name, null)]),
630 );
631 }
685 - cacheLoads.push({name, index, value: wrapCacheDep(cx, name)});
632 + cacheLoads.push({name, index, value: name});
633 cx.declare(identifier);
634 }
635 for (const reassignment of scope.reassignments) {
@@ -691,8 +638,7 @@ function codegenReactiveScope(
638 firstOutputIndex = index;
639 }
640 const name = convertIdentifier(reassignment);
694 - outputComments.push(name.name);
695 - cacheLoads.push({name, index, value: wrapCacheDep(cx, name)});
641 + cacheLoads.push({name, index, value: name});
642 }
643
644 let testCondition = (changeExpressions as Array<t.Expression>).reduce(
@@ -724,187 +670,44 @@ function codegenReactiveScope(
670 );
671 }
672
727 - if (cx.env.config.disableMemoizationForDebugging) {
728 - CompilerError.invariant(
729 - cx.env.config.enableChangeDetectionForDebugging == null,
730 - {
731 - reason: `Expected to not have both change detection enabled and memoization disabled`,
732 - description: `Incompatible config options`,
733 - loc: GeneratedSource,
734 - },
735 - );
736 - testCondition = t.logicalExpression(
737 - '||',
738 - testCondition,
739 - t.booleanLiteral(true),
740 - );
741 - }
673 let computationBlock = codegenBlock(cx, block);
674
675 let memoStatement;
745 - const detectionFunction = cx.env.config.enableChangeDetectionForDebugging;
746 - if (detectionFunction != null && changeExpressions.length > 0) {
747 - const loc =
748 - typeof scope.loc === 'symbol'
749 - ? 'unknown location'
750 - : `(${scope.loc.start.line}:${scope.loc.end.line})`;
751 - const importedDetectionFunctionIdentifier =
752 - cx.env.programContext.addImportSpecifier(detectionFunction).name;
753 - const cacheLoadOldValueStatements: Array<t.Statement> = [];
754 - const changeDetectionStatements: Array<t.Statement> = [];
755 - const idempotenceDetectionStatements: Array<t.Statement> = [];
756 -
757 - for (const {name, index, value} of cacheLoads) {
758 - const loadName = cx.synthesizeName(`old$${name.name}`);
759 - const slot = t.memberExpression(
760 - t.identifier(cx.synthesizeName('$')),
761 - t.numericLiteral(index),
762 - true,
763 - );
764 - cacheStoreStatements.push(
765 - t.expressionStatement(t.assignmentExpression('=', slot, value)),
766 - );
767 - cacheLoadOldValueStatements.push(
768 - t.variableDeclaration('let', [
769 - t.variableDeclarator(t.identifier(loadName), slot),
770 - ]),
771 - );
772 - changeDetectionStatements.push(
773 - t.expressionStatement(
774 - t.callExpression(t.identifier(importedDetectionFunctionIdentifier), [
775 - t.identifier(loadName),
776 - t.cloneNode(name, true),
777 - t.stringLiteral(name.name),
778 - t.stringLiteral(cx.fnName),
779 - t.stringLiteral('cached'),
780 - t.stringLiteral(loc),
781 - ]),
782 - ),
783 - );
784 - idempotenceDetectionStatements.push(
785 - t.expressionStatement(
786 - t.callExpression(t.identifier(importedDetectionFunctionIdentifier), [
787 - t.cloneNode(slot, true),
788 - t.cloneNode(name, true),
789 - t.stringLiteral(name.name),
790 - t.stringLiteral(cx.fnName),
791 - t.stringLiteral('recomputed'),
792 - t.stringLiteral(loc),
793 - ]),
794 - ),
795 - );
796 - idempotenceDetectionStatements.push(
797 - t.expressionStatement(t.assignmentExpression('=', name, slot)),
798 - );
799 - }
800 - const condition = cx.synthesizeName('condition');
801 - const recomputationBlock = t.cloneNode(computationBlock, true);
802 - memoStatement = t.blockStatement([
803 - ...computationBlock.body,
804 - t.variableDeclaration('let', [
805 - t.variableDeclarator(t.identifier(condition), testCondition),
806 - ]),
807 - t.ifStatement(
808 - t.unaryExpression('!', t.identifier(condition)),
809 - t.blockStatement([
810 - ...cacheLoadOldValueStatements,
811 - ...changeDetectionStatements,
812 - ]),
813 - ),
814 - ...cacheStoreStatements,
815 - t.ifStatement(
816 - t.identifier(condition),
817 - t.blockStatement([
818 - ...recomputationBlock.body,
819 - ...idempotenceDetectionStatements,
820 - ]),
821 - ),
822 - ]);
823 - } else {
824 - for (const {name, index, value} of cacheLoads) {
825 - cacheStoreStatements.push(
826 - t.expressionStatement(
827 - t.assignmentExpression(
828 - '=',
829 - t.memberExpression(
830 - t.identifier(cx.synthesizeName('$')),
831 - t.numericLiteral(index),
832 - true,
833 - ),
834 - value,
676 + for (const {name, index, value} of cacheLoads) {
677 + cacheStoreStatements.push(
678 + t.expressionStatement(
679 + t.assignmentExpression(
680 + '=',
681 + t.memberExpression(
682 + t.identifier(cx.synthesizeName('$')),
683 + t.numericLiteral(index),
684 + true,
685 ),
686 + value,
687 ),
837 - );
838 - cacheLoadStatements.push(
839 - t.expressionStatement(
840 - t.assignmentExpression(
841 - '=',
842 - name,
843 - t.memberExpression(
844 - t.identifier(cx.synthesizeName('$')),
845 - t.numericLiteral(index),
846 - true,
847 - ),
688 + ),
689 + );
690 + cacheLoadStatements.push(
691 + t.expressionStatement(
692 + t.assignmentExpression(
693 + '=',
694 + name,
695 + t.memberExpression(
696 + t.identifier(cx.synthesizeName('$')),
697 + t.numericLiteral(index),
698 + true,
699 ),
700 ),
850 - );
851 - }
852 - computationBlock.body.push(...cacheStoreStatements);
853 - memoStatement = t.ifStatement(
854 - testCondition,
855 - computationBlock,
856 - t.blockStatement(cacheLoadStatements),
701 + ),
702 );
703 }
704 + computationBlock.body.push(...cacheStoreStatements);
705 + memoStatement = t.ifStatement(
706 + testCondition,
707 + computationBlock,
708 + t.blockStatement(cacheLoadStatements),
709 + );
710
860 - if (cx.env.config.enableMemoizationComments) {
861 - if (changeExpressionComments.length) {
862 - t.addComment(
863 - memoStatement,
864 - 'leading',
865 - ` check if ${printDelimitedCommentList(
866 - changeExpressionComments,
867 - 'or',
868 - )} changed`,
869 - true,
870 - );
871 - t.addComment(
872 - memoStatement,
873 - 'leading',
874 - ` "useMemo" for ${printDelimitedCommentList(outputComments, 'and')}:`,
875 - true,
876 - );
877 - } else {
878 - t.addComment(
879 - memoStatement,
880 - 'leading',
881 - ' cache value with no dependencies',
882 - true,
883 - );
884 - t.addComment(
885 - memoStatement,
886 - 'leading',
887 - ` "useMemo" for ${printDelimitedCommentList(outputComments, 'and')}:`,
888 - true,
889 - );
890 - }
891 - if (computationBlock.body.length > 0) {
892 - t.addComment(
893 - computationBlock.body[0]!,
894 - 'leading',
895 - ` Inputs changed, recompute`,
896 - true,
897 - );
898 - }
899 - if (cacheLoadStatements.length > 0) {
900 - t.addComment(
901 - cacheLoadStatements[0]!,
902 - 'leading',
903 - ` Inputs did not change, use cached value`,
904 - true,
905 - );
906 - }
907 - }
711 statements.push(memoStatement);
712
713 const earlyReturnValue = scope.earlyReturnValue;
@@ -1431,41 +1234,6 @@ function codegenForInit(
1234 }
1235 }
1236
1434 -function printDependencyComment(dependency: ReactiveScopeDependency): string {
1435 - const identifier = convertIdentifier(dependency.identifier);
1436 - let name = identifier.name;
1437 - if (dependency.path !== null) {
1438 - for (const path of dependency.path) {
1439 - name += `.${path.property}`;
1440 - }
1441 - }
1442 - return name;
1443 -}
1444 -
1445 -function printDelimitedCommentList(
1446 - items: Array<string>,
1447 - finalCompletion: string,
1448 -): string {
1449 - if (items.length === 2) {
1450 - return items.join(` ${finalCompletion} `);
1451 - } else if (items.length <= 1) {
1452 - return items.join('');
1453 - }
1454 -
1455 - let output = [];
1456 - for (let i = 0; i < items.length; i++) {
1457 - const item = items[i]!;
1458 - if (i < items.length - 2) {
1459 - output.push(`${item}, `);
1460 - } else if (i === items.length - 2) {
1461 - output.push(`${item}, ${finalCompletion} `);
1462 - } else {
1463 - output.push(item);
1464 - }
1465 - }
1466 - return output.join('');
1467 -}
1468 -
1237 function codegenDependency(
1238 cx: Context,
1239 dependency: ReactiveScopeDependency,
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts deleted
-294
@@ -1,294 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import {CompilerError} from '../CompilerError';
9 -import {
10 - Environment,
11 - Identifier,
12 - IdentifierId,
13 - InstructionId,
14 - Place,
15 - PropertyLiteral,
16 - ReactiveBlock,
17 - ReactiveFunction,
18 - ReactiveInstruction,
19 - ReactiveScopeBlock,
20 - ReactiveTerminalStatement,
21 - getHookKind,
22 - isUseRefType,
23 - isUseStateType,
24 -} from '../HIR';
25 -import {eachCallArgument, eachInstructionLValue} from '../HIR/visitors';
26 -import DisjointSet from '../Utils/DisjointSet';
27 -import {assertExhaustive} from '../Utils/utils';
28 -import {ReactiveFunctionVisitor, visitReactiveFunction} from './visitors';
29 -
30 -/**
31 - * This pass is built based on the observation by @jbrown215 that arguments
32 - * to useState and useRef are only used the first time a component is rendered.
33 - * Any subsequent times, the arguments will be evaluated but ignored. In this pass,
34 - * we use this fact to improve the output of the compiler by not recomputing values that
35 - * are only used as arguments (or inputs to arguments to) useState and useRef.
36 - *
37 - * This pass isn't yet stress-tested so it's not enabled by default. It's only enabled
38 - * to support certain debug modes that detect non-idempotent code, since non-idempotent
39 - * code can "safely" be used if its only passed to useState and useRef. We plan to rewrite
40 - * this pass in HIR and enable it as an optimization in the future.
41 - *
42 - * Algorithm:
43 - * We take two passes over the reactive function AST. In the first pass, we gather
44 - * aliases and build relationships between property accesses--the key thing we need
45 - * to do here is to find that, e.g., $0.x and $1 refer to the same value if
46 - * $1 = PropertyLoad $0.x.
47 - *
48 - * In the second pass, we traverse the AST in reverse order and track how each place
49 - * is used. If a place is read from in any Terminal, we mark the place as "Update", meaning
50 - * it is used whenever the component is updated/re-rendered. If a place is read from in
51 - * a useState or useRef hook call, we mark it as "Create", since it is only used when the
52 - * component is created. In other instructions, we propagate the inferred place for the
53 - * instructions lvalues onto any other instructions that are read.
54 - *
55 - * Whenever we finish this reverse pass over a reactive block, we can look at the blocks
56 - * dependencies and see whether the dependencies are used in an "Update" context or only
57 - * in a "Create" context. If a dependency is create-only, then we can remove that dependency
58 - * from the block.
59 - */
60 -
61 -type CreateUpdate = 'Create' | 'Update' | 'Unknown';
62 -
63 -type KindMap = Map<IdentifierId, CreateUpdate>;
64 -
65 -class Visitor extends ReactiveFunctionVisitor<CreateUpdate> {
66 - map: KindMap = new Map();
67 - aliases: DisjointSet<IdentifierId>;
68 - paths: Map<IdentifierId, Map<PropertyLiteral, IdentifierId>>;
69 - env: Environment;
70 -
71 - constructor(
72 - env: Environment,
73 - aliases: DisjointSet<IdentifierId>,
74 - paths: Map<IdentifierId, Map<PropertyLiteral, IdentifierId>>,
75 - ) {
76 - super();
77 - this.aliases = aliases;
78 - this.paths = paths;
79 - this.env = env;
80 - }
81 -
82 - join(values: Array<CreateUpdate>): CreateUpdate {
83 - function join2(l: CreateUpdate, r: CreateUpdate): CreateUpdate {
84 - if (l === 'Update' || r === 'Update') {
85 - return 'Update';
86 - } else if (l === 'Create' || r === 'Create') {
87 - return 'Create';
88 - } else if (l === 'Unknown' || r === 'Unknown') {
89 - return 'Unknown';
90 - }
91 - assertExhaustive(r, `Unhandled variable kind ${r}`);
92 - }
93 - return values.reduce(join2, 'Unknown');
94 - }
95 -
96 - isCreateOnlyHook(id: Identifier): boolean {
97 - return isUseStateType(id) || isUseRefType(id);
98 - }
99 -
100 - override visitPlace(
101 - _: InstructionId,
102 - place: Place,
103 - state: CreateUpdate,
104 - ): void {
105 - this.map.set(
106 - place.identifier.id,
107 - this.join([state, this.map.get(place.identifier.id) ?? 'Unknown']),
108 - );
109 - }
110 -
111 - override visitBlock(block: ReactiveBlock, state: CreateUpdate): void {
112 - super.visitBlock([...block].reverse(), state);
113 - }
114 -
115 - override visitInstruction(instruction: ReactiveInstruction): void {
116 - const state = this.join(
117 - [...eachInstructionLValue(instruction)].map(
118 - operand => this.map.get(operand.identifier.id) ?? 'Unknown',
119 - ),
120 - );
121 -
122 - const visitCallOrMethodNonArgs = (): void => {
123 - switch (instruction.value.kind) {
124 - case 'CallExpression': {
125 - this.visitPlace(instruction.id, instruction.value.callee, state);
126 - break;
127 - }
128 - case 'MethodCall': {
129 - this.visitPlace(instruction.id, instruction.value.property, state);
130 - this.visitPlace(instruction.id, instruction.value.receiver, state);
131 - break;
132 - }
133 - }
134 - };
135 -
136 - const isHook = (): boolean => {
137 - let callee = null;
138 - switch (instruction.value.kind) {
139 - case 'CallExpression': {
140 - callee = instruction.value.callee.identifier;
141 - break;
142 - }
143 - case 'MethodCall': {
144 - callee = instruction.value.property.identifier;
145 - break;
146 - }
147 - }
148 - return callee != null && getHookKind(this.env, callee) != null;
149 - };
150 -
151 - switch (instruction.value.kind) {
152 - case 'CallExpression':
153 - case 'MethodCall': {
154 - if (
155 - instruction.lvalue &&
156 - this.isCreateOnlyHook(instruction.lvalue.identifier)
157 - ) {
158 - [...eachCallArgument(instruction.value.args)].forEach(operand =>
159 - this.visitPlace(instruction.id, operand, 'Create'),
160 - );
161 - visitCallOrMethodNonArgs();
162 - } else {
163 - this.traverseInstruction(instruction, isHook() ? 'Update' : state);
164 - }
165 - break;
166 - }
167 - default: {
168 - this.traverseInstruction(instruction, state);
169 - }
170 - }
171 - }
172 -
173 - override visitScope(scope: ReactiveScopeBlock): void {
174 - const state = this.join(
175 - [
176 - ...scope.scope.declarations.keys(),
177 - ...[...scope.scope.reassignments.values()].map(ident => ident.id),
178 - ].map(id => this.map.get(id) ?? 'Unknown'),
179 - );
180 - super.visitScope(scope, state);
181 - [...scope.scope.dependencies].forEach(ident => {
182 - let target: undefined | IdentifierId =
183 - this.aliases.find(ident.identifier.id) ?? ident.identifier.id;
184 - ident.path.forEach(token => {
185 - target &&= this.paths.get(target)?.get(token.property);
186 - });
187 - if (target && this.map.get(target) === 'Create') {
188 - scope.scope.dependencies.delete(ident);
189 - }
190 - });
191 - }
192 -
193 - override visitTerminal(
194 - stmt: ReactiveTerminalStatement,
195 - state: CreateUpdate,
196 - ): void {
197 - CompilerError.invariant(state !== 'Create', {
198 - reason: "Visiting a terminal statement with state 'Create'",
199 - loc: stmt.terminal.loc,
200 - });
201 - super.visitTerminal(stmt, state);
202 - }
203 -
204 - override visitReactiveFunctionValue(
205 - _id: InstructionId,
206 - _dependencies: Array<Place>,
207 - fn: ReactiveFunction,
208 - state: CreateUpdate,
209 - ): void {
210 - visitReactiveFunction(fn, this, state);
211 - }
212 -}
213 -
214 -export default function pruneInitializationDependencies(
215 - fn: ReactiveFunction,
216 -): void {
217 - const [aliases, paths] = getAliases(fn);
218 - visitReactiveFunction(fn, new Visitor(fn.env, aliases, paths), 'Update');
219 -}
220 -
221 -function update(
222 - map: Map<IdentifierId, Map<PropertyLiteral, IdentifierId>>,
223 - key: IdentifierId,
224 - path: PropertyLiteral,
225 - value: IdentifierId,
226 -): void {
227 - const inner = map.get(key) ?? new Map();
228 - inner.set(path, value);
229 - map.set(key, inner);
230 -}
231 -
232 -class AliasVisitor extends ReactiveFunctionVisitor {
233 - scopeIdentifiers: DisjointSet<IdentifierId> = new DisjointSet<IdentifierId>();
234 - scopePaths: Map<IdentifierId, Map<PropertyLiteral, IdentifierId>> = new Map();
235 -
236 - override visitInstruction(instr: ReactiveInstruction): void {
237 - if (
238 - instr.value.kind === 'StoreLocal' ||
239 - instr.value.kind === 'StoreContext'
240 - ) {
241 - this.scopeIdentifiers.union([
242 - instr.value.lvalue.place.identifier.id,
243 - instr.value.value.identifier.id,
244 - ]);
245 - } else if (
246 - instr.value.kind === 'LoadLocal' ||
247 - instr.value.kind === 'LoadContext'
248 - ) {
249 - instr.lvalue &&
250 - this.scopeIdentifiers.union([
251 - instr.lvalue.identifier.id,
252 - instr.value.place.identifier.id,
253 - ]);
254 - } else if (instr.value.kind === 'PropertyLoad') {
255 - instr.lvalue &&
256 - update(
257 - this.scopePaths,
258 - instr.value.object.identifier.id,
259 - instr.value.property,
260 - instr.lvalue.identifier.id,
261 - );
262 - } else if (instr.value.kind === 'PropertyStore') {
263 - update(
264 - this.scopePaths,
265 - instr.value.object.identifier.id,
266 - instr.value.property,
267 - instr.value.value.identifier.id,
268 - );
269 - }
270 - }
271 -}
272 -
273 -function getAliases(
274 - fn: ReactiveFunction,
275 -): [
276 - DisjointSet<IdentifierId>,
277 - Map<IdentifierId, Map<PropertyLiteral, IdentifierId>>,
278 -] {
279 - const visitor = new AliasVisitor();
280 - visitReactiveFunction(fn, visitor, null);
281 - let disjoint = visitor.scopeIdentifiers;
282 - let scopePaths = new Map<IdentifierId, Map<PropertyLiteral, IdentifierId>>();
283 - for (const [key, value] of visitor.scopePaths) {
284 - for (const [path, id] of value) {
285 - update(
286 - scopePaths,
287 - disjoint.find(key) ?? key,
288 - path,
289 - disjoint.find(id) ?? id,
290 - );
291 - }
292 - }
293 - return [disjoint, scopePaths];
294 -}
compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts deleted
-739
@@ -1,739 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import {CompilerError, CompilerErrorDetailOptions, SourceLocation} from '..';
9 -import {
10 - ArrayExpression,
11 - CallExpression,
12 - Effect,
13 - Environment,
14 - FunctionExpression,
15 - GeneratedSource,
16 - HIRFunction,
17 - Identifier,
18 - IdentifierId,
19 - Instruction,
20 - InstructionId,
21 - InstructionKind,
22 - InstructionValue,
23 - isUseEffectHookType,
24 - LoadLocal,
25 - makeInstructionId,
26 - NonLocalImportSpecifier,
27 - Place,
28 - promoteTemporary,
29 -} from '../HIR';
30 -import {createTemporaryPlace, markInstructionIds} from '../HIR/HIRBuilder';
31 -import {getOrInsertWith} from '../Utils/utils';
32 -import {
33 - BuiltInFireFunctionId,
34 - BuiltInFireId,
35 - DefaultNonmutatingHook,
36 -} from '../HIR/ObjectShape';
37 -import {eachInstructionOperand} from '../HIR/visitors';
38 -import {printSourceLocationLine} from '../HIR/PrintHIR';
39 -import {USE_FIRE_FUNCTION_NAME} from '../HIR/Environment';
40 -import {ErrorCategory} from '../CompilerError';
41 -
42 -/*
43 - * TODO(jmbrown):
44 - * - traverse object methods
45 - * - method calls
46 - * - React.useEffect calls
47 - */
48 -
49 -const CANNOT_COMPILE_FIRE = 'Cannot compile `fire`';
50 -
51 -export function transformFire(fn: HIRFunction): void {
52 - const context = new Context(fn.env);
53 - replaceFireFunctions(fn, context);
54 - if (!context.hasErrors()) {
55 - ensureNoMoreFireUses(fn, context);
56 - }
57 - context.throwIfErrorsFound();
58 -}
59 -
60 -function replaceFireFunctions(fn: HIRFunction, context: Context): void {
61 - let importedUseFire: NonLocalImportSpecifier | null = null;
62 - let hasRewrite = false;
63 - for (const [, block] of fn.body.blocks) {
64 - const rewriteInstrs = new Map<InstructionId, Array<Instruction>>();
65 - const deleteInstrs = new Set<InstructionId>();
66 - for (const instr of block.instructions) {
67 - const {value, lvalue} = instr;
68 - if (
69 - value.kind === 'CallExpression' &&
70 - isUseEffectHookType(value.callee.identifier) &&
71 - value.args.length > 0 &&
72 - value.args[0].kind === 'Identifier'
73 - ) {
74 - const lambda = context.getFunctionExpression(
75 - value.args[0].identifier.id,
76 - );
77 - if (lambda != null) {
78 - const capturedCallees =
79 - visitFunctionExpressionAndPropagateFireDependencies(
80 - lambda,
81 - context,
82 - true,
83 - );
84 -
85 - // Add useFire calls for all fire calls in found in the lambda
86 - const newInstrs = [];
87 - for (const [
88 - fireCalleePlace,
89 - fireCalleeInfo,
90 - ] of capturedCallees.entries()) {
91 - if (!context.hasCalleeWithInsertedFire(fireCalleePlace)) {
92 - context.addCalleeWithInsertedFire(fireCalleePlace);
93 -
94 - importedUseFire ??= fn.env.programContext.addImportSpecifier({
95 - source: fn.env.programContext.reactRuntimeModule,
96 - importSpecifierName: USE_FIRE_FUNCTION_NAME,
97 - });
98 - const loadUseFireInstr = makeLoadUseFireInstruction(
99 - fn.env,
100 - importedUseFire,
101 - );
102 - const loadFireCalleeInstr = makeLoadFireCalleeInstruction(
103 - fn.env,
104 - fireCalleeInfo.capturedCalleeIdentifier,
105 - );
106 - const callUseFireInstr = makeCallUseFireInstruction(
107 - fn.env,
108 - loadUseFireInstr.lvalue,
109 - loadFireCalleeInstr.lvalue,
110 - );
111 - const storeUseFireInstr = makeStoreUseFireInstruction(
112 - fn.env,
113 - callUseFireInstr.lvalue,
114 - fireCalleeInfo.fireFunctionBinding,
115 - );
116 - newInstrs.push(
117 - loadUseFireInstr,
118 - loadFireCalleeInstr,
119 - callUseFireInstr,
120 - storeUseFireInstr,
121 - );
122 -
123 - // We insert all of these instructions before the useEffect is loaded
124 - const loadUseEffectInstrId = context.getLoadGlobalInstrId(
125 - value.callee.identifier.id,
126 - );
127 - if (loadUseEffectInstrId == null) {
128 - context.pushError({
129 - loc: value.loc,
130 - description: null,
131 - category: ErrorCategory.Invariant,
132 - reason: '[InsertFire] No LoadGlobal found for useEffect call',
133 - suggestions: null,
134 - });
135 - continue;
136 - }
137 - rewriteInstrs.set(loadUseEffectInstrId, newInstrs);
138 - }
139 - }
140 - ensureNoRemainingCalleeCaptures(
141 - lambda.loweredFunc.func,
142 - context,
143 - capturedCallees,
144 - );
145 -
146 - if (
147 - value.args.length > 1 &&
148 - value.args[1] != null &&
149 - value.args[1].kind === 'Identifier'
150 - ) {
151 - const depArray = value.args[1];
152 - const depArrayExpression = context.getArrayExpression(
153 - depArray.identifier.id,
154 - );
155 - if (depArrayExpression != null) {
156 - for (const dependency of depArrayExpression.elements) {
157 - if (dependency.kind === 'Identifier') {
158 - const loadOfDependency = context.getLoadLocalInstr(
159 - dependency.identifier.id,
160 - );
161 - if (loadOfDependency != null) {
162 - const replacedDepArrayItem = capturedCallees.get(
163 - loadOfDependency.place.identifier.id,
164 - );
165 - if (replacedDepArrayItem != null) {
166 - loadOfDependency.place =
167 - replacedDepArrayItem.fireFunctionBinding;
168 - }
169 - }
170 - }
171 - }
172 - } else {
173 - context.pushError({
174 - loc: value.args[1].loc,
175 - description:
176 - 'You must use an array literal for an effect dependency array when that effect uses `fire()`',
177 - category: ErrorCategory.Fire,
178 - reason: CANNOT_COMPILE_FIRE,
179 - suggestions: null,
180 - });
181 - }
182 - } else if (value.args.length > 1 && value.args[1].kind === 'Spread') {
183 - context.pushError({
184 - loc: value.args[1].place.loc,
185 - description:
186 - 'You must use an array literal for an effect dependency array when that effect uses `fire()`',
187 - category: ErrorCategory.Fire,
188 - reason: CANNOT_COMPILE_FIRE,
189 - suggestions: null,
190 - });
191 - }
192 - }
193 - } else if (
194 - value.kind === 'CallExpression' &&
195 - value.callee.identifier.type.kind === 'Function' &&
196 - value.callee.identifier.type.shapeId === BuiltInFireId &&
197 - context.inUseEffectLambda()
198 - ) {
199 - /*
200 - * We found a fire(callExpr()) call. We remove the `fire()` call and replace the callExpr()
201 - * with a freshly generated fire function binding. We'll insert the useFire call before the
202 - * useEffect call, which happens in the CallExpression (useEffect) case above.
203 - */
204 -
205 - /*
206 - * We only allow fire to be called with a CallExpression: `fire(f())`
207 - * TODO: add support for method calls: `fire(this.method())`
208 - */
209 - if (value.args.length === 1 && value.args[0].kind === 'Identifier') {
210 - const callExpr = context.getCallExpression(
211 - value.args[0].identifier.id,
212 - );
213 -
214 - if (callExpr != null) {
215 - const calleeId = callExpr.callee.identifier.id;
216 - const loadLocal = context.getLoadLocalInstr(calleeId);
217 - if (loadLocal == null) {
218 - context.pushError({
219 - loc: value.loc,
220 - description: null,
221 - category: ErrorCategory.Invariant,
222 - reason:
223 - '[InsertFire] No loadLocal found for fire call argument',
224 - suggestions: null,
225 - });
226 - continue;
227 - }
228 -
229 - const fireFunctionBinding =
230 - context.getOrGenerateFireFunctionBinding(
231 - loadLocal.place,
232 - value.loc,
233 - );
234 -
235 - loadLocal.place = {...fireFunctionBinding};
236 -
237 - // Delete the fire call expression
238 - deleteInstrs.add(instr.id);
239 - } else {
240 - context.pushError({
241 - loc: value.loc,
242 - description:
243 - '`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed',
244 - category: ErrorCategory.Fire,
245 - reason: CANNOT_COMPILE_FIRE,
246 - suggestions: null,
247 - });
248 - }
249 - } else {
250 - let description: string =
251 - 'fire() can only take in a single call expression as an argument';
252 - if (value.args.length === 0) {
253 - description += ' but received none';
254 - } else if (value.args.length > 1) {
255 - description += ' but received multiple arguments';
256 - } else if (value.args[0].kind === 'Spread') {
257 - description += ' but received a spread argument';
258 - }
259 - context.pushError({
260 - loc: value.loc,
261 - description,
262 - category: ErrorCategory.Fire,
263 - reason: CANNOT_COMPILE_FIRE,
264 - suggestions: null,
265 - });
266 - }
267 - } else if (value.kind === 'CallExpression') {
268 - context.addCallExpression(lvalue.identifier.id, value);
269 - } else if (
270 - value.kind === 'FunctionExpression' &&
271 - context.inUseEffectLambda()
272 - ) {
273 - visitFunctionExpressionAndPropagateFireDependencies(
274 - value,
275 - context,
276 - false,
277 - );
278 - } else if (value.kind === 'FunctionExpression') {
279 - context.addFunctionExpression(lvalue.identifier.id, value);
280 - } else if (value.kind === 'LoadLocal') {
281 - context.addLoadLocalInstr(lvalue.identifier.id, value);
282 - } else if (
283 - value.kind === 'LoadGlobal' &&
284 - value.binding.kind === 'ImportSpecifier' &&
285 - value.binding.module === 'react' &&
286 - value.binding.imported === 'fire' &&
287 - context.inUseEffectLambda()
288 - ) {
289 - deleteInstrs.add(instr.id);
290 - } else if (value.kind === 'LoadGlobal') {
291 - context.addLoadGlobalInstrId(lvalue.identifier.id, instr.id);
292 - } else if (value.kind === 'ArrayExpression') {
293 - context.addArrayExpression(lvalue.identifier.id, value);
294 - }
295 - }
296 - block.instructions = rewriteInstructions(rewriteInstrs, block.instructions);
297 - block.instructions = deleteInstructions(deleteInstrs, block.instructions);
298 -
299 - if (rewriteInstrs.size > 0 || deleteInstrs.size > 0) {
300 - hasRewrite = true;
301 - fn.env.hasFireRewrite = true;
302 - }
303 - }
304 -
305 - if (hasRewrite) {
306 - markInstructionIds(fn.body);
307 - }
308 -}
309 -
310 -/**
311 - * Traverses a function expression to find fire calls fire(foo()) and replaces them with
312 - * fireFoo().
313 - *
314 - * When a function captures a fire call we need to update its context to reflect the newly created
315 - * fire function bindings and update the LoadLocals referenced by the function's dependencies.
316 - *
317 - * @param isUseEffect is necessary so we can keep track of when we should additionally insert
318 - * useFire hooks calls.
319 - */
320 -function visitFunctionExpressionAndPropagateFireDependencies(
321 - fnExpr: FunctionExpression,
322 - context: Context,
323 - enteringUseEffect: boolean,
324 -): FireCalleesToFireFunctionBinding {
325 - let withScope = enteringUseEffect
326 - ? context.withUseEffectLambdaScope.bind(context)
327 - : context.withFunctionScope.bind(context);
328 -
329 - const calleesCapturedByFnExpression = withScope(() =>
330 - replaceFireFunctions(fnExpr.loweredFunc.func, context),
331 - );
332 -
333 - // For each replaced callee, update the context of the function expression to track it
334 - for (
335 - let contextIdx = 0;
336 - contextIdx < fnExpr.loweredFunc.func.context.length;
337 - contextIdx++
338 - ) {
339 - const contextItem = fnExpr.loweredFunc.func.context[contextIdx];
340 - const replacedCallee = calleesCapturedByFnExpression.get(
341 - contextItem.identifier.id,
342 - );
343 - if (replacedCallee != null) {
344 - fnExpr.loweredFunc.func.context[contextIdx] = {
345 - ...replacedCallee.fireFunctionBinding,
346 - };
347 - }
348 - }
349 -
350 - context.mergeCalleesFromInnerScope(calleesCapturedByFnExpression);
351 -
352 - return calleesCapturedByFnExpression;
353 -}
354 -
355 -/*
356 - * eachInstructionOperand is not sufficient for our cases because:
357 - * 1. fire is a global, which will not appear
358 - * 2. The HIR may be malformed, so can't rely on function deps and must
359 - * traverse the whole function.
360 - */
361 -function* eachReachablePlace(fn: HIRFunction): Iterable<Place> {
362 - for (const [, block] of fn.body.blocks) {
363 - for (const instr of block.instructions) {
364 - if (
365 - instr.value.kind === 'FunctionExpression' ||
366 - instr.value.kind === 'ObjectMethod'
367 - ) {
368 - yield* eachReachablePlace(instr.value.loweredFunc.func);
369 - } else {
370 - yield* eachInstructionOperand(instr);
371 - }
372 - }
373 - }
374 -}
375 -
376 -function ensureNoRemainingCalleeCaptures(
377 - fn: HIRFunction,
378 - context: Context,
379 - capturedCallees: FireCalleesToFireFunctionBinding,
380 -): void {
381 - for (const place of eachReachablePlace(fn)) {
382 - const calleeInfo = capturedCallees.get(place.identifier.id);
383 - if (calleeInfo != null) {
384 - const calleeName =
385 - calleeInfo.capturedCalleeIdentifier.name?.kind === 'named'
386 - ? calleeInfo.capturedCalleeIdentifier.name.value
387 - : '<unknown>';
388 - context.pushError({
389 - loc: place.loc,
390 - description: `All uses of ${calleeName} must be either used with a fire() call in \
391 -this effect or not used with a fire() call at all. ${calleeName} was used with fire() on line \
392 -${printSourceLocationLine(calleeInfo.fireLoc)} in this effect`,
393 - category: ErrorCategory.Fire,
394 - reason: CANNOT_COMPILE_FIRE,
395 - suggestions: null,
396 - });
397 - }
398 - }
399 -}
400 -
401 -function ensureNoMoreFireUses(fn: HIRFunction, context: Context): void {
402 - for (const place of eachReachablePlace(fn)) {
403 - if (
404 - place.identifier.type.kind === 'Function' &&
405 - place.identifier.type.shapeId === BuiltInFireId
406 - ) {
407 - context.pushError({
408 - loc: place.identifier.loc,
409 - description: 'Cannot use `fire` outside of a useEffect function',
410 - category: ErrorCategory.Fire,
411 - reason: CANNOT_COMPILE_FIRE,
412 - suggestions: null,
413 - });
414 - }
415 - }
416 -}
417 -
418 -function makeLoadUseFireInstruction(
419 - env: Environment,
420 - importedLoadUseFire: NonLocalImportSpecifier,
421 -): Instruction {
422 - const useFirePlace = createTemporaryPlace(env, GeneratedSource);
423 - useFirePlace.effect = Effect.Read;
424 - useFirePlace.identifier.type = DefaultNonmutatingHook;
425 - const instrValue: InstructionValue = {
426 - kind: 'LoadGlobal',
427 - binding: {...importedLoadUseFire},
428 - loc: GeneratedSource,
429 - };
430 - return {
431 - id: makeInstructionId(0),
432 - value: instrValue,
433 - lvalue: {...useFirePlace},
434 - loc: GeneratedSource,
435 - effects: null,
436 - };
437 -}
438 -
439 -function makeLoadFireCalleeInstruction(
440 - env: Environment,
441 - fireCalleeIdentifier: Identifier,
442 -): Instruction {
443 - const loadedFireCallee = createTemporaryPlace(env, GeneratedSource);
444 - const fireCallee: Place = {
445 - kind: 'Identifier',
446 - identifier: fireCalleeIdentifier,
447 - reactive: false,
448 - effect: Effect.Unknown,
449 - loc: fireCalleeIdentifier.loc,
450 - };
451 - return {
452 - id: makeInstructionId(0),
453 - value: {
454 - kind: 'LoadLocal',
455 - loc: GeneratedSource,
456 - place: {...fireCallee},
457 - },
458 - lvalue: {...loadedFireCallee},
459 - loc: GeneratedSource,
460 - effects: null,
461 - };
462 -}
463 -
464 -function makeCallUseFireInstruction(
465 - env: Environment,
466 - useFirePlace: Place,
467 - argPlace: Place,
468 -): Instruction {
469 - const useFireCallResultPlace = createTemporaryPlace(env, GeneratedSource);
470 - useFireCallResultPlace.effect = Effect.Read;
471 -
472 - const useFireCall: CallExpression = {
473 - kind: 'CallExpression',
474 - callee: {...useFirePlace},
475 - args: [argPlace],
476 - loc: GeneratedSource,
477 - };
478 -
479 - return {
480 - id: makeInstructionId(0),
481 - value: useFireCall,
482 - lvalue: {...useFireCallResultPlace},
483 - loc: GeneratedSource,
484 - effects: null,
485 - };
486 -}
487 -
488 -function makeStoreUseFireInstruction(
489 - env: Environment,
490 - useFireCallResultPlace: Place,
491 - fireFunctionBindingPlace: Place,
492 -): Instruction {
493 - promoteTemporary(fireFunctionBindingPlace.identifier);
494 -
495 - const fireFunctionBindingLValuePlace = createTemporaryPlace(
496 - env,
497 - GeneratedSource,
498 - );
499 - return {
500 - id: makeInstructionId(0),
501 - value: {
502 - kind: 'StoreLocal',
503 - lvalue: {
504 - kind: InstructionKind.Const,
505 - place: {...fireFunctionBindingPlace},
506 - },
507 - value: {...useFireCallResultPlace},
508 - type: null,
509 - loc: GeneratedSource,
510 - },
511 - lvalue: fireFunctionBindingLValuePlace,
512 - loc: GeneratedSource,
513 - effects: null,
514 - };
515 -}
516 -
517 -type FireCalleesToFireFunctionBinding = Map<
518 - IdentifierId,
519 - {
520 - fireFunctionBinding: Place;
521 - capturedCalleeIdentifier: Identifier;
522 - fireLoc: SourceLocation;
523 - }
524 ->;
525 -
526 -class Context {
527 - #env: Environment;
528 -
529 - #errors: CompilerError = new CompilerError();
530 -
531 - /*
532 - * Used to look up the call expression passed to a `fire(callExpr())`. Gives back
533 - * the `callExpr()`.
534 - */
535 - #callExpressions = new Map<IdentifierId, CallExpression>();
536 -
537 - /*
538 - * We keep track of function expressions so that we can traverse them when
539 - * we encounter a lambda passed to a useEffect call
540 - */
541 - #functionExpressions = new Map<IdentifierId, FunctionExpression>();
542 -
543 - /*
544 - * Mapping from lvalue ids to the LoadLocal for it. Allows us to replace dependency LoadLocals.
545 - */
546 - #loadLocals = new Map<IdentifierId, LoadLocal>();
547 -
548 - /*
549 - * Maps all of the fire callees found in a component/hook to the generated fire function places
550 - * we create for them. Allows us to reuse already-inserted useFire results
551 - */
552 - #fireCalleesToFireFunctions: Map<IdentifierId, Place> = new Map();
553 -
554 - /*
555 - * The callees for which we have already created fire bindings. Used to skip inserting a new
556 - * useFire call for a fire callee if one has already been created.
557 - */
558 - #calleesWithInsertedFire = new Set<IdentifierId>();
559 -
560 - /*
561 - * A mapping from fire callees to the created fire function bindings that are reachable from this
562 - * scope.
563 - *
564 - * We additionally keep track of the captured callee identifier so that we can properly reference
565 - * it in the place where we LoadLocal the callee as an argument to useFire.
566 - */
567 - #capturedCalleeIdentifierIds: FireCalleesToFireFunctionBinding = new Map();
568 -
569 - /*
570 - * We only transform fire calls if we're syntactically within a useEffect lambda (for now)
571 - */
572 - #inUseEffectLambda = false;
573 -
574 - /*
575 - * Mapping from useEffect callee identifier ids to the instruction id of the
576 - * load global instruction for the useEffect call. We use this to insert the
577 - * useFire calls before the useEffect call
578 - */
579 - #loadGlobalInstructionIds = new Map<IdentifierId, InstructionId>();
580 -
581 - constructor(env: Environment) {
582 - this.#env = env;
583 - }
584 -
585 - /*
586 - * We keep track of array expressions so we can rewrite dependency arrays passed to useEffect
587 - * to use the fire functions
588 - */
589 - #arrayExpressions = new Map<IdentifierId, ArrayExpression>();
590 -
591 - pushError(error: CompilerErrorDetailOptions): void {
592 - this.#errors.push(error);
593 - }
594 -
595 - withFunctionScope(fn: () => void): FireCalleesToFireFunctionBinding {
596 - fn();
597 - return this.#capturedCalleeIdentifierIds;
598 - }
599 -
600 - withUseEffectLambdaScope(fn: () => void): FireCalleesToFireFunctionBinding {
601 - const capturedCalleeIdentifierIds = this.#capturedCalleeIdentifierIds;
602 - const inUseEffectLambda = this.#inUseEffectLambda;
603 -
604 - this.#capturedCalleeIdentifierIds = new Map();
605 - this.#inUseEffectLambda = true;
606 -
607 - const resultCapturedCalleeIdentifierIds = this.withFunctionScope(fn);
608 -
609 - this.#capturedCalleeIdentifierIds = capturedCalleeIdentifierIds;
610 - this.#inUseEffectLambda = inUseEffectLambda;
611 -
612 - return resultCapturedCalleeIdentifierIds;
613 - }
614 -
615 - addCallExpression(id: IdentifierId, callExpr: CallExpression): void {
616 - this.#callExpressions.set(id, callExpr);
617 - }
618 -
619 - getCallExpression(id: IdentifierId): CallExpression | undefined {
620 - return this.#callExpressions.get(id);
621 - }
622 -
623 - addLoadLocalInstr(id: IdentifierId, loadLocal: LoadLocal): void {
624 - this.#loadLocals.set(id, loadLocal);
625 - }
626 -
627 - getLoadLocalInstr(id: IdentifierId): LoadLocal | undefined {
628 - return this.#loadLocals.get(id);
629 - }
630 - getOrGenerateFireFunctionBinding(
631 - callee: Place,
632 - fireLoc: SourceLocation,
633 - ): Place {
634 - const fireFunctionBinding = getOrInsertWith(
635 - this.#fireCalleesToFireFunctions,
636 - callee.identifier.id,
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,
650 - fireLoc,
651 - });
652 -
653 - return fireFunctionBinding;
654 - }
655 -
656 - mergeCalleesFromInnerScope(
657 - innerCallees: FireCalleesToFireFunctionBinding,
658 - ): void {
659 - for (const [id, calleeInfo] of innerCallees.entries()) {
660 - this.#capturedCalleeIdentifierIds.set(id, calleeInfo);
661 - }
662 - }
663 -
664 - addCalleeWithInsertedFire(id: IdentifierId): void {
665 - this.#calleesWithInsertedFire.add(id);
666 - }
667 -
668 - hasCalleeWithInsertedFire(id: IdentifierId): boolean {
669 - return this.#calleesWithInsertedFire.has(id);
670 - }
671 -
672 - inUseEffectLambda(): boolean {
673 - return this.#inUseEffectLambda;
674 - }
675 -
676 - addFunctionExpression(id: IdentifierId, fn: FunctionExpression): void {
677 - this.#functionExpressions.set(id, fn);
678 - }
679 -
680 - getFunctionExpression(id: IdentifierId): FunctionExpression | undefined {
681 - return this.#functionExpressions.get(id);
682 - }
683 -
684 - addLoadGlobalInstrId(id: IdentifierId, instrId: InstructionId): void {
685 - this.#loadGlobalInstructionIds.set(id, instrId);
686 - }
687 -
688 - getLoadGlobalInstrId(id: IdentifierId): InstructionId | undefined {
689 - return this.#loadGlobalInstructionIds.get(id);
690 - }
691 -
692 - addArrayExpression(id: IdentifierId, array: ArrayExpression): void {
693 - this.#arrayExpressions.set(id, array);
694 - }
695 -
696 - getArrayExpression(id: IdentifierId): ArrayExpression | undefined {
697 - return this.#arrayExpressions.get(id);
698 - }
699 -
700 - hasErrors(): boolean {
701 - return this.#errors.hasAnyErrors();
702 - }
703 -
704 - throwIfErrorsFound(): void {
705 - if (this.hasErrors()) throw this.#errors;
706 - }
707 -}
708 -
709 -function deleteInstructions(
710 - deleteInstrs: Set<InstructionId>,
711 - instructions: Array<Instruction>,
712 -): Array<Instruction> {
713 - if (deleteInstrs.size > 0) {
714 - const newInstrs = instructions.filter(instr => !deleteInstrs.has(instr.id));
715 - return newInstrs;
716 - }
717 - return instructions;
718 -}
719 -
720 -function rewriteInstructions(
721 - rewriteInstrs: Map<InstructionId, Array<Instruction>>,
722 - instructions: Array<Instruction>,
723 -): Array<Instruction> {
724 - if (rewriteInstrs.size > 0) {
725 - const newInstrs = [];
726 - for (const instr of instructions) {
727 - const newInstrsAtId = rewriteInstrs.get(instr.id);
728 - if (newInstrsAtId != null) {
729 - newInstrs.push(...newInstrsAtId, instr);
730 - } else {
731 - newInstrs.push(instr);
732 - }
733 - }
734 -
735 - return newInstrs;
736 - }
737 -
738 - return instructions;
739 -}
compiler/packages/babel-plugin-react-compiler/src/Transform/index.ts
-2
@@ -4,5 +4,3 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7 -
8 -export {transformFire} from './TransformFire';
compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts
+6 -59
@@ -8,7 +8,6 @@
8 import * as t from '@babel/types';
9 import {CompilerError} from '../CompilerError';
10 import {Environment} from '../HIR';
11 -import {lowerType} from '../HIR/BuildHIR';
11 import {
12 GeneratedSource,
13 HIRFunction,
@@ -26,7 +25,6 @@ import {
25 } from '../HIR/HIR';
26 import {
27 BuiltInArrayId,
29 - BuiltInEventHandlerId,
28 BuiltInFunctionId,
29 BuiltInJsxId,
30 BuiltInMixedReadonlyId,
@@ -223,22 +221,11 @@ function* generateInstructionTypes(
221 }
222
223 case 'StoreLocal': {
226 - if (env.config.enableUseTypeAnnotations) {
227 - yield equation(
228 - value.lvalue.place.identifier.type,
229 - value.value.identifier.type,
230 - );
231 - const valueType =
232 - value.type === null ? makeType() : lowerType(value.type);
233 - yield equation(valueType, value.lvalue.place.identifier.type);
234 - yield equation(left, valueType);
235 - } else {
236 - yield equation(left, value.value.identifier.type);
237 - yield equation(
238 - value.lvalue.place.identifier.type,
239 - value.value.identifier.type,
240 - );
241 - }
224 + yield equation(left, value.value.identifier.type);
225 + yield equation(
226 + value.lvalue.place.identifier.type,
227 + value.value.identifier.type,
228 + );
229 break;
230 }
231
@@ -422,12 +409,7 @@ function* generateInstructionTypes(
409 }
410
411 case 'TypeCastExpression': {
425 - if (env.config.enableUseTypeAnnotations) {
426 - yield equation(value.type, value.value.identifier.type);
427 - yield equation(left, value.type);
428 - } else {
429 - yield equation(left, value.value.identifier.type);
430 - }
412 + yield equation(left, value.value.identifier.type);
413 break;
414 }
415
@@ -473,41 +455,6 @@ function* generateInstructionTypes(
455 }
456 }
457 }
476 - if (env.config.enableInferEventHandlers) {
477 - if (
478 - value.kind === 'JsxExpression' &&
479 - value.tag.kind === 'BuiltinTag' &&
480 - !value.tag.name.includes('-')
481 - ) {
482 - /*
483 - * Infer event handler types for built-in DOM elements.
484 - * Props starting with "on" (e.g., onClick, onSubmit) on primitive tags
485 - * are inferred as event handlers. This allows functions with ref access
486 - * to be passed to these props, since DOM event handlers are guaranteed
487 - * by React to only execute in response to events, never during render.
488 - *
489 - * We exclude tags with hyphens to avoid web components (custom elements),
490 - * which are required by the HTML spec to contain a hyphen. Web components
491 - * may call event handler props during their lifecycle methods (e.g.,
492 - * connectedCallback), which would be unsafe for ref access.
493 - */
494 - for (const prop of value.props) {
495 - if (
496 - prop.kind === 'JsxAttribute' &&
497 - prop.name.startsWith('on') &&
498 - prop.name.length > 2 &&
499 - prop.name[2] === prop.name[2].toUpperCase()
500 - ) {
501 - yield equation(prop.place.identifier.type, {
502 - kind: 'Function',
503 - shapeId: BuiltInEventHandlerId,
504 - return: makeType(),
505 - isConstructor: false,
506 - });
507 - }
508 - }
509 - }
510 - }
458 yield equation(left, {kind: 'Object', shapeId: BuiltInJsxId});
459 break;
460 }
compiler/packages/babel-plugin-react-compiler/src/Utils/TestUtils.ts
-39
@@ -39,14 +39,6 @@ function tryParseTestPragmaValue(val: string): Result<unknown, unknown> {
39
40 const testComplexConfigDefaults: PartialEnvironmentConfig = {
41 validateNoCapitalizedCalls: [],
42 - enableChangeDetectionForDebugging: {
43 - source: 'react-compiler-runtime',
44 - importSpecifierName: '$structuralCheck',
45 - },
46 - enableEmitFreeze: {
47 - source: 'react-compiler-runtime',
48 - importSpecifierName: 'makeReadOnly',
49 - },
42 enableEmitInstrumentForget: {
43 fn: {
44 source: 'react-compiler-runtime',
@@ -62,37 +54,6 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
54 source: 'react-compiler-runtime',
55 importSpecifierName: '$dispatcherGuard',
56 },
65 - inlineJsxTransform: {
66 - elementSymbol: 'react.transitional.element',
67 - globalDevVar: 'DEV',
68 - },
69 - lowerContextAccess: {
70 - source: 'react-compiler-runtime',
71 - importSpecifierName: 'useContext_withSelector',
72 - },
73 - inferEffectDependencies: [
74 - {
75 - function: {
76 - source: 'react',
77 - importSpecifierName: 'useEffect',
78 - },
79 - autodepsIndex: 1,
80 - },
81 - {
82 - function: {
83 - source: 'shared-runtime',
84 - importSpecifierName: 'useSpecialEffect',
85 - },
86 - autodepsIndex: 2,
87 - },
88 - {
89 - function: {
90 - source: 'useEffectWrapper',
91 - importSpecifierName: 'default',
92 - },
93 - autodepsIndex: 1,
94 - },
95 - ],
57 };
58
59 function* splitPragma(
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateExhaustiveDependencies.ts
+11 -1
@@ -29,6 +29,9 @@ import {
29 isStableType,
30 isSubPath,
31 isSubPathIgnoringOptionals,
32 + isUseEffectHookType,
33 + isUseInsertionEffectHookType,
34 + isUseLayoutEffectHookType,
35 isUseRefType,
36 LoadGlobal,
37 ManualMemoDependency,
@@ -43,7 +46,6 @@ import {
46 } from '../HIR/visitors';
47 import {Result} from '../Utils/Result';
48 import {retainWhere} from '../Utils/utils';
46 -import {isEffectHook} from './ValidateMemoizedEffectDependencies';
49
50 const DEBUG = false;
51
@@ -1111,3 +1113,11 @@ function createDiagnostic(
1113 suggestions: suggestion != null ? [suggestion] : null,
1114 });
1115 }
1116 +
1117 +export function isEffectHook(identifier: Identifier): boolean {
1118 + return (
1119 + isUseEffectHookType(identifier) ||
1120 + isUseLayoutEffectHookType(identifier) ||
1121 + isUseInsertionEffectHookType(identifier)
1122 + );
1123 +}
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts deleted
-134
@@ -1,134 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import {CompilerError} from '..';
9 -import {ErrorCategory} from '../CompilerError';
10 -import {
11 - Identifier,
12 - Instruction,
13 - ReactiveFunction,
14 - ReactiveInstruction,
15 - ReactiveScopeBlock,
16 - ScopeId,
17 - isUseEffectHookType,
18 - isUseInsertionEffectHookType,
19 - isUseLayoutEffectHookType,
20 -} from '../HIR';
21 -import {isMutable} from '../ReactiveScopes/InferReactiveScopeVariables';
22 -import {
23 - ReactiveFunctionVisitor,
24 - visitReactiveFunction,
25 -} from '../ReactiveScopes/visitors';
26 -import {Result} from '../Utils/Result';
27 -
28 -/**
29 - * Validates that all known effect dependencies are memoized. The algorithm checks two things:
30 - * - Disallow effect dependencies that should be memoized (have a reactive scope assigned) but
31 - * where that reactive scope does not exist. This checks for cases where a reactive scope was
32 - * pruned for some reason, such as spanning a hook.
33 - * - Disallow effect dependencies whose a mutable range that encompasses the effect call.
34 - *
35 - * This latter check corresponds to any values which Forget knows may be mutable and may be mutated
36 - * after the effect. Note that it's possible Forget may miss not memoize a value for some other reason,
37 - * but in general this is a bug. The only reason Forget would _choose_ to skip memoization of an
38 - * effect dependency is because it's mutated later.
39 - *
40 - * Example:
41 - *
42 - * ```javascript
43 - * const object = {}; // mutable range starts here...
44 - *
45 - * useEffect(() => {
46 - * console.log('hello');
47 - * }, [object]); // the dependency array picks up the mutable range of its mutable contents
48 - *
49 - * mutate(object); // ... mutable range ends here after this mutation
50 - * ```
51 - */
52 -export function validateMemoizedEffectDependencies(
53 - fn: ReactiveFunction,
54 -): Result<void, CompilerError> {
55 - const errors = new CompilerError();
56 - visitReactiveFunction(fn, new Visitor(), errors);
57 - return errors.asResult();
58 -}
59 -
60 -class Visitor extends ReactiveFunctionVisitor<CompilerError> {
61 - scopes: Set<ScopeId> = new Set();
62 -
63 - override visitScope(
64 - scopeBlock: ReactiveScopeBlock,
65 - state: CompilerError,
66 - ): void {
67 - this.traverseScope(scopeBlock, state);
68 -
69 - /*
70 - * Record scopes that exist in the AST so we can later check to see if
71 - * effect dependencies which should be memoized (have a scope assigned)
72 - * actually are memoized (that scope exists).
73 - * However, we only record scopes if *their* dependencies are also
74 - * memoized, allowing a transitive memoization check.
75 - */
76 - let areDependenciesMemoized = true;
77 - for (const dep of scopeBlock.scope.dependencies) {
78 - if (isUnmemoized(dep.identifier, this.scopes)) {
79 - areDependenciesMemoized = false;
80 - break;
81 - }
82 - }
83 - if (areDependenciesMemoized) {
84 - this.scopes.add(scopeBlock.scope.id);
85 - for (const id of scopeBlock.scope.merged) {
86 - this.scopes.add(id);
87 - }
88 - }
89 - }
90 -
91 - override visitInstruction(
92 - instruction: ReactiveInstruction,
93 - state: CompilerError,
94 - ): void {
95 - this.traverseInstruction(instruction, state);
96 - if (
97 - instruction.value.kind === 'CallExpression' &&
98 - isEffectHook(instruction.value.callee.identifier) &&
99 - instruction.value.args.length >= 2
100 - ) {
101 - const deps = instruction.value.args[1]!;
102 - if (
103 - deps.kind === 'Identifier' &&
104 - /*
105 - * TODO: isMutable is not safe to call here as it relies on identifier mutableRange which is no longer valid at this point
106 - * in the pipeline
107 - */
108 - (isMutable(instruction as Instruction, deps) ||
109 - isUnmemoized(deps.identifier, this.scopes))
110 - ) {
111 - state.push({
112 - category: ErrorCategory.EffectDependencies,
113 - reason:
114 - 'React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior',
115 - description: null,
116 - loc: typeof instruction.loc !== 'symbol' ? instruction.loc : null,
117 - suggestions: null,
118 - });
119 - }
120 - }
121 - }
122 -}
123 -
124 -function isUnmemoized(operand: Identifier, scopes: Set<ScopeId>): boolean {
125 - return operand.scope != null && !scopes.has(operand.scope.id);
126 -}
127 -
128 -export function isEffectHook(identifier: Identifier): boolean {
129 - return (
130 - isUseEffectHookType(identifier) ||
131 - isUseLayoutEffectHookType(identifier) ||
132 - isUseInsertionEffectHookType(identifier)
133 - );
134 -}
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts
+1 -9
@@ -19,16 +19,8 @@ export function validateNoCapitalizedCalls(
19 ...DEFAULT_GLOBALS.keys(),
20 ...(envConfig.validateNoCapitalizedCalls ?? []),
21 ]);
22 - /*
23 - * The hook pattern may allow uppercase names, like React$useState, so we need to be sure that we
24 - * do not error in those cases
25 - */
26 - const hookPattern =
27 - envConfig.hookPattern != null ? new RegExp(envConfig.hookPattern) : null;
22 const isAllowed = (name: string): boolean => {
29 - return (
30 - ALLOW_LIST.has(name) || (hookPattern != null && hookPattern.test(name))
31 - );
23 + return ALLOW_LIST.has(name);
24 };
25
26 const errors = new CompilerError();
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts
+1 -13
@@ -15,14 +15,12 @@ import {
15 GeneratedSource,
16 HIRFunction,
17 IdentifierId,
18 - Identifier,
18 Place,
19 SourceLocation,
20 getHookKindForType,
21 isRefValueType,
22 isUseRefType,
23 } from '../HIR';
25 -import {BuiltInEventHandlerId} from '../HIR/ObjectShape';
24 import {
25 eachInstructionOperand,
26 eachInstructionValueOperand,
@@ -178,11 +176,6 @@ function refTypeOfType(place: Place): RefAccessType {
176 }
177 }
178
181 -function isEventHandlerType(identifier: Identifier): boolean {
182 - const type = identifier.type;
183 - return type.kind === 'Function' && type.shapeId === BuiltInEventHandlerId;
184 -}
185 -
179 function tyEqual(a: RefAccessType, b: RefAccessType): boolean {
180 if (a.kind !== b.kind) {
181 return false;
@@ -491,9 +484,6 @@ function validateNoRefAccessInRenderImpl(
484 */
485 if (!didError) {
486 const isRefLValue = isUseRefType(instr.lvalue.identifier);
494 - const isEventHandlerLValue = isEventHandlerType(
495 - instr.lvalue.identifier,
496 - );
487 for (const operand of eachInstructionValueOperand(instr.value)) {
488 /**
489 * By default we check that function call operands are not refs,
@@ -501,7 +491,6 @@ function validateNoRefAccessInRenderImpl(
491 */
492 if (
493 isRefLValue ||
504 - isEventHandlerLValue ||
494 (hookKind != null &&
495 hookKind !== 'useState' &&
496 hookKind !== 'useReducer')
@@ -509,8 +498,7 @@ function validateNoRefAccessInRenderImpl(
498 /**
499 * Allow passing refs or ref-accessing functions when:
500 * 1. lvalue is a ref (mergeRefs pattern: `mergeRefs(ref1, ref2)`)
512 - * 2. lvalue is an event handler (DOM events execute outside render)
513 - * 3. calling hooks (independently validated for ref safety)
501 + * 2. calling hooks (independently validated for ref safety)
502 */
503 validateNoDirectRefValueAccess(errors, operand, env);
504 } else if (interpolatedAsJsx.has(instr.lvalue.identifier.id)) {
compiler/packages/babel-plugin-react-compiler/src/Validation/index.ts
-1
@@ -7,7 +7,6 @@
7
8 export {validateContextVariableLValues} from './ValidateContextVariableLValues';
9 export {validateHooksUsage} from './ValidateHooksUsage';
10 -export {validateMemoizedEffectDependencies} from './ValidateMemoizedEffectDependencies';
10 export {validateNoCapitalizedCalls} from './ValidateNoCapitalizedCalls';
11 export {validateNoRefAccessInRender} from './ValidateNoRefAccessInRender';
12 export {validateNoSetStateInRender} from './ValidateNoSetStateInRender';
compiler/packages/babel-plugin-react-compiler/src/__tests__/envConfig-test.ts
-18
@@ -24,24 +24,6 @@ describe('parseConfigPragma()', () => {
24 );
25 });
26
27 - it('effect autodeps config must have at least 1 required argument', () => {
28 - expect(() => {
29 - validateEnvironmentConfig({
30 - inferEffectDependencies: [
31 - {
32 - function: {
33 - source: 'react',
34 - importSpecifierName: 'useEffect',
35 - },
36 - autodepsIndex: 0,
37 - },
38 - ],
39 - } as any);
40 - }).toThrowErrorMatchingInlineSnapshot(
41 - `"Error: Could not validate environment config. Update React Compiler config to fix the error. Validation error: AutodepsIndex must be > 0 at "inferEffectDependencies[0].autodepsIndex"."`,
42 - );
43 - });
44 -
27 it('can parse stringy enums', () => {
28 const stringyHook = {
29 effectKind: 'freeze',
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-async-event-handler-wrapper.expect.md deleted
-148
@@ -1,148 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableInferEventHandlers
6 -import {useRef} from 'react';
7 -
8 -// Simulates react-hook-form's handleSubmit
9 -function handleSubmit<T>(callback: (data: T) => void | Promise<void>) {
10 - return (event: any) => {
11 - event.preventDefault();
12 - callback({} as T);
13 - };
14 -}
15 -
16 -// Simulates an upload function
17 -async function upload(file: any): Promise<{blob: {url: string}}> {
18 - return {blob: {url: 'https://example.com/file.jpg'}};
19 -}
20 -
21 -interface SignatureRef {
22 - toFile(): any;
23 -}
24 -
25 -function Component() {
26 - const ref = useRef<SignatureRef>(null);
27 -
28 - const onSubmit = async (value: any) => {
29 - // This should be allowed: accessing ref.current in an async event handler
30 - // that's wrapped and passed to onSubmit prop
31 - let sigUrl: string;
32 - if (value.hasSignature) {
33 - const {blob} = await upload(ref.current?.toFile());
34 - sigUrl = blob?.url || '';
35 - } else {
36 - sigUrl = value.signature;
37 - }
38 - console.log('Signature URL:', sigUrl);
39 - };
40 -
41 - return (
42 - <form onSubmit={handleSubmit(onSubmit)}>
43 - <input type="text" name="signature" />
44 - <button type="submit">Submit</button>
45 - </form>
46 - );
47 -}
48 -
49 -export const FIXTURE_ENTRYPOINT = {
50 - fn: Component,
51 - params: [{}],
52 -};
53 -
54 -```
55 -
56 -## Code
57 -
58 -```javascript
59 -import { c as _c } from "react/compiler-runtime"; // @enableInferEventHandlers
60 -import { useRef } from "react";
61 -
62 -// Simulates react-hook-form's handleSubmit
63 -function handleSubmit(callback) {
64 - const $ = _c(2);
65 - let t0;
66 - if ($[0] !== callback) {
67 - t0 = (event) => {
68 - event.preventDefault();
69 - callback({} as T);
70 - };
71 - $[0] = callback;
72 - $[1] = t0;
73 - } else {
74 - t0 = $[1];
75 - }
76 - return t0;
77 -}
78 -
79 -// Simulates an upload function
80 -async function upload(file) {
81 - const $ = _c(1);
82 - let t0;
83 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
84 - t0 = { blob: { url: "https://example.com/file.jpg" } };
85 - $[0] = t0;
86 - } else {
87 - t0 = $[0];
88 - }
89 - return t0;
90 -}
91 -
92 -interface SignatureRef {
93 - toFile(): any;
94 -}
95 -
96 -function Component() {
97 - const $ = _c(4);
98 - const ref = useRef(null);
99 -
100 - const onSubmit = async (value) => {
101 - let sigUrl;
102 - if (value.hasSignature) {
103 - const { blob } = await upload(ref.current?.toFile());
104 - sigUrl = blob?.url || "";
105 - } else {
106 - sigUrl = value.signature;
107 - }
108 -
109 - console.log("Signature URL:", sigUrl);
110 - };
111 -
112 - const t0 = handleSubmit(onSubmit);
113 - let t1;
114 - let t2;
115 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
116 - t1 = <input type="text" name="signature" />;
117 - t2 = <button type="submit">Submit</button>;
118 - $[0] = t1;
119 - $[1] = t2;
120 - } else {
121 - t1 = $[0];
122 - t2 = $[1];
123 - }
124 - let t3;
125 - if ($[2] !== t0) {
126 - t3 = (
127 - <form onSubmit={t0}>
128 - {t1}
129 - {t2}
130 - </form>
131 - );
132 - $[2] = t0;
133 - $[3] = t3;
134 - } else {
135 - t3 = $[3];
136 - }
137 - return t3;
138 -}
139 -
140 -export const FIXTURE_ENTRYPOINT = {
141 - fn: Component,
142 - params: [{}],
143 -};
144 -
145 -```
146 -
147 -### Eval output
148 -(kind: ok) <form><input type="text" name="signature"><button type="submit">Submit</button></form>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-async-event-handler-wrapper.tsx deleted
-48
@@ -1,48 +0,0 @@
1 -// @enableInferEventHandlers
2 -import {useRef} from 'react';
3 -
4 -// Simulates react-hook-form's handleSubmit
5 -function handleSubmit<T>(callback: (data: T) => void | Promise<void>) {
6 - return (event: any) => {
7 - event.preventDefault();
8 - callback({} as T);
9 - };
10 -}
11 -
12 -// Simulates an upload function
13 -async function upload(file: any): Promise<{blob: {url: string}}> {
14 - return {blob: {url: 'https://example.com/file.jpg'}};
15 -}
16 -
17 -interface SignatureRef {
18 - toFile(): any;
19 -}
20 -
21 -function Component() {
22 - const ref = useRef<SignatureRef>(null);
23 -
24 - const onSubmit = async (value: any) => {
25 - // This should be allowed: accessing ref.current in an async event handler
26 - // that's wrapped and passed to onSubmit prop
27 - let sigUrl: string;
28 - if (value.hasSignature) {
29 - const {blob} = await upload(ref.current?.toFile());
30 - sigUrl = blob?.url || '';
31 - } else {
32 - sigUrl = value.signature;
33 - }
34 - console.log('Signature URL:', sigUrl);
35 - };
36 -
37 - return (
38 - <form onSubmit={handleSubmit(onSubmit)}>
39 - <input type="text" name="signature" />
40 - <button type="submit">Submit</button>
41 - </form>
42 - );
43 -}
44 -
45 -export const FIXTURE_ENTRYPOINT = {
46 - fn: Component,
47 - params: [{}],
48 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-event-handler-wrapper.expect.md deleted
-100
@@ -1,100 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableInferEventHandlers
6 -import {useRef} from 'react';
7 -
8 -// Simulates react-hook-form's handleSubmit or similar event handler wrappers
9 -function handleSubmit<T>(callback: (data: T) => void) {
10 - return (event: any) => {
11 - event.preventDefault();
12 - callback({} as T);
13 - };
14 -}
15 -
16 -function Component() {
17 - const ref = useRef<HTMLInputElement>(null);
18 -
19 - const onSubmit = (data: any) => {
20 - // This should be allowed: accessing ref.current in an event handler
21 - // that's wrapped by handleSubmit and passed to onSubmit prop
22 - if (ref.current !== null) {
23 - console.log(ref.current.value);
24 - }
25 - };
26 -
27 - return (
28 - <>
29 - <input ref={ref} />
30 - <form onSubmit={handleSubmit(onSubmit)}>
31 - <button type="submit">Submit</button>
32 - </form>
33 - </>
34 - );
35 -}
36 -
37 -export const FIXTURE_ENTRYPOINT = {
38 - fn: Component,
39 - params: [{}],
40 -};
41 -
42 -```
43 -
44 -## Code
45 -
46 -```javascript
47 -import { c as _c } from "react/compiler-runtime"; // @enableInferEventHandlers
48 -import { useRef } from "react";
49 -
50 -// Simulates react-hook-form's handleSubmit or similar event handler wrappers
51 -function handleSubmit(callback) {
52 - const $ = _c(2);
53 - let t0;
54 - if ($[0] !== callback) {
55 - t0 = (event) => {
56 - event.preventDefault();
57 - callback({} as T);
58 - };
59 - $[0] = callback;
60 - $[1] = t0;
61 - } else {
62 - t0 = $[1];
63 - }
64 - return t0;
65 -}
66 -
67 -function Component() {
68 - const $ = _c(1);
69 - const ref = useRef(null);
70 - let t0;
71 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
72 - const onSubmit = (data) => {
73 - if (ref.current !== null) {
74 - console.log(ref.current.value);
75 - }
76 - };
77 - t0 = (
78 - <>
79 - <input ref={ref} />
80 - <form onSubmit={handleSubmit(onSubmit)}>
81 - <button type="submit">Submit</button>
82 - </form>
83 - </>
84 - );
85 - $[0] = t0;
86 - } else {
87 - t0 = $[0];
88 - }
89 - return t0;
90 -}
91 -
92 -export const FIXTURE_ENTRYPOINT = {
93 - fn: Component,
94 - params: [{}],
95 -};
96 -
97 -```
98 -
99 -### Eval output
100 -(kind: ok) <input><form><button type="submit">Submit</button></form>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-event-handler-wrapper.tsx deleted
-36
@@ -1,36 +0,0 @@
1 -// @enableInferEventHandlers
2 -import {useRef} from 'react';
3 -
4 -// Simulates react-hook-form's handleSubmit or similar event handler wrappers
5 -function handleSubmit<T>(callback: (data: T) => void) {
6 - return (event: any) => {
7 - event.preventDefault();
8 - callback({} as T);
9 - };
10 -}
11 -
12 -function Component() {
13 - const ref = useRef<HTMLInputElement>(null);
14 -
15 - const onSubmit = (data: any) => {
16 - // This should be allowed: accessing ref.current in an event handler
17 - // that's wrapped by handleSubmit and passed to onSubmit prop
18 - if (ref.current !== null) {
19 - console.log(ref.current.value);
20 - }
21 - };
22 -
23 - return (
24 - <>
25 - <input ref={ref} />
26 - <form onSubmit={handleSubmit(onSubmit)}>
27 - <button type="submit">Submit</button>
28 - </form>
29 - </>
30 - );
31 -}
32 -
33 -export const FIXTURE_ENTRYPOINT = {
34 - fn: Component,
35 - params: [{}],
36 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capitalized-function-allowlist.expect.md deleted
-53
@@ -1,53 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateNoCapitalizedCalls @hookPattern:".*\b(use[^$]+)$"
6 -import * as React from 'react';
7 -const React$useState = React.useState;
8 -const THIS_IS_A_CONSTANT = () => {};
9 -function Component() {
10 - const b = Boolean(true); // OK
11 - const n = Number(3); // OK
12 - const s = String('foo'); // OK
13 - const [state, setState] = React$useState(0); // OK
14 - const [state2, setState2] = React.useState(1); // OK
15 - const constant = THIS_IS_A_CONSTANT(); // OK
16 - return 3;
17 -}
18 -
19 -export const FIXTURE_ENTRYPOINT = {
20 - fn: Component,
21 - params: [],
22 - isComponent: true,
23 -};
24 -
25 -```
26 -
27 -## Code
28 -
29 -```javascript
30 -// @validateNoCapitalizedCalls @hookPattern:".*\b(use[^$]+)$"
31 -import * as React from "react";
32 -const React$useState = React.useState;
33 -const THIS_IS_A_CONSTANT = () => {};
34 -function Component() {
35 - Boolean(true);
36 - Number(3);
37 - String("foo");
38 - React$useState(0);
39 - React.useState(1);
40 - THIS_IS_A_CONSTANT();
41 - return 3;
42 -}
43 -
44 -export const FIXTURE_ENTRYPOINT = {
45 - fn: Component,
46 - params: [],
47 - isComponent: true,
48 -};
49 -
50 -```
51 -
52 -### Eval output
53 -(kind: ok) 3
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capitalized-function-allowlist.js deleted
-19
@@ -1,19 +0,0 @@
1 -// @validateNoCapitalizedCalls @hookPattern:".*\b(use[^$]+)$"
2 -import * as React from 'react';
3 -const React$useState = React.useState;
4 -const THIS_IS_A_CONSTANT = () => {};
5 -function Component() {
6 - const b = Boolean(true); // OK
7 - const n = Number(3); // OK
8 - const s = String('foo'); // OK
9 - const [state, setState] = React$useState(0); // OK
10 - const [state2, setState2] = React.useState(1); // OK
11 - const constant = THIS_IS_A_CONSTANT(); // OK
12 - return 3;
13 -}
14 -
15 -export const FIXTURE_ENTRYPOINT = {
16 - fn: Component,
17 - params: [],
18 - isComponent: true,
19 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/change-detect-reassign.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableChangeDetectionForDebugging
6 -function Component(props) {
7 - let x = null;
8 - if (props.cond) {
9 - x = [];
10 - x.push(props.value);
11 - }
12 - return x;
13 -}
14 -
15 -```
16 -
17 -## Code
18 -
19 -```javascript
20 -import { $structuralCheck } from "react-compiler-runtime";
21 -import { c as _c } from "react/compiler-runtime"; // @enableChangeDetectionForDebugging
22 -function Component(props) {
23 - const $ = _c(2);
24 - let x = null;
25 - if (props.cond) {
26 - {
27 - x = [];
28 - x.push(props.value);
29 - let condition = $[0] !== props.value;
30 - if (!condition) {
31 - let old$x = $[1];
32 - $structuralCheck(old$x, x, "x", "Component", "cached", "(3:6)");
33 - }
34 - $[0] = props.value;
35 - $[1] = x;
36 - if (condition) {
37 - x = [];
38 - x.push(props.value);
39 - $structuralCheck($[1], x, "x", "Component", "recomputed", "(3:6)");
40 - x = $[1];
41 - }
42 - }
43 - }
44 -
45 - return x;
46 -}
47 -
48 -```
49 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/change-detect-reassign.js deleted
-9
@@ -1,9 +0,0 @@
1 -// @enableChangeDetectionForDebugging
2 -function Component(props) {
3 - let x = null;
4 - if (props.cond) {
5 - x = [];
6 - x.push(props.value);
7 - }
8 - return x;
9 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md deleted
-39
@@ -1,39 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableEmitFreeze @enableEmitInstrumentForget
6 -
7 -function useFoo(props) {
8 - return foo(props.x);
9 -}
10 -
11 -```
12 -
13 -## Code
14 -
15 -```javascript
16 -import {
17 - makeReadOnly,
18 - shouldInstrument,
19 - useRenderCounter,
20 -} from "react-compiler-runtime";
21 -import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @enableEmitInstrumentForget
22 -
23 -function useFoo(props) {
24 - if (DEV && shouldInstrument)
25 - useRenderCounter("useFoo", "/codegen-emit-imports-same-source.ts");
26 - const $ = _c(2);
27 - let t0;
28 - if ($[0] !== props.x) {
29 - t0 = foo(props.x);
30 - $[0] = props.x;
31 - $[1] = __DEV__ ? makeReadOnly(t0, "useFoo") : t0;
32 - } else {
33 - t0 = $[1];
34 - }
35 - return t0;
36 -}
37 -
38 -```
39 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.js deleted
-5
@@ -1,5 +0,0 @@
1 -// @enableEmitFreeze @enableEmitInstrumentForget
2 -
3 -function useFoo(props) {
4 - return foo(props.x);
5 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-make-read-only.expect.md deleted
-44
@@ -1,44 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableEmitFreeze true
6 -
7 -function MyComponentName(props) {
8 - let x = {};
9 - foo(x, props.a);
10 - foo(x, props.b);
11 -
12 - let y = [];
13 - y.push(x);
14 - return y;
15 -}
16 -
17 -```
18 -
19 -## Code
20 -
21 -```javascript
22 -import { makeReadOnly } from "react-compiler-runtime";
23 -import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze true
24 -
25 -function MyComponentName(props) {
26 - const $ = _c(3);
27 - let y;
28 - if ($[0] !== props.a || $[1] !== props.b) {
29 - const x = {};
30 - foo(x, props.a);
31 - foo(x, props.b);
32 - y = [];
33 - y.push(x);
34 - $[0] = props.a;
35 - $[1] = props.b;
36 - $[2] = __DEV__ ? makeReadOnly(y, "MyComponentName") : y;
37 - } else {
38 - y = $[2];
39 - }
40 - return y;
41 -}
42 -
43 -```
44 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-make-read-only.js deleted
-11
@@ -1,11 +0,0 @@
1 -// @enableEmitFreeze true
2 -
3 -function MyComponentName(props) {
4 - let x = {};
5 - foo(x, props.a);
6 - foo(x, props.b);
7 -
8 - let y = [];
9 - y.push(x);
10 - return y;
11 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.expect.md deleted
-37
@@ -1,37 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableEmitFreeze @instrumentForget
6 -
7 -let makeReadOnly = 'conflicting identifier';
8 -function useFoo(props) {
9 - return foo(props.x);
10 -}
11 -
12 -```
13 -
14 -## Code
15 -
16 -```javascript
17 -import { makeReadOnly as _makeReadOnly } from "react-compiler-runtime";
18 -import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @instrumentForget
19 -
20 -let makeReadOnly = "conflicting identifier";
21 -function useFoo(props) {
22 - const $ = _c(2);
23 - let t0;
24 - if ($[0] !== props.x) {
25 - t0 = foo(props.x);
26 - $[0] = props.x;
27 - $[1] = __DEV__ ? _makeReadOnly(t0, "useFoo") : t0;
28 - } else {
29 - t0 = $[1];
30 - }
31 - return t0;
32 -}
33 -
34 -```
35 -
36 -### Eval output
37 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.js deleted
-6
@@ -1,6 +0,0 @@
1 -// @enableEmitFreeze @instrumentForget
2 -
3 -let makeReadOnly = 'conflicting identifier';
4 -function useFoo(props) {
5 - return foo(props.x);
6 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.expect.md deleted
-33
@@ -1,33 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableEmitFreeze @instrumentForget
6 -function useFoo(props) {
7 - return foo(props.x, __DEV__);
8 -}
9 -
10 -```
11 -
12 -## Code
13 -
14 -```javascript
15 -import { makeReadOnly } from "react-compiler-runtime";
16 -import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @instrumentForget
17 -function useFoo(props) {
18 - const $ = _c(2);
19 - let t0;
20 - if ($[0] !== props.x) {
21 - t0 = foo(props.x, __DEV__);
22 - $[0] = props.x;
23 - $[1] = __DEV__ ? makeReadOnly(t0, "useFoo") : t0;
24 - } else {
25 - t0 = $[1];
26 - }
27 - return t0;
28 -}
29 -
30 -```
31 -
32 -### Eval output
33 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.js deleted
-4
@@ -1,4 +0,0 @@
1 -// @enableEmitFreeze @instrumentForget
2 -function useFoo(props) {
3 - return foo(props.x, __DEV__);
4 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.expect.md deleted
-34
@@ -1,34 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableEmitFreeze @instrumentForget
6 -function useFoo(props) {
7 - const __DEV__ = 'conflicting global';
8 - console.log(__DEV__);
9 - return foo(props.x);
10 -}
11 -
12 -```
13 -
14 -
15 -## Error
16 -
17 -```
18 -Found 1 error:
19 -
20 -Todo: Encountered conflicting global in generated program
21 -
22 -Conflict from local binding __DEV__.
23 -
24 -error.emit-freeze-conflicting-global.ts:3:8
25 - 1 | // @enableEmitFreeze @instrumentForget
26 - 2 | function useFoo(props) {
27 -> 3 | const __DEV__ = 'conflicting global';
28 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Encountered conflicting global in generated program
29 - 4 | console.log(__DEV__);
30 - 5 | return foo(props.x);
31 - 6 | }
32 -```
33 -
34 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.js deleted
-6
@@ -1,6 +0,0 @@
1 -// @enableEmitFreeze @instrumentForget
2 -function useFoo(props) {
3 - const __DEV__ = 'conflicting global';
4 - console.log(__DEV__);
5 - return foo(props.x);
6 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.expect.md deleted
-44
@@ -1,44 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateMemoizedEffectDependencies
6 -function Component(props) {
7 - // Items cannot be memoized bc its mutation spans a hook call
8 - const items = [props.value];
9 - const [state, _setState] = useState(null);
10 - mutate(items);
11 -
12 - // Items is no longer mutable here, but it hasn't been memoized
13 - useEffect(() => {
14 - console.log(items);
15 - }, [items]);
16 -
17 - return [items, state];
18 -}
19 -
20 -```
21 -
22 -
23 -## Error
24 -
25 -```
26 -Found 1 error:
27 -
28 -Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
29 -
30 -error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.ts:9:2
31 - 7 |
32 - 8 | // Items is no longer mutable here, but it hasn't been memoized
33 -> 9 | useEffect(() => {
34 - | ^^^^^^^^^^^^^^^^^
35 -> 10 | console.log(items);
36 - | ^^^^^^^^^^^^^^^^^^^^^^^
37 -> 11 | }, [items]);
38 - | ^^^^^^^^^^^^^^ React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
39 - 12 |
40 - 13 | return [items, state];
41 - 14 | }
42 -```
43 -
44 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @validateMemoizedEffectDependencies
2 -function Component(props) {
3 - // Items cannot be memoized bc its mutation spans a hook call
4 - const items = [props.value];
5 - const [state, _setState] = useState(null);
6 - mutate(items);
7 -
8 - // Items is no longer mutable here, but it hasn't been memoized
9 - useEffect(() => {
10 - console.log(items);
11 - }, [items]);
12 -
13 - return [items, state];
14 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useEffect-dep-not-memoized.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateMemoizedEffectDependencies
6 -import {useEffect} from 'react';
7 -
8 -function Component(props) {
9 - const data = {};
10 - useEffect(() => {
11 - console.log(props.value);
12 - }, [data]);
13 - mutate(data);
14 - return data;
15 -}
16 -
17 -```
18 -
19 -
20 -## Error
21 -
22 -```
23 -Found 1 error:
24 -
25 -Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
26 -
27 -error.invalid-useEffect-dep-not-memoized.ts:6:2
28 - 4 | function Component(props) {
29 - 5 | const data = {};
30 -> 6 | useEffect(() => {
31 - | ^^^^^^^^^^^^^^^^^
32 -> 7 | console.log(props.value);
33 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34 -> 8 | }, [data]);
35 - | ^^^^^^^^^^^^^ React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
36 - 9 | mutate(data);
37 - 10 | return data;
38 - 11 | }
39 -```
40 -
41 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useEffect-dep-not-memoized.js deleted
-11
@@ -1,11 +0,0 @@
1 -// @validateMemoizedEffectDependencies
2 -import {useEffect} from 'react';
3 -
4 -function Component(props) {
5 - const data = {};
6 - useEffect(() => {
7 - console.log(props.value);
8 - }, [data]);
9 - mutate(data);
10 - return data;
11 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useInsertionEffect-dep-not-memoized.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateMemoizedEffectDependencies
6 -import {useInsertionEffect} from 'react';
7 -
8 -function Component(props) {
9 - const data = {};
10 - useInsertionEffect(() => {
11 - console.log(props.value);
12 - }, [data]);
13 - mutate(data);
14 - return data;
15 -}
16 -
17 -```
18 -
19 -
20 -## Error
21 -
22 -```
23 -Found 1 error:
24 -
25 -Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
26 -
27 -error.invalid-useInsertionEffect-dep-not-memoized.ts:6:2
28 - 4 | function Component(props) {
29 - 5 | const data = {};
30 -> 6 | useInsertionEffect(() => {
31 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^
32 -> 7 | console.log(props.value);
33 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34 -> 8 | }, [data]);
35 - | ^^^^^^^^^^^^^ React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
36 - 9 | mutate(data);
37 - 10 | return data;
38 - 11 | }
39 -```
40 -
41 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useInsertionEffect-dep-not-memoized.js deleted
-11
@@ -1,11 +0,0 @@
1 -// @validateMemoizedEffectDependencies
2 -import {useInsertionEffect} from 'react';
3 -
4 -function Component(props) {
5 - const data = {};
6 - useInsertionEffect(() => {
7 - console.log(props.value);
8 - }, [data]);
9 - mutate(data);
10 - return data;
11 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useLayoutEffect-dep-not-memoized.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateMemoizedEffectDependencies
6 -import {useLayoutEffect} from 'react';
7 -
8 -function Component(props) {
9 - const data = {};
10 - useLayoutEffect(() => {
11 - console.log(props.value);
12 - }, [data]);
13 - mutate(data);
14 - return data;
15 -}
16 -
17 -```
18 -
19 -
20 -## Error
21 -
22 -```
23 -Found 1 error:
24 -
25 -Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
26 -
27 -error.invalid-useLayoutEffect-dep-not-memoized.ts:6:2
28 - 4 | function Component(props) {
29 - 5 | const data = {};
30 -> 6 | useLayoutEffect(() => {
31 - | ^^^^^^^^^^^^^^^^^^^^^^^
32 -> 7 | console.log(props.value);
33 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34 -> 8 | }, [data]);
35 - | ^^^^^^^^^^^^^ React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
36 - 9 | mutate(data);
37 - 10 | return data;
38 - 11 | }
39 -```
40 -
41 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useLayoutEffect-dep-not-memoized.js deleted
-11
@@ -1,11 +0,0 @@
1 -// @validateMemoizedEffectDependencies
2 -import {useLayoutEffect} from 'react';
3 -
4 -function Component(props) {
5 - const data = {};
6 - useLayoutEffect(() => {
7 - console.log(props.value);
8 - }, [data]);
9 - mutate(data);
10 - return data;
11 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-component-in-normal-function.expect.md deleted
-54
@@ -1,54 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateNoDynamicallyCreatedComponentsOrHooks
6 -export function getInput(a) {
7 - const Wrapper = () => {
8 - const handleChange = () => {
9 - a.onChange();
10 - };
11 -
12 - return <input onChange={handleChange} />;
13 - };
14 -
15 - return Wrapper;
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: getInput,
20 - isComponent: false,
21 - params: [{onChange() {}}],
22 -};
23 -
24 -```
25 -
26 -
27 -## Error
28 -
29 -```
30 -Found 1 error:
31 -
32 -Error: Components and hooks cannot be created dynamically
33 -
34 -The function `Wrapper` appears to be a React component, but it's defined inside `getInput`. Components and Hooks should always be declared at module scope.
35 -
36 -error.nested-component-in-normal-function.ts:2:16
37 - 1 | // @validateNoDynamicallyCreatedComponentsOrHooks
38 -> 2 | export function getInput(a) {
39 - | ^^^^^^^^ this function dynamically created a component/hook
40 - 3 | const Wrapper = () => {
41 - 4 | const handleChange = () => {
42 - 5 | a.onChange();
43 -
44 -error.nested-component-in-normal-function.ts:3:8
45 - 1 | // @validateNoDynamicallyCreatedComponentsOrHooks
46 - 2 | export function getInput(a) {
47 -> 3 | const Wrapper = () => {
48 - | ^^^^^^^ the component is created here
49 - 4 | const handleChange = () => {
50 - 5 | a.onChange();
51 - 6 | };
52 -```
53 -
54 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-component-in-normal-function.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @validateNoDynamicallyCreatedComponentsOrHooks
2 -export function getInput(a) {
3 - const Wrapper = () => {
4 - const handleChange = () => {
5 - a.onChange();
6 - };
7 -
8 - return <input onChange={handleChange} />;
9 - };
10 -
11 - return Wrapper;
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: getInput,
16 - isComponent: false,
17 - params: [{onChange() {}}],
18 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-hook-in-normal-function.expect.md deleted
-59
@@ -1,59 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateNoDynamicallyCreatedComponentsOrHooks
6 -import {useState} from 'react';
7 -
8 -function createCustomHook(config) {
9 - function useConfiguredState() {
10 - const [state, setState] = useState(0);
11 -
12 - const increment = () => {
13 - setState(state + config.step);
14 - };
15 -
16 - return [state, increment];
17 - }
18 -
19 - return useConfiguredState;
20 -}
21 -
22 -export const FIXTURE_ENTRYPOINT = {
23 - fn: createCustomHook,
24 - isComponent: false,
25 - params: [{step: 1}],
26 -};
27 -
28 -```
29 -
30 -
31 -## Error
32 -
33 -```
34 -Found 1 error:
35 -
36 -Error: Components and hooks cannot be created dynamically
37 -
38 -The function `useConfiguredState` appears to be a React hook, but it's defined inside `createCustomHook`. Components and Hooks should always be declared at module scope.
39 -
40 -error.nested-hook-in-normal-function.ts:4:9
41 - 2 | import {useState} from 'react';
42 - 3 |
43 -> 4 | function createCustomHook(config) {
44 - | ^^^^^^^^^^^^^^^^ this function dynamically created a component/hook
45 - 5 | function useConfiguredState() {
46 - 6 | const [state, setState] = useState(0);
47 - 7 |
48 -
49 -error.nested-hook-in-normal-function.ts:5:11
50 - 3 |
51 - 4 | function createCustomHook(config) {
52 -> 5 | function useConfiguredState() {
53 - | ^^^^^^^^^^^^^^^^^^ the component is created here
54 - 6 | const [state, setState] = useState(0);
55 - 7 |
56 - 8 | const increment = () => {
57 -```
58 -
59 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-hook-in-normal-function.js deleted
-22
@@ -1,22 +0,0 @@
1 -// @validateNoDynamicallyCreatedComponentsOrHooks
2 -import {useState} from 'react';
3 -
4 -function createCustomHook(config) {
5 - function useConfiguredState() {
6 - const [state, setState] = useState(0);
7 -
8 - const increment = () => {
9 - setState(state + config.step);
10 - };
11 -
12 - return [state, increment];
13 - }
14 -
15 - return useConfiguredState;
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: createCustomHook,
20 - isComponent: false,
21 - params: [{step: 1}],
22 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nomemo-and-change-detect.expect.md deleted
-19
@@ -1,19 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @disableMemoizationForDebugging @enableChangeDetectionForDebugging
6 -function Component(props) {}
7 -
8 -```
9 -
10 -
11 -## Error
12 -
13 -```
14 -Found 1 error:
15 -
16 -Error: Invalid environment config: the 'disableMemoizationForDebugging' and 'enableChangeDetectionForDebugging' options cannot be used together
17 -```
18 -
19 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nomemo-and-change-detect.js deleted
-2
@@ -1,2 +0,0 @@
1 -// @disableMemoizationForDebugging @enableChangeDetectionForDebugging
2 -function Component(props) {}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-value-in-custom-component-event-handler-wrapper.expect.md deleted
-69
@@ -1,69 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableInferEventHandlers
6 -import {useRef} from 'react';
7 -
8 -// Simulates a custom component wrapper
9 -function CustomForm({onSubmit, children}: any) {
10 - return <form onSubmit={onSubmit}>{children}</form>;
11 -}
12 -
13 -// Simulates react-hook-form's handleSubmit
14 -function handleSubmit<T>(callback: (data: T) => void) {
15 - return (event: any) => {
16 - event.preventDefault();
17 - callback({} as T);
18 - };
19 -}
20 -
21 -function Component() {
22 - const ref = useRef<HTMLInputElement>(null);
23 -
24 - const onSubmit = (data: any) => {
25 - // This should error: passing function with ref access to custom component
26 - // event handler, even though it would be safe on a native <form>
27 - if (ref.current !== null) {
28 - console.log(ref.current.value);
29 - }
30 - };
31 -
32 - return (
33 - <>
34 - <input ref={ref} />
35 - <CustomForm onSubmit={handleSubmit(onSubmit)}>
36 - <button type="submit">Submit</button>
37 - </CustomForm>
38 - </>
39 - );
40 -}
41 -
42 -export const FIXTURE_ENTRYPOINT = {
43 - fn: Component,
44 - params: [{}],
45 -};
46 -
47 -```
48 -
49 -
50 -## Error
51 -
52 -```
53 -Found 1 error:
54 -
55 -Error: Cannot access refs during render
56 -
57 -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef).
58 -
59 -error.ref-value-in-custom-component-event-handler-wrapper.ts:31:41
60 - 29 | <>
61 - 30 | <input ref={ref} />
62 -> 31 | <CustomForm onSubmit={handleSubmit(onSubmit)}>
63 - | ^^^^^^^^ Passing a ref to a function may read its value during render
64 - 32 | <button type="submit">Submit</button>
65 - 33 | </CustomForm>
66 - 34 | </>
67 -```
68 -
69 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-value-in-custom-component-event-handler-wrapper.tsx deleted
-41
@@ -1,41 +0,0 @@
1 -// @enableInferEventHandlers
2 -import {useRef} from 'react';
3 -
4 -// Simulates a custom component wrapper
5 -function CustomForm({onSubmit, children}: any) {
6 - return <form onSubmit={onSubmit}>{children}</form>;
7 -}
8 -
9 -// Simulates react-hook-form's handleSubmit
10 -function handleSubmit<T>(callback: (data: T) => void) {
11 - return (event: any) => {
12 - event.preventDefault();
13 - callback({} as T);
14 - };
15 -}
16 -
17 -function Component() {
18 - const ref = useRef<HTMLInputElement>(null);
19 -
20 - const onSubmit = (data: any) => {
21 - // This should error: passing function with ref access to custom component
22 - // event handler, even though it would be safe on a native <form>
23 - if (ref.current !== null) {
24 - console.log(ref.current.value);
25 - }
26 - };
27 -
28 - return (
29 - <>
30 - <input ref={ref} />
31 - <CustomForm onSubmit={handleSubmit(onSubmit)}>
32 - <button type="submit">Submit</button>
33 - </CustomForm>
34 - </>
35 - );
36 -}
37 -
38 -export const FIXTURE_ENTRYPOINT = {
39 - fn: Component,
40 - params: [{}],
41 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-value-in-event-handler-wrapper.expect.md deleted
-55
@@ -1,55 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableInferEventHandlers
6 -import {useRef} from 'react';
7 -
8 -// Simulates a handler wrapper
9 -function handleClick(value: any) {
10 - return () => {
11 - console.log(value);
12 - };
13 -}
14 -
15 -function Component() {
16 - const ref = useRef(null);
17 -
18 - // This should still error: passing ref.current directly to a wrapper
19 - // The ref value is accessed during render, not in the event handler
20 - return (
21 - <>
22 - <input ref={ref} />
23 - <button onClick={handleClick(ref.current)}>Click</button>
24 - </>
25 - );
26 -}
27 -
28 -export const FIXTURE_ENTRYPOINT = {
29 - fn: Component,
30 - params: [{}],
31 -};
32 -
33 -```
34 -
35 -
36 -## Error
37 -
38 -```
39 -Found 1 error:
40 -
41 -Error: Cannot access refs during render
42 -
43 -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef).
44 -
45 -error.ref-value-in-event-handler-wrapper.ts:19:35
46 - 17 | <>
47 - 18 | <input ref={ref} />
48 -> 19 | <button onClick={handleClick(ref.current)}>Click</button>
49 - | ^^^^^^^^^^^ Cannot access ref value during render
50 - 20 | </>
51 - 21 | );
52 - 22 | }
53 -```
54 -
55 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-value-in-event-handler-wrapper.tsx deleted
-27
@@ -1,27 +0,0 @@
1 -// @enableInferEventHandlers
2 -import {useRef} from 'react';
3 -
4 -// Simulates a handler wrapper
5 -function handleClick(value: any) {
6 - return () => {
7 - console.log(value);
8 - };
9 -}
10 -
11 -function Component() {
12 - const ref = useRef(null);
13 -
14 - // This should still error: passing ref.current directly to a wrapper
15 - // The ref value is accessed during render, not in the event handler
16 - return (
17 - <>
18 - <input ref={ref} />
19 - <button onClick={handleClick(ref.current)}>Click</button>
20 - </>
21 - );
22 -}
23 -
24 -export const FIXTURE_ENTRYPOINT = {
25 - fn: Component,
26 - params: [{}],
27 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-preserve-memo-deps-mixed-optional-nonoptional-property-chain.expect.md
+1 -1
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
5 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
6
7 import {useMemo} from 'react';
8 import {identity, ValidateMemoization} from 'shared-runtime';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-preserve-memo-deps-mixed-optional-nonoptional-property-chain.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
1 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
2
3 import {useMemo} from 'react';
4 import {identity, ValidateMemoization} from 'shared-runtime';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-memoized-effect-deps-invalidated-dep-value.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateMemoizedEffectDependencies
6 -import {useHook} from 'shared-runtime';
7 -
8 -function Component(props) {
9 - const x = [];
10 - useHook(); // intersperse a hook call to prevent memoization of x
11 - x.push(props.value);
12 -
13 - const y = [x];
14 -
15 - useEffect(() => {
16 - console.log(y);
17 - }, [y]);
18 -}
19 -
20 -export const FIXTURE_ENTRYPOINT = {
21 - fn: Component,
22 - params: [{value: 'sathya'}],
23 -};
24 -
25 -```
26 -
27 -
28 -## Error
29 -
30 -```
31 -Found 1 error:
32 -
33 -Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
34 -
35 -error.validate-memoized-effect-deps-invalidated-dep-value.ts:11:2
36 - 9 | const y = [x];
37 - 10 |
38 -> 11 | useEffect(() => {
39 - | ^^^^^^^^^^^^^^^^^
40 -> 12 | console.log(y);
41 - | ^^^^^^^^^^^^^^^^^^^
42 -> 13 | }, [y]);
43 - | ^^^^^^^^^^ React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
44 - 14 | }
45 - 15 |
46 - 16 | export const FIXTURE_ENTRYPOINT = {
47 -```
48 -
49 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-memoized-effect-deps-invalidated-dep-value.js deleted
-19
@@ -1,19 +0,0 @@
1 -// @validateMemoizedEffectDependencies
2 -import {useHook} from 'shared-runtime';
3 -
4 -function Component(props) {
5 - const x = [];
6 - useHook(); // intersperse a hook call to prevent memoization of x
7 - x.push(props.value);
8 -
9 - const y = [x];
10 -
11 - useEffect(() => {
12 - console.log(y);
13 - }, [y]);
14 -}
15 -
16 -export const FIXTURE_ENTRYPOINT = {
17 - fn: Component,
18 - params: [{value: 'sathya'}],
19 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md deleted
-67
@@ -1,67 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableTreatFunctionDepsAsConditional
6 -import {Stringify} from 'shared-runtime';
7 -
8 -function Component({props}) {
9 - const f = () => props.a.b;
10 -
11 - return <Stringify f={props == null ? () => {} : f} />;
12 -}
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: Component,
15 - params: [{props: null}],
16 -};
17 -
18 -```
19 -
20 -## Code
21 -
22 -```javascript
23 -import { c as _c } from "react/compiler-runtime"; // @enableTreatFunctionDepsAsConditional
24 -import { Stringify } from "shared-runtime";
25 -
26 -function Component(t0) {
27 - const $ = _c(7);
28 - const { props } = t0;
29 - let t1;
30 - if ($[0] !== props) {
31 - t1 = () => props.a.b;
32 - $[0] = props;
33 - $[1] = t1;
34 - } else {
35 - t1 = $[1];
36 - }
37 - const f = t1;
38 - let t2;
39 - if ($[2] !== f || $[3] !== props) {
40 - t2 = props == null ? _temp : f;
41 - $[2] = f;
42 - $[3] = props;
43 - $[4] = t2;
44 - } else {
45 - t2 = $[4];
46 - }
47 - let t3;
48 - if ($[5] !== t2) {
49 - t3 = <Stringify f={t2} />;
50 - $[5] = t2;
51 - $[6] = t3;
52 - } else {
53 - t3 = $[6];
54 - }
55 - return t3;
56 -}
57 -function _temp() {}
58 -
59 -export const FIXTURE_ENTRYPOINT = {
60 - fn: Component,
61 - params: [{ props: null }],
62 -};
63 -
64 -```
65 -
66 -### Eval output
67 -(kind: ok) <div>{"f":"[[ function params=0 ]]"}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.tsx deleted
-12
@@ -1,12 +0,0 @@
1 -// @enableTreatFunctionDepsAsConditional
2 -import {Stringify} from 'shared-runtime';
3 -
4 -function Component({props}) {
5 - const f = () => props.a.b;
6 -
7 - return <Stringify f={props == null ? () => {} : f} />;
8 -}
9 -export const FIXTURE_ENTRYPOINT = {
10 - fn: Component,
11 - params: [{props: null}],
12 -};
deleted
-58
@@ -1,58 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableTreatFunctionDepsAsConditional
6 -function Component(props) {
7 - function getLength() {
8 - return props.bar.length;
9 - }
10 -
11 - return props.bar && getLength();
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{bar: null}],
17 -};
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { c as _c } from "react/compiler-runtime"; // @enableTreatFunctionDepsAsConditional
25 -function Component(props) {
26 - const $ = _c(5);
27 - let t0;
28 - if ($[0] !== props.bar) {
29 - t0 = function getLength() {
30 - return props.bar.length;
31 - };
32 - $[0] = props.bar;
33 - $[1] = t0;
34 - } else {
35 - t0 = $[1];
36 - }
37 - const getLength = t0;
38 - let t1;
39 - if ($[2] !== getLength || $[3] !== props.bar) {
40 - t1 = props.bar && getLength();
41 - $[2] = getLength;
42 - $[3] = props.bar;
43 - $[4] = t1;
44 - } else {
45 - t1 = $[4];
46 - }
47 - return t1;
48 -}
49 -
50 -export const FIXTURE_ENTRYPOINT = {
51 - fn: Component,
52 - params: [{ bar: null }],
53 -};
54 -
55 -```
56 -
57 -### Eval output
58 -(kind: ok) null
\ No newline at end of file
deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableTreatFunctionDepsAsConditional
2 -function Component(props) {
3 - function getLength() {
4 - return props.bar.length;
5 - }
6 -
7 - return props.bar && getLength();
8 -}
9 -
10 -export const FIXTURE_ENTRYPOINT = {
11 - fn: Component,
12 - params: [{bar: null}],
13 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/error.dynamic-gating-invalid-identifier-nopanic-required-feature.expect.md deleted
-42
@@ -1,42 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @dynamicGating:{"source":"shared-runtime"} @panicThreshold:"none" @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function ReactiveVariable({propVal}) {
10 - 'use memo if(invalid identifier)';
11 - const arr = [propVal];
12 - useEffect(() => print(arr), AUTODEPS);
13 -}
14 -
15 -export const FIXTURE_ENTRYPOINT = {
16 - fn: ReactiveVariable,
17 - params: [{}],
18 -};
19 -
20 -```
21 -
22 -
23 -## Error
24 -
25 -```
26 -Found 1 error:
27 -
28 -Error: Cannot infer dependencies of this effect. This will break your build!
29 -
30 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
31 -
32 -error.dynamic-gating-invalid-identifier-nopanic-required-feature.ts:8:2
33 - 6 | 'use memo if(invalid identifier)';
34 - 7 | const arr = [propVal];
35 -> 8 | useEffect(() => print(arr), AUTODEPS);
36 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
37 - 9 | }
38 - 10 |
39 - 11 | export const FIXTURE_ENTRYPOINT = {
40 -```
41 -
42 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/error.dynamic-gating-invalid-identifier-nopanic-required-feature.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @dynamicGating:{"source":"shared-runtime"} @panicThreshold:"none" @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function ReactiveVariable({propVal}) {
6 - 'use memo if(invalid identifier)';
7 - const arr = [propVal];
8 - useEffect(() => print(arr), AUTODEPS);
9 -}
10 -
11 -export const FIXTURE_ENTRYPOINT = {
12 - fn: ReactiveVariable,
13 - params: [{}],
14 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hooks-with-prefix.expect.md deleted
-95
@@ -1,95 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @hookPattern:".*\b(use[^$]+)$" @enablePreserveExistingMemoizationGuarantees:false
6 -
7 -import * as React from 'react';
8 -import {makeArray, useHook} from 'shared-runtime';
9 -
10 -const React$useState = React.useState;
11 -const React$useMemo = React.useMemo;
12 -const Internal$Reassigned$useHook = useHook;
13 -
14 -function Component() {
15 - const [state, setState] = React$useState(0);
16 - const object = Internal$Reassigned$useHook();
17 - const json = JSON.stringify(object);
18 - const doubledArray = React$useMemo(() => {
19 - return makeArray(state);
20 - }, [state]);
21 - return (
22 - <div>
23 - {doubledArray.join('')}
24 - {json}
25 - </div>
26 - );
27 -}
28 -
29 -export const FIXTURE_ENTRYPOINT = {
30 - fn: Component,
31 - params: [{}],
32 -};
33 -
34 -```
35 -
36 -## Code
37 -
38 -```javascript
39 -import { c as _c } from "react/compiler-runtime"; // @hookPattern:".*\b(use[^$]+)$" @enablePreserveExistingMemoizationGuarantees:false
40 -
41 -import * as React from "react";
42 -import { makeArray, useHook } from "shared-runtime";
43 -
44 -const React$useState = React.useState;
45 -const React$useMemo = React.useMemo;
46 -const Internal$Reassigned$useHook = useHook;
47 -
48 -function Component() {
49 - const $ = _c(7);
50 - const [state] = React$useState(0);
51 - const object = Internal$Reassigned$useHook();
52 - let t0;
53 - if ($[0] !== object) {
54 - t0 = JSON.stringify(object);
55 - $[0] = object;
56 - $[1] = t0;
57 - } else {
58 - t0 = $[1];
59 - }
60 - const json = t0;
61 - let t1;
62 - if ($[2] !== state) {
63 - const doubledArray = makeArray(state);
64 - t1 = doubledArray.join("");
65 - $[2] = state;
66 - $[3] = t1;
67 - } else {
68 - t1 = $[3];
69 - }
70 - let t2;
71 - if ($[4] !== json || $[5] !== t1) {
72 - t2 = (
73 - <div>
74 - {t1}
75 - {json}
76 - </div>
77 - );
78 - $[4] = json;
79 - $[5] = t1;
80 - $[6] = t2;
81 - } else {
82 - t2 = $[6];
83 - }
84 - return t2;
85 -}
86 -
87 -export const FIXTURE_ENTRYPOINT = {
88 - fn: Component,
89 - params: [{}],
90 -};
91 -
92 -```
93 -
94 -### Eval output
95 -(kind: ok) <div>0{"a":0,"b":"value1","c":true}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hooks-with-prefix.js deleted
-28
@@ -1,28 +0,0 @@
1 -// @hookPattern:".*\b(use[^$]+)$" @enablePreserveExistingMemoizationGuarantees:false
2 -
3 -import * as React from 'react';
4 -import {makeArray, useHook} from 'shared-runtime';
5 -
6 -const React$useState = React.useState;
7 -const React$useMemo = React.useMemo;
8 -const Internal$Reassigned$useHook = useHook;
9 -
10 -function Component() {
11 - const [state, setState] = React$useState(0);
12 - const object = Internal$Reassigned$useHook();
13 - const json = JSON.stringify(object);
14 - const doubledArray = React$useMemo(() => {
15 - return makeArray(state);
16 - }, [state]);
17 - return (
18 - <div>
19 - {doubledArray.join('')}
20 - {json}
21 - </div>
22 - );
23 -}
24 -
25 -export const FIXTURE_ENTRYPOINT = {
26 - fn: Component,
27 - params: [{}],
28 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.callsite-in-non-react-fn-default-import.expect.md deleted
-34
@@ -1,34 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @compilationMode:"infer" @panicThreshold:"none"
6 -import useMyEffect from 'useEffectWrapper';
7 -import {AUTODEPS} from 'react';
8 -
9 -function nonReactFn(arg) {
10 - useMyEffect(() => [1, 2, arg], AUTODEPS);
11 -}
12 -
13 -```
14 -
15 -
16 -## Error
17 -
18 -```
19 -Found 1 error:
20 -
21 -Error: Cannot infer dependencies of this effect. This will break your build!
22 -
23 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
24 -
25 -error.callsite-in-non-react-fn-default-import.ts:6:2
26 - 4 |
27 - 5 | function nonReactFn(arg) {
28 -> 6 | useMyEffect(() => [1, 2, arg], AUTODEPS);
29 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
30 - 7 | }
31 - 8 |
32 -```
33 -
34 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.callsite-in-non-react-fn-default-import.js deleted
-7
@@ -1,7 +0,0 @@
1 -// @inferEffectDependencies @compilationMode:"infer" @panicThreshold:"none"
2 -import useMyEffect from 'useEffectWrapper';
3 -import {AUTODEPS} from 'react';
4 -
5 -function nonReactFn(arg) {
6 - useMyEffect(() => [1, 2, arg], AUTODEPS);
7 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.callsite-in-non-react-fn.expect.md deleted
-33
@@ -1,33 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @compilationMode:"infer" @panicThreshold:"none"
6 -import {useEffect, AUTODEPS} from 'react';
7 -
8 -function nonReactFn(arg) {
9 - useEffect(() => [1, 2, arg], AUTODEPS);
10 -}
11 -
12 -```
13 -
14 -
15 -## Error
16 -
17 -```
18 -Found 1 error:
19 -
20 -Error: Cannot infer dependencies of this effect. This will break your build!
21 -
22 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
23 -
24 -error.callsite-in-non-react-fn.ts:5:2
25 - 3 |
26 - 4 | function nonReactFn(arg) {
27 -> 5 | useEffect(() => [1, 2, arg], AUTODEPS);
28 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
29 - 6 | }
30 - 7 |
31 -```
32 -
33 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.callsite-in-non-react-fn.js deleted
-6
@@ -1,6 +0,0 @@
1 -// @inferEffectDependencies @compilationMode:"infer" @panicThreshold:"none"
2 -import {useEffect, AUTODEPS} from 'react';
3 -
4 -function nonReactFn(arg) {
5 - useEffect(() => [1, 2, arg], AUTODEPS);
6 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.non-inlined-effect-fn.expect.md deleted
-48
@@ -1,48 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import {useEffect, AUTODEPS} from 'react';
7 -
8 -/**
9 - * Error on non-inlined effect functions:
10 - * 1. From the effect hook callee's perspective, it only makes sense
11 - * to either
12 - * (a) never hard error (i.e. failing to infer deps is acceptable) or
13 - * (b) always hard error,
14 - * regardless of whether the callback function is an inline fn.
15 - * 2. (Technical detail) it's harder to support detecting cases in which
16 - * function (pre-Forget transform) was inline but becomes memoized
17 - */
18 -function Component({foo}) {
19 - function f() {
20 - console.log(foo);
21 - }
22 -
23 - // No inferred dep array, the argument is not a lambda
24 - useEffect(f, AUTODEPS);
25 -}
26 -
27 -```
28 -
29 -
30 -## Error
31 -
32 -```
33 -Found 1 error:
34 -
35 -Error: Cannot infer dependencies of this effect. This will break your build!
36 -
37 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
38 -
39 -error.non-inlined-effect-fn.ts:20:2
40 - 18 |
41 - 19 | // No inferred dep array, the argument is not a lambda
42 -> 20 | useEffect(f, AUTODEPS);
43 - | ^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
44 - 21 | }
45 - 22 |
46 -```
47 -
48 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.non-inlined-effect-fn.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import {useEffect, AUTODEPS} from 'react';
3 -
4 -/**
5 - * Error on non-inlined effect functions:
6 - * 1. From the effect hook callee's perspective, it only makes sense
7 - * to either
8 - * (a) never hard error (i.e. failing to infer deps is acceptable) or
9 - * (b) always hard error,
10 - * regardless of whether the callback function is an inline fn.
11 - * 2. (Technical detail) it's harder to support detecting cases in which
12 - * function (pre-Forget transform) was inline but becomes memoized
13 - */
14 -function Component({foo}) {
15 - function f() {
16 - console.log(foo);
17 - }
18 -
19 - // No inferred dep array, the argument is not a lambda
20 - useEffect(f, AUTODEPS);
21 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-dynamic-gating.expect.md deleted
-50
@@ -1,50 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @dynamicGating:{"source":"shared-runtime"} @inferEffectDependencies @panicThreshold:"none"
6 -
7 -import useEffectWrapper from 'useEffectWrapper';
8 -import {AUTODEPS} from 'react';
9 -
10 -/**
11 - * TODO: run the non-forget enabled version through the effect inference
12 - * pipeline.
13 - */
14 -function Component({foo}) {
15 - 'use memo if(getTrue)';
16 - const arr = [];
17 - useEffectWrapper(() => arr.push(foo), AUTODEPS);
18 - arr.push(2);
19 - return arr;
20 -}
21 -
22 -export const FIXTURE_ENTRYPOINT = {
23 - fn: Component,
24 - params: [{foo: 1}],
25 - sequentialRenders: [{foo: 1}, {foo: 2}],
26 -};
27 -
28 -```
29 -
30 -
31 -## Error
32 -
33 -```
34 -Found 1 error:
35 -
36 -Error: Cannot infer dependencies of this effect. This will break your build!
37 -
38 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
39 -
40 -error.todo-dynamic-gating.ts:13:2
41 - 11 | 'use memo if(getTrue)';
42 - 12 | const arr = [];
43 -> 13 | useEffectWrapper(() => arr.push(foo), AUTODEPS);
44 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
45 - 14 | arr.push(2);
46 - 15 | return arr;
47 - 16 | }
48 -```
49 -
50 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-dynamic-gating.js deleted
-22
@@ -1,22 +0,0 @@
1 -// @dynamicGating:{"source":"shared-runtime"} @inferEffectDependencies @panicThreshold:"none"
2 -
3 -import useEffectWrapper from 'useEffectWrapper';
4 -import {AUTODEPS} from 'react';
5 -
6 -/**
7 - * TODO: run the non-forget enabled version through the effect inference
8 - * pipeline.
9 - */
10 -function Component({foo}) {
11 - 'use memo if(getTrue)';
12 - const arr = [];
13 - useEffectWrapper(() => arr.push(foo), AUTODEPS);
14 - arr.push(2);
15 - return arr;
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: Component,
20 - params: [{foo: 1}],
21 - sequentialRenders: [{foo: 1}, {foo: 2}],
22 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-gating.expect.md deleted
-48
@@ -1,48 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @gating @inferEffectDependencies @panicThreshold:"none"
6 -import useEffectWrapper from 'useEffectWrapper';
7 -import {AUTODEPS} from 'react';
8 -
9 -/**
10 - * TODO: run the non-forget enabled version through the effect inference
11 - * pipeline.
12 - */
13 -function Component({foo}) {
14 - const arr = [];
15 - useEffectWrapper(() => arr.push(foo), AUTODEPS);
16 - arr.push(2);
17 - return arr;
18 -}
19 -
20 -export const FIXTURE_ENTRYPOINT = {
21 - fn: Component,
22 - params: [{foo: 1}],
23 - sequentialRenders: [{foo: 1}, {foo: 2}],
24 -};
25 -
26 -```
27 -
28 -
29 -## Error
30 -
31 -```
32 -Found 1 error:
33 -
34 -Error: Cannot infer dependencies of this effect. This will break your build!
35 -
36 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
37 -
38 -error.todo-gating.ts:11:2
39 - 9 | function Component({foo}) {
40 - 10 | const arr = [];
41 -> 11 | useEffectWrapper(() => arr.push(foo), AUTODEPS);
42 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
43 - 12 | arr.push(2);
44 - 13 | return arr;
45 - 14 | }
46 -```
47 -
48 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-gating.js deleted
-20
@@ -1,20 +0,0 @@
1 -// @gating @inferEffectDependencies @panicThreshold:"none"
2 -import useEffectWrapper from 'useEffectWrapper';
3 -import {AUTODEPS} from 'react';
4 -
5 -/**
6 - * TODO: run the non-forget enabled version through the effect inference
7 - * pipeline.
8 - */
9 -function Component({foo}) {
10 - const arr = [];
11 - useEffectWrapper(() => arr.push(foo), AUTODEPS);
12 - arr.push(2);
13 - return arr;
14 -}
15 -
16 -export const FIXTURE_ENTRYPOINT = {
17 - fn: Component,
18 - params: [{foo: 1}],
19 - sequentialRenders: [{foo: 1}, {foo: 2}],
20 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-import-default-property-useEffect.expect.md deleted
-34
@@ -1,34 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import React from 'react';
7 -
8 -function NonReactiveDepInEffect() {
9 - const obj = makeObject_Primitives();
10 - React.useEffect(() => print(obj), React.AUTODEPS);
11 -}
12 -
13 -```
14 -
15 -
16 -## Error
17 -
18 -```
19 -Found 1 error:
20 -
21 -Error: Cannot infer dependencies of this effect. This will break your build!
22 -
23 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
24 -
25 -error.todo-import-default-property-useEffect.ts:6:2
26 - 4 | function NonReactiveDepInEffect() {
27 - 5 | const obj = makeObject_Primitives();
28 -> 6 | React.useEffect(() => print(obj), React.AUTODEPS);
29 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
30 - 7 | }
31 - 8 |
32 -```
33 -
34 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-import-default-property-useEffect.js deleted
-7
@@ -1,7 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import React from 'react';
3 -
4 -function NonReactiveDepInEffect() {
5 - const obj = makeObject_Primitives();
6 - React.useEffect(() => print(obj), React.AUTODEPS);
7 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md deleted
-60
@@ -1,60 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import {useSpecialEffect} from 'shared-runtime';
7 -import {AUTODEPS} from 'react';
8 -
9 -/**
10 - * Note that a react compiler-based transform still has limitations on JS syntax.
11 - * We should surface these as actionable lint / build errors to devs.
12 - */
13 -function Component({prop1}) {
14 - 'use memo';
15 - useSpecialEffect(
16 - () => {
17 - try {
18 - console.log(prop1);
19 - } finally {
20 - console.log('exiting');
21 - }
22 - },
23 - [prop1],
24 - AUTODEPS
25 - );
26 - return <div>{prop1}</div>;
27 -}
28 -
29 -```
30 -
31 -
32 -## Error
33 -
34 -```
35 -Found 1 error:
36 -
37 -Error: Cannot infer dependencies of this effect. This will break your build!
38 -
39 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (13:6).
40 -
41 -error.todo-syntax.ts:11:2
42 - 9 | function Component({prop1}) {
43 - 10 | 'use memo';
44 -> 11 | useSpecialEffect(
45 - | ^^^^^^^^^^^^^^^^^
46 -> 12 | () => {
47 - | ^^^^^^^^^^^
48 -> 13 | try {
49 - …
50 - | ^^^^^^^^^^^
51 -> 20 | AUTODEPS
52 - | ^^^^^^^^^^^
53 -> 21 | );
54 - | ^^^^ Cannot infer dependencies
55 - 22 | return <div>{prop1}</div>;
56 - 23 | }
57 - 24 |
58 -```
59 -
60 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.js deleted
-23
@@ -1,23 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import {useSpecialEffect} from 'shared-runtime';
3 -import {AUTODEPS} from 'react';
4 -
5 -/**
6 - * Note that a react compiler-based transform still has limitations on JS syntax.
7 - * We should surface these as actionable lint / build errors to devs.
8 - */
9 -function Component({prop1}) {
10 - 'use memo';
11 - useSpecialEffect(
12 - () => {
13 - try {
14 - console.log(prop1);
15 - } finally {
16 - console.log('exiting');
17 - }
18 - },
19 - [prop1],
20 - AUTODEPS
21 - );
22 - return <div>{prop1}</div>;
23 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.use-no-memo.expect.md deleted
-34
@@ -1,34 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import {useEffect, AUTODEPS} from 'react';
7 -
8 -function Component({propVal}) {
9 - 'use no memo';
10 - useEffect(() => [propVal], AUTODEPS);
11 -}
12 -
13 -```
14 -
15 -
16 -## Error
17 -
18 -```
19 -Found 1 error:
20 -
21 -Error: Cannot infer dependencies of this effect. This will break your build!
22 -
23 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
24 -
25 -error.use-no-memo.ts:6:2
26 - 4 | function Component({propVal}) {
27 - 5 | 'use no memo';
28 -> 6 | useEffect(() => [propVal], AUTODEPS);
29 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
30 - 7 | }
31 - 8 |
32 -```
33 -
34 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.use-no-memo.js deleted
-7
@@ -1,7 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import {useEffect, AUTODEPS} from 'react';
3 -
4 -function Component({propVal}) {
5 - 'use no memo';
6 - useEffect(() => [propVal], AUTODEPS);
7 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-granular-access.expect.md deleted
-39
@@ -1,39 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function Component({foo}) {
10 - const arr = [];
11 - // Taking either arr[0].value or arr as a dependency is reasonable
12 - // as long as developers know what to expect.
13 - useEffect(() => print(arr[0].value), AUTODEPS);
14 - arr.push({value: foo});
15 - return arr;
16 -}
17 -
18 -```
19 -
20 -## Code
21 -
22 -```javascript
23 -// @inferEffectDependencies @panicThreshold:"none"
24 -import { useEffect, AUTODEPS } from "react";
25 -import { print } from "shared-runtime";
26 -
27 -function Component(t0) {
28 - const { foo } = t0;
29 - const arr = [];
30 -
31 - useEffect(() => print(arr[0].value), [arr[0].value]);
32 - arr.push({ value: foo });
33 - return arr;
34 -}
35 -
36 -```
37 -
38 -### Eval output
39 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-granular-access.js deleted
-12
@@ -1,12 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function Component({foo}) {
6 - const arr = [];
7 - // Taking either arr[0].value or arr as a dependency is reasonable
8 - // as long as developers know what to expect.
9 - useEffect(() => print(arr[0].value), AUTODEPS);
10 - arr.push({value: foo});
11 - return arr;
12 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md deleted
-58
@@ -1,58 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function Component({foo}) {
10 - const arr = [];
11 - // Taking either arr[0].value or arr as a dependency is reasonable
12 - // as long as developers know what to expect.
13 - useEffect(() => print(arr[0]?.value), AUTODEPS);
14 - arr.push({value: foo});
15 - return arr;
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: Component,
20 - params: [{foo: 1}],
21 -};
22 -
23 -```
24 -
25 -## Code
26 -
27 -```javascript
28 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
29 -import { useEffect, AUTODEPS } from "react";
30 -import { print } from "shared-runtime";
31 -
32 -function Component(t0) {
33 - const { foo } = t0;
34 - const arr = [];
35 -
36 - useEffect(() => print(arr[0]?.value), [arr[0]?.value]);
37 - arr.push({ value: foo });
38 - return arr;
39 -}
40 -
41 -export const FIXTURE_ENTRYPOINT = {
42 - fn: Component,
43 - params: [{ foo: 1 }],
44 -};
45 -
46 -```
47 -
48 -## Logs
49 -
50 -```
51 -{"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":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":365},"end":{"line":10,"column":5,"index":368},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
52 -{"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"}]}
53 -{"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}
54 -```
55 -
56 -### Eval output
57 -(kind: ok) [{"value":1}]
58 -logs: [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.js deleted
-17
@@ -1,17 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function Component({foo}) {
6 - const arr = [];
7 - // Taking either arr[0].value or arr as a dependency is reasonable
8 - // as long as developers know what to expect.
9 - useEffect(() => print(arr[0]?.value), AUTODEPS);
10 - arr.push({value: foo});
11 - return arr;
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{foo: 1}],
17 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md deleted
-57
@@ -1,57 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
6 -
7 -import {useEffect, useRef, AUTODEPS} from 'react';
8 -import {print} from 'shared-runtime';
9 -
10 -function Component({arrRef}) {
11 - // Avoid taking arr.current as a dependency
12 - useEffect(() => print(arrRef.current), AUTODEPS);
13 - arrRef.current.val = 2;
14 - return arrRef;
15 -}
16 -
17 -export const FIXTURE_ENTRYPOINT = {
18 - fn: Component,
19 - params: [{arrRef: {current: {val: 'initial ref value'}}}],
20 -};
21 -
22 -```
23 -
24 -## Code
25 -
26 -```javascript
27 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
28 -
29 -import { useEffect, useRef, AUTODEPS } from "react";
30 -import { print } from "shared-runtime";
31 -
32 -function Component(t0) {
33 - const { arrRef } = t0;
34 -
35 - useEffect(() => print(arrRef.current), [arrRef]);
36 - arrRef.current.val = 2;
37 - return arrRef;
38 -}
39 -
40 -export const FIXTURE_ENTRYPOINT = {
41 - fn: Component,
42 - params: [{ arrRef: { current: { val: "initial ref value" } } }],
43 -};
44 -
45 -```
46 -
47 -## Logs
48 -
49 -```
50 -{"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":{"options":{"category":"Refs","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
51 -{"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"}]}
52 -{"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}
53 -```
54 -
55 -### Eval output
56 -(kind: ok) {"current":{"val":2}}
57 -logs: [{ val: 2 }]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.js deleted
-16
@@ -1,16 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
2 -
3 -import {useEffect, useRef, AUTODEPS} from 'react';
4 -import {print} from 'shared-runtime';
5 -
6 -function Component({arrRef}) {
7 - // Avoid taking arr.current as a dependency
8 - useEffect(() => print(arrRef.current), AUTODEPS);
9 - arrRef.current.val = 2;
10 - return arrRef;
11 -}
12 -
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: Component,
15 - params: [{arrRef: {current: {val: 'initial ref value'}}}],
16 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md deleted
-56
@@ -1,56 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
6 -import {useEffect, AUTODEPS} from 'react';
7 -
8 -function Component({foo}) {
9 - const arr = [];
10 - useEffect(() => {
11 - arr.push(foo);
12 - }, AUTODEPS);
13 - arr.push(2);
14 - return arr;
15 -}
16 -
17 -export const FIXTURE_ENTRYPOINT = {
18 - fn: Component,
19 - params: [{foo: 1}],
20 -};
21 -
22 -```
23 -
24 -## Code
25 -
26 -```javascript
27 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
28 -import { useEffect, AUTODEPS } from "react";
29 -
30 -function Component(t0) {
31 - const { foo } = t0;
32 - const arr = [];
33 - useEffect(() => {
34 - arr.push(foo);
35 - }, [arr, foo]);
36 - arr.push(2);
37 - return arr;
38 -}
39 -
40 -export const FIXTURE_ENTRYPOINT = {
41 - fn: Component,
42 - params: [{ foo: 1 }],
43 -};
44 -
45 -```
46 -
47 -## Logs
48 -
49 -```
50 -{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":214},"end":{"line":9,"column":5,"index":217},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
51 -{"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"}]}
52 -{"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}
53 -```
54 -
55 -### Eval output
56 -(kind: ok) [2]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.js deleted
-16
@@ -1,16 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
2 -import {useEffect, AUTODEPS} from 'react';
3 -
4 -function Component({foo}) {
5 - const arr = [];
6 - useEffect(() => {
7 - arr.push(foo);
8 - }, AUTODEPS);
9 - arr.push(2);
10 - return arr;
11 -}
12 -
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: Component,
15 - params: [{foo: 1}],
16 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index-no-func.expect.md deleted
-33
@@ -1,33 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -
8 -function Component({foo}) {
9 - useEffect(AUTODEPS);
10 -}
11 -
12 -```
13 -
14 -
15 -## Error
16 -
17 -```
18 -Found 1 error:
19 -
20 -Error: Cannot infer dependencies of this effect. This will break your build!
21 -
22 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
23 -
24 -error.wrong-index-no-func.ts:5:2
25 - 3 |
26 - 4 | function Component({foo}) {
27 -> 5 | useEffect(AUTODEPS);
28 - | ^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
29 - 6 | }
30 - 7 |
31 -```
32 -
33 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index-no-func.js deleted
-6
@@ -1,6 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -
4 -function Component({foo}) {
5 - useEffect(AUTODEPS);
6 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index.expect.md deleted
-52
@@ -1,52 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {AUTODEPS} from 'react';
7 -import useEffectWrapper from 'useEffectWrapper';
8 -
9 -function Component({foo}) {
10 - useEffectWrapper(
11 - () => {
12 - console.log(foo);
13 - },
14 - [foo],
15 - AUTODEPS
16 - );
17 -}
18 -
19 -```
20 -
21 -
22 -## Error
23 -
24 -```
25 -Found 1 error:
26 -
27 -Error: Cannot infer dependencies of this effect. This will break your build!
28 -
29 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
30 -
31 -error.wrong-index.ts:6:2
32 - 4 |
33 - 5 | function Component({foo}) {
34 -> 6 | useEffectWrapper(
35 - | ^^^^^^^^^^^^^^^^^
36 -> 7 | () => {
37 - | ^^^^^^^^^^^
38 -> 8 | console.log(foo);
39 - | ^^^^^^^^^^^
40 -> 9 | },
41 - | ^^^^^^^^^^^
42 -> 10 | [foo],
43 - | ^^^^^^^^^^^
44 -> 11 | AUTODEPS
45 - | ^^^^^^^^^^^
46 -> 12 | );
47 - | ^^^^ Cannot infer dependencies
48 - 13 | }
49 - 14 |
50 -```
51 -
52 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @inferEffectDependencies
2 -import {AUTODEPS} from 'react';
3 -import useEffectWrapper from 'useEffectWrapper';
4 -
5 -function Component({foo}) {
6 - useEffectWrapper(
7 - () => {
8 - console.log(foo);
9 - },
10 - [foo],
11 - AUTODEPS
12 - );
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/helper-nonreactive.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, useRef, AUTODEPS} from 'react';
7 -function useCustomRef() {
8 - const ref = useRef();
9 - return ref;
10 -}
11 -function NonReactiveWrapper() {
12 - const ref = useCustomRef();
13 - useEffect(() => {
14 - print(ref);
15 - }, AUTODEPS);
16 -}
17 -
18 -```
19 -
20 -## Code
21 -
22 -```javascript
23 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
24 -import { useEffect, useRef, AUTODEPS } from "react";
25 -function useCustomRef() {
26 - const ref = useRef();
27 - return ref;
28 -}
29 -
30 -function NonReactiveWrapper() {
31 - const $ = _c(2);
32 - const ref = useCustomRef();
33 - let t0;
34 - if ($[0] !== ref) {
35 - t0 = () => {
36 - print(ref);
37 - };
38 - $[0] = ref;
39 - $[1] = t0;
40 - } else {
41 - t0 = $[1];
42 - }
43 - useEffect(t0, [ref]);
44 -}
45 -
46 -```
47 -
48 -### Eval output
49 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/helper-nonreactive.js deleted
-12
@@ -1,12 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, useRef, AUTODEPS} from 'react';
3 -function useCustomRef() {
4 - const ref = useRef();
5 - return ref;
6 -}
7 -function NonReactiveWrapper() {
8 - const ref = useCustomRef();
9 - useEffect(() => {
10 - print(ref);
11 - }, AUTODEPS);
12 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/import-namespace-useEffect.expect.md deleted
-59
@@ -1,59 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import * as React from 'react';
7 -import * as SharedRuntime from 'shared-runtime';
8 -
9 -function NonReactiveDepInEffect() {
10 - const obj = makeObject_Primitives();
11 - React.useEffect(() => print(obj), React.AUTODEPS);
12 - SharedRuntime.useSpecialEffect(() => print(obj), [obj], React.AUTODEPS);
13 -}
14 -
15 -```
16 -
17 -## Code
18 -
19 -```javascript
20 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
21 -import * as React from "react";
22 -import * as SharedRuntime from "shared-runtime";
23 -
24 -function NonReactiveDepInEffect() {
25 - const $ = _c(4);
26 - let t0;
27 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28 - t0 = makeObject_Primitives();
29 - $[0] = t0;
30 - } else {
31 - t0 = $[0];
32 - }
33 - const obj = t0;
34 - let t1;
35 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
36 - t1 = () => print(obj);
37 - $[1] = t1;
38 - } else {
39 - t1 = $[1];
40 - }
41 - React.useEffect(t1, [obj]);
42 - let t2;
43 - let t3;
44 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
45 - t2 = () => print(obj);
46 - t3 = [obj];
47 - $[2] = t2;
48 - $[3] = t3;
49 - } else {
50 - t2 = $[2];
51 - t3 = $[3];
52 - }
53 - SharedRuntime.useSpecialEffect(t2, t3, [obj]);
54 -}
55 -
56 -```
57 -
58 -### Eval output
59 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/import-namespace-useEffect.js deleted
-9
@@ -1,9 +0,0 @@
1 -// @inferEffectDependencies
2 -import * as React from 'react';
3 -import * as SharedRuntime from 'shared-runtime';
4 -
5 -function NonReactiveDepInEffect() {
6 - const obj = makeObject_Primitives();
7 - React.useEffect(() => print(obj), React.AUTODEPS);
8 - SharedRuntime.useSpecialEffect(() => print(obj), [obj], React.AUTODEPS);
9 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/infer-deps-custom-config.expect.md deleted
-63
@@ -1,63 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {print, useSpecialEffect} from 'shared-runtime';
7 -import {AUTODEPS} from 'react';
8 -
9 -function CustomConfig({propVal}) {
10 - // Insertion
11 - useSpecialEffect(() => print(propVal), [propVal], AUTODEPS);
12 - // No insertion
13 - useSpecialEffect(() => print(propVal), [propVal], [propVal]);
14 -}
15 -
16 -```
17 -
18 -## Code
19 -
20 -```javascript
21 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
22 -import { print, useSpecialEffect } from "shared-runtime";
23 -import { AUTODEPS } from "react";
24 -
25 -function CustomConfig(t0) {
26 - const $ = _c(7);
27 - const { propVal } = t0;
28 - let t1;
29 - let t2;
30 - if ($[0] !== propVal) {
31 - t1 = () => print(propVal);
32 - t2 = [propVal];
33 - $[0] = propVal;
34 - $[1] = t1;
35 - $[2] = t2;
36 - } else {
37 - t1 = $[1];
38 - t2 = $[2];
39 - }
40 - useSpecialEffect(t1, t2, [propVal]);
41 - let t3;
42 - let t4;
43 - let t5;
44 - if ($[3] !== propVal) {
45 - t3 = () => print(propVal);
46 - t4 = [propVal];
47 - t5 = [propVal];
48 - $[3] = propVal;
49 - $[4] = t3;
50 - $[5] = t4;
51 - $[6] = t5;
52 - } else {
53 - t3 = $[4];
54 - t4 = $[5];
55 - t5 = $[6];
56 - }
57 - useSpecialEffect(t3, t4, t5);
58 -}
59 -
60 -```
61 -
62 -### Eval output
63 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/infer-deps-custom-config.js deleted
-10
@@ -1,10 +0,0 @@
1 -// @inferEffectDependencies
2 -import {print, useSpecialEffect} from 'shared-runtime';
3 -import {AUTODEPS} from 'react';
4 -
5 -function CustomConfig({propVal}) {
6 - // Insertion
7 - useSpecialEffect(() => print(propVal), [propVal], AUTODEPS);
8 - // No insertion
9 - useSpecialEffect(() => print(propVal), [propVal], [propVal]);
10 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/infer-effect-dependencies.expect.md deleted
-129
@@ -1,129 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, useRef, AUTODEPS} from 'react';
7 -import useEffectWrapper from 'useEffectWrapper';
8 -
9 -const moduleNonReactive = 0;
10 -
11 -function Component({foo, bar}) {
12 - const localNonreactive = 0;
13 - const ref = useRef(0);
14 - const localNonPrimitiveReactive = {
15 - foo,
16 - };
17 - const localNonPrimitiveNonreactive = {};
18 - useEffect(() => {
19 - console.log(foo);
20 - console.log(bar);
21 - console.log(moduleNonReactive);
22 - console.log(localNonreactive);
23 - console.log(globalValue);
24 - console.log(ref.current);
25 - console.log(localNonPrimitiveReactive);
26 - console.log(localNonPrimitiveNonreactive);
27 - }, AUTODEPS);
28 -
29 - // Optional chains and property accesses
30 - // TODO: we may be able to save bytes by omitting property accesses if the
31 - // object of the member expression is already included in the inferred deps
32 - useEffect(() => {
33 - console.log(bar?.baz);
34 - console.log(bar.qux);
35 - }, AUTODEPS);
36 -
37 - useEffectWrapper(() => {
38 - console.log(foo);
39 - }, AUTODEPS);
40 -}
41 -
42 -```
43 -
44 -## Code
45 -
46 -```javascript
47 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
48 -import { useEffect, useRef, AUTODEPS } from "react";
49 -import useEffectWrapper from "useEffectWrapper";
50 -
51 -const moduleNonReactive = 0;
52 -
53 -function Component(t0) {
54 - const $ = _c(12);
55 - const { foo, bar } = t0;
56 -
57 - const ref = useRef(0);
58 - let t1;
59 - if ($[0] !== foo) {
60 - t1 = { foo };
61 - $[0] = foo;
62 - $[1] = t1;
63 - } else {
64 - t1 = $[1];
65 - }
66 - const localNonPrimitiveReactive = t1;
67 - let t2;
68 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
69 - t2 = {};
70 - $[2] = t2;
71 - } else {
72 - t2 = $[2];
73 - }
74 - const localNonPrimitiveNonreactive = t2;
75 - let t3;
76 - if ($[3] !== bar || $[4] !== foo || $[5] !== localNonPrimitiveReactive) {
77 - t3 = () => {
78 - console.log(foo);
79 - console.log(bar);
80 - console.log(moduleNonReactive);
81 - console.log(0);
82 - console.log(globalValue);
83 - console.log(ref.current);
84 - console.log(localNonPrimitiveReactive);
85 - console.log(localNonPrimitiveNonreactive);
86 - };
87 - $[3] = bar;
88 - $[4] = foo;
89 - $[5] = localNonPrimitiveReactive;
90 - $[6] = t3;
91 - } else {
92 - t3 = $[6];
93 - }
94 - useEffect(t3, [
95 - foo,
96 - bar,
97 - localNonPrimitiveReactive,
98 - localNonPrimitiveNonreactive,
99 - ]);
100 - let t4;
101 - if ($[7] !== bar.baz || $[8] !== bar.qux) {
102 - t4 = () => {
103 - console.log(bar?.baz);
104 - console.log(bar.qux);
105 - };
106 - $[7] = bar.baz;
107 - $[8] = bar.qux;
108 - $[9] = t4;
109 - } else {
110 - t4 = $[9];
111 - }
112 - useEffect(t4, [bar.baz, bar.qux]);
113 - let t5;
114 - if ($[10] !== foo) {
115 - t5 = () => {
116 - console.log(foo);
117 - };
118 - $[10] = foo;
119 - $[11] = t5;
120 - } else {
121 - t5 = $[11];
122 - }
123 - useEffectWrapper(t5, [foo]);
124 -}
125 -
126 -```
127 -
128 -### Eval output
129 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/infer-effect-dependencies.js deleted
-36
@@ -1,36 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, useRef, AUTODEPS} from 'react';
3 -import useEffectWrapper from 'useEffectWrapper';
4 -
5 -const moduleNonReactive = 0;
6 -
7 -function Component({foo, bar}) {
8 - const localNonreactive = 0;
9 - const ref = useRef(0);
10 - const localNonPrimitiveReactive = {
11 - foo,
12 - };
13 - const localNonPrimitiveNonreactive = {};
14 - useEffect(() => {
15 - console.log(foo);
16 - console.log(bar);
17 - console.log(moduleNonReactive);
18 - console.log(localNonreactive);
19 - console.log(globalValue);
20 - console.log(ref.current);
21 - console.log(localNonPrimitiveReactive);
22 - console.log(localNonPrimitiveNonreactive);
23 - }, AUTODEPS);
24 -
25 - // Optional chains and property accesses
26 - // TODO: we may be able to save bytes by omitting property accesses if the
27 - // object of the member expression is already included in the inferred deps
28 - useEffect(() => {
29 - console.log(bar?.baz);
30 - console.log(bar.qux);
31 - }, AUTODEPS);
32 -
33 - useEffectWrapper(() => {
34 - console.log(foo);
35 - }, AUTODEPS);
36 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-dep.expect.md deleted
-80
@@ -1,80 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {makeObject_Primitives, print} from 'shared-runtime';
8 -
9 -/**
10 - * Note that `obj` is currently added to the effect dependency array, even
11 - * though it's non-reactive due to memoization.
12 - *
13 - * This is a TODO in effect dependency inference. Note that we cannot simply
14 - * filter out non-reactive effect dependencies, as some non-reactive (by data
15 - * flow) values become reactive due to scope pruning. See the
16 - * `infer-effect-deps/pruned-nonreactive-obj` fixture for why this matters.
17 - *
18 - * Realizing that this `useEffect` should have an empty dependency array
19 - * requires effect dependency inference to be structured similarly to memo
20 - * dependency inference.
21 - * Pass 1: add all potential dependencies regardless of dataflow reactivity
22 - * Pass 2: (todo) prune non-reactive dependencies
23 - *
24 - * Note that instruction reordering should significantly reduce scope pruning
25 - */
26 -function NonReactiveDepInEffect() {
27 - const obj = makeObject_Primitives();
28 - useEffect(() => print(obj), AUTODEPS);
29 -}
30 -
31 -```
32 -
33 -## Code
34 -
35 -```javascript
36 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
37 -import { useEffect, AUTODEPS } from "react";
38 -import { makeObject_Primitives, print } from "shared-runtime";
39 -
40 -/**
41 - * Note that `obj` is currently added to the effect dependency array, even
42 - * though it's non-reactive due to memoization.
43 - *
44 - * This is a TODO in effect dependency inference. Note that we cannot simply
45 - * filter out non-reactive effect dependencies, as some non-reactive (by data
46 - * flow) values become reactive due to scope pruning. See the
47 - * `infer-effect-deps/pruned-nonreactive-obj` fixture for why this matters.
48 - *
49 - * Realizing that this `useEffect` should have an empty dependency array
50 - * requires effect dependency inference to be structured similarly to memo
51 - * dependency inference.
52 - * Pass 1: add all potential dependencies regardless of dataflow reactivity
53 - * Pass 2: (todo) prune non-reactive dependencies
54 - *
55 - * Note that instruction reordering should significantly reduce scope pruning
56 - */
57 -function NonReactiveDepInEffect() {
58 - const $ = _c(2);
59 - let t0;
60 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
61 - t0 = makeObject_Primitives();
62 - $[0] = t0;
63 - } else {
64 - t0 = $[0];
65 - }
66 - const obj = t0;
67 - let t1;
68 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
69 - t1 = () => print(obj);
70 - $[1] = t1;
71 - } else {
72 - t1 = $[1];
73 - }
74 - useEffect(t1, [obj]);
75 -}
76 -
77 -```
78 -
79 -### Eval output
80 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-dep.js deleted
-25
@@ -1,25 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {makeObject_Primitives, print} from 'shared-runtime';
4 -
5 -/**
6 - * Note that `obj` is currently added to the effect dependency array, even
7 - * though it's non-reactive due to memoization.
8 - *
9 - * This is a TODO in effect dependency inference. Note that we cannot simply
10 - * filter out non-reactive effect dependencies, as some non-reactive (by data
11 - * flow) values become reactive due to scope pruning. See the
12 - * `infer-effect-deps/pruned-nonreactive-obj` fixture for why this matters.
13 - *
14 - * Realizing that this `useEffect` should have an empty dependency array
15 - * requires effect dependency inference to be structured similarly to memo
16 - * dependency inference.
17 - * Pass 1: add all potential dependencies regardless of dataflow reactivity
18 - * Pass 2: (todo) prune non-reactive dependencies
19 - *
20 - * Note that instruction reordering should significantly reduce scope pruning
21 - */
22 -function NonReactiveDepInEffect() {
23 - const obj = makeObject_Primitives();
24 - useEffect(() => print(obj), AUTODEPS);
25 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-effect-event.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, useEffectEvent, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -/**
10 - * We do not include effect events in dep arrays.
11 - */
12 -function NonReactiveEffectEvent() {
13 - const fn = useEffectEvent(() => print('hello world'));
14 - useEffect(() => fn(), AUTODEPS);
15 -}
16 -
17 -```
18 -
19 -## Code
20 -
21 -```javascript
22 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
23 -import { useEffect, useEffectEvent, AUTODEPS } from "react";
24 -import { print } from "shared-runtime";
25 -
26 -/**
27 - * We do not include effect events in dep arrays.
28 - */
29 -function NonReactiveEffectEvent() {
30 - const $ = _c(2);
31 - const fn = useEffectEvent(_temp);
32 - let t0;
33 - if ($[0] !== fn) {
34 - t0 = () => fn();
35 - $[0] = fn;
36 - $[1] = t0;
37 - } else {
38 - t0 = $[1];
39 - }
40 - useEffect(t0, []);
41 -}
42 -function _temp() {
43 - return print("hello world");
44 -}
45 -
46 -```
47 -
48 -### Eval output
49 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-effect-event.js deleted
-11
@@ -1,11 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, useEffectEvent, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -/**
6 - * We do not include effect events in dep arrays.
7 - */
8 -function NonReactiveEffectEvent() {
9 - const fn = useEffectEvent(() => print('hello world'));
10 - useEffect(() => fn(), AUTODEPS);
11 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-ref-helper.expect.md deleted
-89
@@ -1,89 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -/**
10 - * We never include a .current access in a dep array because it may be a ref access.
11 - * This might over-capture objects that are not refs and happen to have fields named
12 - * current, but that should be a rare case and the result would still be correct
13 - * (assuming the effect is idempotent). In the worst case, you can always write a manual
14 - * dep array.
15 - */
16 -function RefsInEffects() {
17 - const ref = useRefHelper();
18 - const wrapped = useDeeperRefHelper();
19 - useEffect(() => {
20 - print(ref.current);
21 - print(wrapped.foo.current);
22 - }, AUTODEPS);
23 -}
24 -
25 -function useRefHelper() {
26 - return useRef(0);
27 -}
28 -
29 -function useDeeperRefHelper() {
30 - return {foo: useRefHelper()};
31 -}
32 -
33 -```
34 -
35 -## Code
36 -
37 -```javascript
38 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
39 -import { useEffect, AUTODEPS } from "react";
40 -import { print } from "shared-runtime";
41 -
42 -/**
43 - * We never include a .current access in a dep array because it may be a ref access.
44 - * This might over-capture objects that are not refs and happen to have fields named
45 - * current, but that should be a rare case and the result would still be correct
46 - * (assuming the effect is idempotent). In the worst case, you can always write a manual
47 - * dep array.
48 - */
49 -function RefsInEffects() {
50 - const $ = _c(3);
51 - const ref = useRefHelper();
52 - const wrapped = useDeeperRefHelper();
53 - let t0;
54 - if ($[0] !== ref || $[1] !== wrapped.foo.current) {
55 - t0 = () => {
56 - print(ref.current);
57 - print(wrapped.foo.current);
58 - };
59 - $[0] = ref;
60 - $[1] = wrapped.foo.current;
61 - $[2] = t0;
62 - } else {
63 - t0 = $[2];
64 - }
65 - useEffect(t0, [ref, wrapped.foo]);
66 -}
67 -
68 -function useRefHelper() {
69 - return useRef(0);
70 -}
71 -
72 -function useDeeperRefHelper() {
73 - const $ = _c(2);
74 - const t0 = useRefHelper();
75 - let t1;
76 - if ($[0] !== t0) {
77 - t1 = { foo: t0 };
78 - $[0] = t0;
79 - $[1] = t1;
80 - } else {
81 - t1 = $[1];
82 - }
83 - return t1;
84 -}
85 -
86 -```
87 -
88 -### Eval output
89 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-ref-helper.js deleted
-27
@@ -1,27 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -/**
6 - * We never include a .current access in a dep array because it may be a ref access.
7 - * This might over-capture objects that are not refs and happen to have fields named
8 - * current, but that should be a rare case and the result would still be correct
9 - * (assuming the effect is idempotent). In the worst case, you can always write a manual
10 - * dep array.
11 - */
12 -function RefsInEffects() {
13 - const ref = useRefHelper();
14 - const wrapped = useDeeperRefHelper();
15 - useEffect(() => {
16 - print(ref.current);
17 - print(wrapped.foo.current);
18 - }, AUTODEPS);
19 -}
20 -
21 -function useRefHelper() {
22 - return useRef(0);
23 -}
24 -
25 -function useDeeperRefHelper() {
26 - return {foo: useRefHelper()};
27 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-ref.expect.md deleted
-51
@@ -1,51 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, useRef, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -/**
10 - * Special case of `infer-effect-deps/nonreactive-dep`.
11 - *
12 - * We know that local `useRef` return values are stable, regardless of
13 - * inferred memoization.
14 - */
15 -function NonReactiveRefInEffect() {
16 - const ref = useRef('initial value');
17 - useEffect(() => print(ref.current), AUTODEPS);
18 -}
19 -
20 -```
21 -
22 -## Code
23 -
24 -```javascript
25 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
26 -import { useEffect, useRef, AUTODEPS } from "react";
27 -import { print } from "shared-runtime";
28 -
29 -/**
30 - * Special case of `infer-effect-deps/nonreactive-dep`.
31 - *
32 - * We know that local `useRef` return values are stable, regardless of
33 - * inferred memoization.
34 - */
35 -function NonReactiveRefInEffect() {
36 - const $ = _c(1);
37 - const ref = useRef("initial value");
38 - let t0;
39 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
40 - t0 = () => print(ref.current);
41 - $[0] = t0;
42 - } else {
43 - t0 = $[0];
44 - }
45 - useEffect(t0, []);
46 -}
47 -
48 -```
49 -
50 -### Eval output
51 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-ref.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, useRef, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -/**
6 - * Special case of `infer-effect-deps/nonreactive-dep`.
7 - *
8 - * We know that local `useRef` return values are stable, regardless of
9 - * inferred memoization.
10 - */
11 -function NonReactiveRefInEffect() {
12 - const ref = useRef('initial value');
13 - useEffect(() => print(ref.current), AUTODEPS);
14 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-setState.expect.md deleted
-51
@@ -1,51 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, useState, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -/**
10 - * Special case of `infer-effect-deps/nonreactive-dep`.
11 - *
12 - * We know that local `useRef` return values are stable, regardless of
13 - * inferred memoization.
14 - */
15 -function NonReactiveSetStateInEffect() {
16 - const [_, setState] = useState('initial value');
17 - useEffect(() => print(setState), AUTODEPS);
18 -}
19 -
20 -```
21 -
22 -## Code
23 -
24 -```javascript
25 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
26 -import { useEffect, useState, AUTODEPS } from "react";
27 -import { print } from "shared-runtime";
28 -
29 -/**
30 - * Special case of `infer-effect-deps/nonreactive-dep`.
31 - *
32 - * We know that local `useRef` return values are stable, regardless of
33 - * inferred memoization.
34 - */
35 -function NonReactiveSetStateInEffect() {
36 - const $ = _c(1);
37 - const [, setState] = useState("initial value");
38 - let t0;
39 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
40 - t0 = () => print(setState);
41 - $[0] = t0;
42 - } else {
43 - t0 = $[0];
44 - }
45 - useEffect(t0, []);
46 -}
47 -
48 -```
49 -
50 -### Eval output
51 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/nonreactive-setState.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, useState, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -/**
6 - * Special case of `infer-effect-deps/nonreactive-dep`.
7 - *
8 - * We know that local `useRef` return values are stable, regardless of
9 - * inferred memoization.
10 - */
11 -function NonReactiveSetStateInEffect() {
12 - const [_, setState] = useState('initial value');
13 - useEffect(() => print(setState), AUTODEPS);
14 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/outlined-function.expect.md deleted
-46
@@ -1,46 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -/**
9 - * This compiled output is technically incorrect but this is currently the same
10 - * case as a bailout (an effect that overfires).
11 - *
12 - * To ensure an empty deps array is passed, we need special case
13 - * `InferEffectDependencies` for outlined functions (likely easier) or run it
14 - * before OutlineFunctions
15 - */
16 -function OutlinedFunctionInEffect() {
17 - useEffect(() => print('hello world!'), AUTODEPS);
18 -}
19 -
20 -```
21 -
22 -## Code
23 -
24 -```javascript
25 -// @inferEffectDependencies
26 -import { useEffect, AUTODEPS } from "react";
27 -import { print } from "shared-runtime";
28 -/**
29 - * This compiled output is technically incorrect but this is currently the same
30 - * case as a bailout (an effect that overfires).
31 - *
32 - * To ensure an empty deps array is passed, we need special case
33 - * `InferEffectDependencies` for outlined functions (likely easier) or run it
34 - * before OutlineFunctions
35 - */
36 -function OutlinedFunctionInEffect() {
37 - useEffect(_temp, []);
38 -}
39 -function _temp() {
40 - return print("hello world!");
41 -}
42 -
43 -```
44 -
45 -### Eval output
46 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/outlined-function.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -/**
5 - * This compiled output is technically incorrect but this is currently the same
6 - * case as a bailout (an effect that overfires).
7 - *
8 - * To ensure an empty deps array is passed, we need special case
9 - * `InferEffectDependencies` for outlined functions (likely easier) or run it
10 - * before OutlineFunctions
11 - */
12 -function OutlinedFunctionInEffect() {
13 - useEffect(() => print('hello world!'), AUTODEPS);
14 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/pruned-nonreactive-obj.expect.md deleted
-119
@@ -1,119 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useIdentity, mutate, makeObject} from 'shared-runtime';
7 -import {useEffect, AUTODEPS} from 'react';
8 -
9 -/**
10 - * When a semantically non-reactive value has a pruned scope (i.e. the object
11 - * identity becomes reactive, but the underlying value it represents should be
12 - * constant), the compiler can choose to either
13 - * - add it as a dependency (and rerun the effect)
14 - * - not add it as a dependency
15 - *
16 - * We keep semantically non-reactive values in both memo block and effect
17 - * dependency arrays to avoid versioning invariants e.g. `x !== y.aliasedX`.
18 - * ```js
19 - * function Component() {
20 - * // obj is semantically non-reactive, but its memo scope is pruned due to
21 - * // the interleaving hook call
22 - * const obj = {};
23 - * useHook();
24 - * write(obj);
25 - *
26 - * const ref = useRef();
27 - *
28 - * // this effect needs to be rerun when obj's referential identity changes,
29 - * // because it might alias obj to a useRef / mutable store.
30 - * useEffect(() => ref.current = obj, ???);
31 - *
32 - * // in a custom hook (or child component), the user might expect versioning
33 - * // invariants to hold
34 - * useHook(ref, obj);
35 - * }
36 - *
37 - * // defined elsewhere
38 - * function useHook(someRef, obj) {
39 - * useEffect(
40 - * () => assert(someRef.current === obj),
41 - * [someRef, obj]
42 - * );
43 - * }
44 - * ```
45 - */
46 -function PrunedNonReactive() {
47 - const obj = makeObject();
48 - useIdentity(null);
49 - mutate(obj);
50 -
51 - useEffect(() => print(obj.value), AUTODEPS);
52 -}
53 -
54 -```
55 -
56 -## Code
57 -
58 -```javascript
59 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
60 -import { useIdentity, mutate, makeObject } from "shared-runtime";
61 -import { useEffect, AUTODEPS } from "react";
62 -
63 -/**
64 - * When a semantically non-reactive value has a pruned scope (i.e. the object
65 - * identity becomes reactive, but the underlying value it represents should be
66 - * constant), the compiler can choose to either
67 - * - add it as a dependency (and rerun the effect)
68 - * - not add it as a dependency
69 - *
70 - * We keep semantically non-reactive values in both memo block and effect
71 - * dependency arrays to avoid versioning invariants e.g. `x !== y.aliasedX`.
72 - * ```js
73 - * function Component() {
74 - * // obj is semantically non-reactive, but its memo scope is pruned due to
75 - * // the interleaving hook call
76 - * const obj = {};
77 - * useHook();
78 - * write(obj);
79 - *
80 - * const ref = useRef();
81 - *
82 - * // this effect needs to be rerun when obj's referential identity changes,
83 - * // because it might alias obj to a useRef / mutable store.
84 - * useEffect(() => ref.current = obj, ???);
85 - *
86 - * // in a custom hook (or child component), the user might expect versioning
87 - * // invariants to hold
88 - * useHook(ref, obj);
89 - * }
90 - *
91 - * // defined elsewhere
92 - * function useHook(someRef, obj) {
93 - * useEffect(
94 - * () => assert(someRef.current === obj),
95 - * [someRef, obj]
96 - * );
97 - * }
98 - * ```
99 - */
100 -function PrunedNonReactive() {
101 - const $ = _c(2);
102 - const obj = makeObject();
103 - useIdentity(null);
104 - mutate(obj);
105 - let t0;
106 - if ($[0] !== obj.value) {
107 - t0 = () => print(obj.value);
108 - $[0] = obj.value;
109 - $[1] = t0;
110 - } else {
111 - t0 = $[1];
112 - }
113 - useEffect(t0, [obj.value]);
114 -}
115 -
116 -```
117 -
118 -### Eval output
119 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/pruned-nonreactive-obj.js deleted
-48
@@ -1,48 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useIdentity, mutate, makeObject} from 'shared-runtime';
3 -import {useEffect, AUTODEPS} from 'react';
4 -
5 -/**
6 - * When a semantically non-reactive value has a pruned scope (i.e. the object
7 - * identity becomes reactive, but the underlying value it represents should be
8 - * constant), the compiler can choose to either
9 - * - add it as a dependency (and rerun the effect)
10 - * - not add it as a dependency
11 - *
12 - * We keep semantically non-reactive values in both memo block and effect
13 - * dependency arrays to avoid versioning invariants e.g. `x !== y.aliasedX`.
14 - * ```js
15 - * function Component() {
16 - * // obj is semantically non-reactive, but its memo scope is pruned due to
17 - * // the interleaving hook call
18 - * const obj = {};
19 - * useHook();
20 - * write(obj);
21 - *
22 - * const ref = useRef();
23 - *
24 - * // this effect needs to be rerun when obj's referential identity changes,
25 - * // because it might alias obj to a useRef / mutable store.
26 - * useEffect(() => ref.current = obj, ???);
27 - *
28 - * // in a custom hook (or child component), the user might expect versioning
29 - * // invariants to hold
30 - * useHook(ref, obj);
31 - * }
32 - *
33 - * // defined elsewhere
34 - * function useHook(someRef, obj) {
35 - * useEffect(
36 - * () => assert(someRef.current === obj),
37 - * [someRef, obj]
38 - * );
39 - * }
40 - * ```
41 - */
42 -function PrunedNonReactive() {
43 - const obj = makeObject();
44 - useIdentity(null);
45 - mutate(obj);
46 -
47 - useEffect(() => print(obj.value), AUTODEPS);
48 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-memberexpr-merge.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function ReactiveMemberExprMerge({propVal}) {
10 - const obj = {a: {b: propVal}};
11 - useEffect(() => print(obj.a, obj.a.b), AUTODEPS);
12 -}
13 -
14 -```
15 -
16 -## Code
17 -
18 -```javascript
19 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
20 -import { useEffect, AUTODEPS } from "react";
21 -import { print } from "shared-runtime";
22 -
23 -function ReactiveMemberExprMerge(t0) {
24 - const $ = _c(4);
25 - const { propVal } = t0;
26 - let t1;
27 - if ($[0] !== propVal) {
28 - t1 = { a: { b: propVal } };
29 - $[0] = propVal;
30 - $[1] = t1;
31 - } else {
32 - t1 = $[1];
33 - }
34 - const obj = t1;
35 - let t2;
36 - if ($[2] !== obj.a) {
37 - t2 = () => print(obj.a, obj.a.b);
38 - $[2] = obj.a;
39 - $[3] = t2;
40 - } else {
41 - t2 = $[3];
42 - }
43 - useEffect(t2, [obj.a]);
44 -}
45 -
46 -```
47 -
48 -### Eval output
49 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-memberexpr-merge.js deleted
-8
@@ -1,8 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function ReactiveMemberExprMerge({propVal}) {
6 - const obj = {a: {b: propVal}};
7 - useEffect(() => print(obj.a, obj.a.b), AUTODEPS);
8 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-memberexpr.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function ReactiveMemberExpr({propVal}) {
10 - const obj = {a: {b: propVal}};
11 - useEffect(() => print(obj.a.b), AUTODEPS);
12 -}
13 -
14 -```
15 -
16 -## Code
17 -
18 -```javascript
19 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
20 -import { useEffect, AUTODEPS } from "react";
21 -import { print } from "shared-runtime";
22 -
23 -function ReactiveMemberExpr(t0) {
24 - const $ = _c(4);
25 - const { propVal } = t0;
26 - let t1;
27 - if ($[0] !== propVal) {
28 - t1 = { a: { b: propVal } };
29 - $[0] = propVal;
30 - $[1] = t1;
31 - } else {
32 - t1 = $[1];
33 - }
34 - const obj = t1;
35 - let t2;
36 - if ($[2] !== obj.a.b) {
37 - t2 = () => print(obj.a.b);
38 - $[2] = obj.a.b;
39 - $[3] = t2;
40 - } else {
41 - t2 = $[3];
42 - }
43 - useEffect(t2, [obj.a.b]);
44 -}
45 -
46 -```
47 -
48 -### Eval output
49 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-memberexpr.js deleted
-8
@@ -1,8 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function ReactiveMemberExpr({propVal}) {
6 - const obj = {a: {b: propVal}};
7 - useEffect(() => print(obj.a.b), AUTODEPS);
8 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-optional-chain-complex.expect.md deleted
-100
@@ -1,100 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print, shallowCopy} from 'shared-runtime';
8 -
9 -function ReactiveMemberExpr({cond, propVal}) {
10 - const obj = {a: cond ? {b: propVal} : null, c: null};
11 - const other = shallowCopy({a: {b: {c: {d: {e: {f: propVal + 1}}}}}});
12 - const primitive = shallowCopy(propVal);
13 - useEffect(
14 - () => print(obj.a?.b, other?.a?.b?.c?.d?.e.f, primitive.a?.b.c?.d?.e.f),
15 - AUTODEPS
16 - );
17 -}
18 -
19 -export const FIXTURE_ENTRYPOINT = {
20 - fn: ReactiveMemberExpr,
21 - params: [{cond: true, propVal: 1}],
22 -};
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
30 -import { useEffect, AUTODEPS } from "react";
31 -import { print, shallowCopy } from "shared-runtime";
32 -
33 -function ReactiveMemberExpr(t0) {
34 - const $ = _c(13);
35 - const { cond, propVal } = t0;
36 - let t1;
37 - if ($[0] !== cond || $[1] !== propVal) {
38 - t1 = cond ? { b: propVal } : null;
39 - $[0] = cond;
40 - $[1] = propVal;
41 - $[2] = t1;
42 - } else {
43 - t1 = $[2];
44 - }
45 - let t2;
46 - if ($[3] !== t1) {
47 - t2 = { a: t1, c: null };
48 - $[3] = t1;
49 - $[4] = t2;
50 - } else {
51 - t2 = $[4];
52 - }
53 - const obj = t2;
54 - const t3 = propVal + 1;
55 - let t4;
56 - if ($[5] !== t3) {
57 - t4 = shallowCopy({ a: { b: { c: { d: { e: { f: t3 } } } } } });
58 - $[5] = t3;
59 - $[6] = t4;
60 - } else {
61 - t4 = $[6];
62 - }
63 - const other = t4;
64 - let t5;
65 - if ($[7] !== propVal) {
66 - t5 = shallowCopy(propVal);
67 - $[7] = propVal;
68 - $[8] = t5;
69 - } else {
70 - t5 = $[8];
71 - }
72 - const primitive = t5;
73 - let t6;
74 - if (
75 - $[9] !== obj.a?.b ||
76 - $[10] !== other?.a?.b?.c?.d?.e.f ||
77 - $[11] !== primitive.a?.b.c?.d?.e.f
78 - ) {
79 - t6 = () =>
80 - print(obj.a?.b, other?.a?.b?.c?.d?.e.f, primitive.a?.b.c?.d?.e.f);
81 - $[9] = obj.a?.b;
82 - $[10] = other?.a?.b?.c?.d?.e.f;
83 - $[11] = primitive.a?.b.c?.d?.e.f;
84 - $[12] = t6;
85 - } else {
86 - t6 = $[12];
87 - }
88 - useEffect(t6, [obj.a?.b, other?.a?.b?.c?.d?.e.f, primitive.a?.b.c?.d?.e.f]);
89 -}
90 -
91 -export const FIXTURE_ENTRYPOINT = {
92 - fn: ReactiveMemberExpr,
93 - params: [{ cond: true, propVal: 1 }],
94 -};
95 -
96 -```
97 -
98 -### Eval output
99 -(kind: ok)
100 -logs: [1,2,undefined]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-optional-chain-complex.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print, shallowCopy} from 'shared-runtime';
4 -
5 -function ReactiveMemberExpr({cond, propVal}) {
6 - const obj = {a: cond ? {b: propVal} : null, c: null};
7 - const other = shallowCopy({a: {b: {c: {d: {e: {f: propVal + 1}}}}}});
8 - const primitive = shallowCopy(propVal);
9 - useEffect(
10 - () => print(obj.a?.b, other?.a?.b?.c?.d?.e.f, primitive.a?.b.c?.d?.e.f),
11 - AUTODEPS
12 - );
13 -}
14 -
15 -export const FIXTURE_ENTRYPOINT = {
16 - fn: ReactiveMemberExpr,
17 - params: [{cond: true, propVal: 1}],
18 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-optional-chain.expect.md deleted
-79
@@ -1,79 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function ReactiveMemberExpr({cond, propVal}) {
10 - const obj = {a: cond ? {b: propVal} : null, c: null};
11 - useEffect(() => print(obj.a?.b), AUTODEPS);
12 - useEffect(() => print(obj.c?.d), AUTODEPS);
13 -}
14 -
15 -export const FIXTURE_ENTRYPOINT = {
16 - fn: ReactiveMemberExpr,
17 - params: [{cond: true, propVal: 1}],
18 -};
19 -
20 -```
21 -
22 -## Code
23 -
24 -```javascript
25 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
26 -import { useEffect, AUTODEPS } from "react";
27 -import { print } from "shared-runtime";
28 -
29 -function ReactiveMemberExpr(t0) {
30 - const $ = _c(9);
31 - const { cond, propVal } = t0;
32 - let t1;
33 - if ($[0] !== cond || $[1] !== propVal) {
34 - t1 = cond ? { b: propVal } : null;
35 - $[0] = cond;
36 - $[1] = propVal;
37 - $[2] = t1;
38 - } else {
39 - t1 = $[2];
40 - }
41 - let t2;
42 - if ($[3] !== t1) {
43 - t2 = { a: t1, c: null };
44 - $[3] = t1;
45 - $[4] = t2;
46 - } else {
47 - t2 = $[4];
48 - }
49 - const obj = t2;
50 - let t3;
51 - if ($[5] !== obj.a?.b) {
52 - t3 = () => print(obj.a?.b);
53 - $[5] = obj.a?.b;
54 - $[6] = t3;
55 - } else {
56 - t3 = $[6];
57 - }
58 - useEffect(t3, [obj.a?.b]);
59 - let t4;
60 - if ($[7] !== obj.c?.d) {
61 - t4 = () => print(obj.c?.d);
62 - $[7] = obj.c?.d;
63 - $[8] = t4;
64 - } else {
65 - t4 = $[8];
66 - }
67 - useEffect(t4, [obj.c?.d]);
68 -}
69 -
70 -export const FIXTURE_ENTRYPOINT = {
71 - fn: ReactiveMemberExpr,
72 - params: [{ cond: true, propVal: 1 }],
73 -};
74 -
75 -```
76 -
77 -### Eval output
78 -(kind: ok)
79 -logs: [1,undefined]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-optional-chain.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function ReactiveMemberExpr({cond, propVal}) {
6 - const obj = {a: cond ? {b: propVal} : null, c: null};
7 - useEffect(() => print(obj.a?.b), AUTODEPS);
8 - useEffect(() => print(obj.c?.d), AUTODEPS);
9 -}
10 -
11 -export const FIXTURE_ENTRYPOINT = {
12 - fn: ReactiveMemberExpr,
13 - params: [{cond: true, propVal: 1}],
14 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-ref-ternary.expect.md deleted
-69
@@ -1,69 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useRef, useEffect, AUTODEPS} from 'react';
7 -import {print, mutate} from 'shared-runtime';
8 -
9 -function Component({cond}) {
10 - const arr = useRef([]);
11 - const other = useRef([]);
12 - // Although arr and other are both stable, derived is not
13 - const derived = cond ? arr : other;
14 - useEffect(() => {
15 - mutate(derived.current);
16 - print(derived.current);
17 - }, AUTODEPS);
18 - return arr;
19 -}
20 -
21 -```
22 -
23 -## Code
24 -
25 -```javascript
26 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
27 -import { useRef, useEffect, AUTODEPS } from "react";
28 -import { print, mutate } from "shared-runtime";
29 -
30 -function Component(t0) {
31 - const $ = _c(4);
32 - const { cond } = t0;
33 - let t1;
34 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
35 - t1 = [];
36 - $[0] = t1;
37 - } else {
38 - t1 = $[0];
39 - }
40 - const arr = useRef(t1);
41 - let t2;
42 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
43 - t2 = [];
44 - $[1] = t2;
45 - } else {
46 - t2 = $[1];
47 - }
48 - const other = useRef(t2);
49 -
50 - const derived = cond ? arr : other;
51 - let t3;
52 - if ($[2] !== derived) {
53 - t3 = () => {
54 - mutate(derived.current);
55 - print(derived.current);
56 - };
57 - $[2] = derived;
58 - $[3] = t3;
59 - } else {
60 - t3 = $[3];
61 - }
62 - useEffect(t3, [derived]);
63 - return arr;
64 -}
65 -
66 -```
67 -
68 -### Eval output
69 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-ref-ternary.js deleted
-15
@@ -1,15 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useRef, useEffect, AUTODEPS} from 'react';
3 -import {print, mutate} from 'shared-runtime';
4 -
5 -function Component({cond}) {
6 - const arr = useRef([]);
7 - const other = useRef([]);
8 - // Although arr and other are both stable, derived is not
9 - const derived = cond ? arr : other;
10 - useEffect(() => {
11 - mutate(derived.current);
12 - print(derived.current);
13 - }, AUTODEPS);
14 - return arr;
15 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-ref.expect.md deleted
-66
@@ -1,66 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, useRef, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -/*
10 - * Ref types are not enough to determine to omit from deps. Must also take reactivity into account.
11 - */
12 -function ReactiveRefInEffect(props) {
13 - const ref1 = useRef('initial value');
14 - const ref2 = useRef('initial value');
15 - let ref;
16 - if (props.foo) {
17 - ref = ref1;
18 - } else {
19 - ref = ref2;
20 - }
21 - useEffect(() => print(ref), AUTODEPS);
22 -}
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
30 -import { useEffect, useRef, AUTODEPS } from "react";
31 -import { print } from "shared-runtime";
32 -
33 -/*
34 - * Ref types are not enough to determine to omit from deps. Must also take reactivity into account.
35 - */
36 -function ReactiveRefInEffect(props) {
37 - const $ = _c(4);
38 - const ref1 = useRef("initial value");
39 - const ref2 = useRef("initial value");
40 - let ref;
41 - if ($[0] !== props.foo) {
42 - if (props.foo) {
43 - ref = ref1;
44 - } else {
45 - ref = ref2;
46 - }
47 - $[0] = props.foo;
48 - $[1] = ref;
49 - } else {
50 - ref = $[1];
51 - }
52 - let t0;
53 - if ($[2] !== ref) {
54 - t0 = () => print(ref);
55 - $[2] = ref;
56 - $[3] = t0;
57 - } else {
58 - t0 = $[3];
59 - }
60 - useEffect(t0, [ref]);
61 -}
62 -
63 -```
64 -
65 -### Eval output
66 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-ref.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, useRef, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -/*
6 - * Ref types are not enough to determine to omit from deps. Must also take reactivity into account.
7 - */
8 -function ReactiveRefInEffect(props) {
9 - const ref1 = useRef('initial value');
10 - const ref2 = useRef('initial value');
11 - let ref;
12 - if (props.foo) {
13 - ref = ref1;
14 - } else {
15 - ref = ref2;
16 - }
17 - useEffect(() => print(ref), AUTODEPS);
18 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-setState.expect.md deleted
-66
@@ -1,66 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, useState, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -/*
10 - * setState types are not enough to determine to omit from deps. Must also take reactivity into account.
11 - */
12 -function ReactiveRefInEffect(props) {
13 - const [_state1, setState1] = useRef('initial value');
14 - const [_state2, setState2] = useRef('initial value');
15 - let setState;
16 - if (props.foo) {
17 - setState = setState1;
18 - } else {
19 - setState = setState2;
20 - }
21 - useEffect(() => print(setState), AUTODEPS);
22 -}
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
30 -import { useEffect, useState, AUTODEPS } from "react";
31 -import { print } from "shared-runtime";
32 -
33 -/*
34 - * setState types are not enough to determine to omit from deps. Must also take reactivity into account.
35 - */
36 -function ReactiveRefInEffect(props) {
37 - const $ = _c(4);
38 - const [, setState1] = useRef("initial value");
39 - const [, setState2] = useRef("initial value");
40 - let setState;
41 - if ($[0] !== props.foo) {
42 - if (props.foo) {
43 - setState = setState1;
44 - } else {
45 - setState = setState2;
46 - }
47 - $[0] = props.foo;
48 - $[1] = setState;
49 - } else {
50 - setState = $[1];
51 - }
52 - let t0;
53 - if ($[2] !== setState) {
54 - t0 = () => print(setState);
55 - $[2] = setState;
56 - $[3] = t0;
57 - } else {
58 - t0 = $[3];
59 - }
60 - useEffect(t0, [setState]);
61 -}
62 -
63 -```
64 -
65 -### Eval output
66 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-setState.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, useState, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -/*
6 - * setState types are not enough to determine to omit from deps. Must also take reactivity into account.
7 - */
8 -function ReactiveRefInEffect(props) {
9 - const [_state1, setState1] = useRef('initial value');
10 - const [_state2, setState2] = useRef('initial value');
11 - let setState;
12 - if (props.foo) {
13 - setState = setState1;
14 - } else {
15 - setState = setState2;
16 - }
17 - useEffect(() => print(setState), AUTODEPS);
18 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-variable.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function ReactiveVariable({propVal}) {
10 - const arr = [propVal];
11 - useEffect(() => print(arr), AUTODEPS);
12 -}
13 -
14 -```
15 -
16 -## Code
17 -
18 -```javascript
19 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
20 -import { useEffect, AUTODEPS } from "react";
21 -import { print } from "shared-runtime";
22 -
23 -function ReactiveVariable(t0) {
24 - const $ = _c(4);
25 - const { propVal } = t0;
26 - let t1;
27 - if ($[0] !== propVal) {
28 - t1 = [propVal];
29 - $[0] = propVal;
30 - $[1] = t1;
31 - } else {
32 - t1 = $[1];
33 - }
34 - const arr = t1;
35 - let t2;
36 - if ($[2] !== arr) {
37 - t2 = () => print(arr);
38 - $[2] = arr;
39 - $[3] = t2;
40 - } else {
41 - t2 = $[3];
42 - }
43 - useEffect(t2, [arr]);
44 -}
45 -
46 -```
47 -
48 -### Eval output
49 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-variable.js deleted
-8
@@ -1,8 +0,0 @@
1 -// @inferEffectDependencies
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function ReactiveVariable({propVal}) {
6 - const arr = [propVal];
7 - useEffect(() => print(arr), AUTODEPS);
8 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation--lint.expect.md deleted
-48
@@ -1,48 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
6 -import {print} from 'shared-runtime';
7 -import useEffectWrapper from 'useEffectWrapper';
8 -import {AUTODEPS} from 'react';
9 -
10 -function Foo({propVal}) {
11 - const arr = [propVal];
12 - useEffectWrapper(() => print(arr), AUTODEPS);
13 -
14 - const arr2 = [];
15 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
16 - arr2.push(2);
17 - return {arr, arr2};
18 -}
19 -
20 -export const FIXTURE_ENTRYPOINT = {
21 - fn: Foo,
22 - params: [{propVal: 1}],
23 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
24 -};
25 -
26 -```
27 -
28 -
29 -## Error
30 -
31 -```
32 -Found 1 error:
33 -
34 -Error: Cannot infer dependencies of this effect. This will break your build!
35 -
36 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
37 -
38 -error.infer-effect-deps-with-rule-violation--lint.ts:8:2
39 - 6 | function Foo({propVal}) {
40 - 7 | const arr = [propVal];
41 -> 8 | useEffectWrapper(() => print(arr), AUTODEPS);
42 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
43 - 9 |
44 - 10 | const arr2 = [];
45 - 11 | useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
46 -```
47 -
48 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation--lint.js deleted
-20
@@ -1,20 +0,0 @@
1 -// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
2 -import {print} from 'shared-runtime';
3 -import useEffectWrapper from 'useEffectWrapper';
4 -import {AUTODEPS} from 'react';
5 -
6 -function Foo({propVal}) {
7 - const arr = [propVal];
8 - useEffectWrapper(() => print(arr), AUTODEPS);
9 -
10 - const arr2 = [];
11 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
12 - arr2.push(2);
13 - return {arr, arr2};
14 -}
15 -
16 -export const FIXTURE_ENTRYPOINT = {
17 - fn: Foo,
18 - params: [{propVal: 1}],
19 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
20 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation-use-memo-opt-in--lint.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
6 -import {print} from 'shared-runtime';
7 -import useEffectWrapper from 'useEffectWrapper';
8 -import {AUTODEPS} from 'react';
9 -
10 -function Foo({propVal}) {
11 - 'use memo';
12 - const arr = [propVal];
13 - useEffectWrapper(() => print(arr), AUTODEPS);
14 -
15 - const arr2 = [];
16 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
17 - arr2.push(2);
18 - return {arr, arr2};
19 -}
20 -
21 -export const FIXTURE_ENTRYPOINT = {
22 - fn: Foo,
23 - params: [{propVal: 1}],
24 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
25 -};
26 -
27 -```
28 -
29 -
30 -## Error
31 -
32 -```
33 -Found 1 error:
34 -
35 -Error: Cannot infer dependencies of this effect. This will break your build!
36 -
37 -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
38 -
39 -error.infer-effect-deps-with-rule-violation-use-memo-opt-in--lint.ts:9:2
40 - 7 | 'use memo';
41 - 8 | const arr = [propVal];
42 -> 9 | useEffectWrapper(() => print(arr), AUTODEPS);
43 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
44 - 10 |
45 - 11 | const arr2 = [];
46 - 12 | useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
47 -```
48 -
49 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation-use-memo-opt-in--lint.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
2 -import {print} from 'shared-runtime';
3 -import useEffectWrapper from 'useEffectWrapper';
4 -import {AUTODEPS} from 'react';
5 -
6 -function Foo({propVal}) {
7 - 'use memo';
8 - const arr = [propVal];
9 - useEffectWrapper(() => print(arr), AUTODEPS);
10 -
11 - const arr2 = [];
12 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
13 - arr2.push(2);
14 - return {arr, arr2};
15 -}
16 -
17 -export const FIXTURE_ENTRYPOINT = {
18 - fn: Foo,
19 - params: [{propVal: 1}],
20 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
21 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation--compile.expect.md deleted
-58
@@ -1,58 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import {print} from 'shared-runtime';
7 -import useEffectWrapper from 'useEffectWrapper';
8 -import {AUTODEPS} from 'react';
9 -
10 -function Foo({propVal}) {
11 - const arr = [propVal];
12 - useEffectWrapper(() => print(arr), AUTODEPS);
13 -
14 - const arr2 = [];
15 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
16 - arr2.push(2);
17 - return {arr, arr2};
18 -}
19 -
20 -export const FIXTURE_ENTRYPOINT = {
21 - fn: Foo,
22 - params: [{propVal: 1}],
23 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
24 -};
25 -
26 -```
27 -
28 -## Code
29 -
30 -```javascript
31 -// @inferEffectDependencies @panicThreshold:"none"
32 -import { print } from "shared-runtime";
33 -import useEffectWrapper from "useEffectWrapper";
34 -import { AUTODEPS } from "react";
35 -
36 -function Foo(t0) {
37 - const { propVal } = t0;
38 - const arr = [propVal];
39 - useEffectWrapper(() => print(arr), [arr]);
40 -
41 - const arr2 = [];
42 - useEffectWrapper(() => arr2.push(propVal), [arr2, propVal]);
43 - arr2.push(2);
44 - return { arr, arr2 };
45 -}
46 -
47 -export const FIXTURE_ENTRYPOINT = {
48 - fn: Foo,
49 - params: [{ propVal: 1 }],
50 - sequentialRenders: [{ propVal: 1 }, { propVal: 2 }],
51 -};
52 -
53 -```
54 -
55 -### Eval output
56 -(kind: ok) {"arr":[1],"arr2":[2]}
57 -{"arr":[2],"arr2":[2]}
58 -logs: [[ 1 ],[ 2 ]]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation--compile.js deleted
-20
@@ -1,20 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import {print} from 'shared-runtime';
3 -import useEffectWrapper from 'useEffectWrapper';
4 -import {AUTODEPS} from 'react';
5 -
6 -function Foo({propVal}) {
7 - const arr = [propVal];
8 - useEffectWrapper(() => print(arr), AUTODEPS);
9 -
10 - const arr2 = [];
11 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
12 - arr2.push(2);
13 - return {arr, arr2};
14 -}
15 -
16 -export const FIXTURE_ENTRYPOINT = {
17 - fn: Foo,
18 - params: [{propVal: 1}],
19 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
20 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation-use-memo-opt-in--compile.expect.md deleted
-61
@@ -1,61 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import {print} from 'shared-runtime';
7 -import useEffectWrapper from 'useEffectWrapper';
8 -import {AUTODEPS} from 'react';
9 -
10 -function Foo({propVal}) {
11 - 'use memo';
12 - const arr = [propVal];
13 - useEffectWrapper(() => print(arr), AUTODEPS);
14 -
15 - const arr2 = [];
16 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
17 - arr2.push(2);
18 - return {arr, arr2};
19 -}
20 -
21 -export const FIXTURE_ENTRYPOINT = {
22 - fn: Foo,
23 - params: [{propVal: 1}],
24 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
25 -};
26 -
27 -```
28 -
29 -## Code
30 -
31 -```javascript
32 -// @inferEffectDependencies @panicThreshold:"none"
33 -import { print } from "shared-runtime";
34 -import useEffectWrapper from "useEffectWrapper";
35 -import { AUTODEPS } from "react";
36 -
37 -function Foo(t0) {
38 - "use memo";
39 - const { propVal } = t0;
40 -
41 - const arr = [propVal];
42 - useEffectWrapper(() => print(arr), [arr]);
43 -
44 - const arr2 = [];
45 - useEffectWrapper(() => arr2.push(propVal), [arr2, propVal]);
46 - arr2.push(2);
47 - return { arr, arr2 };
48 -}
49 -
50 -export const FIXTURE_ENTRYPOINT = {
51 - fn: Foo,
52 - params: [{ propVal: 1 }],
53 - sequentialRenders: [{ propVal: 1 }, { propVal: 2 }],
54 -};
55 -
56 -```
57 -
58 -### Eval output
59 -(kind: ok) {"arr":[1],"arr2":[2]}
60 -{"arr":[2],"arr2":[2]}
61 -logs: [[ 1 ],[ 2 ]]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation-use-memo-opt-in--compile.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import {print} from 'shared-runtime';
3 -import useEffectWrapper from 'useEffectWrapper';
4 -import {AUTODEPS} from 'react';
5 -
6 -function Foo({propVal}) {
7 - 'use memo';
8 - const arr = [propVal];
9 - useEffectWrapper(() => print(arr), AUTODEPS);
10 -
11 - const arr2 = [];
12 - useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
13 - arr2.push(2);
14 - return {arr, arr2};
15 -}
16 -
17 -export const FIXTURE_ENTRYPOINT = {
18 - fn: Foo,
19 - params: [{propVal: 1}],
20 - sequentialRenders: [{propVal: 1}, {propVal: 2}],
21 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/lint-repro.expect.md deleted
-33
@@ -1,33 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @outputMode:"lint"
6 -import {print} from 'shared-runtime';
7 -import useEffectWrapper from 'useEffectWrapper';
8 -import {AUTODEPS} from 'react';
9 -
10 -function ReactiveVariable({propVal}) {
11 - const arr = [propVal];
12 - useEffectWrapper(() => print(arr), AUTODEPS);
13 -}
14 -
15 -```
16 -
17 -## Code
18 -
19 -```javascript
20 -// @inferEffectDependencies @outputMode:"lint"
21 -import { print } from "shared-runtime";
22 -import useEffectWrapper from "useEffectWrapper";
23 -import { AUTODEPS } from "react";
24 -
25 -function ReactiveVariable({ propVal }) {
26 - const arr = [propVal];
27 - useEffectWrapper(() => print(arr), AUTODEPS);
28 -}
29 -
30 -```
31 -
32 -### Eval output
33 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/lint-repro.js deleted
-9
@@ -1,9 +0,0 @@
1 -// @inferEffectDependencies @outputMode:"lint"
2 -import {print} from 'shared-runtime';
3 -import useEffectWrapper from 'useEffectWrapper';
4 -import {AUTODEPS} from 'react';
5 -
6 -function ReactiveVariable({propVal}) {
7 - const arr = [propVal];
8 - useEffectWrapper(() => print(arr), AUTODEPS);
9 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md deleted
-478
@@ -1,478 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inlineJsxTransform
6 -
7 -function Parent({children, a: _a, b: _b, c: _c, ref}) {
8 - return <div ref={ref}>{children}</div>;
9 -}
10 -
11 -function Child({children}) {
12 - return <>{children}</>;
13 -}
14 -
15 -function GrandChild({className}) {
16 - return (
17 - <span className={className}>
18 - <React.Fragment key="fragmentKey">Hello world</React.Fragment>
19 - </span>
20 - );
21 -}
22 -
23 -function ParentAndRefAndKey(props) {
24 - const testRef = useRef();
25 - return <Parent a="a" b={{b: 'b'}} c={C} key="testKey" ref={testRef} />;
26 -}
27 -
28 -function ParentAndChildren(props) {
29 - const render = () => {
30 - return <div key="d">{props.foo}</div>;
31 - };
32 - return (
33 - <Parent>
34 - <Child key="a" {...props} />
35 - <Child key="b">
36 - <GrandChild key="c" className={props.foo} {...props} />
37 - {render()}
38 - </Child>
39 - </Parent>
40 - );
41 -}
42 -
43 -const propsToSpread = {a: 'a', b: 'b', c: 'c'};
44 -function PropsSpread() {
45 - return (
46 - <>
47 - <Test key="a" {...propsToSpread} />
48 - <Test key="b" {...propsToSpread} a="z" />
49 - </>
50 - );
51 -}
52 -
53 -function ConditionalJsx({shouldWrap}) {
54 - let content = <div>Hello</div>;
55 -
56 - if (shouldWrap) {
57 - content = <Parent>{content}</Parent>;
58 - }
59 -
60 - return content;
61 -}
62 -
63 -function ComponentWithSpreadPropsAndRef({ref, ...other}) {
64 - return <Foo ref={ref} {...other} />;
65 -}
66 -
67 -// TODO: Support value blocks
68 -function TernaryJsx({cond}) {
69 - return cond ? <div /> : null;
70 -}
71 -
72 -global.DEV = true;
73 -export const FIXTURE_ENTRYPOINT = {
74 - fn: ParentAndChildren,
75 - params: [{foo: 'abc'}],
76 -};
77 -
78 -```
79 -
80 -## Code
81 -
82 -```javascript
83 -import { c as _c2 } from "react/compiler-runtime"; // @inlineJsxTransform
84 -
85 -function Parent(t0) {
86 - const $ = _c2(3);
87 - const { children, ref } = t0;
88 - let t1;
89 - if ($[0] !== children || $[1] !== ref) {
90 - if (DEV) {
91 - t1 = <div ref={ref}>{children}</div>;
92 - } else {
93 - t1 = {
94 - $$typeof: Symbol.for("react.transitional.element"),
95 - type: "div",
96 - ref: ref,
97 - key: null,
98 - props: { ref: ref, children: children },
99 - };
100 - }
101 - $[0] = children;
102 - $[1] = ref;
103 - $[2] = t1;
104 - } else {
105 - t1 = $[2];
106 - }
107 - return t1;
108 -}
109 -
110 -function Child(t0) {
111 - const $ = _c2(2);
112 - const { children } = t0;
113 - let t1;
114 - if ($[0] !== children) {
115 - if (DEV) {
116 - t1 = <>{children}</>;
117 - } else {
118 - t1 = {
119 - $$typeof: Symbol.for("react.transitional.element"),
120 - type: Symbol.for("react.fragment"),
121 - ref: null,
122 - key: null,
123 - props: { children: children },
124 - };
125 - }
126 - $[0] = children;
127 - $[1] = t1;
128 - } else {
129 - t1 = $[1];
130 - }
131 - return t1;
132 -}
133 -
134 -function GrandChild(t0) {
135 - const $ = _c2(3);
136 - const { className } = t0;
137 - let t1;
138 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
139 - if (DEV) {
140 - t1 = <React.Fragment key="fragmentKey">Hello world</React.Fragment>;
141 - } else {
142 - t1 = {
143 - $$typeof: Symbol.for("react.transitional.element"),
144 - type: React.Fragment,
145 - ref: null,
146 - key: "fragmentKey",
147 - props: { children: "Hello world" },
148 - };
149 - }
150 - $[0] = t1;
151 - } else {
152 - t1 = $[0];
153 - }
154 - let t2;
155 - if ($[1] !== className) {
156 - if (DEV) {
157 - t2 = <span className={className}>{t1}</span>;
158 - } else {
159 - t2 = {
160 - $$typeof: Symbol.for("react.transitional.element"),
161 - type: "span",
162 - ref: null,
163 - key: null,
164 - props: { className: className, children: t1 },
165 - };
166 - }
167 - $[1] = className;
168 - $[2] = t2;
169 - } else {
170 - t2 = $[2];
171 - }
172 - return t2;
173 -}
174 -
175 -function ParentAndRefAndKey(props) {
176 - const $ = _c2(1);
177 - const testRef = useRef();
178 - let t0;
179 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
180 - if (DEV) {
181 - t0 = <Parent a="a" b={{ b: "b" }} c={C} key="testKey" ref={testRef} />;
182 - } else {
183 - t0 = {
184 - $$typeof: Symbol.for("react.transitional.element"),
185 - type: Parent,
186 - ref: testRef,
187 - key: "testKey",
188 - props: { a: "a", b: { b: "b" }, c: C, ref: testRef },
189 - };
190 - }
191 - $[0] = t0;
192 - } else {
193 - t0 = $[0];
194 - }
195 - return t0;
196 -}
197 -
198 -function ParentAndChildren(props) {
199 - const $ = _c2(14);
200 - let t0;
201 - if ($[0] !== props.foo) {
202 - t0 = () => {
203 - let t1;
204 - if (DEV) {
205 - t1 = <div key="d">{props.foo}</div>;
206 - } else {
207 - t1 = {
208 - $$typeof: Symbol.for("react.transitional.element"),
209 - type: "div",
210 - ref: null,
211 - key: "d",
212 - props: { children: props.foo },
213 - };
214 - }
215 - return t1;
216 - };
217 - $[0] = props.foo;
218 - $[1] = t0;
219 - } else {
220 - t0 = $[1];
221 - }
222 - const render = t0;
223 - let t1;
224 - if ($[2] !== props) {
225 - if (DEV) {
226 - t1 = <Child key="a" {...props} />;
227 - } else {
228 - t1 = {
229 - $$typeof: Symbol.for("react.transitional.element"),
230 - type: Child,
231 - ref: null,
232 - key: "a",
233 - props: props,
234 - };
235 - }
236 - $[2] = props;
237 - $[3] = t1;
238 - } else {
239 - t1 = $[3];
240 - }
241 -
242 - const t2 = props.foo;
243 - let t3;
244 - if ($[4] !== props) {
245 - if (DEV) {
246 - t3 = <GrandChild key="c" className={t2} {...props} />;
247 - } else {
248 - t3 = {
249 - $$typeof: Symbol.for("react.transitional.element"),
250 - type: GrandChild,
251 - ref: null,
252 - key: "c",
253 - props: { className: t2, ...props },
254 - };
255 - }
256 - $[4] = props;
257 - $[5] = t3;
258 - } else {
259 - t3 = $[5];
260 - }
261 - let t4;
262 - if ($[6] !== render) {
263 - t4 = render();
264 - $[6] = render;
265 - $[7] = t4;
266 - } else {
267 - t4 = $[7];
268 - }
269 - let t5;
270 - if ($[8] !== t3 || $[9] !== t4) {
271 - if (DEV) {
272 - t5 = (
273 - <Child key="b">
274 - {t3}
275 - {t4}
276 - </Child>
277 - );
278 - } else {
279 - t5 = {
280 - $$typeof: Symbol.for("react.transitional.element"),
281 - type: Child,
282 - ref: null,
283 - key: "b",
284 - props: { children: [t3, t4] },
285 - };
286 - }
287 - $[8] = t3;
288 - $[9] = t4;
289 - $[10] = t5;
290 - } else {
291 - t5 = $[10];
292 - }
293 - let t6;
294 - if ($[11] !== t1 || $[12] !== t5) {
295 - if (DEV) {
296 - t6 = (
297 - <Parent>
298 - {t1}
299 - {t5}
300 - </Parent>
301 - );
302 - } else {
303 - t6 = {
304 - $$typeof: Symbol.for("react.transitional.element"),
305 - type: Parent,
306 - ref: null,
307 - key: null,
308 - props: { children: [t1, t5] },
309 - };
310 - }
311 - $[11] = t1;
312 - $[12] = t5;
313 - $[13] = t6;
314 - } else {
315 - t6 = $[13];
316 - }
317 - return t6;
318 -}
319 -
320 -const propsToSpread = { a: "a", b: "b", c: "c" };
321 -function PropsSpread() {
322 - const $ = _c2(1);
323 - let t0;
324 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
325 - let t1;
326 - if (DEV) {
327 - t1 = <Test key="a" {...propsToSpread} />;
328 - } else {
329 - t1 = {
330 - $$typeof: Symbol.for("react.transitional.element"),
331 - type: Test,
332 - ref: null,
333 - key: "a",
334 - props: propsToSpread,
335 - };
336 - }
337 - let t2;
338 - if (DEV) {
339 - t2 = <Test key="b" {...propsToSpread} a="z" />;
340 - } else {
341 - t2 = {
342 - $$typeof: Symbol.for("react.transitional.element"),
343 - type: Test,
344 - ref: null,
345 - key: "b",
346 - props: { ...propsToSpread, a: "z" },
347 - };
348 - }
349 - if (DEV) {
350 - t0 = (
351 - <>
352 - {t1}
353 - {t2}
354 - </>
355 - );
356 - } else {
357 - t0 = {
358 - $$typeof: Symbol.for("react.transitional.element"),
359 - type: Symbol.for("react.fragment"),
360 - ref: null,
361 - key: null,
362 - props: { children: [t1, t2] },
363 - };
364 - }
365 - $[0] = t0;
366 - } else {
367 - t0 = $[0];
368 - }
369 - return t0;
370 -}
371 -
372 -function ConditionalJsx(t0) {
373 - const $ = _c2(2);
374 - const { shouldWrap } = t0;
375 - let t1;
376 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
377 - if (DEV) {
378 - t1 = <div>Hello</div>;
379 - } else {
380 - t1 = {
381 - $$typeof: Symbol.for("react.transitional.element"),
382 - type: "div",
383 - ref: null,
384 - key: null,
385 - props: { children: "Hello" },
386 - };
387 - }
388 - $[0] = t1;
389 - } else {
390 - t1 = $[0];
391 - }
392 - let content = t1;
393 -
394 - if (shouldWrap) {
395 - const t2 = content;
396 - let t3;
397 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
398 - if (DEV) {
399 - t3 = <Parent>{t2}</Parent>;
400 - } else {
401 - t3 = {
402 - $$typeof: Symbol.for("react.transitional.element"),
403 - type: Parent,
404 - ref: null,
405 - key: null,
406 - props: { children: t2 },
407 - };
408 - }
409 - $[1] = t3;
410 - } else {
411 - t3 = $[1];
412 - }
413 - content = t3;
414 - }
415 -
416 - return content;
417 -}
418 -
419 -function ComponentWithSpreadPropsAndRef(t0) {
420 - const $ = _c2(6);
421 - let other;
422 - let ref;
423 - if ($[0] !== t0) {
424 - ({ ref, ...other } = t0);
425 - $[0] = t0;
426 - $[1] = other;
427 - $[2] = ref;
428 - } else {
429 - other = $[1];
430 - ref = $[2];
431 - }
432 - let t1;
433 - if ($[3] !== other || $[4] !== ref) {
434 - if (DEV) {
435 - t1 = <Foo ref={ref} {...other} />;
436 - } else {
437 - t1 = {
438 - $$typeof: Symbol.for("react.transitional.element"),
439 - type: Foo,
440 - ref: ref,
441 - key: null,
442 - props: { ref: ref, ...other },
443 - };
444 - }
445 - $[3] = other;
446 - $[4] = ref;
447 - $[5] = t1;
448 - } else {
449 - t1 = $[5];
450 - }
451 - return t1;
452 -}
453 -
454 -// TODO: Support value blocks
455 -function TernaryJsx(t0) {
456 - const $ = _c2(2);
457 - const { cond } = t0;
458 - let t1;
459 - if ($[0] !== cond) {
460 - t1 = cond ? <div /> : null;
461 - $[0] = cond;
462 - $[1] = t1;
463 - } else {
464 - t1 = $[1];
465 - }
466 - return t1;
467 -}
468 -
469 -global.DEV = true;
470 -export const FIXTURE_ENTRYPOINT = {
471 - fn: ParentAndChildren,
472 - params: [{ foo: "abc" }],
473 -};
474 -
475 -```
476 -
477 -### Eval output
478 -(kind: ok) <div><span class="abc">Hello world</span><div>abc</div></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js deleted
-72
@@ -1,72 +0,0 @@
1 -// @inlineJsxTransform
2 -
3 -function Parent({children, a: _a, b: _b, c: _c, ref}) {
4 - return <div ref={ref}>{children}</div>;
5 -}
6 -
7 -function Child({children}) {
8 - return <>{children}</>;
9 -}
10 -
11 -function GrandChild({className}) {
12 - return (
13 - <span className={className}>
14 - <React.Fragment key="fragmentKey">Hello world</React.Fragment>
15 - </span>
16 - );
17 -}
18 -
19 -function ParentAndRefAndKey(props) {
20 - const testRef = useRef();
21 - return <Parent a="a" b={{b: 'b'}} c={C} key="testKey" ref={testRef} />;
22 -}
23 -
24 -function ParentAndChildren(props) {
25 - const render = () => {
26 - return <div key="d">{props.foo}</div>;
27 - };
28 - return (
29 - <Parent>
30 - <Child key="a" {...props} />
31 - <Child key="b">
32 - <GrandChild key="c" className={props.foo} {...props} />
33 - {render()}
34 - </Child>
35 - </Parent>
36 - );
37 -}
38 -
39 -const propsToSpread = {a: 'a', b: 'b', c: 'c'};
40 -function PropsSpread() {
41 - return (
42 - <>
43 - <Test key="a" {...propsToSpread} />
44 - <Test key="b" {...propsToSpread} a="z" />
45 - </>
46 - );
47 -}
48 -
49 -function ConditionalJsx({shouldWrap}) {
50 - let content = <div>Hello</div>;
51 -
52 - if (shouldWrap) {
53 - content = <Parent>{content}</Parent>;
54 - }
55 -
56 - return content;
57 -}
58 -
59 -function ComponentWithSpreadPropsAndRef({ref, ...other}) {
60 - return <Foo ref={ref} {...other} />;
61 -}
62 -
63 -// TODO: Support value blocks
64 -function TernaryJsx({cond}) {
65 - return cond ? <div /> : null;
66 -}
67 -
68 -global.DEV = true;
69 -export const FIXTURE_ENTRYPOINT = {
70 - fn: ParentAndChildren,
71 - params: [{foo: 'abc'}],
72 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.expect.md deleted
-66
@@ -1,66 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess @enableEmitHookGuards
6 -function App() {
7 - const {foo} = useContext(MyContext);
8 - const {bar} = useContext(MyContext);
9 - return <Bar foo={foo} bar={bar} />;
10 -}
11 -
12 -```
13 -
14 -## Code
15 -
16 -```javascript
17 -import {
18 - $dispatcherGuard,
19 - useContext_withSelector,
20 -} from "react-compiler-runtime";
21 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess @enableEmitHookGuards
22 -function App() {
23 - const $ = _c(3);
24 - try {
25 - $dispatcherGuard(0);
26 - const { foo } = (function () {
27 - try {
28 - $dispatcherGuard(2);
29 - return useContext_withSelector(MyContext, _temp);
30 - } finally {
31 - $dispatcherGuard(3);
32 - }
33 - })();
34 - const { bar } = (function () {
35 - try {
36 - $dispatcherGuard(2);
37 - return useContext_withSelector(MyContext, _temp2);
38 - } finally {
39 - $dispatcherGuard(3);
40 - }
41 - })();
42 - let t0;
43 - if ($[0] !== bar || $[1] !== foo) {
44 - t0 = <Bar foo={foo} bar={bar} />;
45 - $[0] = bar;
46 - $[1] = foo;
47 - $[2] = t0;
48 - } else {
49 - t0 = $[2];
50 - }
51 - return t0;
52 - } finally {
53 - $dispatcherGuard(1);
54 - }
55 -}
56 -function _temp2(t0) {
57 - return [t0.bar];
58 -}
59 -function _temp(t0) {
60 - return [t0.foo];
61 -}
62 -
63 -```
64 -
65 -### Eval output
66 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.js deleted
-6
@@ -1,6 +0,0 @@
1 -// @lowerContextAccess @enableEmitHookGuards
2 -function App() {
3 - const {foo} = useContext(MyContext);
4 - const {bar} = useContext(MyContext);
5 - return <Bar foo={foo} bar={bar} />;
6 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md deleted
-42
@@ -1,42 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess
6 -function App() {
7 - const {foo} = useContext(MyContext);
8 - const {bar} = useContext(MyContext);
9 - return <Bar foo={foo} bar={bar} />;
10 -}
11 -
12 -```
13 -
14 -## Code
15 -
16 -```javascript
17 -import { useContext_withSelector } from "react-compiler-runtime";
18 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess
19 -function App() {
20 - const $ = _c(3);
21 - const { foo } = useContext_withSelector(MyContext, _temp);
22 - const { bar } = useContext_withSelector(MyContext, _temp2);
23 - let t0;
24 - if ($[0] !== bar || $[1] !== foo) {
25 - t0 = <Bar foo={foo} bar={bar} />;
26 - $[0] = bar;
27 - $[1] = foo;
28 - $[2] = t0;
29 - } else {
30 - t0 = $[2];
31 - }
32 - return t0;
33 -}
34 -function _temp2(t0) {
35 - return [t0.bar];
36 -}
37 -function _temp(t0) {
38 - return [t0.foo];
39 -}
40 -
41 -```
42 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.js deleted
-6
@@ -1,6 +0,0 @@
1 -// @lowerContextAccess
2 -function App() {
3 - const {foo} = useContext(MyContext);
4 - const {bar} = useContext(MyContext);
5 - return <Bar foo={foo} bar={bar} />;
6 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md deleted
-37
@@ -1,37 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess
6 -function App() {
7 - const {foo, bar} = useContext(MyContext);
8 - return <Bar foo={foo} bar={bar} />;
9 -}
10 -
11 -```
12 -
13 -## Code
14 -
15 -```javascript
16 -import { useContext_withSelector } from "react-compiler-runtime";
17 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess
18 -function App() {
19 - const $ = _c(3);
20 - const { foo, bar } = useContext_withSelector(MyContext, _temp);
21 - let t0;
22 - if ($[0] !== bar || $[1] !== foo) {
23 - t0 = <Bar foo={foo} bar={bar} />;
24 - $[0] = bar;
25 - $[1] = foo;
26 - $[2] = t0;
27 - } else {
28 - t0 = $[2];
29 - }
30 - return t0;
31 -}
32 -function _temp(t0) {
33 - return [t0.foo, t0.bar];
34 -}
35 -
36 -```
37 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.js deleted
-5
@@ -1,5 +0,0 @@
1 -// @lowerContextAccess
2 -function App() {
3 - const {foo, bar} = useContext(MyContext);
4 - return <Bar foo={foo} bar={bar} />;
5 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/memoization-comments.expect.md deleted
-78
@@ -1,78 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableMemoizationComments
6 -import {addOne, getNumber, identity} from 'shared-runtime';
7 -
8 -function Component(props) {
9 - const x = identity(props.a);
10 - const y = addOne(x);
11 - const z = identity(props.b);
12 - return [x, y, z];
13 -}
14 -
15 -export const FIXTURE_ENTRYPOINT = {
16 - fn: Component,
17 - params: [{a: 1, b: 10}],
18 -};
19 -
20 -```
21 -
22 -## Code
23 -
24 -```javascript
25 -import { c as _c } from "react/compiler-runtime"; // @enableMemoizationComments
26 -import { addOne, getNumber, identity } from "shared-runtime";
27 -
28 -function Component(props) {
29 - const $ = _c(9);
30 - let t0;
31 - let x; // "useMemo" for t0 and x:
32 - // check if props.a changed
33 - if ($[0] !== props.a) {
34 - // Inputs changed, recompute
35 - x = identity(props.a);
36 - t0 = addOne(x);
37 - $[0] = props.a;
38 - $[1] = t0;
39 - $[2] = x;
40 - } else {
41 - // Inputs did not change, use cached value
42 - t0 = $[1];
43 - x = $[2];
44 - }
45 - const y = t0;
46 - let t1; // "useMemo" for t1:
47 - // check if props.b changed
48 - if ($[3] !== props.b) {
49 - // Inputs changed, recompute
50 - t1 = identity(props.b);
51 - $[3] = props.b;
52 - $[4] = t1;
53 - } else {
54 - // Inputs did not change, use cached value
55 - t1 = $[4];
56 - }
57 - const z = t1;
58 - let t2; // "useMemo" for t2:
59 - // check if x, y, or z changed
60 - if ($[5] !== x || $[6] !== y || $[7] !== z) {
61 - // Inputs changed, recompute
62 - t2 = [x, y, z];
63 - $[5] = x;
64 - $[6] = y;
65 - $[7] = z;
66 - $[8] = t2;
67 - } else {
68 - // Inputs did not change, use cached value
69 - t2 = $[8];
70 - }
71 - return t2;
72 -}
73 -export const FIXTURE_ENTRYPOINT = { fn: Component, params: [{ a: 1, b: 10 }] };
74 -
75 -```
76 -
77 -### Eval output
78 -(kind: ok) [1,2,10]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/memoization-comments.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @enableMemoizationComments
2 -import {addOne, getNumber, identity} from 'shared-runtime';
3 -
4 -function Component(props) {
5 - const x = identity(props.a);
6 - const y = addOne(x);
7 - const z = identity(props.b);
8 - return [x, y, z];
9 -}
10 -
11 -export const FIXTURE_ENTRYPOINT = {
12 - fn: Component,
13 - params: [{a: 1, b: 10}],
14 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-scopes-reordering.expect.md deleted
-88
@@ -1,88 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableInstructionReordering
6 -import {useState} from 'react';
7 -import {Stringify} from 'shared-runtime';
8 -
9 -function Component() {
10 - let [state, setState] = useState(0);
11 - return (
12 - <div>
13 - <Stringify text="Counter" />
14 - <span>{state}</span>
15 - <button data-testid="button" onClick={() => setState(state + 1)}>
16 - increment
17 - </button>
18 - </div>
19 - );
20 -}
21 -
22 -export const FIXTURE_ENTRYPOINT = {
23 - fn: Component,
24 - params: [{value: 42}],
25 -};
26 -
27 -```
28 -
29 -## Code
30 -
31 -```javascript
32 -import { c as _c } from "react/compiler-runtime"; // @enableInstructionReordering
33 -import { useState } from "react";
34 -import { Stringify } from "shared-runtime";
35 -
36 -function Component() {
37 - const $ = _c(7);
38 - const [state, setState] = useState(0);
39 - let t0;
40 - let t1;
41 - if ($[0] !== state) {
42 - t0 = (
43 - <button data-testid="button" onClick={() => setState(state + 1)}>
44 - increment
45 - </button>
46 - );
47 - t1 = <span>{state}</span>;
48 - $[0] = state;
49 - $[1] = t0;
50 - $[2] = t1;
51 - } else {
52 - t0 = $[1];
53 - t1 = $[2];
54 - }
55 - let t2;
56 - if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
57 - t2 = <Stringify text="Counter" />;
58 - $[3] = t2;
59 - } else {
60 - t2 = $[3];
61 - }
62 - let t3;
63 - if ($[4] !== t0 || $[5] !== t1) {
64 - t3 = (
65 - <div>
66 - {t2}
67 - {t1}
68 - {t0}
69 - </div>
70 - );
71 - $[4] = t0;
72 - $[5] = t1;
73 - $[6] = t3;
74 - } else {
75 - t3 = $[6];
76 - }
77 - return t3;
78 -}
79 -
80 -export const FIXTURE_ENTRYPOINT = {
81 - fn: Component,
82 - params: [{ value: 42 }],
83 -};
84 -
85 -```
86 -
87 -### Eval output
88 -(kind: ok) <div><div>{"text":"Counter"}</div><span>0</span><button data-testid="button">increment</button></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-scopes-reordering.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @enableInstructionReordering
2 -import {useState} from 'react';
3 -import {Stringify} from 'shared-runtime';
4 -
5 -function Component() {
6 - let [state, setState] = useState(0);
7 - return (
8 - <div>
9 - <Stringify text="Counter" />
10 - <span>{state}</span>
11 - <button data-testid="button" onClick={() => setState(state + 1)}>
12 - increment
13 - </button>
14 - </div>
15 - );
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: Component,
20 - params: [{value: 42}],
21 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-scopes-callback.expect.md deleted
-71
@@ -1,71 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableInstructionReordering
6 -import {useState} from 'react';
7 -
8 -function Component() {
9 - const [state, setState] = useState(0);
10 - const onClick = () => {
11 - setState(s => s + 1);
12 - };
13 - return (
14 - <>
15 - <span>Count: {state}</span>
16 - <button onClick={onClick}>Increment</button>
17 - </>
18 - );
19 -}
20 -
21 -```
22 -
23 -## Code
24 -
25 -```javascript
26 -import { c as _c } from "react/compiler-runtime"; // @enableInstructionReordering
27 -import { useState } from "react";
28 -
29 -function Component() {
30 - const $ = _c(4);
31 - const [state, setState] = useState(0);
32 - let t0;
33 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
34 - t0 = () => {
35 - setState(_temp);
36 - };
37 - $[0] = t0;
38 - } else {
39 - t0 = $[0];
40 - }
41 - const onClick = t0;
42 - let t1;
43 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
44 - t1 = <button onClick={onClick}>Increment</button>;
45 - $[1] = t1;
46 - } else {
47 - t1 = $[1];
48 - }
49 - let t2;
50 - if ($[2] !== state) {
51 - t2 = (
52 - <>
53 - <span>Count: {state}</span>
54 - {t1}
55 - </>
56 - );
57 - $[2] = state;
58 - $[3] = t2;
59 - } else {
60 - t2 = $[3];
61 - }
62 - return t2;
63 -}
64 -function _temp(s) {
65 - return s + 1;
66 -}
67 -
68 -```
69 -
70 -### Eval output
71 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-scopes-callback.js deleted
-15
@@ -1,15 +0,0 @@
1 -// @enableInstructionReordering
2 -import {useState} from 'react';
3 -
4 -function Component() {
5 - const [state, setState] = useState(0);
6 - const onClick = () => {
7 - setState(s => s + 1);
8 - };
9 - return (
10 - <>
11 - <span>Count: {state}</span>
12 - <button onClick={onClick}>Increment</button>
13 - </>
14 - );
15 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merged-scopes-are-valid-effect-deps.expect.md deleted
-74
@@ -1,74 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateMemoizedEffectDependencies
6 -
7 -import {useEffect} from 'react';
8 -
9 -function Component(props) {
10 - const y = [[props.value]]; // merged w scope for inner array
11 -
12 - useEffect(() => {
13 - console.log(y);
14 - }, [y]); // should still be a valid dependency here
15 -
16 - return y;
17 -}
18 -
19 -export const FIXTURE_ENTRYPOINT = {
20 - fn: Component,
21 - params: [{value: 42}],
22 - isComponent: false,
23 -};
24 -
25 -```
26 -
27 -## Code
28 -
29 -```javascript
30 -import { c as _c } from "react/compiler-runtime"; // @validateMemoizedEffectDependencies
31 -
32 -import { useEffect } from "react";
33 -
34 -function Component(props) {
35 - const $ = _c(5);
36 - let t0;
37 - if ($[0] !== props.value) {
38 - t0 = [[props.value]];
39 - $[0] = props.value;
40 - $[1] = t0;
41 - } else {
42 - t0 = $[1];
43 - }
44 - const y = t0;
45 - let t1;
46 - let t2;
47 - if ($[2] !== y) {
48 - t1 = () => {
49 - console.log(y);
50 - };
51 - t2 = [y];
52 - $[2] = y;
53 - $[3] = t1;
54 - $[4] = t2;
55 - } else {
56 - t1 = $[3];
57 - t2 = $[4];
58 - }
59 - useEffect(t1, t2);
60 -
61 - return y;
62 -}
63 -
64 -export const FIXTURE_ENTRYPOINT = {
65 - fn: Component,
66 - params: [{ value: 42 }],
67 - isComponent: false,
68 -};
69 -
70 -```
71 -
72 -### Eval output
73 -(kind: ok) [[42]]
74 -logs: [[ [ 42 ] ]]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merged-scopes-are-valid-effect-deps.js deleted
-19
@@ -1,19 +0,0 @@
1 -// @validateMemoizedEffectDependencies
2 -
3 -import {useEffect} from 'react';
4 -
5 -function Component(props) {
6 - const y = [[props.value]]; // merged w scope for inner array
7 -
8 - useEffect(() => {
9 - console.log(y);
10 - }, [y]); // should still be a valid dependency here
11 -
12 - return y;
13 -}
14 -
15 -export const FIXTURE_ENTRYPOINT = {
16 - fn: Component,
17 - params: [{value: 42}],
18 - isComponent: false,
19 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md deleted
-58
@@ -1,58 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
6 -import {useEffect, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -function Component({foo}) {
10 - const arr = [];
11 - // Taking either arr[0].value or arr as a dependency is reasonable
12 - // as long as developers know what to expect.
13 - useEffect(() => print(arr[0]?.value), AUTODEPS);
14 - arr.push({value: foo});
15 - return arr;
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: Component,
20 - params: [{foo: 1}],
21 -};
22 -
23 -```
24 -
25 -## Code
26 -
27 -```javascript
28 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
29 -import { useEffect, AUTODEPS } from "react";
30 -import { print } from "shared-runtime";
31 -
32 -function Component(t0) {
33 - const { foo } = t0;
34 - const arr = [];
35 -
36 - useEffect(() => print(arr[0]?.value), [arr[0]?.value]);
37 - arr.push({ value: foo });
38 - return arr;
39 -}
40 -
41 -export const FIXTURE_ENTRYPOINT = {
42 - fn: Component,
43 - params: [{ foo: 1 }],
44 -};
45 -
46 -```
47 -
48 -## Logs
49 -
50 -```
51 -{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":397},"end":{"line":10,"column":5,"index":400},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
52 -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":346},"end":{"line":9,"column":49,"index":393},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":368},"end":{"line":9,"column":27,"index":371},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
53 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
54 -```
55 -
56 -### Eval output
57 -(kind: ok) [{"value":1}]
58 -logs: [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.js deleted
-17
@@ -1,17 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
2 -import {useEffect, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -function Component({foo}) {
6 - const arr = [];
7 - // Taking either arr[0].value or arr as a dependency is reasonable
8 - // as long as developers know what to expect.
9 - useEffect(() => print(arr[0]?.value), AUTODEPS);
10 - arr.push({value: foo});
11 - return arr;
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{foo: 1}],
17 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md deleted
-57
@@ -1,57 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
6 -
7 -import {useEffect, useRef, AUTODEPS} from 'react';
8 -import {print} from 'shared-runtime';
9 -
10 -function Component({arrRef}) {
11 - // Avoid taking arr.current as a dependency
12 - useEffect(() => print(arrRef.current), AUTODEPS);
13 - arrRef.current.val = 2;
14 - return arrRef;
15 -}
16 -
17 -export const FIXTURE_ENTRYPOINT = {
18 - fn: Component,
19 - params: [{arrRef: {current: {val: 'initial ref value'}}}],
20 -};
21 -
22 -```
23 -
24 -## Code
25 -
26 -```javascript
27 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
28 -
29 -import { useEffect, useRef, AUTODEPS } from "react";
30 -import { print } from "shared-runtime";
31 -
32 -function Component(t0) {
33 - const { arrRef } = t0;
34 -
35 - useEffect(() => print(arrRef.current), [arrRef]);
36 - arrRef.current.val = 2;
37 - return arrRef;
38 -}
39 -
40 -export const FIXTURE_ENTRYPOINT = {
41 - fn: Component,
42 - params: [{ arrRef: { current: { val: "initial ref value" } } }],
43 -};
44 -
45 -```
46 -
47 -## Logs
48 -
49 -```
50 -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":321},"end":{"line":9,"column":16,"index":335},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
51 -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":269},"end":{"line":8,"column":50,"index":317},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":291},"end":{"line":8,"column":30,"index":297},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
52 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 -```
54 -
55 -### Eval output
56 -(kind: ok) {"current":{"val":2}}
57 -logs: [{ val: 2 }]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.js deleted
-16
@@ -1,16 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
2 -
3 -import {useEffect, useRef, AUTODEPS} from 'react';
4 -import {print} from 'shared-runtime';
5 -
6 -function Component({arrRef}) {
7 - // Avoid taking arr.current as a dependency
8 - useEffect(() => print(arrRef.current), AUTODEPS);
9 - arrRef.current.val = 2;
10 - return arrRef;
11 -}
12 -
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: Component,
15 - params: [{arrRef: {current: {val: 'initial ref value'}}}],
16 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md deleted
-56
@@ -1,56 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
6 -import {useEffect, AUTODEPS} from 'react';
7 -
8 -function Component({foo}) {
9 - const arr = [];
10 - useEffect(() => {
11 - arr.push(foo);
12 - }, AUTODEPS);
13 - arr.push(2);
14 - return arr;
15 -}
16 -
17 -export const FIXTURE_ENTRYPOINT = {
18 - fn: Component,
19 - params: [{foo: 1}],
20 -};
21 -
22 -```
23 -
24 -## Code
25 -
26 -```javascript
27 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
28 -import { useEffect, AUTODEPS } from "react";
29 -
30 -function Component(t0) {
31 - const { foo } = t0;
32 - const arr = [];
33 - useEffect(() => {
34 - arr.push(foo);
35 - }, [arr, foo]);
36 - arr.push(2);
37 - return arr;
38 -}
39 -
40 -export const FIXTURE_ENTRYPOINT = {
41 - fn: Component,
42 - params: [{ foo: 1 }],
43 -};
44 -
45 -```
46 -
47 -## Logs
48 -
49 -```
50 -{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":246},"end":{"line":9,"column":5,"index":249},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
51 -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":191},"end":{"line":8,"column":14,"index":242},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":213},"end":{"line":7,"column":7,"index":216},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":213},"end":{"line":7,"column":7,"index":216},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":222},"end":{"line":7,"column":16,"index":225},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
52 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 -```
54 -
55 -### Eval output
56 -(kind: ok) [2]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.js deleted
-16
@@ -1,16 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
2 -import {useEffect, AUTODEPS} from 'react';
3 -
4 -function Component({foo}) {
5 - const arr = [];
6 - useEffect(() => {
7 - arr.push(foo);
8 - }, AUTODEPS);
9 - arr.push(2);
10 - return arr;
11 -}
12 -
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: Component,
15 - params: [{foo: 1}],
16 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.expect.md deleted
-66
@@ -1,66 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @enableNewMutationAliasingModel
6 -import {useEffect, useState, AUTODEPS} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -/*
10 - * setState types are not enough to determine to omit from deps. Must also take reactivity into account.
11 - */
12 -function ReactiveRefInEffect(props) {
13 - const [_state1, setState1] = useRef('initial value');
14 - const [_state2, setState2] = useRef('initial value');
15 - let setState;
16 - if (props.foo) {
17 - setState = setState1;
18 - } else {
19 - setState = setState2;
20 - }
21 - useEffect(() => print(setState), AUTODEPS);
22 -}
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies @enableNewMutationAliasingModel
30 -import { useEffect, useState, AUTODEPS } from "react";
31 -import { print } from "shared-runtime";
32 -
33 -/*
34 - * setState types are not enough to determine to omit from deps. Must also take reactivity into account.
35 - */
36 -function ReactiveRefInEffect(props) {
37 - const $ = _c(4);
38 - const [, setState1] = useRef("initial value");
39 - const [, setState2] = useRef("initial value");
40 - let setState;
41 - if ($[0] !== props.foo) {
42 - if (props.foo) {
43 - setState = setState1;
44 - } else {
45 - setState = setState2;
46 - }
47 - $[0] = props.foo;
48 - $[1] = setState;
49 - } else {
50 - setState = $[1];
51 - }
52 - let t0;
53 - if ($[2] !== setState) {
54 - t0 = () => print(setState);
55 - $[2] = setState;
56 - $[3] = t0;
57 - } else {
58 - t0 = $[3];
59 - }
60 - useEffect(t0, [setState]);
61 -}
62 -
63 -```
64 -
65 -### Eval output
66 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @inferEffectDependencies @enableNewMutationAliasingModel
2 -import {useEffect, useState, AUTODEPS} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -/*
6 - * setState types are not enough to determine to omit from deps. Must also take reactivity into account.
7 - */
8 -function ReactiveRefInEffect(props) {
9 - const [_state1, setState1] = useRef('initial value');
10 - const [_state2, setState2] = useRef('initial value');
11 - let setState;
12 - if (props.foo) {
13 - setState = setState1;
14 - } else {
15 - setState = setState2;
16 - }
17 - useEffect(() => print(setState), AUTODEPS);
18 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.expect.md deleted
-81
@@ -1,81 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @enableNewMutationAliasingModel
6 -import {fire} from 'react';
7 -
8 -function Component({bar, baz}) {
9 - const foo = () => {
10 - console.log(bar);
11 - };
12 - useEffect(() => {
13 - fire(foo(bar));
14 - fire(baz(bar));
15 - });
16 -
17 - useEffect(() => {
18 - fire(foo(bar));
19 - });
20 -
21 - return null;
22 -}
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire @enableNewMutationAliasingModel
30 -import { fire } from "react";
31 -
32 -function Component(t0) {
33 - const $ = _c(9);
34 - const { bar, baz } = t0;
35 - let t1;
36 - if ($[0] !== bar) {
37 - t1 = () => {
38 - console.log(bar);
39 - };
40 - $[0] = bar;
41 - $[1] = t1;
42 - } else {
43 - t1 = $[1];
44 - }
45 - const foo = t1;
46 - const t2 = useFire(foo);
47 - const t3 = useFire(baz);
48 - let t4;
49 - if ($[2] !== bar || $[3] !== t2 || $[4] !== t3) {
50 - t4 = () => {
51 - t2(bar);
52 - t3(bar);
53 - };
54 - $[2] = bar;
55 - $[3] = t2;
56 - $[4] = t3;
57 - $[5] = t4;
58 - } else {
59 - t4 = $[5];
60 - }
61 - useEffect(t4);
62 - let t5;
63 - if ($[6] !== bar || $[7] !== t2) {
64 - t5 = () => {
65 - t2(bar);
66 - };
67 - $[6] = bar;
68 - $[7] = t2;
69 - $[8] = t5;
70 - } else {
71 - t5 = $[8];
72 - }
73 - useEffect(t5);
74 -
75 - return null;
76 -}
77 -
78 -```
79 -
80 -### Eval output
81 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @enableFire @enableNewMutationAliasingModel
2 -import {fire} from 'react';
3 -
4 -function Component({bar, baz}) {
5 - const foo = () => {
6 - console.log(bar);
7 - };
8 - useEffect(() => {
9 - fire(foo(bar));
10 - fire(baz(bar));
11 - });
12 -
13 - useEffect(() => {
14 - fire(foo(bar));
15 - });
16 -
17 - return null;
18 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.expect.md deleted
-47
@@ -1,47 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableChangeVariableCodegen
6 -function Component(props) {
7 - const c_0 = [props.a, props.b.c];
8 - return c_0;
9 -}
10 -
11 -export const FIXTURE_ENTRYPOINT = {
12 - fn: Component,
13 - params: [{a: 3.14, b: {c: true}}],
14 -};
15 -
16 -```
17 -
18 -## Code
19 -
20 -```javascript
21 -import { c as _c } from "react/compiler-runtime"; // @enableChangeVariableCodegen
22 -function Component(props) {
23 - const $ = _c(3);
24 - const c_00 = $[0] !== props.a;
25 - const c_1 = $[1] !== props.b.c;
26 - let t0;
27 - if (c_00 || c_1) {
28 - t0 = [props.a, props.b.c];
29 - $[0] = props.a;
30 - $[1] = props.b.c;
31 - $[2] = t0;
32 - } else {
33 - t0 = $[2];
34 - }
35 - const c_0 = t0;
36 - return c_0;
37 -}
38 -
39 -export const FIXTURE_ENTRYPOINT = {
40 - fn: Component,
41 - params: [{ a: 3.14, b: { c: true } }],
42 -};
43 -
44 -```
45 -
46 -### Eval output
47 -(kind: ok) [3.14,true]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.js deleted
-10
@@ -1,10 +0,0 @@
1 -// @enableChangeVariableCodegen
2 -function Component(props) {
3 - const c_0 = [props.a, props.b.c];
4 - return c_0;
5 -}
6 -
7 -export const FIXTURE_ENTRYPOINT = {
8 - fn: Component,
9 - params: [{a: 3.14, b: {c: true}}],
10 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-deps-conditional-property-chain-less-precise-deps.expect.md
+2 -2
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
5 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
6
7 import {useMemo} from 'react';
8 import {identity, ValidateMemoization} from 'shared-runtime';
@@ -43,7 +43,7 @@ export const FIXTURE_ENTRYPOINT = {
43 ## Code
44
45 ```javascript
46 -import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
46 +import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
47
48 import { useMemo } from "react";
49 import { identity, ValidateMemoization } from "shared-runtime";
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-deps-conditional-property-chain-less-precise-deps.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
1 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
2
3 import {useMemo} from 'react';
4 import {identity, ValidateMemoization} from 'shared-runtime';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-deps-conditional-property-chain.expect.md
+2 -2
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
5 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
6
7 import {useMemo} from 'react';
8 import {identity, ValidateMemoization} from 'shared-runtime';
@@ -39,7 +39,7 @@ export const FIXTURE_ENTRYPOINT = {
39 ## Code
40
41 ```javascript
42 -import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
42 +import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
43
44 import { useMemo } from "react";
45 import { identity, ValidateMemoization } from "shared-runtime";
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-deps-conditional-property-chain.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
1 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
2
3 import {useMemo} from 'react';
4 import {identity, ValidateMemoization} from 'shared-runtime';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-deps-optional-property-chain.expect.md
+2 -2
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
5 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
6
7 import {useMemo} from 'react';
8 import {identity, ValidateMemoization} from 'shared-runtime';
@@ -44,7 +44,7 @@ export const FIXTURE_ENTRYPOINT = {
44 ## Code
45
46 ```javascript
47 -import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
47 +import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
48
49 import { useMemo } from "react";
50 import { identity, ValidateMemoization } from "shared-runtime";
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-deps-optional-property-chain.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enableTreatFunctionDepsAsConditional:false
1 +// @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies
2
3 import {useMemo} from 'react';
4 import {identity, ValidateMemoization} from 'shared-runtime';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-function.expect.md deleted
-78
@@ -1,78 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableChangeVariableCodegen
6 -import {identity} from 'shared-runtime';
7 -
8 -const $ = 'module_$';
9 -const t0 = 'module_t0';
10 -const c_0 = 'module_c_0';
11 -function useFoo(props: {value: number}): number {
12 - const a = () => {
13 - const b = () => {
14 - const c = () => {
15 - console.log($);
16 - console.log(t0);
17 - console.log(c_0);
18 - return identity(props.value);
19 - };
20 - return c;
21 - };
22 - return b;
23 - };
24 - return a()()();
25 -}
26 -
27 -export const FIXTURE_ENTRYPOINT = {
28 - fn: useFoo,
29 - params: [{value: 42}],
30 -};
31 -
32 -```
33 -
34 -## Code
35 -
36 -```javascript
37 -import { c as _c } from "react/compiler-runtime"; // @enableChangeVariableCodegen
38 -import { identity } from "shared-runtime";
39 -
40 -const $ = "module_$";
41 -const t0 = "module_t0";
42 -const c_0 = "module_c_0";
43 -function useFoo(props) {
44 - const $0 = _c(2);
45 - const c_00 = $0[0] !== props.value;
46 - let t1;
47 - if (c_00) {
48 - const a = () => {
49 - const b = () => {
50 - const c = () => {
51 - console.log($);
52 - console.log(t0);
53 - console.log(c_0);
54 - return identity(props.value);
55 - };
56 - return c;
57 - };
58 - return b;
59 - };
60 - t1 = a()()();
61 - $0[0] = props.value;
62 - $0[1] = t1;
63 - } else {
64 - t1 = $0[1];
65 - }
66 - return t1;
67 -}
68 -
69 -export const FIXTURE_ENTRYPOINT = {
70 - fn: useFoo,
71 - params: [{ value: 42 }],
72 -};
73 -
74 -```
75 -
76 -### Eval output
77 -(kind: ok) 42
78 -logs: ['module_$','module_t0','module_c_0']
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-function.js deleted
-26
@@ -1,26 +0,0 @@
1 -// @enableChangeVariableCodegen
2 -import {identity} from 'shared-runtime';
3 -
4 -const $ = 'module_$';
5 -const t0 = 'module_t0';
6 -const c_0 = 'module_c_0';
7 -function useFoo(props: {value: number}): number {
8 - const a = () => {
9 - const b = () => {
10 - const c = () => {
11 - console.log($);
12 - console.log(t0);
13 - console.log(c_0);
14 - return identity(props.value);
15 - };
16 - return c;
17 - };
18 - return b;
19 - };
20 - return a()()();
21 -}
22 -
23 -export const FIXTURE_ENTRYPOINT = {
24 - fn: useFoo,
25 - params: [{value: 42}],
26 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-object-method.expect.md deleted
-80
@@ -1,80 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableChangeVariableCodegen
6 -import {identity} from 'shared-runtime';
7 -
8 -const $ = 'module_$';
9 -const t0 = 'module_t0';
10 -const c_0 = 'module_c_0';
11 -function useFoo(props: {value: number}): number {
12 - const a = {
13 - foo() {
14 - const b = {
15 - bar() {
16 - console.log($);
17 - console.log(t0);
18 - console.log(c_0);
19 - return identity(props.value);
20 - },
21 - };
22 - return b;
23 - },
24 - };
25 - return a.foo().bar();
26 -}
27 -
28 -export const FIXTURE_ENTRYPOINT = {
29 - fn: useFoo,
30 - params: [{value: 42}],
31 -};
32 -
33 -```
34 -
35 -## Code
36 -
37 -```javascript
38 -import { c as _c } from "react/compiler-runtime"; // @enableChangeVariableCodegen
39 -import { identity } from "shared-runtime";
40 -
41 -const $ = "module_$";
42 -const t0 = "module_t0";
43 -const c_0 = "module_c_0";
44 -function useFoo(props) {
45 - const $0 = _c(2);
46 - const c_00 = $0[0] !== props;
47 - let t1;
48 - if (c_00) {
49 - const a = {
50 - foo() {
51 - const b = {
52 - bar() {
53 - console.log($);
54 - console.log(t0);
55 - console.log(c_0);
56 - return identity(props.value);
57 - },
58 - };
59 - return b;
60 - },
61 - };
62 - t1 = a.foo().bar();
63 - $0[0] = props;
64 - $0[1] = t1;
65 - } else {
66 - t1 = $0[1];
67 - }
68 - return t1;
69 -}
70 -
71 -export const FIXTURE_ENTRYPOINT = {
72 - fn: useFoo,
73 - params: [{ value: 42 }],
74 -};
75 -
76 -```
77 -
78 -### Eval output
79 -(kind: ok) 42
80 -logs: ['module_$','module_t0','module_c_0']
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-object-method.js deleted
-27
@@ -1,27 +0,0 @@
1 -// @enableChangeVariableCodegen
2 -import {identity} from 'shared-runtime';
3 -
4 -const $ = 'module_$';
5 -const t0 = 'module_t0';
6 -const c_0 = 'module_c_0';
7 -function useFoo(props: {value: number}): number {
8 - const a = {
9 - foo() {
10 - const b = {
11 - bar() {
12 - console.log($);
13 - console.log(t0);
14 - console.log(c_0);
15 - return identity(props.value);
16 - },
17 - };
18 - return b;
19 - },
20 - };
21 - return a.foo().bar();
22 -}
23 -
24 -export const FIXTURE_ENTRYPOINT = {
25 - fn: useFoo,
26 - params: [{value: 42}],
27 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables.expect.md deleted
-62
@@ -1,62 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableChangeVariableCodegen
6 -import {identity} from 'shared-runtime';
7 -
8 -const $ = 'module_$';
9 -const t0 = 'module_t0';
10 -const c_0 = 'module_c_0';
11 -function useFoo(props: {value: number}): number {
12 - const results = identity(props.value);
13 - console.log($);
14 - console.log(t0);
15 - console.log(c_0);
16 - return results;
17 -}
18 -
19 -export const FIXTURE_ENTRYPOINT = {
20 - fn: useFoo,
21 - params: [{value: 0}],
22 -};
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @enableChangeVariableCodegen
30 -import { identity } from "shared-runtime";
31 -
32 -const $ = "module_$";
33 -const t0 = "module_t0";
34 -const c_0 = "module_c_0";
35 -function useFoo(props) {
36 - const $0 = _c(2);
37 - const c_00 = $0[0] !== props.value;
38 - let t1;
39 - if (c_00) {
40 - t1 = identity(props.value);
41 - $0[0] = props.value;
42 - $0[1] = t1;
43 - } else {
44 - t1 = $0[1];
45 - }
46 - const results = t1;
47 - console.log($);
48 - console.log(t0);
49 - console.log(c_0);
50 - return results;
51 -}
52 -
53 -export const FIXTURE_ENTRYPOINT = {
54 - fn: useFoo,
55 - params: [{ value: 0 }],
56 -};
57 -
58 -```
59 -
60 -### Eval output
61 -(kind: ok) 0
62 -logs: ['module_$','module_t0','module_c_0']
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables.ts deleted
-18
@@ -1,18 +0,0 @@
1 -// @enableChangeVariableCodegen
2 -import {identity} from 'shared-runtime';
3 -
4 -const $ = 'module_$';
5 -const t0 = 'module_t0';
6 -const c_0 = 'module_c_0';
7 -function useFoo(props: {value: number}): number {
8 - const results = identity(props.value);
9 - console.log($);
10 - console.log(t0);
11 - console.log(c_0);
12 - return results;
13 -}
14 -
15 -export const FIXTURE_ENTRYPOINT = {
16 - fn: useFoo,
17 - params: [{value: 0}],
18 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-dont-add-hook-guards-on-retry.expect.md deleted
-27
@@ -1,27 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @flow @enableEmitHookGuards @panicThreshold:"none" @enableFire
6 -
7 -component Foo(useDynamicHook) {
8 - useDynamicHook();
9 - return <div>hello world</div>;
10 -}
11 -
12 -```
13 -
14 -## Code
15 -
16 -```javascript
17 -function Foo({
18 - useDynamicHook,
19 -}: $ReadOnly<{ useDynamicHook: any }>): React.Node {
20 - useDynamicHook();
21 - return <div>hello world</div>;
22 -}
23 -
24 -```
25 -
26 -### Eval output
27 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-dont-add-hook-guards-on-retry.js deleted
-6
@@ -1,6 +0,0 @@
1 -// @flow @enableEmitHookGuards @panicThreshold:"none" @enableFire
2 -
3 -component Foo(useDynamicHook) {
4 - useDynamicHook();
5 - return <div>hello world</div>;
6 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md deleted
-90
@@ -1,90 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @flow @validatePreserveExistingMemoizationGuarantees @enableUseTypeAnnotations
6 -import {useMemo} from 'react';
7 -import {useFragment} from 'shared-runtime';
8 -
9 -// This is a version of error.todo-repro-missing-memoization-lack-of-phi-types
10 -// with explicit type annotations and using enableUseTypeAnnotations to demonstrate
11 -// that type information is sufficient to preserve memoization in this example
12 -function Component() {
13 - const data = useFragment();
14 - const nodes: Array<any> = data.nodes ?? [];
15 - const flatMap: Array<any> = nodes.flatMap(node => node.items);
16 - const filtered: Array<any> = flatMap.filter(item => item != null);
17 - const map: Array<any> = useMemo(() => filtered.map(), [filtered]);
18 - const index: Array<any> = filtered.findIndex(x => x === null);
19 -
20 - return (
21 - <div>
22 - {map}
23 - {index}
24 - </div>
25 - );
26 -}
27 -
28 -```
29 -
30 -## Code
31 -
32 -```javascript
33 -import { c as _c } from "react/compiler-runtime";
34 -import { useMemo } from "react";
35 -import { useFragment } from "shared-runtime";
36 -
37 -function Component() {
38 - const $ = _c(7);
39 - const data = useFragment();
40 - let t0;
41 - if ($[0] !== data.nodes) {
42 - const nodes = data.nodes ?? [];
43 - const flatMap = nodes.flatMap(_temp);
44 - t0 = flatMap.filter(_temp2);
45 - $[0] = data.nodes;
46 - $[1] = t0;
47 - } else {
48 - t0 = $[1];
49 - }
50 - const filtered = t0;
51 - let t1;
52 - if ($[2] !== filtered) {
53 - t1 = filtered.map();
54 - $[2] = filtered;
55 - $[3] = t1;
56 - } else {
57 - t1 = $[3];
58 - }
59 - const map = t1;
60 - const index = filtered.findIndex(_temp3);
61 - let t2;
62 - if ($[4] !== index || $[5] !== map) {
63 - t2 = (
64 - <div>
65 - {map}
66 - {index}
67 - </div>
68 - );
69 - $[4] = index;
70 - $[5] = map;
71 - $[6] = t2;
72 - } else {
73 - t2 = $[6];
74 - }
75 - return t2;
76 -}
77 -function _temp3(x) {
78 - return x === null;
79 -}
80 -function _temp2(item) {
81 - return item != null;
82 -}
83 -function _temp(node) {
84 - return node.items;
85 -}
86 -
87 -```
88 -
89 -### Eval output
90 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.js deleted
-22
@@ -1,22 +0,0 @@
1 -// @flow @validatePreserveExistingMemoizationGuarantees @enableUseTypeAnnotations
2 -import {useMemo} from 'react';
3 -import {useFragment} from 'shared-runtime';
4 -
5 -// This is a version of error.todo-repro-missing-memoization-lack-of-phi-types
6 -// with explicit type annotations and using enableUseTypeAnnotations to demonstrate
7 -// that type information is sufficient to preserve memoization in this example
8 -function Component() {
9 - const data = useFragment();
10 - const nodes: Array<any> = data.nodes ?? [];
11 - const flatMap: Array<any> = nodes.flatMap(node => node.items);
12 - const filtered: Array<any> = flatMap.filter(item => item != null);
13 - const map: Array<any> = useMemo(() => filtered.map(), [filtered]);
14 - const index: Array<any> = filtered.findIndex(x => x === null);
15 -
16 - return (
17 - <div>
18 - {map}
19 - {index}
20 - </div>
21 - );
22 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-array-destructuring.expect.md deleted
-33
@@ -1,33 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess
6 -function App() {
7 - const [foo, bar] = useContext(MyContext);
8 - return <Bar foo={foo} bar={bar} />;
9 -}
10 -
11 -```
12 -
13 -## Code
14 -
15 -```javascript
16 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess
17 -function App() {
18 - const $ = _c(3);
19 - const [foo, bar] = useContext(MyContext);
20 - let t0;
21 - if ($[0] !== bar || $[1] !== foo) {
22 - t0 = <Bar foo={foo} bar={bar} />;
23 - $[0] = bar;
24 - $[1] = foo;
25 - $[2] = t0;
26 - } else {
27 - t0 = $[2];
28 - }
29 - return t0;
30 -}
31 -
32 -```
33 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-array-destructuring.js deleted
-5
@@ -1,5 +0,0 @@
1 -// @lowerContextAccess
2 -function App() {
3 - const [foo, bar] = useContext(MyContext);
4 - return <Bar foo={foo} bar={bar} />;
5 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-destructure-multiple.expect.md deleted
-37
@@ -1,37 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess
6 -function App() {
7 - const context = useContext(MyContext);
8 - const {foo} = context;
9 - const {bar} = context;
10 - return <Bar foo={foo} bar={bar} />;
11 -}
12 -
13 -```
14 -
15 -## Code
16 -
17 -```javascript
18 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess
19 -function App() {
20 - const $ = _c(3);
21 - const context = useContext(MyContext);
22 - const { foo } = context;
23 - const { bar } = context;
24 - let t0;
25 - if ($[0] !== bar || $[1] !== foo) {
26 - t0 = <Bar foo={foo} bar={bar} />;
27 - $[0] = bar;
28 - $[1] = foo;
29 - $[2] = t0;
30 - } else {
31 - t0 = $[2];
32 - }
33 - return t0;
34 -}
35 -
36 -```
37 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-destructure-multiple.js deleted
-7
@@ -1,7 +0,0 @@
1 -// @lowerContextAccess
2 -function App() {
3 - const context = useContext(MyContext);
4 - const {foo} = context;
5 - const {bar} = context;
6 - return <Bar foo={foo} bar={bar} />;
7 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-mixed-array-obj.expect.md deleted
-37
@@ -1,37 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess
6 -function App() {
7 - const context = useContext(MyContext);
8 - const [foo] = context;
9 - const {bar} = context;
10 - return <Bar foo={foo} bar={bar} />;
11 -}
12 -
13 -```
14 -
15 -## Code
16 -
17 -```javascript
18 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess
19 -function App() {
20 - const $ = _c(3);
21 - const context = useContext(MyContext);
22 - const [foo] = context;
23 - const { bar } = context;
24 - let t0;
25 - if ($[0] !== bar || $[1] !== foo) {
26 - t0 = <Bar foo={foo} bar={bar} />;
27 - $[0] = bar;
28 - $[1] = foo;
29 - $[2] = t0;
30 - } else {
31 - t0 = $[2];
32 - }
33 - return t0;
34 -}
35 -
36 -```
37 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-mixed-array-obj.js deleted
-7
@@ -1,7 +0,0 @@
1 -// @lowerContextAccess
2 -function App() {
3 - const context = useContext(MyContext);
4 - const [foo] = context;
5 - const {bar} = context;
6 - return <Bar foo={foo} bar={bar} />;
7 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-nested-destructuring.expect.md deleted
-37
@@ -1,37 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess
6 -function App() {
7 - const {
8 - joe: {foo},
9 - bar,
10 - } = useContext(MyContext);
11 - return <Bar foo={foo} bar={bar} />;
12 -}
13 -
14 -```
15 -
16 -## Code
17 -
18 -```javascript
19 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess
20 -function App() {
21 - const $ = _c(3);
22 - const { joe: t0, bar } = useContext(MyContext);
23 - const { foo } = t0;
24 - let t1;
25 - if ($[0] !== bar || $[1] !== foo) {
26 - t1 = <Bar foo={foo} bar={bar} />;
27 - $[0] = bar;
28 - $[1] = foo;
29 - $[2] = t1;
30 - } else {
31 - t1 = $[2];
32 - }
33 - return t1;
34 -}
35 -
36 -```
37 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-nested-destructuring.js deleted
-8
@@ -1,8 +0,0 @@
1 -// @lowerContextAccess
2 -function App() {
3 - const {
4 - joe: {foo},
5 - bar,
6 - } = useContext(MyContext);
7 - return <Bar foo={foo} bar={bar} />;
8 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-property-load.expect.md deleted
-37
@@ -1,37 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @lowerContextAccess
6 -function App() {
7 - const context = useContext(MyContext);
8 - const foo = context.foo;
9 - const bar = context.bar;
10 - return <Bar foo={foo} bar={bar} />;
11 -}
12 -
13 -```
14 -
15 -## Code
16 -
17 -```javascript
18 -import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess
19 -function App() {
20 - const $ = _c(3);
21 - const context = useContext(MyContext);
22 - const foo = context.foo;
23 - const bar = context.bar;
24 - let t0;
25 - if ($[0] !== bar || $[1] !== foo) {
26 - t0 = <Bar foo={foo} bar={bar} />;
27 - $[0] = bar;
28 - $[1] = foo;
29 - $[2] = t0;
30 - } else {
31 - t0 = $[2];
32 - }
33 - return t0;
34 -}
35 -
36 -```
37 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-property-load.js deleted
-7
@@ -1,7 +0,0 @@
1 -// @lowerContextAccess
2 -function App() {
3 - const context = useContext(MyContext);
4 - const foo = context.foo;
5 - const bar = context.bar;
6 - return <Bar foo={foo} bar={bar} />;
7 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-capitalized-fn-call.expect.md deleted
-51
@@ -1,51 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validateNoCapitalizedCalls @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -const CapitalizedCall = require('shared-runtime').sum;
8 -
9 -function Component({prop1, bar}) {
10 - const foo = () => {
11 - console.log(prop1);
12 - };
13 - useEffect(() => {
14 - fire(foo(prop1));
15 - fire(foo());
16 - fire(bar());
17 - });
18 -
19 - return CapitalizedCall();
20 -}
21 -
22 -```
23 -
24 -## Code
25 -
26 -```javascript
27 -import { useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire @panicThreshold:"none"
28 -import { fire } from "react";
29 -const CapitalizedCall = require("shared-runtime").sum;
30 -
31 -function Component(t0) {
32 - const { prop1, bar } = t0;
33 - const foo = () => {
34 - console.log(prop1);
35 - };
36 - const t1 = useFire(foo);
37 - const t2 = useFire(bar);
38 -
39 - useEffect(() => {
40 - t1(prop1);
41 - t1();
42 - t2();
43 - });
44 -
45 - return CapitalizedCall();
46 -}
47 -
48 -```
49 -
50 -### Eval output
51 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-capitalized-fn-call.js deleted
-16
@@ -1,16 +0,0 @@
1 -// @validateNoCapitalizedCalls @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -const CapitalizedCall = require('shared-runtime').sum;
4 -
5 -function Component({prop1, bar}) {
6 - const foo = () => {
7 - console.log(prop1);
8 - };
9 - useEffect(() => {
10 - fire(foo(prop1));
11 - fire(foo());
12 - fire(bar());
13 - });
14 -
15 - return CapitalizedCall();
16 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-eslint-suppressions.expect.md deleted
-55
@@ -1,55 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @panicThreshold:"none"
6 -import {useRef} from 'react';
7 -
8 -function Component({props, bar}) {
9 - const foo = () => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(foo(props));
14 - fire(foo());
15 - fire(bar());
16 - });
17 -
18 - const ref = useRef(null);
19 - // eslint-disable-next-line react-hooks/rules-of-hooks
20 - ref.current = 'bad';
21 - return <button ref={ref} />;
22 -}
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold:"none"
30 -import { useRef } from "react";
31 -
32 -function Component(t0) {
33 - const { props, bar } = t0;
34 - const foo = () => {
35 - console.log(props);
36 - };
37 - const t1 = useFire(foo);
38 - const t2 = useFire(bar);
39 -
40 - useEffect(() => {
41 - t1(props);
42 - t1();
43 - t2();
44 - });
45 -
46 - const ref = useRef(null);
47 -
48 - ref.current = "bad";
49 - return <button ref={ref} />;
50 -}
51 -
52 -```
53 -
54 -### Eval output
55 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-eslint-suppressions.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @enableFire @panicThreshold:"none"
2 -import {useRef} from 'react';
3 -
4 -function Component({props, bar}) {
5 - const foo = () => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(foo(props));
10 - fire(foo());
11 - fire(bar());
12 - });
13 -
14 - const ref = useRef(null);
15 - // eslint-disable-next-line react-hooks/rules-of-hooks
16 - ref.current = 'bad';
17 - return <button ref={ref} />;
18 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-preserve-memo.expect.md deleted
-51
@@ -1,51 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @validatePreserveExistingMemoizationGuarantees @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -import {sum} from 'shared-runtime';
8 -
9 -function Component({prop1, bar}) {
10 - const foo = () => {
11 - console.log(prop1);
12 - };
13 - useEffect(() => {
14 - fire(foo(prop1));
15 - fire(foo());
16 - fire(bar());
17 - });
18 -
19 - return useMemo(() => sum(bar), []);
20 -}
21 -
22 -```
23 -
24 -## Code
25 -
26 -```javascript
27 -import { useFire } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableFire @panicThreshold:"none"
28 -import { fire } from "react";
29 -import { sum } from "shared-runtime";
30 -
31 -function Component(t0) {
32 - const { prop1, bar } = t0;
33 - const foo = () => {
34 - console.log(prop1);
35 - };
36 - const t1 = useFire(foo);
37 - const t2 = useFire(bar);
38 -
39 - useEffect(() => {
40 - t1(prop1);
41 - t1();
42 - t2();
43 - });
44 -
45 - return useMemo(() => sum(bar), []);
46 -}
47 -
48 -```
49 -
50 -### Eval output
51 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-preserve-memo.js deleted
-16
@@ -1,16 +0,0 @@
1 -// @validatePreserveExistingMemoizationGuarantees @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -import {sum} from 'shared-runtime';
4 -
5 -function Component({prop1, bar}) {
6 - const foo = () => {
7 - console.log(prop1);
8 - };
9 - useEffect(() => {
10 - fire(foo(prop1));
11 - fire(foo());
12 - fire(bar());
13 - });
14 -
15 - return useMemo(() => sum(bar), []);
16 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-prop-write.expect.md deleted
-42
@@ -1,42 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -
8 -function Component({prop1}) {
9 - const foo = () => {
10 - console.log(prop1);
11 - };
12 - useEffect(() => {
13 - fire(foo(prop1));
14 - });
15 - prop1.value += 1;
16 -}
17 -
18 -```
19 -
20 -## Code
21 -
22 -```javascript
23 -import { useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold:"none"
24 -import { fire } from "react";
25 -
26 -function Component(t0) {
27 - const { prop1 } = t0;
28 - const foo = () => {
29 - console.log(prop1);
30 - };
31 - const t1 = useFire(foo);
32 -
33 - useEffect(() => {
34 - t1(prop1);
35 - });
36 - prop1.value = prop1.value + 1;
37 -}
38 -
39 -```
40 -
41 -### Eval output
42 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-prop-write.js deleted
-12
@@ -1,12 +0,0 @@
1 -// @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -
4 -function Component({prop1}) {
5 - const foo = () => {
6 - console.log(prop1);
7 - };
8 - useEffect(() => {
9 - fire(foo(prop1));
10 - });
11 - prop1.value += 1;
12 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-ref-current-access.expect.md deleted
-51
@@ -1,51 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @flow @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -import {print} from 'shared-runtime';
8 -
9 -component Component(prop1, ref) {
10 - const foo = () => {
11 - console.log(prop1);
12 - };
13 - useEffect(() => {
14 - fire(foo(prop1));
15 - bar();
16 - fire(foo());
17 - });
18 -
19 - print(ref.current);
20 - return null;
21 -}
22 -
23 -```
24 -
25 -## Code
26 -
27 -```javascript
28 -import { useFire } from "react/compiler-runtime";
29 -import { fire } from "react";
30 -import { print } from "shared-runtime";
31 -
32 -const Component = React.forwardRef(Component_withRef);
33 -function Component_withRef(t0, ref) {
34 - const { prop1 } = t0;
35 - const foo = () => {
36 - console.log(prop1);
37 - };
38 - const t1 = useFire(foo);
39 - useEffect(() => {
40 - t1(prop1);
41 - bar();
42 - t1();
43 - });
44 - print(ref.current);
45 - return null;
46 -}
47 -
48 -```
49 -
50 -### Eval output
51 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-ref-current-access.js deleted
-17
@@ -1,17 +0,0 @@
1 -// @flow @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -import {print} from 'shared-runtime';
4 -
5 -component Component(prop1, ref) {
6 - const foo = () => {
7 - console.log(prop1);
8 - };
9 - useEffect(() => {
10 - fire(foo(prop1));
11 - bar();
12 - fire(foo());
13 - });
14 -
15 - print(ref.current);
16 - return null;
17 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.todo-syntax.expect.md deleted
-48
@@ -1,48 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -
8 -/**
9 - * Note that a react compiler-based transform still has limitations on JS syntax.
10 - * In practice, we expect to surface these as actionable errors to the user, in
11 - * the same way that invalid `fire` calls error.
12 - */
13 -function Component({prop1}) {
14 - const foo = () => {
15 - try {
16 - console.log(prop1);
17 - } finally {
18 - console.log('jbrown215');
19 - }
20 - };
21 - useEffect(() => {
22 - fire(foo());
23 - });
24 -}
25 -
26 -```
27 -
28 -
29 -## Error
30 -
31 -```
32 -Found 1 error:
33 -
34 -Error: [Fire] Untransformed reference to compiler-required feature.
35 -
36 -Either remove this `fire` call or ensure it is successfully transformed by the compiler Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (11:4).
37 -
38 -error.todo-syntax.ts:18:4
39 - 16 | };
40 - 17 | useEffect(() => {
41 -> 18 | fire(foo());
42 - | ^^^^ Untransformed `fire` call
43 - 19 | });
44 - 20 | }
45 - 21 |
46 -```
47 -
48 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.todo-syntax.js deleted
-20
@@ -1,20 +0,0 @@
1 -// @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -
4 -/**
5 - * Note that a react compiler-based transform still has limitations on JS syntax.
6 - * In practice, we expect to surface these as actionable errors to the user, in
7 - * the same way that invalid `fire` calls error.
8 - */
9 -function Component({prop1}) {
10 - const foo = () => {
11 - try {
12 - console.log(prop1);
13 - } finally {
14 - console.log('jbrown215');
15 - }
16 - };
17 - useEffect(() => {
18 - fire(foo());
19 - });
20 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.untransformed-fire-reference.expect.md deleted
-30
@@ -1,30 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -
8 -console.log(fire == null);
9 -
10 -```
11 -
12 -
13 -## Error
14 -
15 -```
16 -Found 1 error:
17 -
18 -Error: [Fire] Untransformed reference to compiler-required feature.
19 -
20 -Either remove this `fire` call or ensure it is successfully transformed by the compiler.
21 -
22 -error.untransformed-fire-reference.ts:4:12
23 - 2 | import {fire} from 'react';
24 - 3 |
25 -> 4 | console.log(fire == null);
26 - | ^^^^ Untransformed `fire` call
27 - 5 |
28 -```
29 -
30 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.untransformed-fire-reference.js deleted
-4
@@ -1,4 +0,0 @@
1 -// @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -
4 -console.log(fire == null);
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.use-no-memo.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -
8 -/**
9 - * TODO: we should eventually distinguish between `use no memo` and `use no
10 - * compiler` directives. The former should be used to *only* disable memoization
11 - * features.
12 - */
13 -function Component({props, bar}) {
14 - 'use no memo';
15 - const foo = () => {
16 - console.log(props);
17 - };
18 - useEffect(() => {
19 - fire(foo(props));
20 - fire(foo());
21 - fire(bar());
22 - });
23 -
24 - return null;
25 -}
26 -
27 -```
28 -
29 -
30 -## Error
31 -
32 -```
33 -Found 1 error:
34 -
35 -Error: [Fire] Untransformed reference to compiler-required feature.
36 -
37 -Either remove this `fire` call or ensure it is successfully transformed by the compiler.
38 -
39 -error.use-no-memo.ts:15:4
40 - 13 | };
41 - 14 | useEffect(() => {
42 -> 15 | fire(foo(props));
43 - | ^^^^ Untransformed `fire` call
44 - 16 | fire(foo());
45 - 17 | fire(bar());
46 - 18 | });
47 -```
48 -
49 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.use-no-memo.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -
4 -/**
5 - * TODO: we should eventually distinguish between `use no memo` and `use no
6 - * compiler` directives. The former should be used to *only* disable memoization
7 - * features.
8 - */
9 -function Component({props, bar}) {
10 - 'use no memo';
11 - const foo = () => {
12 - console.log(props);
13 - };
14 - useEffect(() => {
15 - fire(foo(props));
16 - fire(foo());
17 - fire(bar());
18 - });
19 -
20 - return null;
21 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/infer-deps-on-retry.expect.md deleted
-59
@@ -1,59 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @inferEffectDependencies @panicThreshold:"none"
6 -import {useRef, AUTODEPS} from 'react';
7 -import {useSpecialEffect} from 'shared-runtime';
8 -
9 -/**
10 - * The retry pipeline disables memoization features, which means we need to
11 - * provide an alternate implementation of effect dependencies which does not
12 - * rely on memoization.
13 - */
14 -function useFoo({cond}) {
15 - const ref = useRef();
16 - const derived = cond ? ref.current : makeObject();
17 - useSpecialEffect(
18 - () => {
19 - log(derived);
20 - },
21 - [derived],
22 - AUTODEPS
23 - );
24 - return ref;
25 -}
26 -
27 -```
28 -
29 -## Code
30 -
31 -```javascript
32 -// @inferEffectDependencies @panicThreshold:"none"
33 -import { useRef, AUTODEPS } from "react";
34 -import { useSpecialEffect } from "shared-runtime";
35 -
36 -/**
37 - * The retry pipeline disables memoization features, which means we need to
38 - * provide an alternate implementation of effect dependencies which does not
39 - * rely on memoization.
40 - */
41 -function useFoo(t0) {
42 - const { cond } = t0;
43 - const ref = useRef();
44 - const derived = cond ? ref.current : makeObject();
45 - useSpecialEffect(
46 - () => {
47 - log(derived);
48 - },
49 -
50 - [derived],
51 - [derived],
52 - );
53 - return ref;
54 -}
55 -
56 -```
57 -
58 -### Eval output
59 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/infer-deps-on-retry.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @inferEffectDependencies @panicThreshold:"none"
2 -import {useRef, AUTODEPS} from 'react';
3 -import {useSpecialEffect} from 'shared-runtime';
4 -
5 -/**
6 - * The retry pipeline disables memoization features, which means we need to
7 - * provide an alternate implementation of effect dependencies which does not
8 - * rely on memoization.
9 - */
10 -function useFoo({cond}) {
11 - const ref = useRef();
12 - const derived = cond ? ref.current : makeObject();
13 - useSpecialEffect(
14 - () => {
15 - log(derived);
16 - },
17 - [derived],
18 - AUTODEPS
19 - );
20 - return ref;
21 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/no-fire-todo-syntax-shouldnt-throw.expect.md deleted
-95
@@ -1,95 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @panicThreshold:"none"
6 -import {fire} from 'react';
7 -
8 -/**
9 - * Compilation of this file should succeed.
10 - */
11 -function NonFireComponent({prop1}) {
12 - /**
13 - * This component bails out but does not use fire
14 - */
15 - const foo = () => {
16 - try {
17 - console.log(prop1);
18 - } finally {
19 - console.log('jbrown215');
20 - }
21 - };
22 - useEffect(() => {
23 - foo();
24 - });
25 -}
26 -
27 -function FireComponent(props) {
28 - /**
29 - * This component uses fire and compiles successfully
30 - */
31 - const foo = props => {
32 - console.log(props);
33 - };
34 - useEffect(() => {
35 - fire(foo(props));
36 - });
37 -
38 - return null;
39 -}
40 -
41 -```
42 -
43 -## Code
44 -
45 -```javascript
46 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold:"none"
47 -import { fire } from "react";
48 -
49 -/**
50 - * Compilation of this file should succeed.
51 - */
52 -function NonFireComponent({ prop1 }) {
53 - /**
54 - * This component bails out but does not use fire
55 - */
56 - const foo = () => {
57 - try {
58 - console.log(prop1);
59 - } finally {
60 - console.log("jbrown215");
61 - }
62 - };
63 - useEffect(() => {
64 - foo();
65 - });
66 -}
67 -
68 -function FireComponent(props) {
69 - const $ = _c(3);
70 -
71 - const foo = _temp;
72 - const t0 = useFire(foo);
73 - let t1;
74 - if ($[0] !== props || $[1] !== t0) {
75 - t1 = () => {
76 - t0(props);
77 - };
78 - $[0] = props;
79 - $[1] = t0;
80 - $[2] = t1;
81 - } else {
82 - t1 = $[2];
83 - }
84 - useEffect(t1);
85 -
86 - return null;
87 -}
88 -function _temp(props_0) {
89 - console.log(props_0);
90 -}
91 -
92 -```
93 -
94 -### Eval output
95 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/no-fire-todo-syntax-shouldnt-throw.js deleted
-35
@@ -1,35 +0,0 @@
1 -// @enableFire @panicThreshold:"none"
2 -import {fire} from 'react';
3 -
4 -/**
5 - * Compilation of this file should succeed.
6 - */
7 -function NonFireComponent({prop1}) {
8 - /**
9 - * This component bails out but does not use fire
10 - */
11 - const foo = () => {
12 - try {
13 - console.log(prop1);
14 - } finally {
15 - console.log('jbrown215');
16 - }
17 - };
18 - useEffect(() => {
19 - foo();
20 - });
21 -}
22 -
23 -function FireComponent(props) {
24 - /**
25 - * This component uses fire and compiles successfully
26 - */
27 - const foo = props => {
28 - console.log(props);
29 - };
30 - useEffect(() => {
31 - fire(foo(props));
32 - });
33 -
34 - return null;
35 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md deleted
-59
@@ -1,59 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @panicThreshold:"none"
6 -import {fire, useEffect} from 'react';
7 -import {Stringify} from 'shared-runtime';
8 -
9 -/**
10 - * When @enableFire is specified, retry compilation with validation passes (e.g.
11 - * hook usage) disabled
12 - */
13 -function Component(props) {
14 - const foo = props => {
15 - console.log(props);
16 - };
17 -
18 - if (props.cond) {
19 - useEffect(() => {
20 - fire(foo(props));
21 - });
22 - }
23 -
24 - return <Stringify />;
25 -}
26 -
27 -```
28 -
29 -## Code
30 -
31 -```javascript
32 -import { useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold:"none"
33 -import { fire, useEffect } from "react";
34 -import { Stringify } from "shared-runtime";
35 -
36 -/**
37 - * When @enableFire is specified, retry compilation with validation passes (e.g.
38 - * hook usage) disabled
39 - */
40 -function Component(props) {
41 - const foo = _temp;
42 -
43 - if (props.cond) {
44 - const t0 = useFire(foo);
45 - useEffect(() => {
46 - t0(props);
47 - });
48 - }
49 -
50 - return <Stringify />;
51 -}
52 -function _temp(props_0) {
53 - console.log(props_0);
54 -}
55 -
56 -```
57 -
58 -### Eval output
59 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @enableFire @panicThreshold:"none"
2 -import {fire, useEffect} from 'react';
3 -import {Stringify} from 'shared-runtime';
4 -
5 -/**
6 - * When @enableFire is specified, retry compilation with validation passes (e.g.
7 - * hook usage) disabled
8 - */
9 -function Component(props) {
10 - const foo = props => {
11 - console.log(props);
12 - };
13 -
14 - if (props.cond) {
15 - useEffect(() => {
16 - fire(foo(props));
17 - });
18 - }
19 -
20 - return <Stringify />;
21 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/basic.expect.md deleted
-53
@@ -1,53 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(foo(props));
14 - });
15 -
16 - return null;
17 -}
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire
25 -import { fire } from "react";
26 -
27 -function Component(props) {
28 - const $ = _c(3);
29 - const foo = _temp;
30 - const t0 = useFire(foo);
31 - let t1;
32 - if ($[0] !== props || $[1] !== t0) {
33 - t1 = () => {
34 - t0(props);
35 - };
36 - $[0] = props;
37 - $[1] = t0;
38 - $[2] = t1;
39 - } else {
40 - t1 = $[2];
41 - }
42 - useEffect(t1);
43 -
44 - return null;
45 -}
46 -function _temp(props_0) {
47 - console.log(props_0);
48 -}
49 -
50 -```
51 -
52 -### Eval output
53 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/basic.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(foo(props));
10 - });
11 -
12 - return null;
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/deep-scope.expect.md deleted
-74
@@ -1,74 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - function nested() {
14 - function nestedAgain() {
15 - function nestedThrice() {
16 - fire(foo(props));
17 - }
18 - nestedThrice();
19 - }
20 - nestedAgain();
21 - }
22 - nested();
23 - });
24 -
25 - return null;
26 -}
27 -
28 -```
29 -
30 -## Code
31 -
32 -```javascript
33 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire
34 -import { fire } from "react";
35 -
36 -function Component(props) {
37 - const $ = _c(3);
38 - const foo = _temp;
39 - const t0 = useFire(foo);
40 - let t1;
41 - if ($[0] !== props || $[1] !== t0) {
42 - t1 = () => {
43 - const nested = function nested() {
44 - const nestedAgain = function nestedAgain() {
45 - const nestedThrice = function nestedThrice() {
46 - t0(props);
47 - };
48 -
49 - nestedThrice();
50 - };
51 -
52 - nestedAgain();
53 - };
54 -
55 - nested();
56 - };
57 - $[0] = props;
58 - $[1] = t0;
59 - $[2] = t1;
60 - } else {
61 - t1 = $[2];
62 - }
63 - useEffect(t1);
64 -
65 - return null;
66 -}
67 -function _temp(props_0) {
68 - console.log(props_0);
69 -}
70 -
71 -```
72 -
73 -### Eval output
74 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/deep-scope.js deleted
-22
@@ -1,22 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - function nested() {
10 - function nestedAgain() {
11 - function nestedThrice() {
12 - fire(foo(props));
13 - }
14 - nestedThrice();
15 - }
16 - nestedAgain();
17 - }
18 - nested();
19 - });
20 -
21 - return null;
22 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-mix-fire-and-no-fire.expect.md deleted
-46
@@ -1,46 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - function nested() {
14 - fire(foo(props));
15 - foo(props);
16 - }
17 -
18 - nested();
19 - });
20 -
21 - return null;
22 -}
23 -
24 -```
25 -
26 -
27 -## Error
28 -
29 -```
30 -Found 1 error:
31 -
32 -Error: Cannot compile `fire`
33 -
34 -All uses of foo must be either used with a fire() call in this effect or not used with a fire() call at all. foo was used with fire() on line 10:10 in this effect.
35 -
36 -error.invalid-mix-fire-and-no-fire.ts:11:6
37 - 9 | function nested() {
38 - 10 | fire(foo(props));
39 -> 11 | foo(props);
40 - | ^^^ Cannot compile `fire`
41 - 12 | }
42 - 13 |
43 - 14 | nested();
44 -```
45 -
46 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-mix-fire-and-no-fire.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - function nested() {
10 - fire(foo(props));
11 - foo(props);
12 - }
13 -
14 - nested();
15 - });
16 -
17 - return null;
18 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-multiple-args.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component({bar, baz}) {
9 - const foo = () => {
10 - console.log(bar, baz);
11 - };
12 - useEffect(() => {
13 - fire(foo(bar), baz);
14 - });
15 -
16 - return null;
17 -}
18 -
19 -```
20 -
21 -
22 -## Error
23 -
24 -```
25 -Found 1 error:
26 -
27 -Error: Cannot compile `fire`
28 -
29 -fire() can only take in a single call expression as an argument but received multiple arguments.
30 -
31 -error.invalid-multiple-args.ts:9:4
32 - 7 | };
33 - 8 | useEffect(() => {
34 -> 9 | fire(foo(bar), baz);
35 - | ^^^^^^^^^^^^^^^^^^^ Cannot compile `fire`
36 - 10 | });
37 - 11 |
38 - 12 | return null;
39 -```
40 -
41 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-multiple-args.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component({bar, baz}) {
5 - const foo = () => {
6 - console.log(bar, baz);
7 - };
8 - useEffect(() => {
9 - fire(foo(bar), baz);
10 - });
11 -
12 - return null;
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-nested-use-effect.expect.md deleted
-47
@@ -1,47 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enable
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - useEffect(() => {
14 - function nested() {
15 - fire(foo(props));
16 - }
17 -
18 - nested();
19 - });
20 - });
21 -
22 - return null;
23 -}
24 -
25 -```
26 -
27 -
28 -## Error
29 -
30 -```
31 -Found 1 error:
32 -
33 -Error: Hooks must be called at the top level in the body of a function component or custom hook, and may not be called within function expressions. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning)
34 -
35 -Cannot call useEffect within a function expression.
36 -
37 -error.invalid-nested-use-effect.ts:9:4
38 - 7 | };
39 - 8 | useEffect(() => {
40 -> 9 | useEffect(() => {
41 - | ^^^^^^^^^ Hooks must be called at the top level in the body of a function component or custom hook, and may not be called within function expressions. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning)
42 - 10 | function nested() {
43 - 11 | fire(foo(props));
44 - 12 | }
45 -```
46 -
47 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-nested-use-effect.js deleted
-19
@@ -1,19 +0,0 @@
1 -// @enable
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - useEffect(() => {
10 - function nested() {
11 - fire(foo(props));
12 - }
13 -
14 - nested();
15 - });
16 - });
17 -
18 - return null;
19 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-not-call.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = () => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(props);
14 - });
15 -
16 - return null;
17 -}
18 -
19 -```
20 -
21 -
22 -## Error
23 -
24 -```
25 -Found 1 error:
26 -
27 -Error: Cannot compile `fire`
28 -
29 -`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed.
30 -
31 -error.invalid-not-call.ts:9:4
32 - 7 | };
33 - 8 | useEffect(() => {
34 -> 9 | fire(props);
35 - | ^^^^^^^^^^^ Cannot compile `fire`
36 - 10 | });
37 - 11 |
38 - 12 | return null;
39 -```
40 -
41 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-not-call.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = () => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(props);
10 - });
11 -
12 - return null;
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md deleted
-56
@@ -1,56 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire, useCallback} from 'react';
7 -
8 -function Component({props, bar}) {
9 - const foo = () => {
10 - console.log(props);
11 - };
12 - fire(foo(props));
13 -
14 - useCallback(() => {
15 - fire(foo(props));
16 - }, [foo, props]);
17 -
18 - return null;
19 -}
20 -
21 -```
22 -
23 -
24 -## Error
25 -
26 -```
27 -Found 2 errors:
28 -
29 -Error: Cannot compile `fire`
30 -
31 -Cannot use `fire` outside of a useEffect function.
32 -
33 -error.invalid-outside-effect.ts:8:2
34 - 6 | console.log(props);
35 - 7 | };
36 -> 8 | fire(foo(props));
37 - | ^^^^ Cannot compile `fire`
38 - 9 |
39 - 10 | useCallback(() => {
40 - 11 | fire(foo(props));
41 -
42 -Error: Cannot compile `fire`
43 -
44 -Cannot use `fire` outside of a useEffect function.
45 -
46 -error.invalid-outside-effect.ts:11:4
47 - 9 |
48 - 10 | useCallback(() => {
49 -> 11 | fire(foo(props));
50 - | ^^^^ Cannot compile `fire`
51 - 12 | }, [foo, props]);
52 - 13 |
53 - 14 | return null;
54 -```
55 -
56 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.js deleted
-15
@@ -1,15 +0,0 @@
1 -// @enableFire
2 -import {fire, useCallback} from 'react';
3 -
4 -function Component({props, bar}) {
5 - const foo = () => {
6 - console.log(props);
7 - };
8 - fire(foo(props));
9 -
10 - useCallback(() => {
11 - fire(foo(props));
12 - }, [foo, props]);
13 -
14 - return null;
15 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md deleted
-44
@@ -1,44 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 -
13 - const deps = [foo, props];
14 -
15 - useEffect(() => {
16 - fire(foo(props));
17 - }, deps);
18 -
19 - return null;
20 -}
21 -
22 -```
23 -
24 -
25 -## Error
26 -
27 -```
28 -Found 1 error:
29 -
30 -Error: Cannot compile `fire`
31 -
32 -You must use an array literal for an effect dependency array when that effect uses `fire()`.
33 -
34 -error.invalid-rewrite-deps-no-array-literal.ts:13:5
35 - 11 | useEffect(() => {
36 - 12 | fire(foo(props));
37 -> 13 | }, deps);
38 - | ^^^^ Cannot compile `fire`
39 - 14 |
40 - 15 | return null;
41 - 16 | }
42 -```
43 -
44 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.js deleted
-16
@@ -1,16 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 -
9 - const deps = [foo, props];
10 -
11 - useEffect(() => {
12 - fire(foo(props));
13 - }, deps);
14 -
15 - return null;
16 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md deleted
-47
@@ -1,47 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 -
13 - const deps = [foo, props];
14 -
15 - useEffect(
16 - () => {
17 - fire(foo(props));
18 - },
19 - ...deps
20 - );
21 -
22 - return null;
23 -}
24 -
25 -```
26 -
27 -
28 -## Error
29 -
30 -```
31 -Found 1 error:
32 -
33 -Error: Cannot compile `fire`
34 -
35 -You must use an array literal for an effect dependency array when that effect uses `fire()`.
36 -
37 -error.invalid-rewrite-deps-spread.ts:15:7
38 - 13 | fire(foo(props));
39 - 14 | },
40 -> 15 | ...deps
41 - | ^^^^ Cannot compile `fire`
42 - 16 | );
43 - 17 |
44 - 18 | return null;
45 -```
46 -
47 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.js deleted
-19
@@ -1,19 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 -
9 - const deps = [foo, props];
10 -
11 - useEffect(
12 - () => {
13 - fire(foo(props));
14 - },
15 - ...deps
16 - );
17 -
18 - return null;
19 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-spread.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = () => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(...foo);
14 - });
15 -
16 - return null;
17 -}
18 -
19 -```
20 -
21 -
22 -## Error
23 -
24 -```
25 -Found 1 error:
26 -
27 -Error: Cannot compile `fire`
28 -
29 -fire() can only take in a single call expression as an argument but received a spread argument.
30 -
31 -error.invalid-spread.ts:9:4
32 - 7 | };
33 - 8 | useEffect(() => {
34 -> 9 | fire(...foo);
35 - | ^^^^^^^^^^^^ Cannot compile `fire`
36 - 10 | });
37 - 11 |
38 - 12 | return null;
39 -```
40 -
41 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-spread.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = () => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(...foo);
10 - });
11 -
12 - return null;
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.todo-method.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = () => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(props.foo());
14 - });
15 -
16 - return null;
17 -}
18 -
19 -```
20 -
21 -
22 -## Error
23 -
24 -```
25 -Found 1 error:
26 -
27 -Error: Cannot compile `fire`
28 -
29 -`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed.
30 -
31 -error.todo-method.ts:9:4
32 - 7 | };
33 - 8 | useEffect(() => {
34 -> 9 | fire(props.foo());
35 - | ^^^^^^^^^^^^^^^^^ Cannot compile `fire`
36 - 10 | });
37 - 11 |
38 - 12 | return null;
39 -```
40 -
41 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.todo-method.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = () => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(props.foo());
10 - });
11 -
12 - return null;
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.expect.md deleted
-73
@@ -1,73 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire @enableEmitHookGuards
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(foo(props));
14 - });
15 -
16 - return null;
17 -}
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { $dispatcherGuard } from "react-compiler-runtime";
25 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire @enableEmitHookGuards
26 -import { fire } from "react";
27 -
28 -function Component(props) {
29 - const $ = _c(3);
30 - try {
31 - $dispatcherGuard(0);
32 - const foo = _temp;
33 - const t0 = (function () {
34 - try {
35 - $dispatcherGuard(2);
36 - return useFire(foo);
37 - } finally {
38 - $dispatcherGuard(3);
39 - }
40 - })();
41 - let t1;
42 - if ($[0] !== props || $[1] !== t0) {
43 - t1 = () => {
44 - t0(props);
45 - };
46 - $[0] = props;
47 - $[1] = t0;
48 - $[2] = t1;
49 - } else {
50 - t1 = $[2];
51 - }
52 - (function () {
53 - try {
54 - $dispatcherGuard(2);
55 - return useEffect(t1);
56 - } finally {
57 - $dispatcherGuard(3);
58 - }
59 - })();
60 -
61 - return null;
62 - } finally {
63 - $dispatcherGuard(1);
64 - }
65 -}
66 -function _temp(props_0) {
67 - console.log(props_0);
68 -}
69 -
70 -```
71 -
72 -### Eval output
73 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableFire @enableEmitHookGuards
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(foo(props));
10 - });
11 -
12 - return null;
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/multiple-scope.expect.md deleted
-66
@@ -1,66 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(foo(props));
14 - function nested() {
15 - fire(foo(props));
16 - function innerNested() {
17 - fire(foo(props));
18 - }
19 - }
20 -
21 - nested();
22 - });
23 -
24 - return null;
25 -}
26 -
27 -```
28 -
29 -## Code
30 -
31 -```javascript
32 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire
33 -import { fire } from "react";
34 -
35 -function Component(props) {
36 - const $ = _c(3);
37 - const foo = _temp;
38 - const t0 = useFire(foo);
39 - let t1;
40 - if ($[0] !== props || $[1] !== t0) {
41 - t1 = () => {
42 - t0(props);
43 - const nested = function nested() {
44 - t0(props);
45 - };
46 -
47 - nested();
48 - };
49 - $[0] = props;
50 - $[1] = t0;
51 - $[2] = t1;
52 - } else {
53 - t1 = $[2];
54 - }
55 - useEffect(t1);
56 -
57 - return null;
58 -}
59 -function _temp(props_0) {
60 - console.log(props_0);
61 -}
62 -
63 -```
64 -
65 -### Eval output
66 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/multiple-scope.js deleted
-21
@@ -1,21 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(foo(props));
10 - function nested() {
11 - fire(foo(props));
12 - function innerNested() {
13 - fire(foo(props));
14 - }
15 - }
16 -
17 - nested();
18 - });
19 -
20 - return null;
21 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repeated-calls.expect.md deleted
-62
@@ -1,62 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = () => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(foo(props));
14 - fire(foo(props));
15 - });
16 -
17 - return null;
18 -}
19 -
20 -```
21 -
22 -## Code
23 -
24 -```javascript
25 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire
26 -import { fire } from "react";
27 -
28 -function Component(props) {
29 - const $ = _c(5);
30 - let t0;
31 - if ($[0] !== props) {
32 - t0 = () => {
33 - console.log(props);
34 - };
35 - $[0] = props;
36 - $[1] = t0;
37 - } else {
38 - t0 = $[1];
39 - }
40 - const foo = t0;
41 - const t1 = useFire(foo);
42 - let t2;
43 - if ($[2] !== props || $[3] !== t1) {
44 - t2 = () => {
45 - t1(props);
46 - t1(props);
47 - };
48 - $[2] = props;
49 - $[3] = t1;
50 - $[4] = t2;
51 - } else {
52 - t2 = $[4];
53 - }
54 - useEffect(t2);
55 -
56 - return null;
57 -}
58 -
59 -```
60 -
61 -### Eval output
62 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repeated-calls.js deleted
-14
@@ -1,14 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = () => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(foo(props));
10 - fire(foo(props));
11 - });
12 -
13 - return null;
14 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repro-dont-add-hook-guards-on-retry.expect.md deleted
-49
@@ -1,49 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @flow @enableEmitHookGuards @panicThreshold:"none" @enableFire
6 -import {useEffect, fire} from 'react';
7 -
8 -function Component(props, useDynamicHook) {
9 - 'use memo';
10 - useDynamicHook();
11 - const foo = props => {
12 - console.log(props);
13 - };
14 - useEffect(() => {
15 - fire(foo(props));
16 - });
17 -
18 - return <div>hello world</div>;
19 -}
20 -
21 -```
22 -
23 -## Code
24 -
25 -```javascript
26 -import { useFire } from "react/compiler-runtime";
27 -import { useEffect, fire } from "react";
28 -
29 -function Component(props, useDynamicHook) {
30 - "use memo";
31 -
32 - useDynamicHook();
33 - const foo = _temp;
34 - const t0 = useFire(foo);
35 -
36 - useEffect(() => {
37 - t0(props);
38 - });
39 -
40 - return <div>hello world</div>;
41 -}
42 -function _temp(props_0) {
43 - console.log(props_0);
44 -}
45 -
46 -```
47 -
48 -### Eval output
49 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repro-dont-add-hook-guards-on-retry.js deleted
-15
@@ -1,15 +0,0 @@
1 -// @flow @enableEmitHookGuards @panicThreshold:"none" @enableFire
2 -import {useEffect, fire} from 'react';
3 -
4 -function Component(props, useDynamicHook) {
5 - 'use memo';
6 - useDynamicHook();
7 - const foo = props => {
8 - console.log(props);
9 - };
10 - useEffect(() => {
11 - fire(foo(props));
12 - });
13 -
14 - return <div>hello world</div>;
15 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/rewrite-deps.expect.md deleted
-57
@@ -1,57 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - const foo = props => {
10 - console.log(props);
11 - };
12 - useEffect(() => {
13 - fire(foo(props));
14 - }, [foo, props]);
15 -
16 - return null;
17 -}
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire
25 -import { fire } from "react";
26 -
27 -function Component(props) {
28 - const $ = _c(4);
29 - const foo = _temp;
30 - const t0 = useFire(foo);
31 - let t1;
32 - let t2;
33 - if ($[0] !== props || $[1] !== t0) {
34 - t1 = () => {
35 - t0(props);
36 - };
37 - t2 = [t0, props];
38 - $[0] = props;
39 - $[1] = t0;
40 - $[2] = t1;
41 - $[3] = t2;
42 - } else {
43 - t1 = $[2];
44 - t2 = $[3];
45 - }
46 - useEffect(t1, t2);
47 -
48 - return null;
49 -}
50 -function _temp(props_0) {
51 - console.log(props_0);
52 -}
53 -
54 -```
55 -
56 -### Eval output
57 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/rewrite-deps.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - const foo = props => {
6 - console.log(props);
7 - };
8 - useEffect(() => {
9 - fire(foo(props));
10 - }, [foo, props]);
11 -
12 - return null;
13 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/shared-hook-calls.expect.md deleted
-81
@@ -1,81 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component({bar, baz}) {
9 - const foo = () => {
10 - console.log(bar);
11 - };
12 - useEffect(() => {
13 - fire(foo(bar));
14 - fire(baz(bar));
15 - });
16 -
17 - useEffect(() => {
18 - fire(foo(bar));
19 - });
20 -
21 - return null;
22 -}
23 -
24 -```
25 -
26 -## Code
27 -
28 -```javascript
29 -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire
30 -import { fire } from "react";
31 -
32 -function Component(t0) {
33 - const $ = _c(9);
34 - const { bar, baz } = t0;
35 - let t1;
36 - if ($[0] !== bar) {
37 - t1 = () => {
38 - console.log(bar);
39 - };
40 - $[0] = bar;
41 - $[1] = t1;
42 - } else {
43 - t1 = $[1];
44 - }
45 - const foo = t1;
46 - const t2 = useFire(foo);
47 - const t3 = useFire(baz);
48 - let t4;
49 - if ($[2] !== bar || $[3] !== t2 || $[4] !== t3) {
50 - t4 = () => {
51 - t2(bar);
52 - t3(bar);
53 - };
54 - $[2] = bar;
55 - $[3] = t2;
56 - $[4] = t3;
57 - $[5] = t4;
58 - } else {
59 - t4 = $[5];
60 - }
61 - useEffect(t4);
62 - let t5;
63 - if ($[6] !== bar || $[7] !== t2) {
64 - t5 = () => {
65 - t2(bar);
66 - };
67 - $[6] = bar;
68 - $[7] = t2;
69 - $[8] = t5;
70 - } else {
71 - t5 = $[8];
72 - }
73 - useEffect(t5);
74 -
75 - return null;
76 -}
77 -
78 -```
79 -
80 -### Eval output
81 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/shared-hook-calls.js deleted
-18
@@ -1,18 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component({bar, baz}) {
5 - const foo = () => {
6 - console.log(bar);
7 - };
8 - useEffect(() => {
9 - fire(foo(bar));
10 - fire(baz(bar));
11 - });
12 -
13 - useEffect(() => {
14 - fire(foo(bar));
15 - });
16 -
17 - return null;
18 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/use-effect-no-args-no-op.expect.md deleted
-31
@@ -1,31 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableFire
6 -import {fire} from 'react';
7 -
8 -function Component(props) {
9 - useEffect();
10 -
11 - return null;
12 -}
13 -
14 -```
15 -
16 -## Code
17 -
18 -```javascript
19 -// @enableFire
20 -import { fire } from "react";
21 -
22 -function Component(props) {
23 - useEffect();
24 -
25 - return null;
26 -}
27 -
28 -```
29 -
30 -### Eval output
31 -(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/use-effect-no-args-no-op.js deleted
-8
@@ -1,8 +0,0 @@
1 -// @enableFire
2 -import {fire} from 'react';
3 -
4 -function Component(props) {
5 - useEffect();
6 -
7 - return null;
8 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/todo_type-annotations-props.expect.md deleted
-48
@@ -1,48 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableUseTypeAnnotations
6 -function useArray(items: Array<number>) {
7 - // With type information we know that the callback cannot escape
8 - // and does not need to be memoized, only the result needs to be
9 - // memoized:
10 - return items.filter(x => x !== 0);
11 -}
12 -
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: useArray,
15 - params: [[1, 0, 2, 0, 3, 0, 42]],
16 -};
17 -
18 -```
19 -
20 -## Code
21 -
22 -```javascript
23 -import { c as _c } from "react/compiler-runtime"; // @enableUseTypeAnnotations
24 -function useArray(items) {
25 - const $ = _c(2);
26 - let t0;
27 - if ($[0] !== items) {
28 - t0 = items.filter(_temp);
29 - $[0] = items;
30 - $[1] = t0;
31 - } else {
32 - t0 = $[1];
33 - }
34 - return t0;
35 -}
36 -function _temp(x) {
37 - return x !== 0;
38 -}
39 -
40 -export const FIXTURE_ENTRYPOINT = {
41 - fn: useArray,
42 - params: [[1, 0, 2, 0, 3, 0, 42]],
43 -};
44 -
45 -```
46 -
47 -### Eval output
48 -(kind: ok) [1,2,3,42]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/todo_type-annotations-props.ts deleted
-12
@@ -1,12 +0,0 @@
1 -// @enableUseTypeAnnotations
2 -function useArray(items: Array<number>) {
3 - // With type information we know that the callback cannot escape
4 - // and does not need to be memoized, only the result needs to be
5 - // memoized:
6 - return items.filter(x => x !== 0);
7 -}
8 -
9 -export const FIXTURE_ENTRYPOINT = {
10 - fn: useArray,
11 - params: [[1, 0, 2, 0, 3, 0, 42]],
12 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-array.expect.md deleted
-71
@@ -1,71 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableUseTypeAnnotations
6 -function Component(props: {id: number}) {
7 - const x = makeArray(props.id) as number[];
8 - const y = x.at(0);
9 - return y;
10 -}
11 -
12 -function makeArray<T>(x: T): Array<T> {
13 - return [x];
14 -}
15 -
16 -export const FIXTURE_ENTRYPOINT = {
17 - fn: Component,
18 - params: [{id: 42}],
19 -};
20 -
21 -```
22 -
23 -## Code
24 -
25 -```javascript
26 -import { c as _c } from "react/compiler-runtime"; // @enableUseTypeAnnotations
27 -function Component(props) {
28 - const $ = _c(4);
29 - let t0;
30 - if ($[0] !== props.id) {
31 - t0 = makeArray(props.id);
32 - $[0] = props.id;
33 - $[1] = t0;
34 - } else {
35 - t0 = $[1];
36 - }
37 - const x = t0 as number[];
38 - let t1;
39 - if ($[2] !== x) {
40 - t1 = x.at(0);
41 - $[2] = x;
42 - $[3] = t1;
43 - } else {
44 - t1 = $[3];
45 - }
46 - const y = t1;
47 - return y;
48 -}
49 -
50 -function makeArray(x) {
51 - const $ = _c(2);
52 - let t0;
53 - if ($[0] !== x) {
54 - t0 = [x];
55 - $[0] = x;
56 - $[1] = t0;
57 - } else {
58 - t0 = $[1];
59 - }
60 - return t0;
61 -}
62 -
63 -export const FIXTURE_ENTRYPOINT = {
64 - fn: Component,
65 - params: [{ id: 42 }],
66 -};
67 -
68 -```
69 -
70 -### Eval output
71 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-array.ts deleted
-15
@@ -1,15 +0,0 @@
1 -// @enableUseTypeAnnotations
2 -function Component(props: {id: number}) {
3 - const x = makeArray(props.id) as number[];
4 - const y = x.at(0);
5 - return y;
6 -}
7 -
8 -function makeArray<T>(x: T): Array<T> {
9 - return [x];
10 -}
11 -
12 -export const FIXTURE_ENTRYPOINT = {
13 - fn: Component,
14 - params: [{id: 42}],
15 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-array_.flow.expect.md deleted
-58
@@ -1,58 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @flow @enableUseTypeAnnotations
6 -import {identity, makeArray} from 'shared-runtime';
7 -
8 -function Component(props: {id: number}) {
9 - const x = (makeArray(props.id): Array<number>);
10 - const y = x.at(0);
11 - return y;
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{id: 42}],
17 -};
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { c as _c } from "react/compiler-runtime";
25 -import { identity, makeArray } from "shared-runtime";
26 -
27 -function Component(props) {
28 - const $ = _c(4);
29 - let t0;
30 - if ($[0] !== props.id) {
31 - t0 = makeArray(props.id);
32 - $[0] = props.id;
33 - $[1] = t0;
34 - } else {
35 - t0 = $[1];
36 - }
37 - const x = (t0: Array<number>);
38 - let t1;
39 - if ($[2] !== x) {
40 - t1 = x.at(0);
41 - $[2] = x;
42 - $[3] = t1;
43 - } else {
44 - t1 = $[3];
45 - }
46 - const y = t1;
47 - return y;
48 -}
49 -
50 -export const FIXTURE_ENTRYPOINT = {
51 - fn: Component,
52 - params: [{ id: 42 }],
53 -};
54 -
55 -```
56 -
57 -### Eval output
58 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-array_.flow.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @flow @enableUseTypeAnnotations
2 -import {identity, makeArray} from 'shared-runtime';
3 -
4 -function Component(props: {id: number}) {
5 - const x = (makeArray(props.id): Array<number>);
6 - const y = x.at(0);
7 - return y;
8 -}
9 -
10 -export const FIXTURE_ENTRYPOINT = {
11 - fn: Component,
12 - params: [{id: 42}],
13 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-number.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableUseTypeAnnotations
6 -import {identity} from 'shared-runtime';
7 -
8 -function Component(props: {id: number}) {
9 - const x = identity(props.id);
10 - const y = x as number;
11 - return y;
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{id: 42}],
17 -};
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -// @enableUseTypeAnnotations
25 -import { identity } from "shared-runtime";
26 -
27 -function Component(props) {
28 - const x = identity(props.id);
29 - const y = x as number;
30 - return y;
31 -}
32 -
33 -export const FIXTURE_ENTRYPOINT = {
34 - fn: Component,
35 - params: [{ id: 42 }],
36 -};
37 -
38 -```
39 -
40 -### Eval output
41 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-number.ts deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableUseTypeAnnotations
2 -import {identity} from 'shared-runtime';
3 -
4 -function Component(props: {id: number}) {
5 - const x = identity(props.id);
6 - const y = x as number;
7 - return y;
8 -}
9 -
10 -export const FIXTURE_ENTRYPOINT = {
11 - fn: Component,
12 - params: [{id: 42}],
13 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-number_.flow.expect.md deleted
-40
@@ -1,40 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @flow @enableUseTypeAnnotations
6 -import {identity} from 'shared-runtime';
7 -
8 -function Component(props: {id: number}) {
9 - const x = identity(props.id);
10 - const y = (x: number);
11 - return y;
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{id: 42}],
17 -};
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { identity } from "shared-runtime";
25 -
26 -function Component(props) {
27 - const x = identity(props.id);
28 - const y = (x: number);
29 - return y;
30 -}
31 -
32 -export const FIXTURE_ENTRYPOINT = {
33 - fn: Component,
34 - params: [{ id: 42 }],
35 -};
36 -
37 -```
38 -
39 -### Eval output
40 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-as-number_.flow.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @flow @enableUseTypeAnnotations
2 -import {identity} from 'shared-runtime';
3 -
4 -function Component(props: {id: number}) {
5 - const x = identity(props.id);
6 - const y = (x: number);
7 - return y;
8 -}
9 -
10 -export const FIXTURE_ENTRYPOINT = {
11 - fn: Component,
12 - params: [{id: 42}],
13 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-satisfies-array.expect.md deleted
-71
@@ -1,71 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableUseTypeAnnotations
6 -function Component(props: {id: number}) {
7 - const x = makeArray(props.id) satisfies number[];
8 - const y = x.at(0);
9 - return y;
10 -}
11 -
12 -function makeArray<T>(x: T): Array<T> {
13 - return [x];
14 -}
15 -
16 -export const FIXTURE_ENTRYPOINT = {
17 - fn: Component,
18 - params: [{id: 42}],
19 -};
20 -
21 -```
22 -
23 -## Code
24 -
25 -```javascript
26 -import { c as _c } from "react/compiler-runtime"; // @enableUseTypeAnnotations
27 -function Component(props) {
28 - const $ = _c(4);
29 - let t0;
30 - if ($[0] !== props.id) {
31 - t0 = makeArray(props.id);
32 - $[0] = props.id;
33 - $[1] = t0;
34 - } else {
35 - t0 = $[1];
36 - }
37 - const x = t0 satisfies number[];
38 - let t1;
39 - if ($[2] !== x) {
40 - t1 = x.at(0);
41 - $[2] = x;
42 - $[3] = t1;
43 - } else {
44 - t1 = $[3];
45 - }
46 - const y = t1;
47 - return y;
48 -}
49 -
50 -function makeArray(x) {
51 - const $ = _c(2);
52 - let t0;
53 - if ($[0] !== x) {
54 - t0 = [x];
55 - $[0] = x;
56 - $[1] = t0;
57 - } else {
58 - t0 = $[1];
59 - }
60 - return t0;
61 -}
62 -
63 -export const FIXTURE_ENTRYPOINT = {
64 - fn: Component,
65 - params: [{ id: 42 }],
66 -};
67 -
68 -```
69 -
70 -### Eval output
71 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-satisfies-array.ts deleted
-15
@@ -1,15 +0,0 @@
1 -// @enableUseTypeAnnotations
2 -function Component(props: {id: number}) {
3 - const x = makeArray(props.id) satisfies number[];
4 - const y = x.at(0);
5 - return y;
6 -}
7 -
8 -function makeArray<T>(x: T): Array<T> {
9 - return [x];
10 -}
11 -
12 -export const FIXTURE_ENTRYPOINT = {
13 - fn: Component,
14 - params: [{id: 42}],
15 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-satisfies-number.expect.md deleted
-41
@@ -1,41 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableUseTypeAnnotations
6 -import {identity} from 'shared-runtime';
7 -
8 -function Component(props: {id: number}) {
9 - const x = identity(props.id);
10 - const y = x satisfies number;
11 - return y;
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{id: 42}],
17 -};
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -// @enableUseTypeAnnotations
25 -import { identity } from "shared-runtime";
26 -
27 -function Component(props) {
28 - const x = identity(props.id);
29 - const y = x satisfies number;
30 - return y;
31 -}
32 -
33 -export const FIXTURE_ENTRYPOINT = {
34 - fn: Component,
35 - params: [{ id: 42 }],
36 -};
37 -
38 -```
39 -
40 -### Eval output
41 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-satisfies-number.ts deleted
-13
@@ -1,13 +0,0 @@
1 -// @enableUseTypeAnnotations
2 -import {identity} from 'shared-runtime';
3 -
4 -function Component(props: {id: number}) {
5 - const x = identity(props.id);
6 - const y = x satisfies number;
7 - return y;
8 -}
9 -
10 -export const FIXTURE_ENTRYPOINT = {
11 - fn: Component,
12 - params: [{id: 42}],
13 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array.expect.md deleted
-63
@@ -1,63 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableUseTypeAnnotations
6 -function Component(props: {id: number}) {
7 - const x: number[] = makeArray(props.id);
8 - const y = x.at(0);
9 - return y;
10 -}
11 -
12 -function makeArray<T>(x: T): Array<T> {
13 - return [x];
14 -}
15 -
16 -export const FIXTURE_ENTRYPOINT = {
17 - fn: Component,
18 - params: [{id: 42}],
19 -};
20 -
21 -```
22 -
23 -## Code
24 -
25 -```javascript
26 -import { c as _c } from "react/compiler-runtime"; // @enableUseTypeAnnotations
27 -function Component(props) {
28 - const $ = _c(2);
29 - let t0;
30 - if ($[0] !== props.id) {
31 - const x = makeArray(props.id);
32 - t0 = x.at(0);
33 - $[0] = props.id;
34 - $[1] = t0;
35 - } else {
36 - t0 = $[1];
37 - }
38 - const y = t0;
39 - return y;
40 -}
41 -
42 -function makeArray(x) {
43 - const $ = _c(2);
44 - let t0;
45 - if ($[0] !== x) {
46 - t0 = [x];
47 - $[0] = x;
48 - $[1] = t0;
49 - } else {
50 - t0 = $[1];
51 - }
52 - return t0;
53 -}
54 -
55 -export const FIXTURE_ENTRYPOINT = {
56 - fn: Component,
57 - params: [{ id: 42 }],
58 -};
59 -
60 -```
61 -
62 -### Eval output
63 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array.ts deleted
-15
@@ -1,15 +0,0 @@
1 -// @enableUseTypeAnnotations
2 -function Component(props: {id: number}) {
3 - const x: number[] = makeArray(props.id);
4 - const y = x.at(0);
5 - return y;
6 -}
7 -
8 -function makeArray<T>(x: T): Array<T> {
9 - return [x];
10 -}
11 -
12 -export const FIXTURE_ENTRYPOINT = {
13 - fn: Component,
14 - params: [{id: 42}],
15 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array_.flow.expect.md deleted
-67
@@ -1,67 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @flow @enableUseTypeAnnotations
6 -import {identity} from 'shared-runtime';
7 -
8 -function Component(props: {id: number}) {
9 - const x: Array<number> = makeArray(props.id);
10 - const y = x.at(0);
11 - return y;
12 -}
13 -
14 -function makeArray<T>(x: T): Array<T> {
15 - return [x];
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: Component,
20 - params: [{id: 42}],
21 -};
22 -
23 -```
24 -
25 -## Code
26 -
27 -```javascript
28 -import { c as _c } from "react/compiler-runtime";
29 -import { identity } from "shared-runtime";
30 -
31 -function Component(props) {
32 - const $ = _c(2);
33 - let t0;
34 - if ($[0] !== props.id) {
35 - const x = makeArray(props.id);
36 - t0 = x.at(0);
37 - $[0] = props.id;
38 - $[1] = t0;
39 - } else {
40 - t0 = $[1];
41 - }
42 - const y = t0;
43 - return y;
44 -}
45 -
46 -function makeArray(x) {
47 - const $ = _c(2);
48 - let t0;
49 - if ($[0] !== x) {
50 - t0 = [x];
51 - $[0] = x;
52 - $[1] = t0;
53 - } else {
54 - t0 = $[1];
55 - }
56 - return t0;
57 -}
58 -
59 -export const FIXTURE_ENTRYPOINT = {
60 - fn: Component,
61 - params: [{ id: 42 }],
62 -};
63 -
64 -```
65 -
66 -### Eval output
67 -(kind: ok) 42
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array_.flow.js deleted
-17
@@ -1,17 +0,0 @@
1 -// @flow @enableUseTypeAnnotations
2 -import {identity} from 'shared-runtime';
3 -
4 -function Component(props: {id: number}) {
5 - const x: Array<number> = makeArray(props.id);
6 - const y = x.at(0);
7 - return y;
8 -}
9 -
10 -function makeArray<T>(x: T): Array<T> {
11 - return [x];
12 -}
13 -
14 -export const FIXTURE_ENTRYPOINT = {
15 - fn: Component,
16 - params: [{id: 42}],
17 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-simple-preserved-nomemo.expect.md deleted
-66
@@ -1,66 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @disableMemoizationForDebugging
6 -import {useMemo} from 'react';
7 -
8 -function Component({a}) {
9 - let x = useMemo(() => [a], []);
10 - return <div>{x}</div>;
11 -}
12 -
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: Component,
15 - params: [{a: 42}],
16 - isComponent: true,
17 -};
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { c as _c } from "react/compiler-runtime"; // @disableMemoizationForDebugging
25 -import { useMemo } from "react";
26 -
27 -function Component(t0) {
28 - const $ = _c(5);
29 - const { a } = t0;
30 - let t1;
31 - if ($[0] !== a || true) {
32 - t1 = () => [a];
33 - $[0] = a;
34 - $[1] = t1;
35 - } else {
36 - t1 = $[1];
37 - }
38 - let t2;
39 - if ($[2] === Symbol.for("react.memo_cache_sentinel") || true) {
40 - t2 = [];
41 - $[2] = t2;
42 - } else {
43 - t2 = $[2];
44 - }
45 - const x = useMemo(t1, t2);
46 - let t3;
47 - if ($[3] !== x || true) {
48 - t3 = <div>{x}</div>;
49 - $[3] = x;
50 - $[4] = t3;
51 - } else {
52 - t3 = $[4];
53 - }
54 - return t3;
55 -}
56 -
57 -export const FIXTURE_ENTRYPOINT = {
58 - fn: Component,
59 - params: [{ a: 42 }],
60 - isComponent: true,
61 -};
62 -
63 -```
64 -
65 -### Eval output
66 -(kind: ok) <div>42</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-simple-preserved-nomemo.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @disableMemoizationForDebugging
2 -import {useMemo} from 'react';
3 -
4 -function Component({a}) {
5 - let x = useMemo(() => [a], []);
6 - return <div>{x}</div>;
7 -}
8 -
9 -export const FIXTURE_ENTRYPOINT = {
10 - fn: Component,
11 - params: [{a: 42}],
12 - isComponent: true,
13 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-simple-preserved.expect.md deleted
-66
@@ -1,66 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enablePreserveExistingManualUseMemo
6 -import {useMemo} from 'react';
7 -
8 -function Component({a}) {
9 - let x = useMemo(() => [a], []);
10 - return <div>{x}</div>;
11 -}
12 -
13 -export const FIXTURE_ENTRYPOINT = {
14 - fn: Component,
15 - params: [{a: 42}],
16 - isComponent: true,
17 -};
18 -
19 -```
20 -
21 -## Code
22 -
23 -```javascript
24 -import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingManualUseMemo
25 -import { useMemo } from "react";
26 -
27 -function Component(t0) {
28 - const $ = _c(5);
29 - const { a } = t0;
30 - let t1;
31 - if ($[0] !== a) {
32 - t1 = () => [a];
33 - $[0] = a;
34 - $[1] = t1;
35 - } else {
36 - t1 = $[1];
37 - }
38 - let t2;
39 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
40 - t2 = [];
41 - $[2] = t2;
42 - } else {
43 - t2 = $[2];
44 - }
45 - const x = useMemo(t1, t2);
46 - let t3;
47 - if ($[3] !== x) {
48 - t3 = <div>{x}</div>;
49 - $[3] = x;
50 - $[4] = t3;
51 - } else {
52 - t3 = $[4];
53 - }
54 - return t3;
55 -}
56 -
57 -export const FIXTURE_ENTRYPOINT = {
58 - fn: Component,
59 - params: [{ a: 42 }],
60 - isComponent: true,
61 -};
62 -
63 -```
64 -
65 -### Eval output
66 -(kind: ok) <div>42</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-simple-preserved.js deleted
-13
@@ -1,13 +0,0 @@
1 -// @enablePreserveExistingManualUseMemo
2 -import {useMemo} from 'react';
3 -
4 -function Component({a}) {
5 - let x = useMemo(() => [a], []);
6 - return <div>{x}</div>;
7 -}
8 -
9 -export const FIXTURE_ENTRYPOINT = {
10 - fn: Component,
11 - params: [{a: 42}],
12 - isComponent: true,
13 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-and-other-hook-unpruned-dependency.expect.md deleted
-92
@@ -1,92 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -import {useState} from 'react'; // @enableChangeDetectionForDebugging
6 -
7 -function useOther(x) {
8 - return x;
9 -}
10 -
11 -function Component(props) {
12 - const w = f(props.x);
13 - const z = useOther(w);
14 - const [x, _] = useState(z);
15 - return <div>{x}</div>;
16 -}
17 -
18 -function f(x) {
19 - return x;
20 -}
21 -
22 -export const FIXTURE_ENTRYPOINT = {
23 - fn: Component,
24 - params: [{x: 42}],
25 - isComponent: true,
26 -};
27 -
28 -```
29 -
30 -## Code
31 -
32 -```javascript
33 -import { $structuralCheck } from "react-compiler-runtime";
34 -import { c as _c } from "react/compiler-runtime";
35 -import { useState } from "react"; // @enableChangeDetectionForDebugging
36 -
37 -function useOther(x) {
38 - return x;
39 -}
40 -
41 -function Component(props) {
42 - const $ = _c(4);
43 - let t0;
44 - {
45 - t0 = f(props.x);
46 - let condition = $[0] !== props.x;
47 - if (!condition) {
48 - let old$t0 = $[1];
49 - $structuralCheck(old$t0, t0, "t0", "Component", "cached", "(8:8)");
50 - }
51 - $[0] = props.x;
52 - $[1] = t0;
53 - if (condition) {
54 - t0 = f(props.x);
55 - $structuralCheck($[1], t0, "t0", "Component", "recomputed", "(8:8)");
56 - t0 = $[1];
57 - }
58 - }
59 - const w = t0;
60 - const z = useOther(w);
61 - const [x] = useState(z);
62 - let t1;
63 - {
64 - t1 = <div>{x}</div>;
65 - let condition = $[2] !== x;
66 - if (!condition) {
67 - let old$t1 = $[3];
68 - $structuralCheck(old$t1, t1, "t1", "Component", "cached", "(11:11)");
69 - }
70 - $[2] = x;
71 - $[3] = t1;
72 - if (condition) {
73 - t1 = <div>{x}</div>;
74 - $structuralCheck($[3], t1, "t1", "Component", "recomputed", "(11:11)");
75 - t1 = $[3];
76 - }
77 - }
78 - return t1;
79 -}
80 -
81 -function f(x) {
82 - return x;
83 -}
84 -
85 -export const FIXTURE_ENTRYPOINT = {
86 - fn: Component,
87 - params: [{ x: 42 }],
88 - isComponent: true,
89 -};
90 -
91 -```
92 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-and-other-hook-unpruned-dependency.js deleted
-22
@@ -1,22 +0,0 @@
1 -import {useState} from 'react'; // @enableChangeDetectionForDebugging
2 -
3 -function useOther(x) {
4 - return x;
5 -}
6 -
7 -function Component(props) {
8 - const w = f(props.x);
9 - const z = useOther(w);
10 - const [x, _] = useState(z);
11 - return <div>{x}</div>;
12 -}
13 -
14 -function f(x) {
15 - return x;
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: Component,
20 - params: [{x: 42}],
21 - isComponent: true,
22 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-pruned-dependency-change-detect.expect.md deleted
-52
@@ -1,52 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableChangeDetectionForDebugging
6 -import {useState} from 'react';
7 -
8 -function Component(props) {
9 - const [x, _] = useState(f(props.x));
10 - return <div>{x}</div>;
11 -}
12 -
13 -```
14 -
15 -## Code
16 -
17 -```javascript
18 -import { $structuralCheck } from "react-compiler-runtime";
19 -import { c as _c } from "react/compiler-runtime"; // @enableChangeDetectionForDebugging
20 -import { useState } from "react";
21 -
22 -function Component(props) {
23 - const $ = _c(3);
24 - let t0;
25 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
26 - t0 = f(props.x);
27 - $[0] = t0;
28 - } else {
29 - t0 = $[0];
30 - }
31 - const [x] = useState(t0);
32 - let t1;
33 - {
34 - t1 = <div>{x}</div>;
35 - let condition = $[1] !== x;
36 - if (!condition) {
37 - let old$t1 = $[2];
38 - $structuralCheck(old$t1, t1, "t1", "Component", "cached", "(6:6)");
39 - }
40 - $[1] = x;
41 - $[2] = t1;
42 - if (condition) {
43 - t1 = <div>{x}</div>;
44 - $structuralCheck($[2], t1, "t1", "Component", "recomputed", "(6:6)");
45 - t1 = $[2];
46 - }
47 - }
48 - return t1;
49 -}
50 -
51 -```
52 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-pruned-dependency-change-detect.js deleted
-7
@@ -1,7 +0,0 @@
1 -// @enableChangeDetectionForDebugging
2 -import {useState} from 'react';
3 -
4 -function Component(props) {
5 - const [x, _] = useState(f(props.x));
6 - return <div>{x}</div>;
7 -}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md deleted
-98
@@ -1,98 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -import {useState} from 'react'; // @enableChangeDetectionForDebugging
6 -
7 -function Component(props) {
8 - const w = f(props.x);
9 - const [x, _] = useState(w);
10 - return (
11 - <div>
12 - {x}
13 - {w}
14 - </div>
15 - );
16 -}
17 -
18 -function f(x) {
19 - return x;
20 -}
21 -
22 -export const FIXTURE_ENTRYPOINT = {
23 - fn: Component,
24 - params: [{x: 42}],
25 - isComponent: true,
26 -};
27 -
28 -```
29 -
30 -## Code
31 -
32 -```javascript
33 -import { $structuralCheck } from "react-compiler-runtime";
34 -import { c as _c } from "react/compiler-runtime";
35 -import { useState } from "react"; // @enableChangeDetectionForDebugging
36 -
37 -function Component(props) {
38 - const $ = _c(5);
39 - let t0;
40 - {
41 - t0 = f(props.x);
42 - let condition = $[0] !== props.x;
43 - if (!condition) {
44 - let old$t0 = $[1];
45 - $structuralCheck(old$t0, t0, "t0", "Component", "cached", "(4:4)");
46 - }
47 - $[0] = props.x;
48 - $[1] = t0;
49 - if (condition) {
50 - t0 = f(props.x);
51 - $structuralCheck($[1], t0, "t0", "Component", "recomputed", "(4:4)");
52 - t0 = $[1];
53 - }
54 - }
55 - const w = t0;
56 - const [x] = useState(w);
57 - let t1;
58 - {
59 - t1 = (
60 - <div>
61 - {x}
62 - {w}
63 - </div>
64 - );
65 - let condition = $[2] !== w || $[3] !== x;
66 - if (!condition) {
67 - let old$t1 = $[4];
68 - $structuralCheck(old$t1, t1, "t1", "Component", "cached", "(7:10)");
69 - }
70 - $[2] = w;
71 - $[3] = x;
72 - $[4] = t1;
73 - if (condition) {
74 - t1 = (
75 - <div>
76 - {x}
77 - {w}
78 - </div>
79 - );
80 - $structuralCheck($[4], t1, "t1", "Component", "recomputed", "(7:10)");
81 - t1 = $[4];
82 - }
83 - }
84 - return t1;
85 -}
86 -
87 -function f(x) {
88 - return x;
89 -}
90 -
91 -export const FIXTURE_ENTRYPOINT = {
92 - fn: Component,
93 - params: [{ x: 42 }],
94 - isComponent: true,
95 -};
96 -
97 -```
98 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.js deleted
-22
@@ -1,22 +0,0 @@
1 -import {useState} from 'react'; // @enableChangeDetectionForDebugging
2 -
3 -function Component(props) {
4 - const w = f(props.x);
5 - const [x, _] = useState(w);
6 - return (
7 - <div>
8 - {x}
9 - {w}
10 - </div>
11 - );
12 -}
13 -
14 -function f(x) {
15 - return x;
16 -}
17 -
18 -export const FIXTURE_ENTRYPOINT = {
19 - fn: Component,
20 - params: [{x: 42}],
21 - isComponent: true,
22 -};
compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts
+3 -3
@@ -14,12 +14,12 @@ describe('parseConfigPragmaForTests()', () => {
14
15 // Validate defaults first to make sure that the parser is getting the value from the pragma,
16 // and not just missing it and getting the default value
17 - expect(defaultConfig.enableUseTypeAnnotations).toBe(false);
17 + expect(defaultConfig.enableForest).toBe(false);
18 expect(defaultConfig.validateNoSetStateInEffects).toBe(false);
19 expect(defaultConfig.validateNoSetStateInRender).toBe(true);
20
21 const config = parseConfigPragmaForTests(
22 - '@enableUseTypeAnnotations @validateNoSetStateInEffects:true @validateNoSetStateInRender:false',
22 + '@enableForest @validateNoSetStateInEffects:true @validateNoSetStateInRender:false',
23 {compilationMode: defaultOptions.compilationMode},
24 );
25 expect(config).toEqual({
@@ -27,7 +27,7 @@ describe('parseConfigPragmaForTests()', () => {
27 panicThreshold: 'all_errors',
28 environment: {
29 ...defaultOptions.environment,
30 - enableUseTypeAnnotations: true,
30 + enableForest: true,
31 validateNoSetStateInEffects: true,
32 validateNoSetStateInRender: false,
33 enableResetCacheOnSourceFileChanges: false,
compiler/packages/babel-plugin-react-compiler/src/index.ts
-1
@@ -34,7 +34,6 @@ export {
34 type Logger,
35 type LoggerEvent,
36 type PluginOptions,
37 - type AutoDepsDecorationsEvent,
37 type CompileSuccessEvent,
38 } from './Entrypoint';
39 export {
compiler/packages/eslint-plugin-react-compiler/__tests__/PluginTest-test.ts
-32
@@ -130,37 +130,5 @@ testRule('plugin-recommended', TestRecommendedRules, {
130 ),
131 ],
132 },
133 - {
134 - name: 'Pipeline errors are reported',
135 - code: normalizeIndent`
136 - import useMyEffect from 'useMyEffect';
137 - import {AUTODEPS} from 'react';
138 - function Component({a}) {
139 - 'use no memo';
140 - useMyEffect(() => console.log(a.b), AUTODEPS);
141 - return <div>Hello world</div>;
142 - }
143 - `,
144 - options: [
145 - {
146 - environment: {
147 - inferEffectDependencies: [
148 - {
149 - function: {
150 - source: 'useMyEffect',
151 - importSpecifierName: 'default',
152 - },
153 - autodepsIndex: 1,
154 - },
155 - ],
156 - },
157 - },
158 - ],
159 - errors: [
160 - {
161 - message: /Cannot infer dependencies of this effect/,
162 - },
163 - ],
164 - },
133 ],
134 });
compiler/packages/react-forgive/client/src/autodeps.ts deleted
-106
@@ -1,106 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import * as vscode from 'vscode';
9 -import {
10 - LanguageClient,
11 - RequestType,
12 - type Position,
13 -} from 'vscode-languageclient/node';
14 -import {positionLiteralToVSCodePosition, positionsToRange} from './mapping';
15 -
16 -export type AutoDepsDecorationsLSPEvent = {
17 - useEffectCallExpr: [Position, Position];
18 - decorations: Array<[Position, Position]>;
19 -};
20 -
21 -export interface AutoDepsDecorationsParams {
22 - position: Position;
23 -}
24 -
25 -export namespace AutoDepsDecorationsRequest {
26 - export const type = new RequestType<
27 - AutoDepsDecorationsParams,
28 - AutoDepsDecorationsLSPEvent | null,
29 - void
30 - >('react/autodeps_decorations');
31 -}
32 -
33 -const inferredEffectDepDecoration =
34 - vscode.window.createTextEditorDecorationType({
35 - // TODO: make configurable?
36 - borderColor: new vscode.ThemeColor('diffEditor.move.border'),
37 - borderStyle: 'solid',
38 - borderWidth: '0 0 4px 0',
39 - });
40 -
41 -let currentlyDecoratedAutoDepFnLoc: vscode.Range | null = null;
42 -export function getCurrentlyDecoratedAutoDepFnLoc(): vscode.Range | null {
43 - return currentlyDecoratedAutoDepFnLoc;
44 -}
45 -export function setCurrentlyDecoratedAutoDepFnLoc(range: vscode.Range): void {
46 - currentlyDecoratedAutoDepFnLoc = range;
47 -}
48 -export function clearCurrentlyDecoratedAutoDepFnLoc(): void {
49 - currentlyDecoratedAutoDepFnLoc = null;
50 -}
51 -
52 -let decorationRequestId = 0;
53 -export type AutoDepsDecorationsOptions = {
54 - shouldUpdateCurrent: boolean;
55 -};
56 -export function requestAutoDepsDecorations(
57 - client: LanguageClient,
58 - position: vscode.Position,
59 - options: AutoDepsDecorationsOptions,
60 -) {
61 - const id = ++decorationRequestId;
62 - client
63 - .sendRequest(AutoDepsDecorationsRequest.type, {position})
64 - .then(response => {
65 - if (response !== null) {
66 - const {
67 - decorations,
68 - useEffectCallExpr: [start, end],
69 - } = response;
70 - // Maintain ordering
71 - if (decorationRequestId === id) {
72 - if (options.shouldUpdateCurrent) {
73 - setCurrentlyDecoratedAutoDepFnLoc(positionsToRange(start, end));
74 - }
75 - drawInferredEffectDepDecorations(decorations);
76 - }
77 - } else {
78 - clearCurrentlyDecoratedAutoDepFnLoc();
79 - clearDecorations(inferredEffectDepDecoration);
80 - }
81 - });
82 -}
83 -
84 -export function drawInferredEffectDepDecorations(
85 - decorations: Array<[Position, Position]>,
86 -): void {
87 - const decorationOptions = decorations.map(([start, end]) => {
88 - return {
89 - range: new vscode.Range(
90 - positionLiteralToVSCodePosition(start),
91 - positionLiteralToVSCodePosition(end),
92 - ),
93 - hoverMessage: 'Inferred as an effect dependency',
94 - };
95 - });
96 - vscode.window.activeTextEditor?.setDecorations(
97 - inferredEffectDepDecoration,
98 - decorationOptions,
99 - );
100 -}
101 -
102 -export function clearDecorations(
103 - decorationType: vscode.TextEditorDecorationType,
104 -) {
105 - vscode.window.activeTextEditor?.setDecorations(decorationType, []);
106 -}
compiler/packages/react-forgive/client/src/extension.ts
-33
@@ -11,15 +11,9 @@ import * as vscode from 'vscode';
11 import {
12 LanguageClient,
13 LanguageClientOptions,
14 - type Position,
14 ServerOptions,
15 TransportKind,
16 } from 'vscode-languageclient/node';
18 -import {positionLiteralToVSCodePosition} from './mapping';
19 -import {
20 - getCurrentlyDecoratedAutoDepFnLoc,
21 - requestAutoDepsDecorations,
22 -} from './autodeps';
17
18 let client: LanguageClient;
19
@@ -63,33 +57,6 @@ export function activate(context: vscode.ExtensionContext) {
57 return;
58 }
59
66 - vscode.languages.registerHoverProvider(documentSelector, {
67 - provideHover(_document, position, _token) {
68 - requestAutoDepsDecorations(client, position, {shouldUpdateCurrent: true});
69 - return null;
70 - },
71 - });
72 -
73 - vscode.workspace.onDidChangeTextDocument(async _e => {
74 - const currentlyDecoratedAutoDepFnLoc = getCurrentlyDecoratedAutoDepFnLoc();
75 - if (currentlyDecoratedAutoDepFnLoc !== null) {
76 - requestAutoDepsDecorations(client, currentlyDecoratedAutoDepFnLoc.start, {
77 - shouldUpdateCurrent: false,
78 - });
79 - }
80 - });
81 -
82 - vscode.commands.registerCommand(
83 - 'react.requestAutoDepsDecorations',
84 - (position: Position) => {
85 - requestAutoDepsDecorations(
86 - client,
87 - positionLiteralToVSCodePosition(position),
88 - {shouldUpdateCurrent: true},
89 - );
90 - },
91 - );
92 -
60 client.registerProposedFeatures();
61 client.start();
62 }
compiler/packages/react-forgive/server/src/index.ts
-116
@@ -7,14 +7,10 @@
7
8 import {TextDocument} from 'vscode-languageserver-textdocument';
9 import {
10 - CodeAction,
11 - CodeActionKind,
10 CodeLens,
13 - Command,
11 createConnection,
12 type InitializeParams,
13 type InitializeResult,
17 - Position,
14 ProposedFeatures,
15 TextDocuments,
16 TextDocumentSyncKind,
@@ -27,17 +23,6 @@ import {
23 defaultOptions,
24 } from 'babel-plugin-react-compiler';
25 import {babelLocationToRange, getRangeFirstCharacter} from './compiler/compat';
30 -import {
31 - type AutoDepsDecorationsLSPEvent,
32 - AutoDepsDecorationsRequest,
33 - mapCompilerEventToLSPEvent,
34 -} from './requests/autodepsdecorations';
35 -import {
36 - isPositionWithinRange,
37 - isRangeWithinRange,
38 - Range,
39 - sourceLocationToRange,
40 -} from './utils/range';
26
27 const SUPPORTED_LANGUAGE_IDS = new Set([
28 'javascript',
@@ -51,47 +36,11 @@ const documents = new TextDocuments(TextDocument);
36
37 let compilerOptions: PluginOptions | null = null;
38 let compiledFns: Set<CompileSuccessEvent> = new Set();
54 -let autoDepsDecorations: Array<AutoDepsDecorationsLSPEvent> = [];
55 -let codeActionEvents: Array<CodeActionLSPEvent> = [];
56 -
57 -type CodeActionLSPEvent = {
58 - title: string;
59 - kind: CodeActionKind;
60 - newText: string;
61 - anchorRange: Range;
62 - editRange: {start: Position; end: Position};
63 -};
39
40 connection.onInitialize((_params: InitializeParams) => {
41 compilerOptions = defaultOptions;
42 compilerOptions = {
43 ...compilerOptions,
69 - environment: {
70 - ...compilerOptions.environment,
71 - inferEffectDependencies: [
72 - {
73 - function: {
74 - importSpecifierName: 'useEffect',
75 - source: 'react',
76 - },
77 - autodepsIndex: 1,
78 - },
79 - {
80 - function: {
81 - importSpecifierName: 'useSpecialEffect',
82 - source: 'shared-runtime',
83 - },
84 - autodepsIndex: 2,
85 - },
86 - {
87 - function: {
88 - importSpecifierName: 'default',
89 - source: 'useEffectWrapper',
90 - },
91 - autodepsIndex: 1,
92 - },
93 - ],
94 - },
44 logger: {
45 logEvent(_filename: string | null, event: LoggerEvent) {
46 connection.console.info(`Received event: ${event.kind}`);
@@ -99,19 +48,6 @@ connection.onInitialize((_params: InitializeParams) => {
48 if (event.kind === 'CompileSuccess') {
49 compiledFns.add(event);
50 }
102 - if (event.kind === 'AutoDepsDecorations') {
103 - autoDepsDecorations.push(mapCompilerEventToLSPEvent(event));
104 - }
105 - if (event.kind === 'AutoDepsEligible') {
106 - const depArrayLoc = sourceLocationToRange(event.depArrayLoc);
107 - codeActionEvents.push({
108 - title: 'Use React Compiler inferred dependency array',
109 - kind: CodeActionKind.QuickFix,
110 - newText: '',
111 - anchorRange: sourceLocationToRange(event.fnLoc),
112 - editRange: {start: depArrayLoc[0], end: depArrayLoc[1]},
113 - });
114 - }
51 },
52 },
53 };
@@ -119,7 +55,6 @@ connection.onInitialize((_params: InitializeParams) => {
55 capabilities: {
56 textDocumentSync: TextDocumentSyncKind.Full,
57 codeLensProvider: {resolveProvider: true},
122 - codeActionProvider: {resolveProvider: true},
58 },
59 };
60 return result;
@@ -192,60 +127,9 @@ connection.onCodeLensResolve(lens => {
127 return lens;
128 });
129
195 -connection.onCodeAction(params => {
196 - const codeActions: Array<CodeAction> = [];
197 - for (const codeActionEvent of codeActionEvents) {
198 - if (
199 - isRangeWithinRange(
200 - [params.range.start, params.range.end],
201 - codeActionEvent.anchorRange,
202 - )
203 - ) {
204 - const codeAction = CodeAction.create(
205 - codeActionEvent.title,
206 - {
207 - changes: {
208 - [params.textDocument.uri]: [
209 - {
210 - newText: codeActionEvent.newText,
211 - range: codeActionEvent.editRange,
212 - },
213 - ],
214 - },
215 - },
216 - codeActionEvent.kind,
217 - );
218 - // After executing a codeaction, we want to draw autodep decorations again
219 - codeAction.command = Command.create(
220 - 'Request autodeps decorations',
221 - 'react.requestAutoDepsDecorations',
222 - codeActionEvent.anchorRange[0],
223 - );
224 - codeActions.push(codeAction);
225 - }
226 - }
227 - return codeActions;
228 -});
229 -
230 -/**
231 - * The client can request the server to compute autodeps decorations based on a currently selected
232 - * position if the selected position is within an autodep eligible function call.
233 - */
234 -connection.onRequest(AutoDepsDecorationsRequest.type, async params => {
235 - const position = params.position;
236 - for (const decoration of autoDepsDecorations) {
237 - if (isPositionWithinRange(position, decoration.useEffectCallExpr)) {
238 - return decoration;
239 - }
240 - }
241 - return null;
242 -});
243 -
130 function resetState() {
131 connection.console.debug('Clearing state');
132 compiledFns.clear();
247 - autoDepsDecorations = [];
248 - codeActionEvents = [];
133 }
134
135 documents.listen(connection);
compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts deleted
-35
@@ -1,35 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -import {type AutoDepsDecorationsEvent} from 'babel-plugin-react-compiler';
9 -import {type Position} from 'vscode-languageserver-textdocument';
10 -import {RequestType} from 'vscode-languageserver/node';
11 -import {type Range, sourceLocationToRange} from '../utils/range';
12 -
13 -export type AutoDepsDecorationsLSPEvent = {
14 - useEffectCallExpr: Range;
15 - decorations: Array<Range>;
16 -};
17 -export interface AutoDepsDecorationsParams {
18 - position: Position;
19 -}
20 -export namespace AutoDepsDecorationsRequest {
21 - export const type = new RequestType<
22 - AutoDepsDecorationsParams,
23 - AutoDepsDecorationsLSPEvent,
24 - void
25 - >('react/autodeps_decorations');
26 -}
27 -
28 -export function mapCompilerEventToLSPEvent(
29 - event: AutoDepsDecorationsEvent,
30 -): AutoDepsDecorationsLSPEvent {
31 - return {
32 - useEffectCallExpr: sourceLocationToRange(event.fnLoc),
33 - decorations: event.decorations.map(sourceLocationToRange),
34 - };
35 -}