diff --git a/compiler/forget/src/Inference/InferReferenceEffects.ts b/compiler/forget/src/Inference/InferReferenceEffects.ts index 0a35a12c91..b0a4bc44bd 100644 --- a/compiler/forget/src/Inference/InferReferenceEffects.ts +++ b/compiler/forget/src/Inference/InferReferenceEffects.ts @@ -584,7 +584,10 @@ function inferBlock(env: Environment, block: BasicBlock) { break; } case "ObjectExpression": { - valueKind = ValueKind.Mutable; + valueKind = hasContextRefOperand(env, instrValue) + ? ValueKind.Context + : ValueKind.Mutable; + // Object construction captures but does not modify the key/property values effectKind = Effect.Capture; lvalueEffect = Effect.Store; @@ -843,3 +846,10 @@ export function parseHookCall(place: Place): Hook | null { valueKind: ValueKind.Mutable, }; } + +function hasContextRefOperand(env: Environment, instrValue: InstructionValue) { + for (const place of eachInstructionValueOperand(instrValue)) { + if (env.kind(place) === ValueKind.Context) return true; + } + return false; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-fun-alias-captured-mutate-2.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-fun-alias-captured-mutate-2.expect.md new file mode 100644 index 0000000000..d36325ba83 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-fun-alias-captured-mutate-2.expect.md @@ -0,0 +1,46 @@ + +## Input + +```javascript +function component(foo, bar) { + let x = { foo }; + let y = { bar }; + (function () { + let a = { y }; + let b = x; + a.x = b; + })(); + mutate(y); + return x; +} + +``` + +## Code + +```javascript +function component(foo, bar) { + const $ = React.unstable_useMemoCache(); + const c_0 = $[0] !== foo; + const c_1 = $[1] !== bar; + let x; + if (c_0 || c_1) { + x = { foo: foo }; + const y = { bar: bar }; + (function () { + let a = { y }; + let b = x; + a.x = b; + })(); + mutate(y); + $[0] = foo; + $[1] = bar; + $[2] = x; + } else { + x = $[2]; + } + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-fun-alias-captured-mutate-2.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-fun-alias-captured-mutate-2.js new file mode 100644 index 0000000000..d00593e420 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-fun-alias-captured-mutate-2.js @@ -0,0 +1,11 @@ +function component(foo, bar) { + let x = { foo }; + let y = { bar }; + (function () { + let a = { y }; + let b = x; + a.x = b; + })(); + mutate(y); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-captured-mutate.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-captured-mutate.expect.md new file mode 100644 index 0000000000..2754e3a266 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-captured-mutate.expect.md @@ -0,0 +1,46 @@ + +## Input + +```javascript +function component(foo, bar) { + let x = { foo }; + let y = { bar }; + (function () { + let a = { y }; + let b = x; + a.x = b; + })(); + mutate(y); + return y; +} + +``` + +## Code + +```javascript +function component(foo, bar) { + const $ = React.unstable_useMemoCache(); + const c_0 = $[0] !== foo; + const c_1 = $[1] !== bar; + let y; + if (c_0 || c_1) { + const x = { foo: foo }; + y = { bar: bar }; + (function () { + let a = { y }; + let b = x; + a.x = b; + })(); + mutate(y); + $[0] = foo; + $[1] = bar; + $[2] = y; + } else { + y = $[2]; + } + return y; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-captured-mutate.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-captured-mutate.js new file mode 100644 index 0000000000..fc1954b554 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-captured-mutate.js @@ -0,0 +1,11 @@ +function component(foo, bar) { + let x = { foo }; + let y = { bar }; + (function () { + let a = { y }; + let b = x; + a.x = b; + })(); + mutate(y); + return y; +}