diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts index 94be2100f57e8..b894eb2898641 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts @@ -954,6 +954,7 @@ function applyEffect( case ValueKind.Primitive: { break; } + case ValueKind.MaybeFrozen: case ValueKind.Frozen: { sourceType = 'frozen'; break; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-destructure-from-prop-with-default-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-destructure-from-prop-with-default-value.expect.md new file mode 100644 index 0000000000000..eec95683aa2a3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-destructure-from-prop-with-default-value.expect.md @@ -0,0 +1,45 @@ + +## Input + +```javascript +export function useFormatRelativeTime(opts = {}) { + const {timeZone, minimal} = opts; + const format = useCallback(function formatWithUnit() {}, [minimal]); + // We previously recorded `{timeZone}` as capturing timeZone into the object, + // then assumed that dateTimeFormat() mutates that object, + // which in turn could mutate timeZone and the object it came from, + // which meanteans that the value `minimal` is derived from can change. + // + // The fix was to record a Capture from a maybefrozen value as an ImmutableCapture + // which doesn't propagate mutations + dateTimeFormat({timeZone}); + return format; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +export function useFormatRelativeTime(t0) { + const $ = _c(1); + const opts = t0 === undefined ? {} : t0; + const { timeZone, minimal } = opts; + let t1; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t1 = function formatWithUnit() {}; + $[0] = t1; + } else { + t1 = $[0]; + } + const format = t1; + + dateTimeFormat({ timeZone }); + return format; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-destructure-from-prop-with-default-value.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-destructure-from-prop-with-default-value.js new file mode 100644 index 0000000000000..dbcb7303778c3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-destructure-from-prop-with-default-value.js @@ -0,0 +1,13 @@ +export function useFormatRelativeTime(opts = {}) { + const {timeZone, minimal} = opts; + const format = useCallback(function formatWithUnit() {}, [minimal]); + // We previously recorded `{timeZone}` as capturing timeZone into the object, + // then assumed that dateTimeFormat() mutates that object, + // which in turn could mutate timeZone and the object it came from, + // which meanteans that the value `minimal` is derived from can change. + // + // The fix was to record a Capture from a maybefrozen value as an ImmutableCapture + // which doesn't propagate mutations + dateTimeFormat({timeZone}); + return format; +}