diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.expect.md
new file mode 100644
index 0000000000..5975d82411
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.expect.md
@@ -0,0 +1,53 @@
+
+## Input
+
+```javascript
+import { identity, mutate, mutateAndReturnNewValue } from "shared-runtime";
+
+function Component(props) {
+ const key = {};
+ // Key is modified by the function, but key itself is not frozen
+ const element =
{props.value}
;
+ // Key is later mutated here: this mutation must be grouped with the
+ // jsx construction above
+ mutate(key);
+ return element;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: 42 }],
+};
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react";
+import { identity, mutate, mutateAndReturnNewValue } from "shared-runtime";
+
+function Component(props) {
+ const $ = useMemoCache(2);
+ let element;
+ if ($[0] !== props.value) {
+ const key = {};
+
+ element = {props.value}
;
+
+ mutate(key);
+ $[0] = props.value;
+ $[1] = element;
+ } else {
+ element = $[1];
+ }
+ return element;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: 42 }],
+};
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.js
new file mode 100644
index 0000000000..1d7302bce5
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.js
@@ -0,0 +1,16 @@
+import { identity, mutate, mutateAndReturnNewValue } from "shared-runtime";
+
+function Component(props) {
+ const key = {};
+ // Key is modified by the function, but key itself is not frozen
+ const element = {props.value}
;
+ // Key is later mutated here: this mutation must be grouped with the
+ // jsx construction above
+ mutate(key);
+ return element;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: 42 }],
+};
diff --git a/compiler/packages/sprout/src/shared-runtime.ts b/compiler/packages/sprout/src/shared-runtime.ts
index 928c064fee..880b5df848 100644
--- a/compiler/packages/sprout/src/shared-runtime.ts
+++ b/compiler/packages/sprout/src/shared-runtime.ts
@@ -73,6 +73,11 @@ export function mutateAndReturn(arg: T): T {
return arg;
}
+export function mutateAndReturnNewValue(arg: T): string {
+ mutate(arg);
+ return "hello!";
+}
+
export function setProperty(arg: any, property: any): void {
// don't mutate primitive
if (typeof arg === null || typeof arg !== "object") {