Test cases for inferring mutability of function expressions (as values)
This PR contains just the test cases from #1717, showing some tricky cases around function expression mutability inference.
Joe Savona committed
Jun 15, 2023 at 09:32 UTC
aae9b01f91347e3417a20da861762ea0402d7cfb
8 files changed
+150
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-function-expression-captures-value-later-frozen-jsx.expect.md
new
+27
@@ -0,0 +1,27 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x = {};
7
+ // onChange should be inferred as immutable, because the value
8
+ // it captures (`x`) is frozen by the time the function is referenced
9
+ const onChange = (e) => {
10
+ maybeMutate(x, e.target.value);
11
+ };
12
+ if (props.cond) {
13
+ <div>{x}</div>;
14
+ }
15
+ return <Foo value={x} onChange={onChange} />;
16
+}
17
+
18
+```
19
+
20
+
21
+## Error
22
+
23
+```
24
+[ReactForget] InvalidInput: Cannot use a mutable function where an immutable value is expected (11:11)
25
+```
26
+
27
+
\ No newline at end of file
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-function-expression-captures-value-later-frozen-jsx.js
new
+12
@@ -0,0 +1,12 @@
1
+function Component(props) {
2
+ let x = {};
3
+ // onChange should be inferred as immutable, because the value
4
+ // it captures (`x`) is frozen by the time the function is referenced
5
+ const onChange = (e) => {
6
+ maybeMutate(x, e.target.value);
7
+ };
8
+ if (props.cond) {
9
+ <div>{x}</div>;
10
+ }
11
+ return <Foo value={x} onChange={onChange} />;
12
+}
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-function-expression-maybe-mutates-hook-return-value.expect.md
new
+27
@@ -0,0 +1,27 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ const id = useSelectedEntitytId();
7
+ // this example should infer `id` as mutable, and then infer `onLoad` as mutable,
8
+ // and be rejected because onLoad cannot be passed as a frozen value in the JSX.
9
+ // however, we likely have to allow this example to work, because hook return
10
+ // values are generally immutable in practice and are also widely referenced in
11
+ // callbacks.
12
+ const onLoad = () => {
13
+ log(id);
14
+ };
15
+ return <Foo onLoad={onLoad} />;
16
+}
17
+
18
+```
19
+
20
+
21
+## Error
22
+
23
+```
24
+[ReactForget] InvalidInput: Cannot use a mutable function where an immutable value is expected (11:11)
25
+```
26
+
27
+
\ No newline at end of file
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-function-expression-maybe-mutates-hook-return-value.js
new
+12
@@ -0,0 +1,12 @@
1
+function Component(props) {
2
+ const id = useSelectedEntitytId();
3
+ // this example should infer `id` as mutable, and then infer `onLoad` as mutable,
4
+ // and be rejected because onLoad cannot be passed as a frozen value in the JSX.
5
+ // however, we likely have to allow this example to work, because hook return
6
+ // values are generally immutable in practice and are also widely referenced in
7
+ // callbacks.
8
+ const onLoad = () => {
9
+ log(id);
10
+ };
11
+ return <Foo onLoad={onLoad} />;
12
+}
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md
new
+58
@@ -0,0 +1,58 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x = {};
7
+ // onChange should be inferred as immutable, because the value
8
+ // it captures (`x`) is frozen by the time the function is referenced
9
+ const onChange = (e) => {
10
+ maybeMutate(x, e.target.value);
11
+ };
12
+ if (props.cond) {
13
+ <div>{x}</div>;
14
+ }
15
+ // ideally this call would be outside the memoization block for `x`
16
+ onChange();
17
+ return <Foo value={x} />;
18
+}
19
+
20
+```
21
+
22
+## Code
23
+
24
+```javascript
25
+import { unstable_useMemoCache as useMemoCache } from "react";
26
+function Component(props) {
27
+ const $ = useMemoCache(4);
28
+ const c_0 = $[0] !== props.cond;
29
+ let x;
30
+ if (c_0) {
31
+ x = {};
32
+
33
+ const onChange = (e) => {
34
+ maybeMutate(x, e.target.value);
35
+ };
36
+ if (props.cond) {
37
+ }
38
+
39
+ onChange();
40
+ $[0] = props.cond;
41
+ $[1] = x;
42
+ } else {
43
+ x = $[1];
44
+ }
45
+ const c_2 = $[2] !== x;
46
+ let t0;
47
+ if (c_2) {
48
+ t0 = <Foo value={x} />;
49
+ $[2] = x;
50
+ $[3] = t0;
51
+ } else {
52
+ t0 = $[3];
53
+ }
54
+ return t0;
55
+}
56
+
57
+```
58
+
\ No newline at end of file
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.js
new
+14
@@ -0,0 +1,14 @@
1
+function Component(props) {
2
+ let x = {};
3
+ // onChange should be inferred as immutable, because the value
4
+ // it captures (`x`) is frozen by the time the function is referenced
5
+ const onChange = (e) => {
6
+ maybeMutate(x, e.target.value);
7
+ };
8
+ if (props.cond) {
9
+ <div>{x}</div>;
10
+ }
11
+ // ideally this call would be outside the memoization block for `x`
12
+ onChange();
13
+ return <Foo value={x} />;
14
+}