diff --git a/compiler/forget/src/Inference/InferReferenceEffects.ts b/compiler/forget/src/Inference/InferReferenceEffects.ts
index bf64963d09..29c5a00099 100644
--- a/compiler/forget/src/Inference/InferReferenceEffects.ts
+++ b/compiler/forget/src/Inference/InferReferenceEffects.ts
@@ -308,7 +308,14 @@ class Environment {
break;
}
case Effect.Capture: {
- effect = Effect.Capture;
+ if (
+ valueKind === ValueKind.Frozen ||
+ valueKind === ValueKind.MaybeFrozen
+ ) {
+ effect = Effect.Read;
+ } else {
+ effect = Effect.Capture;
+ }
break;
}
case Effect.Read: {
diff --git a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md
new file mode 100644
index 0000000000..50fae20d8d
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md
@@ -0,0 +1,127 @@
+
+## Input
+
+```javascript
+// note: comments are for the ideal scopes, not what is currently
+// emitted
+function foo(props) {
+ // scope 0: deps=[props.a] decl=[x] reassign=none
+ let x = [];
+ x.push(props.a);
+
+ // scope 1: deps=[x] decl=[header] reassign=none
+ const header = props.showHeader ?
{x}
: null;
+
+ // scope 2:
+ // deps=[x, props.b, props.c]
+ // decl=none
+ // reassign=[x]
+ const y = [x]; // y depends on the earlier x
+ x = []; // x reassigned
+ y.push(props.b); // interleaved mutation of x/y
+ x.push(props.c); // interleaved mutation
+
+ // scope 3 ...
+ const content = (
+
+ {x}
+ {y}
+
+ );
+
+ // scope 4 ...
+ return (
+ <>
+ {header}
+ {content}
+ >
+ );
+}
+
+```
+
+## Code
+
+```javascript
+// note: comments are for the ideal scopes, not what is currently
+// emitted
+function foo(props) {
+ const $ = React.unstable_useMemoCache();
+ const c_0 = $[0] !== props.a;
+ let x;
+ if (c_0) {
+ x = [];
+ x.push(props.a);
+ $[0] = props.a;
+ $[1] = x;
+ } else {
+ x = $[1];
+ }
+ const c_2 = $[2] !== props;
+ const c_3 = $[3] !== x;
+ let t0;
+ if (c_2 || c_3) {
+ t0 = props.showHeader ? {x}
: null;
+ $[2] = props;
+ $[3] = x;
+ $[4] = t0;
+ } else {
+ t0 = $[4];
+ }
+ const header = t0;
+ const c_5 = $[5] !== x;
+ const c_6 = $[6] !== props.b;
+ const c_7 = $[7] !== props.c;
+ let x$0;
+ let y;
+ if (c_5 || c_6 || c_7) {
+ y = [x];
+ x$0 = [];
+ y.push(props.b);
+ x$0.push(props.c);
+ $[5] = x;
+ $[6] = props.b;
+ $[7] = props.c;
+ $[8] = x$0;
+ $[9] = y;
+ } else {
+ x$0 = $[8];
+ y = $[9];
+ }
+ const c_10 = $[10] !== x$0;
+ const c_11 = $[11] !== y;
+ let content;
+ if (c_10 || c_11) {
+ content = (
+
+ {x$0}
+ {y}
+
+ );
+ $[10] = x$0;
+ $[11] = y;
+ $[12] = content;
+ } else {
+ content = $[12];
+ }
+ const c_13 = $[13] !== header;
+ const c_14 = $[14] !== content;
+ let t1;
+ if (c_13 || c_14) {
+ t1 = (
+ <>
+ {header}
+ {content}
+ >
+ );
+ $[13] = header;
+ $[14] = content;
+ $[15] = t1;
+ } else {
+ t1 = $[15];
+ }
+ return t1;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.js b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.js
new file mode 100644
index 0000000000..67149fb3f3
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.js
@@ -0,0 +1,35 @@
+// note: comments are for the ideal scopes, not what is currently
+// emitted
+function foo(props) {
+ // scope 0: deps=[props.a] decl=[x] reassign=none
+ let x = [];
+ x.push(props.a);
+
+ // scope 1: deps=[x] decl=[header] reassign=none
+ const header = props.showHeader ? {x}
: null;
+
+ // scope 2:
+ // deps=[x, props.b, props.c]
+ // decl=none
+ // reassign=[x]
+ const y = [x]; // y depends on the earlier x
+ x = []; // x reassigned
+ y.push(props.b); // interleaved mutation of x/y
+ x.push(props.c); // interleaved mutation
+
+ // scope 3 ...
+ const content = (
+
+ {x}
+ {y}
+
+ );
+
+ // scope 4 ...
+ return (
+ <>
+ {header}
+ {content}
+ >
+ );
+}
diff --git a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.expect.md b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.expect.md
new file mode 100644
index 0000000000..f975bb3535
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.expect.md
@@ -0,0 +1,124 @@
+
+## Input
+
+```javascript
+// note: comments are for the ideal scopes, not what is currently
+// emitted
+function foo(props) {
+ // scope 0: deps=[props.a] decl=[x] reassign=none
+ let x = [];
+ x.push(props.a);
+
+ // scope 1: deps=[x] decl=[header] reassign=none
+ const header = {x}
;
+
+ // scope 2:
+ // deps=[x, props.b, props.c]
+ // decl=none
+ // reassign=[x]
+ const y = [x]; // y depends on the earlier x
+ x = []; // x reassigned
+ y.push(props.b); // interleaved mutation of x/y
+ x.push(props.c); // interleaved mutation
+
+ // scope 3 ...
+ const content = (
+
+ {x}
+ {y}
+
+ );
+
+ // scope 4 ...
+ return (
+ <>
+ {header}
+ {content}
+ >
+ );
+}
+
+```
+
+## Code
+
+```javascript
+// note: comments are for the ideal scopes, not what is currently
+// emitted
+function foo(props) {
+ const $ = React.unstable_useMemoCache();
+ const c_0 = $[0] !== props.a;
+ let x;
+ if (c_0) {
+ x = [];
+ x.push(props.a);
+ $[0] = props.a;
+ $[1] = x;
+ } else {
+ x = $[1];
+ }
+ const c_2 = $[2] !== x;
+ let header;
+ if (c_2) {
+ header = {x}
;
+ $[2] = x;
+ $[3] = header;
+ } else {
+ header = $[3];
+ }
+ const c_4 = $[4] !== x;
+ const c_5 = $[5] !== props.b;
+ const c_6 = $[6] !== props.c;
+ let x$0;
+ let y;
+ if (c_4 || c_5 || c_6) {
+ y = [x];
+ x$0 = [];
+ y.push(props.b);
+ x$0.push(props.c);
+ $[4] = x;
+ $[5] = props.b;
+ $[6] = props.c;
+ $[7] = x$0;
+ $[8] = y;
+ } else {
+ x$0 = $[7];
+ y = $[8];
+ }
+ const c_9 = $[9] !== x$0;
+ const c_10 = $[10] !== y;
+ let content;
+ if (c_9 || c_10) {
+ content = (
+
+ {x$0}
+ {y}
+
+ );
+ $[9] = x$0;
+ $[10] = y;
+ $[11] = content;
+ } else {
+ content = $[11];
+ }
+ const c_12 = $[12] !== header;
+ const c_13 = $[13] !== content;
+ let t0;
+ if (c_12 || c_13) {
+ t0 = (
+ <>
+ {header}
+ {content}
+ >
+ );
+ $[12] = header;
+ $[13] = content;
+ $[14] = t0;
+ } else {
+ t0 = $[14];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.js b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.js
new file mode 100644
index 0000000000..6d8c5cb3f9
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.js
@@ -0,0 +1,35 @@
+// note: comments are for the ideal scopes, not what is currently
+// emitted
+function foo(props) {
+ // scope 0: deps=[props.a] decl=[x] reassign=none
+ let x = [];
+ x.push(props.a);
+
+ // scope 1: deps=[x] decl=[header] reassign=none
+ const header = {x}
;
+
+ // scope 2:
+ // deps=[x, props.b, props.c]
+ // decl=none
+ // reassign=[x]
+ const y = [x]; // y depends on the earlier x
+ x = []; // x reassigned
+ y.push(props.b); // interleaved mutation of x/y
+ x.push(props.c); // interleaved mutation
+
+ // scope 3 ...
+ const content = (
+
+ {x}
+ {y}
+
+ );
+
+ // scope 4 ...
+ return (
+ <>
+ {header}
+ {content}
+ >
+ );
+}