From 52612a7cbdd8e1fee9599478247f78725869ebad Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 1 Aug 2025 15:10:34 -0400 Subject: [PATCH 1/4] [compiler] Emit more specific error when making identifiers with reserved words (#34080) This currently throws an invariant which may be misleading. I checked the ecma262 spec and used the same list of reserved words in our check. To err on the side of being conservative, we also error when strict mode reserved words are used. --- .../src/HIR/HIR.ts | 22 +++-- .../src/Utils/Keyword.ts | 87 +++++++++++++++++++ .../ecma/error.reserved-words.expect.md | 32 +++++++ .../compiler/ecma/error.reserved-words.ts | 13 +++ 4 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/Utils/Keyword.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index f9caa844f3c..51715b3c1e1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -14,6 +14,7 @@ import type {HookKind} from './ObjectShape'; import {Type, makeType} from './Types'; import {z} from 'zod'; import type {AliasingEffect} from '../Inference/AliasingEffects'; +import {isReservedWord} from '../Utils/Keyword'; /* * ******************************************************************************************* @@ -1320,12 +1321,21 @@ export function forkTemporaryIdentifier( * original source code. */ export function makeIdentifierName(name: string): ValidatedIdentifier { - CompilerError.invariant(t.isValidIdentifier(name), { - reason: `Expected a valid identifier name`, - loc: GeneratedSource, - description: `\`${name}\` is not a valid JavaScript identifier`, - suggestions: null, - }); + if (isReservedWord(name)) { + CompilerError.throwInvalidJS({ + reason: 'Expected a non-reserved identifier name', + loc: GeneratedSource, + description: `\`${name}\` is a reserved word in JavaScript and cannot be used as an identifier name`, + suggestions: null, + }); + } else { + CompilerError.invariant(t.isValidIdentifier(name), { + reason: `Expected a valid identifier name`, + loc: GeneratedSource, + description: `\`${name}\` is not a valid JavaScript identifier`, + suggestions: null, + }); + } return { kind: 'named', value: name as ValidIdentifierName, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Utils/Keyword.ts b/compiler/packages/babel-plugin-react-compiler/src/Utils/Keyword.ts new file mode 100644 index 00000000000..3964f4accc8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/Utils/Keyword.ts @@ -0,0 +1,87 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#sec-keywords-and-reserved-words + */ + +/** + * Note: `await` and `yield` are contextually allowed as identifiers. + * await: reserved inside async functions and modules + * yield: reserved inside generator functions + * + * Note: `async` is not reserved. + */ +const RESERVED_WORDS = new Set([ + 'break', + 'case', + 'catch', + 'class', + 'const', + 'continue', + 'debugger', + 'default', + 'delete', + 'do', + 'else', + 'enum', + 'export', + 'extends', + 'false', + 'finally', + 'for', + 'function', + 'if', + 'import', + 'in', + 'instanceof', + 'new', + 'null', + 'return', + 'super', + 'switch', + 'this', + 'throw', + 'true', + 'try', + 'typeof', + 'var', + 'void', + 'while', + 'with', +]); + +/** + * Reserved when a module has a 'use strict' directive. + */ +const STRICT_MODE_RESERVED_WORDS = new Set([ + 'let', + 'static', + 'implements', + 'interface', + 'package', + 'private', + 'protected', + 'public', +]); +/** + * The names arguments and eval are not keywords, but they are subject to some restrictions in + * strict mode code. + */ +const STRICT_MODE_RESTRICTED_WORDS = new Set(['eval', 'arguments']); + +/** + * Conservative check for whether an identifer name is reserved or not. We assume that code is + * written with strict mode. + */ +export function isReservedWord(identifierName: string): boolean { + return ( + RESERVED_WORDS.has(identifierName) || + STRICT_MODE_RESERVED_WORDS.has(identifierName) || + STRICT_MODE_RESTRICTED_WORDS.has(identifierName) + ); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md new file mode 100644 index 00000000000..a6ee8a798b5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md @@ -0,0 +1,32 @@ + +## Input + +```javascript +import {useRef} from 'react'; + +function useThing(fn) { + const fnRef = useRef(fn); + const ref = useRef(null); + + if (ref.current === null) { + ref.current = function (this: unknown, ...args) { + return fnRef.current.call(this, ...args); + }; + } + return ref.current; +} + +``` + + +## Error + +``` +Found 1 error: + +Error: Expected a non-reserved identifier name + +`this` is a reserved word in JavaScript and cannot be used as an identifier name. +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.ts new file mode 100644 index 00000000000..2937ba8df5e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.ts @@ -0,0 +1,13 @@ +import {useRef} from 'react'; + +function useThing(fn) { + const fnRef = useRef(fn); + const ref = useRef(null); + + if (ref.current === null) { + ref.current = function (this: unknown, ...args) { + return fnRef.current.call(this, ...args); + }; + } + return ref.current; +} From 538ac7ae4b918136c5bd7d15ada19439d15f8080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 1 Aug 2025 15:44:48 -0400 Subject: [PATCH 2/4] [Flight] Fix debug info leaking to outer handler (#34081) The `waitForReference` call for debug info can trigger inside a different object's initializingHandler. In that case, we can get confused by which one is the root object. We have this special case to detect if the initializing handler's object is `null` and we have an empty string key, then we should replace the root object's value with the resolved value. https://github.com/facebook/react/blob/52612a7cbdd8e1fee9599478247f78725869ebad/packages/react-client/src/ReactFlightClient.js#L1374 However, if the initializing handler actually should have the value `null` then we might get confused by this and replace it with the resolved value from a debug object. This fixes it by just using a non-empty string as the key for the waitForReference on debug value since we're not going to use it anyway. It used to be impossible to get into this state since a `null` value at the root couldn't have any reference inside itself but now the debug info for a `null` value can have outstanding references. However, a better fix might be using a placeholder marker object instead of null or better yet ensuring that we know which root we're initializing in the debug model. --- .../react-client/src/ReactFlightClient.js | 2 +- .../src/__tests__/ReactFlightDOMEdge-test.js | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 4a13d094a82..fe88fe0357b 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -879,7 +879,7 @@ function initializeDebugChunk( waitForReference( debugChunk, {}, // noop, since we'll have already added an entry to debug info - '', // noop + 'debug', // noop, but we need it to not be empty string since that indicates the root object response, initializeDebugInfo, [''], // path diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 54177d8f8cb..42cff2ad51d 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -1915,4 +1915,57 @@ describe('ReactFlightDOMEdge', () => { expect(ownerStack).toBeNull(); } }); + + it('can pass an async import that resolves later as a prop to a null component', async () => { + let resolveClientComponentChunk; + const client = clientExports( + { + foo: 'bar', + }, + '42', + '/test.js', + new Promise(resolve => (resolveClientComponentChunk = resolve)), + ); + + function ServerComponent(props) { + return null; + } + + function App() { + return ( +
+ +
+ ); + } + + const stream = await serverAct(() => + passThrough( + ReactServerDOMServer.renderToReadableStream(, webpackMap), + ), + ); + + // Parsing the root blocks because the module hasn't loaded yet + const response = ReactServerDOMClient.createFromReadableStream(stream, { + serverConsumerManifest: { + moduleMap: null, + moduleLoading: null, + }, + }); + + function ClientRoot() { + return use(response); + } + + // Initialize to be blocked. + response.then(() => {}); + // Unblock. + resolveClientComponentChunk(); + + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream(), + ); + const result = await readResult(ssrStream); + expect(result).toEqual('
'); + }); }); From 0860b9cc1f4a7188b41204bddc57a127a8bbf6e9 Mon Sep 17 00:00:00 2001 From: Joseph Savona <6425824+josephsavona@users.noreply.github.com> Date: Fri, 1 Aug 2025 12:59:49 -0700 Subject: [PATCH 3/4] [compiler] Add definitions for Object entries/keys/values (#34047) Fixes remaining issue in #32261, where passing a previously useMemo()-d value to `Object.entries()` makes the compiler think the value is mutated and fail validatePreserveExistingMemo. While I was there I added Object.keys() and Object.values() too. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34047). * #34049 * __->__ #34047 * #34044 --- .../src/HIR/Globals.ts | 93 +++++++++++++++ .../src/HIR/ObjectShape.ts | 1 + .../src/HIR/TypeSchema.ts | 15 +++ ...validate-object-entries-mutation.expect.md | 57 +++++++++ .../error.validate-object-entries-mutation.js | 16 +++ ....validate-object-values-mutation.expect.md | 57 +++++++++ .../error.validate-object-values-mutation.js | 16 +++ .../object-entries-mutation.expect.md | 57 +++++++++ .../compiler/object-entries-mutation.js | 15 +++ .../fixtures/compiler/object-keys.expect.md | 108 ++++++++++++++++++ .../fixtures/compiler/object-keys.js | 36 ++++++ .../compiler/object-values-mutation.expect.md | 57 +++++++++ .../compiler/object-values-mutation.js | 15 +++ .../fixtures/compiler/object-values.expect.md | 103 +++++++++++++++++ .../fixtures/compiler/object-values.js | 39 +++++++ ...repro-object-fromEntries-entries.expect.md | 97 ++++++++++++++++ .../repro-object-fromEntries-entries.js | 36 ++++++ 17 files changed, 818 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts index c3eadb89f50..264174debaf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts @@ -114,6 +114,99 @@ const TYPED_GLOBALS: Array<[string, BuiltInType]> = [ returnValueKind: ValueKind.Mutable, }), ], + [ + 'entries', + addFunction(DEFAULT_SHAPES, [], { + positionalParams: [Effect.Capture], + restParam: null, + returnType: {kind: 'Object', shapeId: BuiltInArrayId}, + calleeEffect: Effect.Read, + returnValueKind: ValueKind.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@object'], + rest: null, + returns: '@returns', + temporaries: [], + effects: [ + { + kind: 'Create', + into: '@returns', + reason: ValueReason.KnownReturnSignature, + value: ValueKind.Mutable, + }, + // Object values are captured into the return + { + kind: 'Capture', + from: '@object', + into: '@returns', + }, + ], + }, + }), + ], + [ + 'keys', + addFunction(DEFAULT_SHAPES, [], { + positionalParams: [Effect.Read], + restParam: null, + returnType: {kind: 'Object', shapeId: BuiltInArrayId}, + calleeEffect: Effect.Read, + returnValueKind: ValueKind.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@object'], + rest: null, + returns: '@returns', + temporaries: [], + effects: [ + { + kind: 'Create', + into: '@returns', + reason: ValueReason.KnownReturnSignature, + value: ValueKind.Mutable, + }, + // Only keys are captured, and keys are immutable + { + kind: 'ImmutableCapture', + from: '@object', + into: '@returns', + }, + ], + }, + }), + ], + [ + 'values', + addFunction(DEFAULT_SHAPES, [], { + positionalParams: [Effect.Capture], + restParam: null, + returnType: {kind: 'Object', shapeId: BuiltInArrayId}, + calleeEffect: Effect.Read, + returnValueKind: ValueKind.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@object'], + rest: null, + returns: '@returns', + temporaries: [], + effects: [ + { + kind: 'Create', + into: '@returns', + reason: ValueReason.KnownReturnSignature, + value: ValueKind.Mutable, + }, + // Object values are captured into the return + { + kind: 'Capture', + from: '@object', + into: '@returns', + }, + ], + }, + }), + ], ]), ], [ diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts index eaf728db951..ced080adcc0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts @@ -142,6 +142,7 @@ function parseAliasingSignatureConfig( const effects = typeConfig.effects.map( (effect: AliasingEffectConfig): AliasingEffect => { switch (effect.kind) { + case 'ImmutableCapture': case 'CreateFrom': case 'Capture': case 'Alias': diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts index 5945e3a0782..e63ef067b20 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts @@ -111,6 +111,19 @@ export const AliasEffectSchema: z.ZodType = z.object({ into: LifetimeIdSchema, }); +export type ImmutableCaptureEffectConfig = { + kind: 'ImmutableCapture'; + from: string; + into: string; +}; + +export const ImmutableCaptureEffectSchema: z.ZodType = + z.object({ + kind: z.literal('ImmutableCapture'), + from: LifetimeIdSchema, + into: LifetimeIdSchema, + }); + export type CaptureEffectConfig = { kind: 'Capture'; from: string; @@ -187,6 +200,7 @@ export type AliasingEffectConfig = | AssignEffectConfig | AliasEffectConfig | CaptureEffectConfig + | ImmutableCaptureEffectConfig | ImpureEffectConfig | MutateEffectConfig | MutateTransitiveConditionallyConfig @@ -199,6 +213,7 @@ export const AliasingEffectSchema: z.ZodType = z.union([ AssignEffectSchema, AliasEffectSchema, CaptureEffectSchema, + ImmutableCaptureEffectSchema, ImpureEffectSchema, MutateEffectSchema, MutateTransitiveConditionallySchema, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.expect.md new file mode 100644 index 00000000000..09ff6e7214b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.expect.md @@ -0,0 +1,57 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const entries = useMemo(() => Object.entries(object), [object]); + entries.map(([, value]) => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; + +``` + + +## Error + +``` +Found 2 errors: + +Memoization: Compilation skipped because existing memoization could not be preserved + +React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly. + +error.validate-object-entries-mutation.ts:6:57 + 4 | function Component(props) { + 5 | const object = {object: props.object}; +> 6 | const entries = useMemo(() => Object.entries(object), [object]); + | ^^^^^^ This dependency may be modified later + 7 | entries.map(([, value]) => { + 8 | value.updated = true; + 9 | }); + +Memoization: Compilation skipped because existing memoization could not be preserved + +React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. + +error.validate-object-entries-mutation.ts:6:18 + 4 | function Component(props) { + 5 | const object = {object: props.object}; +> 6 | const entries = useMemo(() => Object.entries(object), [object]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization + 7 | entries.map(([, value]) => { + 8 | value.updated = true; + 9 | }); +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.js new file mode 100644 index 00000000000..b4145b1617f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-entries-mutation.js @@ -0,0 +1,16 @@ +// @validatePreserveExistingMemoizationGuarantees +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const entries = useMemo(() => Object.entries(object), [object]); + entries.map(([, value]) => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.expect.md new file mode 100644 index 00000000000..b791b629278 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.expect.md @@ -0,0 +1,57 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const values = useMemo(() => Object.values(object), [object]); + values.map(value => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; + +``` + + +## Error + +``` +Found 2 errors: + +Memoization: Compilation skipped because existing memoization could not be preserved + +React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly. + +error.validate-object-values-mutation.ts:6:55 + 4 | function Component(props) { + 5 | const object = {object: props.object}; +> 6 | const values = useMemo(() => Object.values(object), [object]); + | ^^^^^^ This dependency may be modified later + 7 | values.map(value => { + 8 | value.updated = true; + 9 | }); + +Memoization: Compilation skipped because existing memoization could not be preserved + +React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. + +error.validate-object-values-mutation.ts:6:17 + 4 | function Component(props) { + 5 | const object = {object: props.object}; +> 6 | const values = useMemo(() => Object.values(object), [object]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization + 7 | values.map(value => { + 8 | value.updated = true; + 9 | }); +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.js new file mode 100644 index 00000000000..3482887d920 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-object-values-mutation.js @@ -0,0 +1,16 @@ +// @validatePreserveExistingMemoizationGuarantees +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const values = useMemo(() => Object.values(object), [object]); + values.map(value => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.expect.md new file mode 100644 index 00000000000..bc541b47f1f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.expect.md @@ -0,0 +1,57 @@ + +## Input + +```javascript +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const entries = Object.entries(object); + entries.map(([, value]) => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { makeObject_Primitives, Stringify } from "shared-runtime"; + +function Component(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.object) { + const object = { object: props.object }; + const entries = Object.entries(object); + entries.map(_temp); + t0 = ; + $[0] = props.object; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} +function _temp(t0) { + const [, value] = t0; + value.updated = true; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ object: { key: makeObject_Primitives() } }], +}; + +``` + +### Eval output +(kind: ok)
{"entries":[["object",{"key":{"a":0,"b":"value1","c":true},"updated":true}]]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.js new file mode 100644 index 00000000000..2902cffd014 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-entries-mutation.js @@ -0,0 +1,15 @@ +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const entries = Object.entries(object); + entries.map(([, value]) => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.expect.md new file mode 100644 index 00000000000..f076d9032db --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.expect.md @@ -0,0 +1,108 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {Stringify} from 'shared-runtime'; + +// derived from https://github.com/facebook/react/issues/32261 +function Component({items}) { + const record = useMemo( + () => + Object.fromEntries( + items.map(item => [item.id, ref => ]) + ), + [items] + ); + + // Without a declaration for Object.entries(), this would be assumed to mutate + // `record`, meaning existing memoization couldn't be preserved + return ( +
+ {Object.keys(record).map(id => ( + + ))} +
+ ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + {id: '0', name: 'Hello'}, + {id: '1', name: 'World!'}, + ], + }, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees +import { useMemo } from "react"; +import { Stringify } from "shared-runtime"; + +// derived from https://github.com/facebook/react/issues/32261 +function Component(t0) { + const $ = _c(7); + const { items } = t0; + let t1; + if ($[0] !== items) { + t1 = Object.fromEntries(items.map(_temp)); + $[0] = items; + $[1] = t1; + } else { + t1 = $[1]; + } + const record = t1; + let t2; + if ($[2] !== record) { + t2 = Object.keys(record); + $[2] = record; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== record || $[5] !== t2) { + t3 = ( +
+ {t2.map((id) => ( + + ))} +
+ ); + $[4] = record; + $[5] = t2; + $[6] = t3; + } else { + t3 = $[6]; + } + return t3; +} +function _temp(item) { + return [item.id, (ref) => ]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + { id: "0", name: "Hello" }, + { id: "1", name: "World!" }, + ], + }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"render":"[[ function params=1 ]]"}
{"render":"[[ function params=1 ]]"}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.js new file mode 100644 index 00000000000..38ae97ab956 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-keys.js @@ -0,0 +1,36 @@ +// @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {Stringify} from 'shared-runtime'; + +// derived from https://github.com/facebook/react/issues/32261 +function Component({items}) { + const record = useMemo( + () => + Object.fromEntries( + items.map(item => [item.id, ref => ]) + ), + [items] + ); + + // Without a declaration for Object.entries(), this would be assumed to mutate + // `record`, meaning existing memoization couldn't be preserved + return ( +
+ {Object.keys(record).map(id => ( + + ))} +
+ ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + {id: '0', name: 'Hello'}, + {id: '1', name: 'World!'}, + ], + }, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.expect.md new file mode 100644 index 00000000000..bc541b47f1f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.expect.md @@ -0,0 +1,57 @@ + +## Input + +```javascript +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const entries = Object.entries(object); + entries.map(([, value]) => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { makeObject_Primitives, Stringify } from "shared-runtime"; + +function Component(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.object) { + const object = { object: props.object }; + const entries = Object.entries(object); + entries.map(_temp); + t0 = ; + $[0] = props.object; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} +function _temp(t0) { + const [, value] = t0; + value.updated = true; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ object: { key: makeObject_Primitives() } }], +}; + +``` + +### Eval output +(kind: ok)
{"entries":[["object",{"key":{"a":0,"b":"value1","c":true},"updated":true}]]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.js new file mode 100644 index 00000000000..2902cffd014 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values-mutation.js @@ -0,0 +1,15 @@ +import {makeObject_Primitives, Stringify} from 'shared-runtime'; + +function Component(props) { + const object = {object: props.object}; + const entries = Object.entries(object); + entries.map(([, value]) => { + value.updated = true; + }); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{object: {key: makeObject_Primitives()}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.expect.md new file mode 100644 index 00000000000..90039906641 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.expect.md @@ -0,0 +1,103 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {Stringify} from 'shared-runtime'; + +// derived from https://github.com/facebook/react/issues/32261 +function Component({items}) { + const record = useMemo( + () => + Object.fromEntries( + items.map(item => [ + item.id, + {id: item.id, render: ref => }, + ]) + ), + [items] + ); + + // Without a declaration for Object.entries(), this would be assumed to mutate + // `record`, meaning existing memoization couldn't be preserved + return ( +
+ {Object.values(record).map(({id, render}) => ( + + ))} +
+ ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + {id: '0', name: 'Hello'}, + {id: '1', name: 'World!'}, + ], + }, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees +import { useMemo } from "react"; +import { Stringify } from "shared-runtime"; + +// derived from https://github.com/facebook/react/issues/32261 +function Component(t0) { + const $ = _c(4); + const { items } = t0; + let t1; + if ($[0] !== items) { + t1 = Object.fromEntries(items.map(_temp)); + $[0] = items; + $[1] = t1; + } else { + t1 = $[1]; + } + const record = t1; + let t2; + if ($[2] !== record) { + t2 =
{Object.values(record).map(_temp2)}
; + $[2] = record; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} +function _temp2(t0) { + const { id, render } = t0; + return ; +} +function _temp(item) { + return [ + item.id, + { id: item.id, render: (ref) => }, + ]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + { id: "0", name: "Hello" }, + { id: "1", name: "World!" }, + ], + }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"render":"[[ function params=1 ]]"}
{"render":"[[ function params=1 ]]"}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.js new file mode 100644 index 00000000000..4cf229c379a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-values.js @@ -0,0 +1,39 @@ +// @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {Stringify} from 'shared-runtime'; + +// derived from https://github.com/facebook/react/issues/32261 +function Component({items}) { + const record = useMemo( + () => + Object.fromEntries( + items.map(item => [ + item.id, + {id: item.id, render: ref => }, + ]) + ), + [items] + ); + + // Without a declaration for Object.entries(), this would be assumed to mutate + // `record`, meaning existing memoization couldn't be preserved + return ( +
+ {Object.values(record).map(({id, render}) => ( + + ))} +
+ ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + {id: '0', name: 'Hello'}, + {id: '1', name: 'World!'}, + ], + }, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.expect.md new file mode 100644 index 00000000000..b7ebcbc1cf6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.expect.md @@ -0,0 +1,97 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {Stringify} from 'shared-runtime'; + +// derived from https://github.com/facebook/react/issues/32261 +function Component({items}) { + const record = useMemo( + () => + Object.fromEntries( + items.map(item => [item.id, ref => ]) + ), + [items] + ); + + // Without a declaration for Object.entries(), this would be assumed to mutate + // `record`, meaning existing memoization couldn't be preserved + return ( +
+ {Object.entries(record).map(([id, render]) => ( + + ))} +
+ ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + {id: '0', name: 'Hello'}, + {id: '1', name: 'World!'}, + ], + }, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees +import { useMemo } from "react"; +import { Stringify } from "shared-runtime"; + +// derived from https://github.com/facebook/react/issues/32261 +function Component(t0) { + const $ = _c(4); + const { items } = t0; + let t1; + if ($[0] !== items) { + t1 = Object.fromEntries(items.map(_temp)); + $[0] = items; + $[1] = t1; + } else { + t1 = $[1]; + } + const record = t1; + let t2; + if ($[2] !== record) { + t2 =
{Object.entries(record).map(_temp2)}
; + $[2] = record; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} +function _temp2(t0) { + const [id, render] = t0; + return ; +} +function _temp(item) { + return [item.id, (ref) => ]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + { id: "0", name: "Hello" }, + { id: "1", name: "World!" }, + ], + }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"render":"[[ function params=1 ]]"}
{"render":"[[ function params=1 ]]"}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.js new file mode 100644 index 00000000000..7dd8f34826a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-fromEntries-entries.js @@ -0,0 +1,36 @@ +// @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {Stringify} from 'shared-runtime'; + +// derived from https://github.com/facebook/react/issues/32261 +function Component({items}) { + const record = useMemo( + () => + Object.fromEntries( + items.map(item => [item.id, ref => ]) + ), + [items] + ); + + // Without a declaration for Object.entries(), this would be assumed to mutate + // `record`, meaning existing memoization couldn't be preserved + return ( +
+ {Object.entries(record).map(([id, render]) => ( + + ))} +
+ ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [ + { + items: [ + {id: '0', name: 'Hello'}, + {id: '1', name: 'World!'}, + ], + }, + ], +}; From ddf8bc3fbac7aefbf557e2e4a3e14d8de1b80872 Mon Sep 17 00:00:00 2001 From: Joseph Savona <6425824+josephsavona@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:00:01 -0700 Subject: [PATCH 4/4] [compiler] Improve merging of scopes that invalidate together (#34049) We try to merge consecutive reactive scopes that will always invalidate together, but there's one common case that isn't handled. ```js const y = [[x]]; ``` Here we'll create two consecutive scopes for the inner and outer array expressions. Because the input to the second scope is a temporary, they'll merge into one scope. But if we name the inner array, the merging stops: ```js const array = [x]; const y = [array]; ``` This is because the merging logic checks if all the dependencies of the second scope are outputs of the first scope, but doesn't account for renaming due to LoadLocal/StoreLocal. The fix is to track these temporaries. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34049). * __->__ #34049 * #34047 * #34044 --- ...rgeReactiveScopesThatInvalidateTogether.ts | 30 +++++++- .../compiler/array-at-closure.expect.md | 17 ++--- ...ay-map-captures-receiver-noAlias.expect.md | 26 ++----- ...ay-map-noAlias-escaping-function.expect.md | 16 +--- .../capturing-arrow-function-1.expect.md | 20 ++--- .../compiler/capturing-function-1.expect.md | 20 ++--- ...apturing-function-runs-inference.expect.md | 26 ++----- ...pturing-variable-in-nested-block.expect.md | 20 ++--- ...ring-variable-in-nested-function.expect.md | 22 ++---- ...ved-allocating-nested-dependency.expect.md | 27 +++---- .../fbt/fbt-param-with-newline.expect.md | 17 ++--- .../fbt/fbt-param-with-quotes.expect.md | 29 +++---- .../fbt/fbt-param-with-unicode.expect.md | 25 +++--- .../compiler/fbt/fbt-to-string.expect.md | 29 +++---- ...-maybe-mutates-hook-return-value.expect.md | 17 ++--- ...nction-expression-prototype-call.expect.md | 17 ++--- ...ing-functionexpr-conditional-dep.expect.md | 17 ++--- ...setstate-captured-indirectly-jsx.expect.md | 29 +++---- ...rray-map-named-chained-callbacks.expect.md | 76 ++++++++----------- .../conditional-call-chain.expect.md | 17 ++--- ...se-localvar-memberexpr-in-lambda.expect.md | 16 +--- ...ay-map-captures-receiver-noAlias.expect.md | 26 ++----- .../prop-capturing-function-1.expect.md | 20 ++--- ...function-uncond-access-local-var.expect.md | 16 +--- ...function-uncond-access-local-var.expect.md | 16 +--- ...er-nested-function-uncond-access.expect.md | 17 ++--- ...nfer-object-method-uncond-access.expect.md | 17 ++--- ...scopes-whose-deps-invalidate-jsx.expect.md | 17 ++--- ...-whose-deps-may-invalidate-array.expect.md | 17 ++--- .../compiler/reactive-ref-param.expect.md | 16 +--- .../fixtures/compiler/reactive-ref.expect.md | 16 +--- ...-analysis-interleaved-reactivity.expect.md | 27 ++----- ...ivity-via-aliased-mutation-array.expect.md | 20 +++-- ...vity-via-aliased-mutation-lambda.expect.md | 20 +++-- ...rrent-aliased-not-added-to-dep-2.expect.md | 17 ++--- .../ref-current-not-added-to-dep-2.expect.md | 17 ++--- ...source-variables-nested-function.expect.md | 18 ++--- ...lack-of-phi-types-explicit-types.expect.md | 50 +++++------- ...ng-memoization-lack-of-phi-types.expect.md | 50 +++++------- ...-argument-in-function-expression.expect.md | 25 +++--- ...zen-value-in-function-expression.expect.md | 25 +++--- ...repro-renaming-conflicting-decls.expect.md | 67 ++++++++-------- ...ession-of-jsxexpressioncontainer.expect.md | 17 ++--- ...-expression-returns-caught-value.expect.md | 17 ++--- .../type-annotation-var-array.expect.md | 16 +--- .../type-annotation-var-array_.flow.expect.md | 16 +--- .../compiler/use-memo-simple.expect.md | 16 +--- ...context-in-callback-if-condition.expect.md | 25 +++--- 48 files changed, 401 insertions(+), 733 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts index 6f2d97ff8e5..ea2f7987705 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts @@ -119,6 +119,7 @@ class FindLastUsageVisitor extends ReactiveFunctionVisitor { class Transform extends ReactiveFunctionTransform { lastUsage: Map; + temporaries: Map = new Map(); constructor(lastUsage: Map) { super(); @@ -215,6 +216,12 @@ class Transform extends ReactiveFunctionTransform, ): boolean { // Don't merge scopes with reassignments if ( @@ -465,11 +480,14 @@ function canMergeScopes( (next.scope.dependencies.size !== 0 && [...next.scope.dependencies].every( dep => + dep.path.length === 0 && isAlwaysInvalidatingType(dep.identifier.type) && Iterable_some( current.scope.declarations.values(), decl => - decl.identifier.declarationId === dep.identifier.declarationId, + decl.identifier.declarationId === dep.identifier.declarationId || + decl.identifier.declarationId === + temporaries.get(dep.identifier.declarationId), ), )) ) { @@ -477,8 +495,12 @@ function canMergeScopes( return true; } log(` cannot merge scopes:`); - log(` ${printReactiveScopeSummary(current.scope)}`); - log(` ${printReactiveScopeSummary(next.scope)}`); + log( + ` ${printReactiveScopeSummary(current.scope)} ${[...current.scope.declarations.values()].map(decl => decl.identifier.declarationId)}`, + ); + log( + ` ${printReactiveScopeSummary(next.scope)} ${[...next.scope.dependencies].map(dep => `${dep.identifier.declarationId} ${temporaries.get(dep.identifier.declarationId) ?? dep.identifier.declarationId}`)}`, + ); return false; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-closure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-closure.expect.md index 9f26c192f5f..810f1a3f5e4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-closure.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-closure.expect.md @@ -19,7 +19,7 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(7); + const $ = _c(5); let t0; if ($[0] !== props.x) { t0 = foo(props.x); @@ -31,26 +31,19 @@ function Component(props) { const x = t0; let t1; if ($[2] !== props || $[3] !== x) { - t1 = function () { + const fn = function () { const arr = [...bar(props)]; return arr.at(x); }; + + t1 = fn(); $[2] = props; $[3] = x; $[4] = t1; } else { t1 = $[4]; } - const fn = t1; - let t2; - if ($[5] !== fn) { - t2 = fn(); - $[5] = fn; - $[6] = t2; - } else { - t2 = $[6]; - } - const fnResult = t2; + const fnResult = t1; return fnResult; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-captures-receiver-noAlias.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-captures-receiver-noAlias.expect.md index 1680386c741..efd094c1a53 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-captures-receiver-noAlias.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-captures-receiver-noAlias.expect.md @@ -23,34 +23,18 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(6); + const $ = _c(2); let t0; if ($[0] !== props.a) { - t0 = { a: props.a }; + const item = { a: props.a }; + const items = [item]; + t0 = items.map(_temp); $[0] = props.a; $[1] = t0; } else { t0 = $[1]; } - const item = t0; - let t1; - if ($[2] !== item) { - t1 = [item]; - $[2] = item; - $[3] = t1; - } else { - t1 = $[3]; - } - const items = t1; - let t2; - if ($[4] !== items) { - t2 = items.map(_temp); - $[4] = items; - $[5] = t2; - } else { - t2 = $[5]; - } - const mapped = t2; + const mapped = t0; return mapped; } function _temp(item_0) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-noAlias-escaping-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-noAlias-escaping-function.expect.md index 867d51cb232..f165502a29b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-noAlias-escaping-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-noAlias-escaping-function.expect.md @@ -21,26 +21,18 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(2); const f = _temp; let t0; if ($[0] !== props.items) { - t0 = [...props.items].map(f); + const x = [...props.items].map(f); + t0 = [x, f]; $[0] = props.items; $[1] = t0; } else { t0 = $[1]; } - const x = t0; - let t1; - if ($[2] !== x) { - t1 = [x, f]; - $[2] = x; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } function _temp(item) { return item; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-arrow-function-1.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-arrow-function-1.expect.md index a11b0d8ada4..85950edabac 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-arrow-function-1.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-arrow-function-1.expect.md @@ -23,27 +23,19 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function component(a) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== a) { - t0 = { a }; + const z = { a }; + t0 = () => { + console.log(z); + }; $[0] = a; $[1] = t0; } else { t0 = $[1]; } - const z = t0; - let t1; - if ($[2] !== z) { - t1 = () => { - console.log(z); - }; - $[2] = z; - $[3] = t1; - } else { - t1 = $[3]; - } - const x = t1; + const x = t0; return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-1.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-1.expect.md index 206cf4b6b73..41732aed0d6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-1.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-1.expect.md @@ -23,27 +23,19 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function component(a) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== a) { - t0 = { a }; + const z = { a }; + t0 = function () { + console.log(z); + }; $[0] = a; $[1] = t0; } else { t0 = $[1]; } - const z = t0; - let t1; - if ($[2] !== z) { - t1 = function () { - console.log(z); - }; - $[2] = z; - $[3] = t1; - } else { - t1 = $[3]; - } - const x = t1; + const x = t0; return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-runs-inference.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-runs-inference.expect.md index dc0961c6126..31b80bcda3b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-runs-inference.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-runs-inference.expect.md @@ -22,35 +22,19 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; import { Stringify } from "shared-runtime"; function Component(t0) { - const $ = _c(6); + const $ = _c(2); const { a } = t0; let t1; if ($[0] !== a) { - t1 = { a }; + const z = { a }; + const p = () => {z}; + t1 = p(); $[0] = a; $[1] = t1; } else { t1 = $[1]; } - const z = t1; - let t2; - if ($[2] !== z) { - t2 = () => {z}; - $[2] = z; - $[3] = t2; - } else { - t2 = $[3]; - } - const p = t2; - let t3; - if ($[4] !== p) { - t3 = p(); - $[4] = p; - $[5] = t3; - } else { - t3 = $[5]; - } - return t3; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-block.expect.md index 0dc10c48510..ec8a96a3926 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-block.expect.md @@ -25,27 +25,19 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function component(a) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== a) { - t0 = { a }; + const z = { a }; + t0 = function () { + console.log(z); + }; $[0] = a; $[1] = t0; } else { t0 = $[1]; } - const z = t0; - let t1; - if ($[2] !== z) { - t1 = function () { - console.log(z); - }; - $[2] = z; - $[3] = t1; - } else { - t1 = $[3]; - } - const x = t1; + const x = t0; return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-function.expect.md index b66953a43d3..ee41bc88f5e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-variable-in-nested-function.expect.md @@ -25,29 +25,21 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function component(a) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== a) { - t0 = { a }; - $[0] = a; - $[1] = t0; - } else { - t0 = $[1]; - } - const z = t0; - let t1; - if ($[2] !== z) { - t1 = function () { + const z = { a }; + t0 = function () { (function () { console.log(z); })(); }; - $[2] = z; - $[3] = t1; + $[0] = a; + $[1] = t0; } else { - t1 = $[3]; + t0 = $[1]; } - const x = t1; + const x = t0; return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/escape-analysis-non-escaping-interleaved-allocating-nested-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/escape-analysis-non-escaping-interleaved-allocating-nested-dependency.expect.md index 64355ca6262..cee338b14e5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/escape-analysis-non-escaping-interleaved-allocating-nested-dependency.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/escape-analysis-non-escaping-interleaved-allocating-nested-dependency.expect.md @@ -40,36 +40,29 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(7); + const $ = _c(5); let t0; if ($[0] !== props.a) { - t0 = [props.a]; + const a = [props.a]; + + t0 = [a]; $[0] = props.a; $[1] = t0; } else { t0 = $[1]; } - const a = t0; - let t1; - if ($[2] !== a) { - t1 = [a]; - $[2] = a; - $[3] = t1; - } else { - t1 = $[3]; - } - const b = t1; + const b = t0; let c; - if ($[4] !== b || $[5] !== props.b) { + if ($[2] !== b || $[3] !== props.b) { c = []; const d = {}; d.b = b; c.push(props.b); - $[4] = b; - $[5] = props.b; - $[6] = c; + $[2] = b; + $[3] = props.b; + $[4] = c; } else { - c = $[6]; + c = $[4]; } return c; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-newline.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-newline.expect.md index bb1dcba1830..28c2a8e03b5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-newline.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-newline.expect.md @@ -32,10 +32,10 @@ import { c as _c } from "react/compiler-runtime"; import fbt from "fbt"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.name) { - t0 = fbt._( + const element = fbt._( "Hello {a really long description that got split into multiple lines}", [ fbt._param( @@ -46,21 +46,14 @@ function Component(props) { ], { hk: "1euPUp" }, ); + + t0 = element.toString(); $[0] = props.name; $[1] = t0; } else { t0 = $[1]; } - const element = t0; - let t1; - if ($[2] !== element) { - t1 = element.toString(); - $[2] = element; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-quotes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-quotes.expect.md index b1543be773e..eb41b86fdfd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-quotes.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-quotes.expect.md @@ -27,27 +27,28 @@ import { c as _c } from "react/compiler-runtime"; import fbt from "fbt"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.name) { - t0 = fbt._('Hello {"user" name}', [fbt._param('"user" name', props.name)], { - hk: "S0vMe", - }); + const element = fbt._( + 'Hello {"user" name}', + [ + fbt._param( + '"user" name', + + props.name, + ), + ], + { hk: "S0vMe" }, + ); + + t0 = element.toString(); $[0] = props.name; $[1] = t0; } else { t0 = $[1]; } - const element = t0; - let t1; - if ($[2] !== element) { - t1 = element.toString(); - $[2] = element; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-unicode.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-unicode.expect.md index c13f618330d..60d23497466 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-unicode.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-unicode.expect.md @@ -27,29 +27,28 @@ import { c as _c } from "react/compiler-runtime"; import fbt from "fbt"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.name) { - t0 = fbt._( + const element = fbt._( "Hello {user name ☺}", - [fbt._param("user name \u263A", props.name)], + [ + fbt._param( + "user name \u263A", + + props.name, + ), + ], { hk: "1En1lp" }, ); + + t0 = element.toString(); $[0] = props.name; $[1] = t0; } else { t0 = $[1]; } - const element = t0; - let t1; - if ($[2] !== element) { - t1 = element.toString(); - $[2] = element; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-to-string.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-to-string.expect.md index ff7fe4569f0..eca12d2404c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-to-string.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-to-string.expect.md @@ -27,27 +27,28 @@ import { c as _c } from "react/compiler-runtime"; import fbt from "fbt"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.name) { - t0 = fbt._("Hello {user name}", [fbt._param("user name", props.name)], { - hk: "2zEDKF", - }); + const element = fbt._( + "Hello {user name}", + [ + fbt._param( + "user name", + + props.name, + ), + ], + { hk: "2zEDKF" }, + ); + + t0 = element.toString(); $[0] = props.name; $[1] = t0; } else { t0 = $[1]; } - const element = t0; - let t1; - if ($[2] !== element) { - t1 = element.toString(); - $[2] = element; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-maybe-mutates-hook-return-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-maybe-mutates-hook-return-value.expect.md index 0f65c54583a..894c1ecc1d1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-maybe-mutates-hook-return-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-maybe-mutates-hook-return-value.expect.md @@ -22,28 +22,21 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(2); const id = useSelectedEntitytId(); let t0; if ($[0] !== id) { - t0 = () => { + const onLoad = () => { log(id); }; + + t0 = ; $[0] = id; $[1] = t0; } else { t0 = $[1]; } - const onLoad = t0; - let t1; - if ($[2] !== onLoad) { - t1 = ; - $[2] = onLoad; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call.expect.md index 2df5b908902..714e61eb890 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call.expect.md @@ -21,27 +21,20 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props) { - t0 = function () { + const f = function () { return
{props.name}
; }; + + t0 = f.call(); $[0] = props; $[1] = t0; } else { t0 = $[1]; } - const f = t0; - let t1; - if ($[2] !== f) { - t1 = f.call(); - $[2] = f; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-functionexpr-conditional-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-functionexpr-conditional-dep.expect.md index e99e9e1c802..96a1d3e5726 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-functionexpr-conditional-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-functionexpr-conditional-dep.expect.md @@ -55,33 +55,26 @@ import { Stringify } from "shared-runtime"; * (kind: exception) Cannot read properties of null (reading 'prop') */ function Component(t0) { - const $ = _c(5); + const $ = _c(3); const { obj, isObjNull } = t0; let t1; if ($[0] !== isObjNull || $[1] !== obj) { - t1 = () => { + const callback = () => { if (!isObjNull) { return obj.prop; } else { return null; } }; + + t1 = ; $[0] = isObjNull; $[1] = obj; $[2] = t1; } else { t1 = $[2]; } - const callback = t1; - let t2; - if ($[3] !== callback) { - t2 = ; - $[3] = callback; - $[4] = t2; - } else { - t2 = $[4]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md index 55cab1e9f3b..c0c2bff9f7a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md @@ -27,7 +27,7 @@ function useFoo() { ```javascript import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees function useFoo() { - const $ = _c(9); + const $ = _c(7); const onClick = (response) => { setState(DISABLED_FORM); }; @@ -48,31 +48,24 @@ function useFoo() { const handleLogout = t1; let t2; if ($[2] !== handleLogout) { - t2 = () => handleLogout()} />; + const getComponent = () => handleLogout()} />; + + t2 = getComponent(); $[2] = handleLogout; $[3] = t2; } else { t2 = $[3]; } - const getComponent = t2; let t3; - if ($[4] !== getComponent) { - t3 = getComponent(); - $[4] = getComponent; - $[5] = t3; - } else { - t3 = $[5]; - } - let t4; - if ($[6] !== onClick || $[7] !== t3) { - t4 = [t3, onClick]; - $[6] = onClick; - $[7] = t3; - $[8] = t4; + if ($[4] !== onClick || $[5] !== t2) { + t3 = [t2, onClick]; + $[4] = onClick; + $[5] = t2; + $[6] = t3; } else { - t4 = $[8]; + t3 = $[6]; } - return t4; + return t3; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/array-map-named-chained-callbacks.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/array-map-named-chained-callbacks.expect.md index 9bf77fd1276..96ec12d5eab 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/array-map-named-chained-callbacks.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/array-map-named-chained-callbacks.expect.md @@ -42,74 +42,58 @@ import { c as _c } from "react/compiler-runtime"; /** * conservative and assume that all named lambdas are conditionally called. */ function useFoo(t0) { - const $ = _c(17); + const $ = _c(13); const { arr1, arr2 } = t0; let t1; if ($[0] !== arr1[0]) { - t1 = () => arr1[0].value; + const getVal1 = () => arr1[0].value; + t1 = (e) => getVal1() + e.value; $[0] = arr1[0]; $[1] = t1; } else { t1 = $[1]; } - const getVal1 = t1; + const cb1 = t1; let t2; - if ($[2] !== getVal1) { - t2 = (e) => getVal1() + e.value; - $[2] = getVal1; - $[3] = t2; + if ($[2] !== arr1 || $[3] !== cb1) { + t2 = arr1.map(cb1); + $[2] = arr1; + $[3] = cb1; + $[4] = t2; } else { - t2 = $[3]; + t2 = $[4]; } - const cb1 = t2; + const x = t2; let t3; - if ($[4] !== arr1 || $[5] !== cb1) { - t3 = arr1.map(cb1); - $[4] = arr1; - $[5] = cb1; + if ($[5] !== arr2) { + const getVal2 = () => arr2[0].value; + t3 = (e_0) => getVal2() + e_0.value; + $[5] = arr2; $[6] = t3; } else { t3 = $[6]; } - const x = t3; + const cb2 = t3; let t4; - if ($[7] !== arr2) { - t4 = () => arr2[0].value; - $[7] = arr2; - $[8] = t4; + if ($[7] !== arr1 || $[8] !== cb2) { + t4 = arr1.map(cb2); + $[7] = arr1; + $[8] = cb2; + $[9] = t4; } else { - t4 = $[8]; + t4 = $[9]; } - const getVal2 = t4; + const y = t4; let t5; - if ($[9] !== getVal2) { - t5 = (e_0) => getVal2() + e_0.value; - $[9] = getVal2; - $[10] = t5; + if ($[10] !== x || $[11] !== y) { + t5 = [x, y]; + $[10] = x; + $[11] = y; + $[12] = t5; } else { - t5 = $[10]; + t5 = $[12]; } - const cb2 = t5; - let t6; - if ($[11] !== arr1 || $[12] !== cb2) { - t6 = arr1.map(cb2); - $[11] = arr1; - $[12] = cb2; - $[13] = t6; - } else { - t6 = $[13]; - } - const y = t6; - let t7; - if ($[14] !== x || $[15] !== y) { - t7 = [x, y]; - $[14] = x; - $[15] = y; - $[16] = t7; - } else { - t7 = $[16]; - } - return t7; + return t5; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/assume-invoked/conditional-call-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/assume-invoked/conditional-call-chain.expect.md index e0dc1eeb5f7..6114996b896 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/assume-invoked/conditional-call-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-function/nullable-objects/assume-invoked/conditional-call-chain.expect.md @@ -42,7 +42,7 @@ import { useRef } from "react"; import { Stringify } from "shared-runtime"; function Component(t0) { - const $ = _c(9); + const $ = _c(7); const { a, b } = t0; let t1; if ($[0] !== a.value) { @@ -70,29 +70,22 @@ function Component(t0) { const hasLogged = useRef(false); let t3; if ($[4] !== logA || $[5] !== logB) { - t3 = () => { + const log = () => { if (!hasLogged.current) { logA(); logB(); hasLogged.current = true; } }; + + t3 = ; $[4] = logA; $[5] = logB; $[6] = t3; } else { t3 = $[6]; } - const log = t3; - let t4; - if ($[7] !== log) { - t4 = ; - $[7] = log; - $[8] = t4; - } else { - t4 = $[8]; - } - return t4; + return t3; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-lowercase-localvar-memberexpr-in-lambda.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-lowercase-localvar-memberexpr-in-lambda.expect.md index 24823479393..31aa7c77a1e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-lowercase-localvar-memberexpr-in-lambda.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-lowercase-localvar-memberexpr-in-lambda.expect.md @@ -24,28 +24,20 @@ import { c as _c } from "react/compiler-runtime"; import * as SharedRuntime from "shared-runtime"; import { invoke } from "shared-runtime"; function useComponentFactory(t0) { - const $ = _c(4); + const $ = _c(2); const { name } = t0; let t1; if ($[0] !== name) { - t1 = () => ( + const cb = () => ( hello world {name} ); + t1 = invoke(cb); $[0] = name; $[1] = t1; } else { t1 = $[1]; } - const cb = t1; - let t2; - if ($[2] !== cb) { - t2 = invoke(cb); - $[2] = cb; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-captures-receiver-noAlias.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-captures-receiver-noAlias.expect.md index e687c995d07..70872381885 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-captures-receiver-noAlias.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-captures-receiver-noAlias.expect.md @@ -25,34 +25,18 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel function Component(props) { - const $ = _c(6); + const $ = _c(2); let t0; if ($[0] !== props.a) { - t0 = { a: props.a }; + const item = { a: props.a }; + const items = [item]; + t0 = items.map(_temp); $[0] = props.a; $[1] = t0; } else { t0 = $[1]; } - const item = t0; - let t1; - if ($[2] !== item) { - t1 = [item]; - $[2] = item; - $[3] = t1; - } else { - t1 = $[3]; - } - const items = t1; - let t2; - if ($[4] !== items) { - t2 = items.map(_temp); - $[4] = items; - $[5] = t2; - } else { - t2 = $[5]; - } - const mapped = t2; + const mapped = t0; return mapped; } function _temp(item_0) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prop-capturing-function-1.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prop-capturing-function-1.expect.md index a7f50325dd7..9bfd9cf06ad 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prop-capturing-function-1.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prop-capturing-function-1.expect.md @@ -23,28 +23,20 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function component(a, b) { - const $ = _c(5); + const $ = _c(3); let t0; if ($[0] !== a || $[1] !== b) { - t0 = { a, b }; + const z = { a, b }; + t0 = function () { + console.log(z); + }; $[0] = a; $[1] = b; $[2] = t0; } else { t0 = $[2]; } - const z = t0; - let t1; - if ($[3] !== z) { - t1 = function () { - console.log(z); - }; - $[3] = z; - $[4] = t1; - } else { - t1 = $[4]; - } - const x = t1; + const x = t0; return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md index 741a30d7de2..41bab7ccc9d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md @@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { mutate, shallowCopy, Stringify } from "shared-runtime"; function useFoo(t0) { - const $ = _c(6); + const $ = _c(4); const { a } = t0; let local; if ($[0] !== a) { @@ -42,22 +42,14 @@ function useFoo(t0) { } let t1; if ($[2] !== local.b.c) { - t1 = () => local.b.c; + const fn = () => local.b.c; + t1 = ; $[2] = local.b.c; $[3] = t1; } else { t1 = $[3]; } - const fn = t1; - let t2; - if ($[4] !== fn) { - t2 = ; - $[4] = fn; - $[5] = t2; - } else { - t2 = $[5]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md index 53d3d04531b..8a090ef8966 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md @@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { shallowCopy, Stringify, mutate } from "shared-runtime"; function useFoo(t0) { - const $ = _c(6); + const $ = _c(4); const { a } = t0; let local; if ($[0] !== a) { @@ -42,22 +42,14 @@ function useFoo(t0) { } let t1; if ($[2] !== local) { - t1 = () => [() => local.b.c]; + const fn = () => [() => local.b.c]; + t1 = ; $[2] = local; $[3] = t1; } else { t1 = $[3]; } - const fn = t1; - let t2; - if ($[4] !== fn) { - t2 = ; - $[4] = fn; - $[5] = t2; - } else { - t2 = $[5]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md index 22b17977cbc..7ffc258b3d6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md @@ -31,26 +31,19 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { Stringify } from "shared-runtime"; function useFoo(t0) { - const $ = _c(4); + const $ = _c(2); const { a } = t0; let t1; if ($[0] !== a.b.c) { - t1 = () => () => ({ value: a.b.c }); + const fn = () => () => ({ value: a.b.c }); + + t1 = ; $[0] = a.b.c; $[1] = t1; } else { t1 = $[1]; } - const fn = t1; - let t2; - if ($[2] !== fn) { - t2 = ; - $[2] = fn; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md index f8a8af1fd4f..1c01c96b837 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md @@ -31,30 +31,23 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { identity, Stringify } from "shared-runtime"; function useFoo(t0) { - const $ = _c(4); + const $ = _c(2); const { a } = t0; let t1; if ($[0] !== a) { - t1 = { + const x = { fn() { return identity(a.b.c); }, }; + + t1 = ; $[0] = a; $[1] = t1; } else { t1 = $[1]; } - const x = t1; - let t2; - if ($[2] !== x) { - t2 = ; - $[2] = x; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-invalidate-jsx.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-invalidate-jsx.expect.md index 291ba390143..840b79a06b5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-invalidate-jsx.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-invalidate-jsx.expect.md @@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime"; import { useHook } from "shared-runtime"; function Component(props) { - const $ = _c(6); + const $ = _c(4); const o = {}; let t0; if ($[0] !== props.value) { @@ -44,22 +44,15 @@ function Component(props) { o.value = props.value; let t1; if ($[2] !== x) { - t1 =
{x}
; + const y =
{x}
; + + t1 =
{y}
; $[2] = x; $[3] = t1; } else { t1 = $[3]; } - const y = t1; - let t2; - if ($[4] !== y) { - t2 =
{y}
; - $[4] = y; - $[5] = t2; - } else { - t2 = $[5]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-may-invalidate-array.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-may-invalidate-array.expect.md index 91883a9bdf0..953cbef5a7e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-may-invalidate-array.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/prune-scopes-whose-deps-may-invalidate-array.expect.md @@ -31,7 +31,7 @@ import { c as _c } from "react/compiler-runtime"; import { useHook, identity } from "shared-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let x = 42; if (props.cond) { x = []; @@ -41,22 +41,15 @@ function Component(props) { identity(x); let t0; if ($[0] !== x) { - t0 = [x]; + const y = [x]; + + t0 = [y]; $[0] = x; $[1] = t0; } else { t0 = $[1]; } - const y = t0; - let t1; - if ($[2] !== y) { - t1 = [y]; - $[2] = y; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref-param.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref-param.expect.md index c8922ab0c46..96d97e99abf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref-param.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref-param.expect.md @@ -66,25 +66,17 @@ function Parent(t0) { } function ChildImpl(_props, ref) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== ref) { - t0 = () => ref.current; + const cb = () => ref.current; + t0 = ; $[0] = ref; $[1] = t0; } else { t0 = $[1]; } - const cb = t0; - let t1; - if ($[2] !== cb) { - t1 = ; - $[2] = cb; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } const Child = forwardRef(ChildImpl); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref.expect.md index c3876c22924..85969ce25ea 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-ref.expect.md @@ -41,29 +41,21 @@ import { Stringify } from "shared-runtime"; * `pruneNonReactiveDependencies` */ function Component(t0) { - const $ = _c(4); + const $ = _c(2); const { cond } = t0; const ref1 = useRef(1); const ref2 = useRef(2); const ref = cond ? ref1 : ref2; let t1; if ($[0] !== ref) { - t1 = () => ref.current; + const cb = () => ref.current; + t1 = ; $[0] = ref; $[1] = t1; } else { t1 = $[1]; } - const cb = t1; - let t2; - if ($[2] !== cb) { - t2 = ; - $[2] = cb; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md index c6331bd4a08..28263b6dbaf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md @@ -35,34 +35,23 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(6); - let a; + const $ = _c(2); let t0; if ($[0] !== props.b) { - a = {}; + const a = {}; const b = []; b.push(props.b); a.a = null; - t0 = [a]; + const c = [a]; + + t0 = [c, a]; $[0] = props.b; - $[1] = a; - $[2] = t0; - } else { - a = $[1]; - t0 = $[2]; - } - const c = t0; - let t1; - if ($[3] !== a || $[4] !== c) { - t1 = [c, a]; - $[3] = a; - $[4] = c; - $[5] = t1; + $[1] = t0; } else { - t1 = $[5]; + t0 = $[1]; } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-array.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-array.expect.md index b9ff24519e5..1d58d44ef31 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-array.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-array.expect.md @@ -32,18 +32,24 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(2); - let t0; + const $ = _c(4); + let x; if ($[0] !== props.input) { - const x = []; + x = []; const y = x; y.push(props.input); - - t0 = [x[0]]; $[0] = props.input; - $[1] = t0; + $[1] = x; + } else { + x = $[1]; + } + let t0; + if ($[2] !== x[0]) { + t0 = [x[0]]; + $[2] = x[0]; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-lambda.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-lambda.expect.md index ebf30d9d285..36d05dda69c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-lambda.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-via-aliased-mutation-lambda.expect.md @@ -35,22 +35,28 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(2); - let t0; + const $ = _c(4); + let x; if ($[0] !== props.input) { - const x = []; + x = []; const f = (arg) => { const y = x; y.push(arg); }; f(props.input); - - t0 = [x[0]]; $[0] = props.input; - $[1] = t0; + $[1] = x; + } else { + x = $[1]; + } + let t0; + if ($[2] !== x[0]) { + t0 = [x[0]]; + $[2] = x[0]; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-aliased-not-added-to-dep-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-aliased-not-added-to-dep-2.expect.md index f6b90ea1d5f..63268de4271 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-aliased-not-added-to-dep-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-aliased-not-added-to-dep-2.expect.md @@ -18,28 +18,21 @@ function Foo({a}) { ```javascript import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender:false function Foo(t0) { - const $ = _c(4); + const $ = _c(2); const { a } = t0; const ref = useRef(); const val = ref.current; let t1; if ($[0] !== a) { - t1 = { a, val }; + const x = { a, val }; + + t1 = ; $[0] = a; $[1] = t1; } else { t1 = $[1]; } - const x = t1; - let t2; - if ($[2] !== x) { - t2 = ; - $[2] = x; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; + return t1; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep-2.expect.md index da0b97859a5..76a1b00776e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep-2.expect.md @@ -17,27 +17,20 @@ function Foo({a}) { ```javascript import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender:false function Foo(t0) { - const $ = _c(4); + const $ = _c(2); const { a } = t0; const ref = useRef(); let t1; if ($[0] !== a) { - t1 = { a, val: ref.current }; + const x = { a, val: ref.current }; + + t1 = ; $[0] = a; $[1] = t1; } else { t1 = $[1]; } - const x = t1; - let t2; - if ($[2] !== x) { - t2 = ; - $[2] = x; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; + return t1; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-function.expect.md index 3287997cf76..f9471d99501 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-function.expect.md @@ -41,11 +41,11 @@ const $ = "module_$"; const t0 = "module_t0"; const c_0 = "module_c_0"; function useFoo(props) { - const $0 = _c(4); + const $0 = _c(2); const c_00 = $0[0] !== props.value; let t1; if (c_00) { - t1 = () => { + const a = () => { const b = () => { const c = () => { console.log($); @@ -57,22 +57,14 @@ function useFoo(props) { }; return b; }; + + t1 = a()()(); $0[0] = props.value; $0[1] = t1; } else { t1 = $0[1]; } - const a = t1; - const c_2 = $0[2] !== a; - let t2; - if (c_2) { - t2 = a()()(); - $0[2] = a; - $0[3] = t2; - } else { - t2 = $0[3]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md index 1d5ebaad9ac..15bc857ac76 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md @@ -35,60 +35,44 @@ import { useMemo } from "react"; import { useFragment } from "shared-runtime"; function Component() { - const $ = _c(11); + const $ = _c(7); const data = useFragment(); let t0; if ($[0] !== data.nodes) { - t0 = data.nodes ?? []; + const nodes = data.nodes ?? []; + const flatMap = nodes.flatMap(_temp); + t0 = flatMap.filter(_temp2); $[0] = data.nodes; $[1] = t0; } else { t0 = $[1]; } - const nodes = t0; + const filtered = t0; let t1; - if ($[2] !== nodes) { - t1 = nodes.flatMap(_temp); - $[2] = nodes; + if ($[2] !== filtered) { + t1 = filtered.map(); + $[2] = filtered; $[3] = t1; } else { t1 = $[3]; } - const flatMap = t1; - let t2; - if ($[4] !== flatMap) { - t2 = flatMap.filter(_temp2); - $[4] = flatMap; - $[5] = t2; - } else { - t2 = $[5]; - } - const filtered = t2; - let t3; - if ($[6] !== filtered) { - t3 = filtered.map(); - $[6] = filtered; - $[7] = t3; - } else { - t3 = $[7]; - } - const map = t3; + const map = t1; const index = filtered.findIndex(_temp3); - let t4; - if ($[8] !== index || $[9] !== map) { - t4 = ( + let t2; + if ($[4] !== index || $[5] !== map) { + t2 = (
{map} {index}
); - $[8] = index; - $[9] = map; - $[10] = t4; + $[4] = index; + $[5] = map; + $[6] = t2; } else { - t4 = $[10]; + t2 = $[6]; } - return t4; + return t2; } function _temp3(x) { return x === null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md index 8c68340b7f2..4728226c64c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md @@ -32,60 +32,44 @@ import { useMemo } from "react"; import { useFragment } from "shared-runtime"; function Component() { - const $ = _c(11); + const $ = _c(7); const data = useFragment(); let t0; if ($[0] !== data.nodes) { - t0 = data.nodes ?? []; + const nodes = data.nodes ?? []; + const flatMap = nodes.flatMap(_temp); + t0 = flatMap.filter(_temp2); $[0] = data.nodes; $[1] = t0; } else { t0 = $[1]; } - const nodes = t0; + const filtered = t0; let t1; - if ($[2] !== nodes) { - t1 = nodes.flatMap(_temp); - $[2] = nodes; + if ($[2] !== filtered) { + t1 = filtered.map(); + $[2] = filtered; $[3] = t1; } else { t1 = $[3]; } - const flatMap = t1; - let t2; - if ($[4] !== flatMap) { - t2 = flatMap.filter(_temp2); - $[4] = flatMap; - $[5] = t2; - } else { - t2 = $[5]; - } - const filtered = t2; - let t3; - if ($[6] !== filtered) { - t3 = filtered.map(); - $[6] = filtered; - $[7] = t3; - } else { - t3 = $[7]; - } - const map = t3; + const map = t1; const index = filtered.findIndex(_temp3); - let t4; - if ($[8] !== index || $[9] !== map) { - t4 = ( + let t2; + if ($[4] !== index || $[5] !== map) { + t2 = (
{map} {index}
); - $[8] = index; - $[9] = map; - $[10] = t4; + $[4] = index; + $[5] = map; + $[6] = t2; } else { - t4 = $[10]; + t2 = $[6]; } - return t4; + return t2; } function _temp3(x) { return x === null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-function-call-with-frozen-argument-in-function-expression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-function-call-with-frozen-argument-in-function-expression.expect.md index 320b252bb5c..ef65f6026e5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-function-call-with-frozen-argument-in-function-expression.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-function-call-with-frozen-argument-in-function-expression.expect.md @@ -30,40 +30,33 @@ import { c as _c } from "react/compiler-runtime"; import { identity, makeObject_Primitives, Stringify } from "shared-runtime"; function Example(props) { - const $ = _c(7); + const $ = _c(5); const object = props.object; let t0; if ($[0] !== object || $[1] !== props.value) { - t0 = () => { + const f = () => { const obj = identity(object); obj.property = props.value; return obj; }; + + t0 = f(); $[0] = object; $[1] = props.value; $[2] = t0; } else { t0 = $[2]; } - const f = t0; + const obj_0 = t0; let t1; - if ($[3] !== f) { - t1 = f(); - $[3] = f; + if ($[3] !== obj_0) { + t1 = ; + $[3] = obj_0; $[4] = t1; } else { t1 = $[4]; } - const obj_0 = t1; - let t2; - if ($[5] !== obj_0) { - t2 = ; - $[5] = obj_0; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-method-call-on-frozen-value-in-function-expression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-method-call-on-frozen-value-in-function-expression.expect.md index d3dbb86711a..4df503bcd22 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-method-call-on-frozen-value-in-function-expression.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-result-of-method-call-on-frozen-value-in-function-expression.expect.md @@ -30,40 +30,33 @@ import { c as _c } from "react/compiler-runtime"; import { makeObject_Primitives, Stringify } from "shared-runtime"; function Example(props) { - const $ = _c(7); + const $ = _c(5); const object = props.object; let t0; if ($[0] !== object || $[1] !== props.value) { - t0 = () => { + const f = () => { const obj = object.makeObject(); obj.property = props.value; return obj; }; + + t0 = f(); $[0] = object; $[1] = props.value; $[2] = t0; } else { t0 = $[2]; } - const f = t0; + const obj_0 = t0; let t1; - if ($[3] !== f) { - t1 = f(); - $[3] = f; + if ($[3] !== obj_0) { + t1 = ; + $[3] = obj_0; $[4] = t1; } else { t1 = $[4]; } - const obj_0 = t1; - let t2; - if ($[5] !== obj_0) { - t2 = ; - $[5] = obj_0; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md index 7db207a5622..4f2b711d89a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md @@ -45,7 +45,7 @@ import { Stringify, identity, makeArray, toJSON } from "shared-runtime"; import { useMemo } from "react"; function Component(props) { - const $ = _c(12); + const $ = _c(10); let t0; let t1; if ($[0] !== props) { @@ -71,57 +71,50 @@ function Component(props) { } let t2; if ($[3] !== t0) { - t2 = { url: t0 }; - $[3] = t0; - $[4] = t2; - } else { - t2 = $[4]; - } - const linkProps = t2; - let t3; - if ($[5] !== linkProps) { + const linkProps = { url: t0 }; + const x = {}; + let t3; let t4; let t5; let t6; let t7; - let t8; - if ($[7] === Symbol.for("react.memo_cache_sentinel")) { - t4 = [1]; - t5 = [2]; - t6 = [3]; - t7 = [4]; - t8 = [5]; - $[7] = t4; - $[8] = t5; - $[9] = t6; - $[10] = t7; - $[11] = t8; + if ($[5] === Symbol.for("react.memo_cache_sentinel")) { + t3 = [1]; + t4 = [2]; + t5 = [3]; + t6 = [4]; + t7 = [5]; + $[5] = t3; + $[6] = t4; + $[7] = t5; + $[8] = t6; + $[9] = t7; } else { - t4 = $[7]; - t5 = $[8]; - t6 = $[9]; - t7 = $[10]; - t8 = $[11]; + t3 = $[5]; + t4 = $[6]; + t5 = $[7]; + t6 = $[8]; + t7 = $[9]; } - t3 = ( + t2 = ( {makeArray(x, 2)} ); - $[5] = linkProps; - $[6] = t3; + $[3] = t0; + $[4] = t2; } else { - t3 = $[6]; + t2 = $[4]; } - return t3; + return t2; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-undefined-expression-of-jsxexpressioncontainer.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-undefined-expression-of-jsxexpressioncontainer.expect.md index 9d41b7de21f..c5a34bc4cad 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-undefined-expression-of-jsxexpressioncontainer.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-undefined-expression-of-jsxexpressioncontainer.expect.md @@ -48,28 +48,21 @@ import { c as _c } from "react/compiler-runtime"; import { StaticText1, Stringify, Text } from "shared-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(2); const { buttons } = props; let t0; if ($[0] !== buttons) { const [, ...nonPrimaryButtons] = buttons; - t0 = nonPrimaryButtons.map(_temp); + const renderedNonPrimaryButtons = nonPrimaryButtons.map(_temp); + + t0 = {renderedNonPrimaryButtons}; $[0] = buttons; $[1] = t0; } else { t0 = $[1]; } - const renderedNonPrimaryButtons = t0; - let t1; - if ($[2] !== renderedNonPrimaryButtons) { - t1 = {renderedNonPrimaryButtons}; - $[2] = renderedNonPrimaryButtons; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } function _temp(buttonProps, i) { return ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md index db8877f061b..1b45e08393b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md @@ -29,10 +29,10 @@ import { c as _c } from "react/compiler-runtime"; import { throwInput } from "shared-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props) { - t0 = () => { + const callback = () => { try { throwInput([props.value]); } catch (t1) { @@ -40,21 +40,14 @@ function Component(props) { return e; } }; + + t0 = callback(); $[0] = props; $[1] = t0; } else { t0 = $[1]; } - const callback = t0; - let t1; - if ($[2] !== callback) { - t1 = callback(); - $[2] = callback; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array.expect.md index ce8e06fcf92..fc829218f5a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array.expect.md @@ -25,25 +25,17 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; // @enableUseTypeAnnotations function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.id) { - t0 = makeArray(props.id); + const x = makeArray(props.id); + t0 = x.at(0); $[0] = props.id; $[1] = t0; } else { t0 = $[1]; } - const x = t0; - let t1; - if ($[2] !== x) { - t1 = x.at(0); - $[2] = x; - $[3] = t1; - } else { - t1 = $[3]; - } - const y = t1; + const y = t0; return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array_.flow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array_.flow.expect.md index 03d1f66740b..5058015fd32 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array_.flow.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-annotations/type-annotation-var-array_.flow.expect.md @@ -29,25 +29,17 @@ import { c as _c } from "react/compiler-runtime"; import { identity } from "shared-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.id) { - t0 = makeArray(props.id); + const x = makeArray(props.id); + t0 = x.at(0); $[0] = props.id; $[1] = t0; } else { t0 = $[1]; } - const x = t0; - let t1; - if ($[2] !== x) { - t1 = x.at(0); - $[2] = x; - $[3] = t1; - } else { - t1 = $[3]; - } - const y = t1; + const y = t0; return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-memo-simple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-memo-simple.expect.md index d721128cb70..b9e7e1bfe10 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-memo-simple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-memo-simple.expect.md @@ -22,25 +22,17 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function Component(props) { "use memo"; - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.foo) { - t0 = [props.foo]; + const x = [props.foo]; + t0 =
"foo"
; $[0] = props.foo; $[1] = t0; } else { t0 = $[1]; } - const x = t0; - let t1; - if ($[2] !== x) { - t1 =
"foo"
; - $[2] = x; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useContext-read-context-in-callback-if-condition.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useContext-read-context-in-callback-if-condition.expect.md index 1d09cbb3597..611606ea38d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useContext-read-context-in-callback-if-condition.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useContext-read-context-in-callback-if-condition.expect.md @@ -39,41 +39,34 @@ import { Stringify } from "shared-runtime"; const FooContext = createContext({ current: true }); function Component(props) { - const $ = _c(6); + const $ = _c(4); const foo = useContext(FooContext); let t0; if ($[0] !== foo.current) { - t0 = () => { + const getValue = () => { if (foo.current) { return {}; } else { return null; } }; + + t0 = getValue(); $[0] = foo.current; $[1] = t0; } else { t0 = $[1]; } - const getValue = t0; + const value = t0; let t1; - if ($[2] !== getValue) { - t1 = getValue(); - $[2] = getValue; + if ($[2] !== value) { + t1 = ; + $[2] = value; $[3] = t1; } else { t1 = $[3]; } - const value = t1; - let t2; - if ($[4] !== value) { - t2 = ; - $[4] = value; - $[5] = t2; - } else { - t2 = $[5]; - } - return t2; + return t1; } export const FIXTURE_ENTRYPOINT = {