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/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/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/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/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/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-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!'}, + ], + }, + ], +}; 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 = { diff --git a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts index 618d3b78b9d..730b6ff6f85 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts @@ -101,7 +101,7 @@ const COMPILER_OPTIONS: Partial = { // Don't emit errors on Flow suppressions--Flow already gave a signal flowSuppressions: false, environment: validateEnvironmentConfig({ - validateRefAccessDuringRender: false, + validateRefAccessDuringRender: true, validateNoSetStateInRender: true, validateNoSetStateInEffects: true, validateNoJSXInTryStatements: true, diff --git a/packages/eslint-plugin-react-hooks/src/rules/ReactCompiler.ts b/packages/eslint-plugin-react-hooks/src/rules/ReactCompiler.ts index 8961561ef96..795a117981a 100644 --- a/packages/eslint-plugin-react-hooks/src/rules/ReactCompiler.ts +++ b/packages/eslint-plugin-react-hooks/src/rules/ReactCompiler.ts @@ -103,7 +103,7 @@ const COMPILER_OPTIONS: Partial = { // Don't emit errors on Flow suppressions--Flow already gave a signal flowSuppressions: false, environment: validateEnvironmentConfig({ - validateRefAccessDuringRender: false, + validateRefAccessDuringRender: true, validateNoSetStateInRender: true, validateNoSetStateInEffects: true, validateNoJSXInTryStatements: true,