diff --git a/crates/oxc_react_compiler/tests/snapshot.rs b/crates/oxc_react_compiler/tests/snapshot.rs index c758728a3a..35a7e3d148 100644 --- a/crates/oxc_react_compiler/tests/snapshot.rs +++ b/crates/oxc_react_compiler/tests/snapshot.rs @@ -173,6 +173,20 @@ fn parse_pragma(source: &str) -> (SourceType, PluginOptions) { } } + // Mirror the snap runner (`packages/snap/src/compiler.ts`): the fixture corpus runs + // with `validatePreserveExistingMemoizationGuarantees` OFF by default — most fixtures + // care about compilation output, not whether manual memoization is preserved — and it + // is turned on only when the fixture's first line opts in via the directive. Snap keys + // off substring presence alone (ignoring any `:value`), so replicate that exactly and + // let it override whatever the directive loop parsed. Without this, fixtures that set + // `@enablePreserveExistingMemoizationGuarantees:false` still hit `ValidatePreservedManual- + // Memoization` and bail with a spurious "memoization could not be preserved" error. + options.environment.validate_preserve_existing_memoization_guarantees = source + .lines() + .next() + .unwrap_or("") + .contains("@validatePreserveExistingMemoizationGuarantees"); + // Upstream parses every (non-Flow) fixture with the TypeScript + JSX plugins, // regardless of extension, and as a module unless `@script` — so injected runtime // imports are `import`, not `require`. Flow fixtures are excluded (no oxc parser). diff --git a/crates/oxc_react_compiler/tests/snapshots/allow-modify-global-in-callback-jsx.snap b/crates/oxc_react_compiler/tests/snapshots/allow-modify-global-in-callback-jsx.snap index 36c9146fb0..79db72038b 100644 --- a/crates/oxc_react_compiler/tests/snapshots/allow-modify-global-in-callback-jsx.snap +++ b/crates/oxc_react_compiler/tests/snapshots/allow-modify-global-in-callback-jsx.snap @@ -2,8 +2,42 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/allow-modify-global-in-callback-jsx.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(275), length: 71 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `onClick`, but the source dependencies were []. Inferred dependency not present in source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +const someGlobal = { value: 0 }; +function Component(t0) { + const $ = _c(4); + const { value } = t0; + let t1; + if ($[0] !== value) { + t1 = () => { + someGlobal.value = value; + }; + $[0] = value; + $[1] = t1; + } else { + t1 = $[1]; + } + const onClick = t1; + let t2; + if ($[2] !== onClick) { + t2 =
{someGlobal.value}
; + $[2] = onClick; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ value: 0 }], + sequentialRenders: [ + { value: 1 }, + { value: 1 }, + { value: 42 }, + { value: 42 }, + { value: 0 } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/context-variable-as-jsx-element-tag.snap b/crates/oxc_react_compiler/tests/snapshots/context-variable-as-jsx-element-tag.snap index 2aacfa5749..2673952519 100644 --- a/crates/oxc_react_compiler/tests/snapshots/context-variable-as-jsx-element-tag.snap +++ b/crates/oxc_react_compiler/tests/snapshots/context-variable-as-jsx-element-tag.snap @@ -2,9 +2,32 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/context-variable-as-jsx-element-tag.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(244), length: 9 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(200), length: 55 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false +import { useMemo } from "react"; +import { Stringify } from "shared-runtime"; +function Component(props) { + const $ = _c(3); + let Component; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + Component = Stringify; + Component; + Component = Component; + $[0] = Component; + } else { + Component = $[0]; + } + let t0; + if ($[1] !== props) { + t0 = ; + $[1] = props; + $[2] = t0; + } else { + t0 = $[2]; + } + return t0; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ name: "Sathya" }] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/existing-variables-with-c-name.snap b/crates/oxc_react_compiler/tests/snapshots/existing-variables-with-c-name.snap index af894235eb..83746a8871 100644 --- a/crates/oxc_react_compiler/tests/snapshots/existing-variables-with-c-name.snap +++ b/crates/oxc_react_compiler/tests/snapshots/existing-variables-with-c-name.snap @@ -2,8 +2,52 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/existing-variables-with-c-name.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(408), length: 10 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `$c`, but the source dependencies were [state]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c2 } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo, useState } from "react"; +import { ValidateMemoization } from "shared-runtime"; +function Component(props) { + const $ = _c2(7); + const [state] = useState(0); + const c = state; + const _c = c; + const __c = _c; + const c1 = __c; + const $c = c1; + let t0; + if ($[0] !== $c) { + t0 = [$c]; + $[0] = $c; + $[1] = t0; + } else { + t0 = $[1]; + } + const array = t0; + let t1; + if ($[2] !== state) { + t1 = [state]; + $[2] = state; + $[3] = t1; + } else { + t1 = $[3]; + } + let t2; + if ($[4] !== array || $[5] !== t1) { + t2 = ; + $[4] = array; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], + sequentialRenders: [ + {}, + {}, + {} + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity-function-expression.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity-function-expression.snap index 8fded9afc0..caf4153563 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity-function-expression.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity-function-expression.snap @@ -2,8 +2,67 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/mutate-through-identity-function-expression.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(238), length: 28 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { identity, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(9); + const { a, b } = t0; + let x; + if ($[0] !== a || $[1] !== b) { + x = { a }; + const f = () => identity(x); + const x2 = f(); + x2.b = b; + $[0] = a; + $[1] = b; + $[2] = x; + } else { + x = $[2]; + } + let t1; + if ($[3] !== a || $[4] !== b) { + t1 = [a, b]; + $[3] = a; + $[4] = b; + $[5] = t1; + } else { + t1 = $[5]; + } + let t2; + if ($[6] !== t1 || $[7] !== x) { + t2 = ; + $[6] = t1; + $[7] = x; + $[8] = t2; + } else { + t2 = $[8]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0 + }, + { + a: 0, + b: 1 + }, + { + a: 1, + b: 1 + }, + { + a: 0, + b: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity.snap index dab719d360..505530a433 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__mutate-through-identity.snap @@ -2,8 +2,66 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/mutate-through-identity.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(238), length: 28 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { identity, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(9); + const { a, b } = t0; + let x; + if ($[0] !== a || $[1] !== b) { + x = { a }; + const x2 = identity(x); + x2.b = b; + $[0] = a; + $[1] = b; + $[2] = x; + } else { + x = $[2]; + } + let t1; + if ($[3] !== a || $[4] !== b) { + t1 = [a, b]; + $[3] = a; + $[4] = b; + $[5] = t1; + } else { + t1 = $[5]; + } + let t2; + if ($[6] !== t1 || $[7] !== x) { + t2 = ; + $[6] = t1; + $[7] = x; + $[8] = t2; + } else { + t2 = $[8]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0 + }, + { + a: 0, + b: 1 + }, + { + a: 1, + b: 1 + }, + { + a: 0, + b: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-control-flow-sensitive-mutation.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-control-flow-sensitive-mutation.snap index 438623d1f6..ab3b9f6727 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-control-flow-sensitive-mutation.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-control-flow-sensitive-mutation.snap @@ -2,8 +2,127 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/todo-control-flow-sensitive-mutation.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(331), length: 38 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { mutate, typedCapture, typedCreateFrom, typedMutate, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(21); + const { a, b, c } = t0; + let x; + if ($[0] !== a || $[1] !== b || $[2] !== c) { + x = [{ value: a }]; + if (b === 0) { + x.push({ value: c }); + } else { + mutate(x); + } + $[0] = a; + $[1] = b; + $[2] = c; + $[3] = x; + } else { + x = $[3]; + } + let t1; + if ($[4] !== a || $[5] !== b || $[6] !== c) { + t1 = [ + a, + b, + c + ]; + $[4] = a; + $[5] = b; + $[6] = c; + $[7] = t1; + } else { + t1 = $[7]; + } + let t2; + if ($[8] !== t1 || $[9] !== x) { + t2 = ; + $[8] = t1; + $[9] = x; + $[10] = t2; + } else { + t2 = $[10]; + } + let t3; + if ($[11] !== a || $[12] !== b || $[13] !== c) { + t3 = [ + a, + b, + c + ]; + $[11] = a; + $[12] = b; + $[13] = c; + $[14] = t3; + } else { + t3 = $[14]; + } + let t4; + if ($[15] !== t3 || $[16] !== x[0]) { + t4 = ; + $[15] = t3; + $[16] = x[0]; + $[17] = t4; + } else { + t4 = $[17]; + } + let t5; + if ($[18] !== t2 || $[19] !== t4) { + t5 = <>{t2};{t4};; + $[18] = t2; + $[19] = t4; + $[20] = t5; + } else { + t5 = $[20]; + } + return t5; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0, + c: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0, + c: 0 + }, + { + a: 0, + b: 1, + c: 0 + }, + { + a: 1, + b: 1, + c: 0 + }, + { + a: 1, + b: 1, + c: 1 + }, + { + a: 1, + b: 1, + c: 0 + }, + { + a: 1, + b: 0, + c: 0 + }, + { + a: 0, + b: 0, + c: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-transitivity-createfrom-capture-lambda.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-transitivity-createfrom-capture-lambda.snap index fb99fe70ef..842c23b899 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-transitivity-createfrom-capture-lambda.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__todo-transitivity-createfrom-capture-lambda.snap @@ -2,8 +2,71 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/todo-transitivity-createfrom-capture-lambda.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(234), length: 25 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false +import { useMemo } from "react"; +import { typedCapture, typedCreateFrom, typedMutate, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(9); + const { a, b } = t0; + let x; + if ($[0] !== a || $[1] !== b) { + x = [{ a }]; + const f = () => { + const y = typedCreateFrom(x); + const z = typedCapture(y); + return z; + }; + const z_0 = f(); + typedMutate(z_0, b); + $[0] = a; + $[1] = b; + $[2] = x; + } else { + x = $[2]; + } + let t1; + if ($[3] !== a || $[4] !== b) { + t1 = [a, b]; + $[3] = a; + $[4] = b; + $[5] = t1; + } else { + t1 = $[5]; + } + let t2; + if ($[6] !== t1 || $[7] !== x) { + t2 = ; + $[6] = t1; + $[7] = x; + $[8] = t2; + } else { + t2 = $[8]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0 + }, + { + a: 0, + b: 1 + }, + { + a: 1, + b: 1 + }, + { + a: 0, + b: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-add-captured-array-to-itself.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-add-captured-array-to-itself.snap index e1176d9f29..1d372a1bc9 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-add-captured-array-to-itself.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-add-captured-array-to-itself.snap @@ -2,10 +2,98 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/transitivity-add-captured-array-to-itself.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(288), length: 25 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(359), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(339), length: 26 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { typedCapture, typedCreateFrom, typedMutate, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(18); + const { a, b } = t0; + let o; + let x; + if ($[0] !== a || $[1] !== b) { + o = { a }; + x = [o]; + const y = typedCapture(x); + const z = typedCapture(y); + x.push(z); + x.push(b); + $[0] = a; + $[1] = b; + $[2] = o; + $[3] = x; + } else { + o = $[2]; + x = $[3]; + } + let t1; + if ($[4] !== a) { + t1 = [a]; + $[4] = a; + $[5] = t1; + } else { + t1 = $[5]; + } + let t2; + if ($[6] !== o || $[7] !== t1) { + t2 = ; + $[6] = o; + $[7] = t1; + $[8] = t2; + } else { + t2 = $[8]; + } + let t3; + if ($[9] !== a || $[10] !== b) { + t3 = [a, b]; + $[9] = a; + $[10] = b; + $[11] = t3; + } else { + t3 = $[11]; + } + let t4; + if ($[12] !== t3 || $[13] !== x) { + t4 = ; + $[12] = t3; + $[13] = x; + $[14] = t4; + } else { + t4 = $[14]; + } + let t5; + if ($[15] !== t2 || $[16] !== t4) { + t5 = <>{t2};{t4};; + $[15] = t2; + $[16] = t4; + $[17] = t5; + } else { + t5 = $[17]; + } + return t5; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0 + }, + { + a: 0, + b: 1 + }, + { + a: 1, + b: 1 + }, + { + a: 0, + b: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom-lambda.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom-lambda.snap index 69b392123c..88f81c5720 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom-lambda.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom-lambda.snap @@ -2,8 +2,71 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/transitivity-capture-createfrom-lambda.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(307), length: 28 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { typedCapture, typedCreateFrom, typedMutate, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(9); + const { a, b } = t0; + let x; + if ($[0] !== a || $[1] !== b) { + x = { a }; + const f = () => { + const y = typedCapture(x); + const z = typedCreateFrom(y); + return z; + }; + const z_0 = f(); + typedMutate(z_0, b); + $[0] = a; + $[1] = b; + $[2] = x; + } else { + x = $[2]; + } + let t1; + if ($[3] !== a || $[4] !== b) { + t1 = [a, b]; + $[3] = a; + $[4] = b; + $[5] = t1; + } else { + t1 = $[5]; + } + let t2; + if ($[6] !== t1 || $[7] !== x) { + t2 = ; + $[6] = t1; + $[7] = x; + $[8] = t2; + } else { + t2 = $[8]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0 + }, + { + a: 0, + b: 1 + }, + { + a: 1, + b: 1 + }, + { + a: 0, + b: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom.snap index 9521627be7..382e0b3a08 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-capture-createfrom.snap @@ -2,8 +2,67 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/transitivity-capture-createfrom.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(307), length: 28 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { typedCapture, typedCreateFrom, typedMutate, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(9); + const { a, b } = t0; + let x; + if ($[0] !== a || $[1] !== b) { + x = { a }; + const y = typedCapture(x); + const z = typedCreateFrom(y); + typedMutate(z, b); + $[0] = a; + $[1] = b; + $[2] = x; + } else { + x = $[2]; + } + let t1; + if ($[3] !== a || $[4] !== b) { + t1 = [a, b]; + $[3] = a; + $[4] = b; + $[5] = t1; + } else { + t1 = $[5]; + } + let t2; + if ($[6] !== t1 || $[7] !== x) { + t2 = ; + $[6] = t1; + $[7] = x; + $[8] = t2; + } else { + t2 = $[8]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0 + }, + { + a: 0, + b: 1 + }, + { + a: 1, + b: 1 + }, + { + a: 0, + b: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-phi-assign-or-capture.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-phi-assign-or-capture.snap index 499ce0ed85..43b56e614e 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-phi-assign-or-capture.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__transitivity-phi-assign-or-capture.snap @@ -2,8 +2,71 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/transitivity-phi-assign-or-capture.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(283), length: 28 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { typedCapture, typedCreateFrom, typedMutate, ValidateMemoization } from "shared-runtime"; +function Component(t0) { + const $ = _c(9); + const { a, b } = t0; + let x; + if ($[0] !== a || $[1] !== b) { + x = [{ a }]; + let z; + if (b) { + z = x; + } else { + z = typedCapture(x); + } + typedMutate(z, b); + $[0] = a; + $[1] = b; + $[2] = x; + } else { + x = $[2]; + } + let t1; + if ($[3] !== a || $[4] !== b) { + t1 = [a, b]; + $[3] = a; + $[4] = b; + $[5] = t1; + } else { + t1 = $[5]; + } + let t2; + if ($[6] !== t1 || $[7] !== x) { + t2 = ; + $[6] = t1; + $[7] = x; + $[8] = t2; + } else { + t2 = $[8]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ + a: 0, + b: 0 + }], + sequentialRenders: [ + { + a: 0, + b: 0 + }, + { + a: 0, + b: 1 + }, + { + a: 1, + b: 1 + }, + { + a: 0, + b: 0 + } + ] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-deplist-controlflow.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-deplist-controlflow.snap index e519f8f77e..bd4cf4882f 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-deplist-controlflow.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-deplist-controlflow.snap @@ -2,11 +2,67 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/useCallback-reordering-deplist-controlflow.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(440), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(381), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `foo`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(381), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(381), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr2`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enableNewMutationAliasingModel @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useCallback } from "react"; +import { Stringify } from "shared-runtime"; +function Foo(t0) { + const $ = _c(10); + const { arr1, arr2, foo } = t0; + let t1; + if ($[0] !== arr1) { + t1 = [arr1]; + $[0] = arr1; + $[1] = t1; + } else { + t1 = $[1]; + } + const x = t1; + let getVal1; + let t2; + if ($[2] !== arr2 || $[3] !== foo || $[4] !== x) { + let y = []; + getVal1 = _temp; + t2 = () => [y]; + foo ? y = x.concat(arr2) : y; + $[2] = arr2; + $[3] = foo; + $[4] = x; + $[5] = getVal1; + $[6] = t2; + } else { + getVal1 = $[5]; + t2 = $[6]; + } + const getVal2 = t2; + let t3; + if ($[7] !== getVal1 || $[8] !== getVal2) { + t3 = ; + $[7] = getVal1; + $[8] = getVal2; + $[9] = t3; + } else { + t3 = $[9]; + } + return t3; +} +function _temp() { + return { x: 2 }; +} +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ + arr1: [1, 2], + arr2: [3, 4], + foo: true + }], + sequentialRenders: [{ + arr1: [1, 2], + arr2: [3, 4], + foo: true + }, { + arr1: [1, 2], + arr2: [3, 4], + foo: false + }] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-depslist-assignment.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-depslist-assignment.snap index 4537d25258..c690f6d629 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-depslist-assignment.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__useCallback-reordering-depslist-assignment.snap @@ -2,10 +2,45 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/useCallback-reordering-depslist-assignment.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(434), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(381), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(381), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr2`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enableNewMutationAliasingModel @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useCallback } from "react"; +import { Stringify } from "shared-runtime"; +// We currently produce invalid output (incorrect scoping for `y` declaration) +function useFoo(arr1, arr2) { + const $ = _c(7); + let t0; + if ($[0] !== arr1) { + t0 = [arr1]; + $[0] = arr1; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let t1; + if ($[2] !== arr2 || $[3] !== x) { + let y; + t1 = () => ({ y }); + y = x.concat(arr2), y; + $[2] = arr2; + $[3] = x; + $[4] = t1; + } else { + t1 = $[4]; + } + const getVal = t1; + let t2; + if ($[5] !== getVal) { + t2 = ; + $[5] = getVal; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [[1, 2], [3, 4]] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/new-mutability__useMemo-reordering-depslist-assignment.snap b/crates/oxc_react_compiler/tests/snapshots/new-mutability__useMemo-reordering-depslist-assignment.snap index a2d632f3fd..d50c9489f2 100644 --- a/crates/oxc_react_compiler/tests/snapshots/new-mutability__useMemo-reordering-depslist-assignment.snap +++ b/crates/oxc_react_compiler/tests/snapshots/new-mutability__useMemo-reordering-depslist-assignment.snap @@ -2,10 +2,40 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/new-mutability/useMemo-reordering-depslist-assignment.ts --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(297), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(244), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(244), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr2`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enableNewMutationAliasingModel @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +function useFoo(arr1, arr2) { + const $ = _c(7); + let t0; + if ($[0] !== arr1) { + t0 = [arr1]; + $[0] = arr1; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== arr2 || $[3] !== x) { + y = x.concat(arr2), y; + $[2] = arr2; + $[3] = x; + $[4] = y; + } else { + y = $[4]; + } + let t1; + if ($[5] !== y) { + t1 = { y }; + $[5] = y; + $[6] = t1; + } else { + t1 = $[6]; + } + return t1; +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [[1, 2], [3, 4]] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-deplist-controlflow.snap b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-deplist-controlflow.snap index 336666f7af..dc55f3b55d 100644 --- a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-deplist-controlflow.snap +++ b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-deplist-controlflow.snap @@ -2,11 +2,67 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/preserve-memo-validation/useCallback-reordering-deplist-controlflow.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(408), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(349), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `foo`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(349), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(349), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr2`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useCallback } from "react"; +import { Stringify } from "shared-runtime"; +function Foo(t0) { + const $ = _c(10); + const { arr1, arr2, foo } = t0; + let t1; + if ($[0] !== arr1) { + t1 = [arr1]; + $[0] = arr1; + $[1] = t1; + } else { + t1 = $[1]; + } + const x = t1; + let getVal1; + let t2; + if ($[2] !== arr2 || $[3] !== foo || $[4] !== x) { + let y = []; + getVal1 = _temp; + t2 = () => [y]; + foo ? y = x.concat(arr2) : y; + $[2] = arr2; + $[3] = foo; + $[4] = x; + $[5] = getVal1; + $[6] = t2; + } else { + getVal1 = $[5]; + t2 = $[6]; + } + const getVal2 = t2; + let t3; + if ($[7] !== getVal1 || $[8] !== getVal2) { + t3 = ; + $[7] = getVal1; + $[8] = getVal2; + $[9] = t3; + } else { + t3 = $[9]; + } + return t3; +} +function _temp() { + return { x: 2 }; +} +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ + arr1: [1, 2], + arr2: [3, 4], + foo: true + }], + sequentialRenders: [{ + arr1: [1, 2], + arr2: [3, 4], + foo: true + }, { + arr1: [1, 2], + arr2: [3, 4], + foo: false + }] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-depslist-assignment.snap b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-depslist-assignment.snap index 932b90c416..59e5c98ff5 100644 --- a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-depslist-assignment.snap +++ b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useCallback-reordering-depslist-assignment.snap @@ -2,10 +2,45 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/preserve-memo-validation/useCallback-reordering-depslist-assignment.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(402), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(349), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(349), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr2`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useCallback } from "react"; +import { Stringify } from "shared-runtime"; +// We currently produce invalid output (incorrect scoping for `y` declaration) +function useFoo(arr1, arr2) { + const $ = _c(7); + let t0; + if ($[0] !== arr1) { + t0 = [arr1]; + $[0] = arr1; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let t1; + if ($[2] !== arr2 || $[3] !== x) { + let y; + t1 = () => ({ y }); + y = x.concat(arr2), y; + $[2] = arr2; + $[3] = x; + $[4] = t1; + } else { + t1 = $[4]; + } + const getVal = t1; + let t2; + if ($[5] !== getVal) { + t2 = ; + $[5] = getVal; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [[1, 2], [3, 4]] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-assignment.snap b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-assignment.snap index 2315a0cce3..76c87a7f6d 100644 --- a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-assignment.snap +++ b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-assignment.snap @@ -2,10 +2,40 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/preserve-memo-validation/useMemo-reordering-depslist-assignment.ts --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(265), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(212), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(212), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr2`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +function useFoo(arr1, arr2) { + const $ = _c(7); + let t0; + if ($[0] !== arr1) { + t0 = [arr1]; + $[0] = arr1; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== arr2 || $[3] !== x) { + y = x.concat(arr2), y; + $[2] = arr2; + $[3] = x; + $[4] = y; + } else { + y = $[4]; + } + let t1; + if ($[5] !== y) { + t1 = { y }; + $[5] = y; + $[6] = t1; + } else { + t1 = $[6]; + } + return t1; +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [[1, 2], [3, 4]] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-controlflow.snap b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-controlflow.snap index 83057b29d0..fd98a3b3ca 100644 --- a/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-controlflow.snap +++ b/crates/oxc_react_compiler/tests/snapshots/preserve-memo-validation__useMemo-reordering-depslist-controlflow.snap @@ -2,11 +2,63 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/preserve-memo-validation/useMemo-reordering-depslist-controlflow.tsx --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(390), length: 1 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(331), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr1`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(331), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `foo`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing manual memoization"), span: SourceSpan { offset: SourceOffset(331), length: 27 }, primary: false }]), help: Some("React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `arr2`, but the source dependencies were [y]. Inferred different dependency than source"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { Stringify } from "shared-runtime"; +function Foo(t0) { + const $ = _c(9); + const { arr1, arr2, foo } = t0; + let t1; + let val1; + if ($[0] !== arr1 || $[1] !== arr2 || $[2] !== foo) { + const x = [arr1]; + let y = []; + let t2; + if ($[5] === Symbol.for("react.memo_cache_sentinel")) { + t2 = { x: 2 }; + $[5] = t2; + } else { + t2 = $[5]; + } + val1 = t2; + foo ? y = x.concat(arr2) : y; + t1 = (() => [y])(); + $[0] = arr1; + $[1] = arr2; + $[2] = foo; + $[3] = t1; + $[4] = val1; + } else { + t1 = $[3]; + val1 = $[4]; + } + const val2 = t1; + let t2; + if ($[6] !== val1 || $[7] !== val2) { + t2 = ; + $[6] = val1; + $[7] = val2; + $[8] = t2; + } else { + t2 = $[8]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ + arr1: [1, 2], + arr2: [3, 4], + foo: true + }], + sequentialRenders: [{ + arr1: [1, 2], + arr2: [3, 4], + foo: true + }, { + arr1: [1, 2], + arr2: [3, 4], + foo: false + }] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/repro-no-declarations-in-reactive-scope-with-early-return.snap b/crates/oxc_react_compiler/tests/snapshots/repro-no-declarations-in-reactive-scope-with-early-return.snap index ff72d8e0a8..0d1ad96ac1 100644 --- a/crates/oxc_react_compiler/tests/snapshots/repro-no-declarations-in-reactive-scope-with-early-return.snap +++ b/crates/oxc_react_compiler/tests/snapshots/repro-no-declarations-in-reactive-scope-with-early-return.snap @@ -2,8 +2,55 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/repro-no-declarations-in-reactive-scope-with-early-return.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(260), length: 110 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +function Component() { + const $ = _c(6); + const items = useItems(); + let t0; + let t1; + if ($[0] !== items) { + t1 = Symbol.for("react.early_return_sentinel"); + bb0: { + const filteredItems = items.filter(_temp); + if (filteredItems.length === 0) { + let t2; + if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + t2 =
; + $[3] = t2; + } else { + t2 = $[3]; + } + t1 = t2; + break bb0; + } + t0 = filteredItems.map(_temp2); + } + $[0] = items; + $[1] = t0; + $[2] = t1; + } else { + t0 = $[1]; + t1 = $[2]; + } + if (t1 !== Symbol.for("react.early_return_sentinel")) { + return t1; + } + let t2; + if ($[4] !== t0) { + t2 = <>{t0}; + $[4] = t0; + $[5] = t2; + } else { + t2 = $[5]; + } + return t2; +} +function _temp2(t0) { + const [item_0] = t0; + return ; +} +function _temp(t0) { + const [item] = t0; + return item.name != null; +} diff --git a/crates/oxc_react_compiler/tests/snapshots/repro-renaming-conflicting-decls.snap b/crates/oxc_react_compiler/tests/snapshots/repro-renaming-conflicting-decls.snap index d4941d8151..2660be9aaa 100644 --- a/crates/oxc_react_compiler/tests/snapshots/repro-renaming-conflicting-decls.snap +++ b/crates/oxc_react_compiler/tests/snapshots/repro-renaming-conflicting-decls.snap @@ -2,8 +2,70 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/repro-renaming-conflicting-decls.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(207), length: 37 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false +import { Stringify, identity, makeArray, toJSON } from "shared-runtime"; +import { useMemo } from "react"; +function Component(props) { + const $ = _c(10); + let t0; + let t1; + if ($[0] !== props) { + t1 = Symbol.for("react.early_return_sentinel"); + bb0: { + const propsString = toJSON(props); + if (propsString.length <= 2) { + t1 = null; + break bb0; + } + t0 = identity(propsString); + } + $[0] = props; + $[1] = t0; + $[2] = t1; + } else { + t0 = $[1]; + t1 = $[2]; + } + if (t1 !== Symbol.for("react.early_return_sentinel")) { + return t1; + } + let t2; + if ($[3] !== t0) { + const linkProps = { url: t0 }; + const x = {}; + let t3; + let t4; + let t5; + let t6; + let t7; + 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 { + t3 = $[5]; + t4 = $[6]; + t5 = $[7]; + t6 = $[8]; + t7 = $[9]; + } + t2 = {makeArray(x, 2)}; + $[3] = t0; + $[4] = t2; + } else { + t2 = $[4]; + } + return t2; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ val: 2 }] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/useCallback-call-second-function-which-captures-maybe-mutable-value-dont-preserve-memoization.snap b/crates/oxc_react_compiler/tests/snapshots/useCallback-call-second-function-which-captures-maybe-mutable-value-dont-preserve-memoization.snap index 2ff1b8140b..0ae77985b1 100644 --- a/crates/oxc_react_compiler/tests/snapshots/useCallback-call-second-function-which-captures-maybe-mutable-value-dont-preserve-memoization.snap +++ b/crates/oxc_react_compiler/tests/snapshots/useCallback-call-second-function-which-captures-maybe-mutable-value-dont-preserve-memoization.snap @@ -2,9 +2,32 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/useCallback-call-second-function-which-captures-maybe-mutable-value-dont-preserve-memoization.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("This dependency may be modified later"), span: SourceSpan { offset: SourceOffset(425), length: 3 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(400), length: 22 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @enableTransitivelyFreezeFunctionExpressions:false +import { useCallback } from "react"; +import { identity, logValue, makeObject_Primitives, useHook } from "shared-runtime"; +function Component(props) { + const $ = _c(2); + const object = makeObject_Primitives(); + useHook(); + const log = () => { + logValue(object); + }; + const onClick = () => { + log(); + }; + identity(object); + let t0; + if ($[0] !== onClick) { + t0 =
; + $[0] = onClick; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.snap b/crates/oxc_react_compiler/tests/snapshots/useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.snap index 2ba8c1bc8b..839b78e274 100644 --- a/crates/oxc_react_compiler/tests/snapshots/useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.snap +++ b/crates/oxc_react_compiler/tests/snapshots/useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.snap @@ -2,8 +2,23 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(400), length: 104 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useCallback } from "react"; +import { identity, makeObject_Primitives, mutate, useHook } from "shared-runtime"; +function Component(props) { + const free = makeObject_Primitives(); + const free2 = makeObject_Primitives(); + const part = free2.part; + useHook(); + const callback = () => { + const x = makeObject_Primitives(); + x.value = props.value; + mutate(x, free, part); + }; + mutate(free, part); + return callback; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ value: 42 }] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.snap b/crates/oxc_react_compiler/tests/snapshots/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.snap index b25b876d4e..d91cee5b48 100644 --- a/crates/oxc_react_compiler/tests/snapshots/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.snap +++ b/crates/oxc_react_compiler/tests/snapshots/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.snap @@ -2,8 +2,23 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(596), length: 142 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +import { identity, makeObject_Primitives, mutate, useHook } from "shared-runtime"; +function Component(props) { + const free = makeObject_Primitives(); + const free2 = makeObject_Primitives(); + const part = free2.part; + useHook(); + const x = makeObject_Primitives(); + x.value = props.value; + mutate(x, free, part); + const object = x; + identity(free); + identity(part); + return object; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ value: 42 }] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.snap b/crates/oxc_react_compiler/tests/snapshots/useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.snap index 5cf426ba47..e52389ca08 100644 --- a/crates/oxc_react_compiler/tests/snapshots/useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.snap +++ b/crates/oxc_react_compiler/tests/snapshots/useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.snap @@ -2,8 +2,23 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(203), length: 42 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false +import { useMemo } from "react"; +import { identity, makeObject_Primitives, mutate } from "shared-runtime"; +function Component(props) { + const $ = _c(1); + let object; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + object = makeObject_Primitives(); + identity(object); + $[0] = object; + } else { + object = $[0]; + } + return object; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/useMemo-named-function.snap b/crates/oxc_react_compiler/tests/snapshots/useMemo-named-function.snap index 05cac750cf..adb8fe0515 100644 --- a/crates/oxc_react_compiler/tests/snapshots/useMemo-named-function.snap +++ b/crates/oxc_react_compiler/tests/snapshots/useMemo-named-function.snap @@ -2,8 +2,23 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/useMemo-named-function.ts --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] UseMemo: Expected the first argument to be an inline function expression", labels: One([LabeledSpan { label: Some("Expected the first argument to be an inline function expression"), span: SourceSpan { offset: SourceOffset(205), length: 9 }, primary: false }]), help: Some("Expected the first argument to be an inline function expression"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @validateNoSetStateInRender:false @enablePreserveExistingMemoizationGuarantees:false +import { useMemo } from "react"; +import { makeArray } from "shared-runtime"; +function Component() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = makeArray(); + $[0] = t0; + } else { + t0 = $[0]; + } + const x = t0; + return x; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}] +}; diff --git a/crates/oxc_react_compiler/tests/snapshots/useMemo-with-optional.snap b/crates/oxc_react_compiler/tests/snapshots/useMemo-with-optional.snap index e3295fc27c..093e63f438 100644 --- a/crates/oxc_react_compiler/tests/snapshots/useMemo-with-optional.snap +++ b/crates/oxc_react_compiler/tests/snapshots/useMemo-with-optional.snap @@ -2,8 +2,22 @@ source: crates/oxc_react_compiler/tests/snapshot.rs input_file: crates/oxc_react_compiler/fixtures/useMemo-with-optional.js --- -Diagnostics: - -OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] PreserveManualMemo: Existing memoization could not be preserved", labels: One([LabeledSpan { label: Some("Could not preserve existing memoization"), span: SourceSpan { offset: SourceOffset(177), length: 50 }, primary: false }]), help: Some("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"), note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } } - -No changes. +import { c as _c } from "react/compiler-runtime"; +// @enablePreserveExistingMemoizationGuarantees:false @validateExhaustiveMemoizationDependencies:false +import { useMemo } from "react"; +function Component(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.value) { + t0 = (() => [props.value])() || []; + $[0] = props.value; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ value: 1 }] +};