,
+ () => {
+ handleFunction(innerFn);
+ },
+ );
} else {
handleInstruction(instr, context);
}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md
index 2b0031b117..f8712ed728 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md
@@ -58,18 +58,16 @@ function Foo(t0) {
bar = $[1];
result = $[2];
}
-
- const t1 = bar;
- let t2;
- if ($[3] !== result || $[4] !== t1) {
- t2 = ;
- $[3] = result;
- $[4] = t1;
- $[5] = t2;
+ let t1;
+ if ($[3] !== bar || $[4] !== result) {
+ t1 = ;
+ $[3] = bar;
+ $[4] = result;
+ $[5] = t1;
} else {
- t2 = $[5];
+ t1 = $[5];
}
- return t2;
+ return t1;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-assignment-to-context-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-assignment-to-context-var.expect.md
index 7febb3fecb..1268cbcfdc 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-assignment-to-context-var.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-assignment-to-context-var.expect.md
@@ -43,16 +43,15 @@ function Component(props) {
} else {
x = $[1];
}
- const t0 = x;
- let t1;
- if ($[2] !== t0) {
- t1 = { x: t0 };
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== x) {
+ t0 = { x };
+ $[2] = x;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-declaration-to-context-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-declaration-to-context-var.expect.md
index 26b56ea2a4..769e4871f4 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-declaration-to-context-var.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-array-declaration-to-context-var.expect.md
@@ -42,16 +42,15 @@ function Component(props) {
} else {
x = $[1];
}
- const t0 = x;
- let t1;
- if ($[2] !== t0) {
- t1 = {t0}
;
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== x) {
+ t0 = {x}
;
+ $[2] = x;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-assignment-to-context-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-assignment-to-context-var.expect.md
index 5ffa73389f..e66ef2df13 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-assignment-to-context-var.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-assignment-to-context-var.expect.md
@@ -43,16 +43,15 @@ function Component(props) {
} else {
x = $[1];
}
- const t0 = x;
- let t1;
- if ($[2] !== t0) {
- t1 = { x: t0 };
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== x) {
+ t0 = { x };
+ $[2] = x;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-declaration-to-context-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-declaration-to-context-var.expect.md
index 2c495d8223..66799c5c47 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-declaration-to-context-var.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-object-declaration-to-context-var.expect.md
@@ -42,16 +42,15 @@ function Component(props) {
} else {
x = $[1];
}
- const t0 = x;
- let t1;
- if ($[2] !== t0) {
- t1 = { x: t0 };
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== x) {
+ t0 = { x };
+ $[2] = x;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md
index dfe941282e..d34db46d6a 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md
@@ -33,17 +33,15 @@ function f(a) {
} else {
x = $[1];
}
-
- const t0 = x;
- let t1;
- if ($[2] !== t0) {
- t1 = ;
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== x) {
+ t0 = ;
+ $[2] = x;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.todo-useCallback-captures-reassigned-context-property.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.todo-useCallback-captures-reassigned-context-property.expect.md
deleted file mode 100644
index ae44f27912..0000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.todo-useCallback-captures-reassigned-context-property.expect.md
+++ /dev/null
@@ -1,53 +0,0 @@
-
-## Input
-
-```javascript
-// @validatePreserveExistingMemoizationGuarantees
-import {useCallback} from 'react';
-import {Stringify} from 'shared-runtime';
-
-/**
- * TODO: we're currently bailing out because `contextVar` is a context variable
- * and not recorded into the PropagateScopeDeps LoadLocal / PropertyLoad
- * sidemap. Previously, we were able to avoid this as `BuildHIR` hoisted
- * `LoadContext` and `PropertyLoad` instructions into the outer function, which
- * we took as eligible dependencies.
- *
- * One solution is to simply record `LoadContext` identifiers into the
- * temporaries sidemap when the instruction occurs *after* the context
- * variable's mutable range.
- */
-function Foo(props) {
- let contextVar;
- if (props.cond) {
- contextVar = {val: 2};
- } else {
- contextVar = {};
- }
-
- const cb = useCallback(() => [contextVar.val], [contextVar.val]);
-
- return ;
-}
-
-export const FIXTURE_ENTRYPOINT = {
- fn: Foo,
- params: [{cond: true}],
-};
-
-```
-
-
-## Error
-
-```
- 22 | }
- 23 |
-> 24 | const cb = useCallback(() => [contextVar.val], [contextVar.val]);
- | ^^^^^^^^^^^^^^^^^^^^^^ CannotPreserveMemoization: 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 (24:24)
- 25 |
- 26 | return ;
- 27 | }
-```
-
-
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-captures-reassigned-context-property.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-captures-reassigned-context-property.expect.md
new file mode 100644
index 0000000000..a1cbe89a88
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-captures-reassigned-context-property.expect.md
@@ -0,0 +1,101 @@
+
+## Input
+
+```javascript
+// @validatePreserveExistingMemoizationGuarantees
+import {useCallback} from 'react';
+import {Stringify} from 'shared-runtime';
+
+/**
+ * TODO: we're currently bailing out because `contextVar` is a context variable
+ * and not recorded into the PropagateScopeDeps LoadLocal / PropertyLoad
+ * sidemap. Previously, we were able to avoid this as `BuildHIR` hoisted
+ * `LoadContext` and `PropertyLoad` instructions into the outer function, which
+ * we took as eligible dependencies.
+ *
+ * One solution is to simply record `LoadContext` identifiers into the
+ * temporaries sidemap when the instruction occurs *after* the context
+ * variable's mutable range.
+ */
+function Foo(props) {
+ let contextVar;
+ if (props.cond) {
+ contextVar = {val: 2};
+ } else {
+ contextVar = {};
+ }
+
+ const cb = useCallback(() => [contextVar.val], [contextVar.val]);
+
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Foo,
+ params: [{cond: true}],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
+import { useCallback } from "react";
+import { Stringify } from "shared-runtime";
+
+/**
+ * TODO: we're currently bailing out because `contextVar` is a context variable
+ * and not recorded into the PropagateScopeDeps LoadLocal / PropertyLoad
+ * sidemap. Previously, we were able to avoid this as `BuildHIR` hoisted
+ * `LoadContext` and `PropertyLoad` instructions into the outer function, which
+ * we took as eligible dependencies.
+ *
+ * One solution is to simply record `LoadContext` identifiers into the
+ * temporaries sidemap when the instruction occurs *after* the context
+ * variable's mutable range.
+ */
+function Foo(props) {
+ const $ = _c(6);
+ let contextVar;
+ if ($[0] !== props.cond) {
+ if (props.cond) {
+ contextVar = { val: 2 };
+ } else {
+ contextVar = {};
+ }
+ $[0] = props.cond;
+ $[1] = contextVar;
+ } else {
+ contextVar = $[1];
+ }
+ let t0;
+ if ($[2] !== contextVar.val) {
+ t0 = () => [contextVar.val];
+ $[2] = contextVar.val;
+ $[3] = t0;
+ } else {
+ t0 = $[3];
+ }
+ contextVar;
+ const cb = t0;
+ let t1;
+ if ($[4] !== cb) {
+ t1 = ;
+ $[4] = cb;
+ $[5] = t1;
+ } else {
+ t1 = $[5];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Foo,
+ params: [{ cond: true }],
+};
+
+```
+
+### Eval output
+(kind: ok) {"cb":{"kind":"Function","result":[2]},"shouldInvokeFns":true}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.todo-useCallback-captures-reassigned-context-property.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-captures-reassigned-context-property.tsx
similarity index 100%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.todo-useCallback-captures-reassigned-context-property.tsx
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-captures-reassigned-context-property.tsx
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md
index dc1a87fe51..e8a3e2d627 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md
@@ -44,16 +44,15 @@ function useFoo(arr1, arr2) {
y = $[2];
}
let t0;
- const t1 = y;
- let t2;
- if ($[3] !== t1) {
- t2 = { y: t1 };
- $[3] = t1;
- $[4] = t2;
+ let t1;
+ if ($[3] !== y) {
+ t1 = { y };
+ $[3] = y;
+ $[4] = t1;
} else {
- t2 = $[4];
+ t1 = $[4];
}
- t0 = t2;
+ t0 = t1;
return t0;
}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md
index 39f301432e..9d232d8e78 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md
@@ -36,17 +36,15 @@ function HomeDiscoStoreItemTileRating(props) {
} else {
count = $[1];
}
-
- const t0 = count;
- let t1;
- if ($[2] !== t0) {
- t1 = {t0};
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== count) {
+ t0 = {count};
+ $[2] = count;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
```
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md
index 23cc7ee846..ceaa350012 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md
@@ -67,17 +67,15 @@ function Component(props) {
} else {
x = $[1];
}
-
- const t0 = x;
- let t1;
- if ($[2] !== t0) {
- t1 = [t0];
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== x) {
+ t0 = [x];
+ $[2] = x;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/context-var-granular-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/context-var-granular-dep.expect.md
new file mode 100644
index 0000000000..d72f34b4fd
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/context-var-granular-dep.expect.md
@@ -0,0 +1,130 @@
+
+## Input
+
+```javascript
+import {throwErrorWithMessage, ValidateMemoization} from 'shared-runtime';
+
+/**
+ * Context variables are local variables that (1) have at least one reassignment
+ * and (2) are captured into a function expression. These have a known mutable
+ * range: from first declaration / assignment to the last direct or aliased,
+ * mutable reference.
+ *
+ * This fixture validates that forget can take granular dependencies on context
+ * variables when the reference to a context var happens *after* the end of its
+ * mutable range.
+ */
+function Component({cond, a}) {
+ let contextVar;
+ if (cond) {
+ contextVar = {val: a};
+ } else {
+ contextVar = {};
+ throwErrorWithMessage('');
+ }
+ const cb = {cb: () => contextVar.val * 4};
+
+ /**
+ * manually specify input to avoid adding a `PropertyLoad` from contextVar,
+ * which might affect hoistable-objects analysis.
+ */
+ return (
+
+ );
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{cond: false, a: undefined}],
+ sequentialRenders: [
+ {cond: true, a: 2},
+ {cond: true, a: 2},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { throwErrorWithMessage, ValidateMemoization } from "shared-runtime";
+
+/**
+ * Context variables are local variables that (1) have at least one reassignment
+ * and (2) are captured into a function expression. These have a known mutable
+ * range: from first declaration / assignment to the last direct or aliased,
+ * mutable reference.
+ *
+ * This fixture validates that forget can take granular dependencies on context
+ * variables when the reference to a context var happens *after* the end of its
+ * mutable range.
+ */
+function Component(t0) {
+ const $ = _c(10);
+ const { cond, a } = t0;
+ let contextVar;
+ if ($[0] !== a || $[1] !== cond) {
+ if (cond) {
+ contextVar = { val: a };
+ } else {
+ contextVar = {};
+ throwErrorWithMessage("");
+ }
+ $[0] = a;
+ $[1] = cond;
+ $[2] = contextVar;
+ } else {
+ contextVar = $[2];
+ }
+ let t1;
+ if ($[3] !== contextVar.val) {
+ t1 = { cb: () => contextVar.val * 4 };
+ $[3] = contextVar.val;
+ $[4] = t1;
+ } else {
+ t1 = $[4];
+ }
+ const cb = t1;
+
+ const t2 = cond ? a : undefined;
+ let t3;
+ if ($[5] !== t2) {
+ t3 = [t2];
+ $[5] = t2;
+ $[6] = t3;
+ } else {
+ t3 = $[6];
+ }
+ let t4;
+ if ($[7] !== cb || $[8] !== t3) {
+ t4 = (
+
+ );
+ $[7] = cb;
+ $[8] = t3;
+ $[9] = t4;
+ } else {
+ t4 = $[9];
+ }
+ return t4;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ cond: false, a: undefined }],
+ sequentialRenders: [
+ { cond: true, a: 2 },
+ { cond: true, a: 2 },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"inputs":[2],"output":{"cb":"[[ function params=0 ]]"}}
+{"inputs":[2],"output":{"cb":"[[ function params=0 ]]"}}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/context-var-granular-dep.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/context-var-granular-dep.js
new file mode 100644
index 0000000000..b9bdd67e2f
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/context-var-granular-dep.js
@@ -0,0 +1,43 @@
+import {throwErrorWithMessage, ValidateMemoization} from 'shared-runtime';
+
+/**
+ * Context variables are local variables that (1) have at least one reassignment
+ * and (2) are captured into a function expression. These have a known mutable
+ * range: from first declaration / assignment to the last direct or aliased,
+ * mutable reference.
+ *
+ * This fixture validates that forget can take granular dependencies on context
+ * variables when the reference to a context var happens *after* the end of its
+ * mutable range.
+ */
+function Component({cond, a}) {
+ let contextVar;
+ if (cond) {
+ contextVar = {val: a};
+ } else {
+ contextVar = {};
+ throwErrorWithMessage('');
+ }
+ const cb = {cb: () => contextVar.val * 4};
+
+ /**
+ * manually specify input to avoid adding a `PropertyLoad` from contextVar,
+ * which might affect hoistable-objects analysis.
+ */
+ return (
+
+ );
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{cond: false, a: undefined}],
+ sequentialRenders: [
+ {cond: true, a: 2},
+ {cond: true, a: 2},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md
index d8e59c486a..b7c425ba5c 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md
@@ -35,17 +35,15 @@ function HomeDiscoStoreItemTileRating(props) {
} else {
count = $[1];
}
-
- const t0 = count;
- let t1;
- if ($[2] !== t0) {
- t1 = {t0};
- $[2] = t0;
- $[3] = t1;
+ let t0;
+ if ($[2] !== count) {
+ t0 = {count};
+ $[2] = count;
+ $[3] = t0;
} else {
- t1 = $[3];
+ t0 = $[3];
}
- return t1;
+ return t0;
}
```
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md
index d94a5e7e37..e335273026 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md
@@ -88,36 +88,34 @@ function Inner(props) {
input;
input;
let t0;
- const t1 = input;
- let t2;
- if ($[0] !== t1) {
- t2 = [t1];
- $[0] = t1;
- $[1] = t2;
+ let t1;
+ if ($[0] !== input) {
+ t1 = [input];
+ $[0] = input;
+ $[1] = t1;
} else {
- t2 = $[1];
+ t1 = $[1];
}
- t0 = t2;
+ t0 = t1;
const output = t0;
- const t3 = input;
- let t4;
- if ($[2] !== t3) {
- t4 = [t3];
- $[2] = t3;
- $[3] = t4;
+ let t2;
+ if ($[2] !== input) {
+ t2 = [input];
+ $[2] = input;
+ $[3] = t2;
} else {
- t4 = $[3];
+ t2 = $[3];
}
- let t5;
- if ($[4] !== output || $[5] !== t4) {
- t5 = ;
+ let t3;
+ if ($[4] !== output || $[5] !== t2) {
+ t3 = ;
$[4] = output;
- $[5] = t4;
- $[6] = t5;
+ $[5] = t2;
+ $[6] = t3;
} else {
- t5 = $[6];
+ t3 = $[6];
}
- return t5;
+ return t3;
}
export const FIXTURE_ENTRYPOINT = {
diff --git a/compiler/packages/snap/src/sprout/index.ts b/compiler/packages/snap/src/sprout/index.ts
index 733be561c0..04748bed28 100644
--- a/compiler/packages/snap/src/sprout/index.ts
+++ b/compiler/packages/snap/src/sprout/index.ts
@@ -32,7 +32,15 @@ export function runSprout(
originalCode: string,
forgetCode: string,
): SproutResult {
- const forgetResult = doEval(forgetCode);
+ let forgetResult;
+ try {
+ (globalThis as any).__SNAP_EVALUATOR_MODE = 'forget';
+ forgetResult = doEval(forgetCode);
+ } catch (e) {
+ throw e;
+ } finally {
+ (globalThis as any).__SNAP_EVALUATOR_MODE = undefined;
+ }
if (forgetResult.kind === 'UnexpectedError') {
return makeError('Unexpected error in Forget runner', forgetResult.value);
}
diff --git a/compiler/packages/snap/src/sprout/shared-runtime.ts b/compiler/packages/snap/src/sprout/shared-runtime.ts
index 58815842cb..1b8648f4ff 100644
--- a/compiler/packages/snap/src/sprout/shared-runtime.ts
+++ b/compiler/packages/snap/src/sprout/shared-runtime.ts
@@ -259,26 +259,35 @@ export function Throw() {
export function ValidateMemoization({
inputs,
- output,
+ output: rawOutput,
+ onlyCheckCompiled = false,
}: {
inputs: Array;
output: any;
+ onlyCheckCompiled: boolean;
}): React.ReactElement {
'use no forget';
+ // Wrap rawOutput as it might be a function, which useState would invoke.
+ const output = {value: rawOutput};
const [previousInputs, setPreviousInputs] = React.useState(inputs);
const [previousOutput, setPreviousOutput] = React.useState(output);
if (
- inputs.length !== previousInputs.length ||
- inputs.some((item, i) => item !== previousInputs[i])
+ onlyCheckCompiled &&
+ (globalThis as any).__SNAP_EVALUATOR_MODE === 'forget'
) {
- // Some input changed, we expect the output to change
- setPreviousInputs(inputs);
- setPreviousOutput(output);
- } else if (output !== previousOutput) {
- // Else output should be stable
- throw new Error('Output identity changed but inputs did not');
+ if (
+ inputs.length !== previousInputs.length ||
+ inputs.some((item, i) => item !== previousInputs[i])
+ ) {
+ // Some input changed, we expect the output to change
+ setPreviousInputs(inputs);
+ setPreviousOutput(output);
+ } else if (output.value !== previousOutput.value) {
+ // Else output should be stable
+ throw new Error('Output identity changed but inputs did not');
+ }
}
- return React.createElement(Stringify, {inputs, output});
+ return React.createElement(Stringify, {inputs, output: rawOutput});
}
export function createHookWrapper(