diff --git a/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts index 278ab358ed..974e6b83a3 100644 --- a/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts @@ -851,16 +851,19 @@ function inferBlock( ) { /* * None of the args are mutable or mutate their params, we can downgrade to - * treating as all reads + * treating as all reads (except that the receiver may be captured) */ for (const arg of instrValue.args) { const place = arg.kind === "Identifier" ? arg : arg.place; state.reference(place, Effect.Read); } - state.reference(instrValue.receiver, Effect.Read); + state.reference(instrValue.receiver, Effect.Capture); state.initialize(instrValue, signature.returnValueKind); state.define(instr.lvalue, instrValue); - instr.lvalue.effect = Effect.ConditionallyMutate; + instr.lvalue.effect = + instrValue.receiver.effect === Effect.Capture + ? Effect.Store + : Effect.ConditionallyMutate; continue; } diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/array-map-mutable-array-non-mutating-lambda-mutated-result.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/array-map-mutable-array-non-mutating-lambda-mutated-result.expect.md new file mode 100644 index 0000000000..d9aef7904e --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/array-map-mutable-array-non-mutating-lambda-mutated-result.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +function Component(props) { + const x = [{}]; + const y = x.map((item) => { + return item; + }); + y[0].flag = true; + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], + isComponent: false, +}; + +``` + +## Code + +```javascript +import { unstable_useMemoCache as useMemoCache } from "react"; +function Component(props) { + const $ = useMemoCache(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + const x = [{}]; + const y = x.map((item) => item); + y[0].flag = true; + t0 = [x, y]; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], + isComponent: false, +}; + +``` + +### Eval output +(kind: ok) [[{"flag":true}],["[[ cyclic ref *2 ]]"]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/array-map-mutable-array-non-mutating-lambda-mutated-result.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/array-map-mutable-array-non-mutating-lambda-mutated-result.js new file mode 100644 index 0000000000..d048fe444d --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/array-map-mutable-array-non-mutating-lambda-mutated-result.js @@ -0,0 +1,14 @@ +function Component(props) { + const x = [{}]; + const y = x.map((item) => { + return item; + }); + y[0].flag = true; + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], + isComponent: false, +};