@samitouri / QOS-React-2 / commits / dcbdf06491

Extra test case related to memoization "within" freeze

I found an interesting edge case in the previous diff with mutation of a value that appears in the expression of an object key: ```javascript const key = {} const object = { [mutateAndReturnOtherValue(key)]: 42, }; mutate(key); ``` We analyze and represent this correctly all the way through to codegen, but then we hit the bug that @mofeiZ has noticed before: the temporary for `t = mutateAndReturnOtherValue(key)` isn't emitted immediately (bc its a temporary). It gets emitted inside the memo block for `object`, which is incorrect. I tried to reproduce that here with JSX and it works as expected. It's an interesting case though so let's land this to ensure we don't regress.

Joe Savona committed Nov 13, 2023 at 11:03 UTC dcbdf064915fc2187687acc12cf62232ab2b2a47
3 files changed +74
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.expect.md new
+53
@@ -0,0 +1,53 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import { identity, mutate, mutateAndReturnNewValue } from "shared-runtime";
6 +
7 +function Component(props) {
8 + const key = {};
9 + // Key is modified by the function, but key itself is not frozen
10 + const element = <div key={mutateAndReturnNewValue(key)}>{props.value}</div>;
11 + // Key is later mutated here: this mutation must be grouped with the
12 + // jsx construction above
13 + mutate(key);
14 + return element;
15 +}
16 +
17 +export const FIXTURE_ENTRYPOINT = {
18 + fn: Component,
19 + params: [{ value: 42 }],
20 +};
21 +
22 +```
23 +
24 +## Code
25 +
26 +```javascript
27 +import { unstable_useMemoCache as useMemoCache } from "react";
28 +import { identity, mutate, mutateAndReturnNewValue } from "shared-runtime";
29 +
30 +function Component(props) {
31 + const $ = useMemoCache(2);
32 + let element;
33 + if ($[0] !== props.value) {
34 + const key = {};
35 +
36 + element = <div key={mutateAndReturnNewValue(key)}>{props.value}</div>;
37 +
38 + mutate(key);
39 + $[0] = props.value;
40 + $[1] = element;
41 + } else {
42 + element = $[1];
43 + }
44 + return element;
45 +}
46 +
47 +export const FIXTURE_ENTRYPOINT = {
48 + fn: Component,
49 + params: [{ value: 42 }],
50 +};
51 +
52 +```
53 +
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/mutation-during-jsx-construction.js new
+16
@@ -0,0 +1,16 @@
1 +import { identity, mutate, mutateAndReturnNewValue } from "shared-runtime";
2 +
3 +function Component(props) {
4 + const key = {};
5 + // Key is modified by the function, but key itself is not frozen
6 + const element = <div key={mutateAndReturnNewValue(key)}>{props.value}</div>;
7 + // Key is later mutated here: this mutation must be grouped with the
8 + // jsx construction above
9 + mutate(key);
10 + return element;
11 +}
12 +
13 +export const FIXTURE_ENTRYPOINT = {
14 + fn: Component,
15 + params: [{ value: 42 }],
16 +};
compiler/packages/sprout/src/shared-runtime.ts
+5
@@ -73,6 +73,11 @@ export function mutateAndReturn<T>(arg: T): T {
73 return arg;
74 }
75
76 +export function mutateAndReturnNewValue<T>(arg: T): string {
77 + mutate(arg);
78 + return "hello!";
79 +}
80 +
81 export function setProperty(arg: any, property: any): void {
82 // don't mutate primitive
83 if (typeof arg === null || typeof arg !== "object") {