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.
This commit is contained in:
Joe Savona
2023-06-15 09:32:30 -07:00
parent 8fcceb715c
commit aae9b01f91
8 changed files with 150 additions and 0 deletions
@@ -0,0 +1,27 @@
## Input
```javascript
function Component(props) {
let x = {};
// onChange should be inferred as immutable, because the value
// it captures (`x`) is frozen by the time the function is referenced
const onChange = (e) => {
maybeMutate(x, e.target.value);
};
if (props.cond) {
<div>{x}</div>;
}
return <Foo value={x} onChange={onChange} />;
}
```
## Error
```
[ReactForget] InvalidInput: Cannot use a mutable function where an immutable value is expected (11:11)
```
@@ -0,0 +1,12 @@
function Component(props) {
let x = {};
// onChange should be inferred as immutable, because the value
// it captures (`x`) is frozen by the time the function is referenced
const onChange = (e) => {
maybeMutate(x, e.target.value);
};
if (props.cond) {
<div>{x}</div>;
}
return <Foo value={x} onChange={onChange} />;
}
@@ -0,0 +1,27 @@
## Input
```javascript
function Component(props) {
const id = useSelectedEntitytId();
// this example should infer `id` as mutable, and then infer `onLoad` as mutable,
// and be rejected because onLoad cannot be passed as a frozen value in the JSX.
// however, we likely have to allow this example to work, because hook return
// values are generally immutable in practice and are also widely referenced in
// callbacks.
const onLoad = () => {
log(id);
};
return <Foo onLoad={onLoad} />;
}
```
## Error
```
[ReactForget] InvalidInput: Cannot use a mutable function where an immutable value is expected (11:11)
```
@@ -0,0 +1,12 @@
function Component(props) {
const id = useSelectedEntitytId();
// this example should infer `id` as mutable, and then infer `onLoad` as mutable,
// and be rejected because onLoad cannot be passed as a frozen value in the JSX.
// however, we likely have to allow this example to work, because hook return
// values are generally immutable in practice and are also widely referenced in
// callbacks.
const onLoad = () => {
log(id);
};
return <Foo onLoad={onLoad} />;
}
@@ -0,0 +1,58 @@
## Input
```javascript
function Component(props) {
let x = {};
// onChange should be inferred as immutable, because the value
// it captures (`x`) is frozen by the time the function is referenced
const onChange = (e) => {
maybeMutate(x, e.target.value);
};
if (props.cond) {
<div>{x}</div>;
}
// ideally this call would be outside the memoization block for `x`
onChange();
return <Foo value={x} />;
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(4);
const c_0 = $[0] !== props.cond;
let x;
if (c_0) {
x = {};
const onChange = (e) => {
maybeMutate(x, e.target.value);
};
if (props.cond) {
}
onChange();
$[0] = props.cond;
$[1] = x;
} else {
x = $[1];
}
const c_2 = $[2] !== x;
let t0;
if (c_2) {
t0 = <Foo value={x} />;
$[2] = x;
$[3] = t0;
} else {
t0 = $[3];
}
return t0;
}
```
@@ -0,0 +1,14 @@
function Component(props) {
let x = {};
// onChange should be inferred as immutable, because the value
// it captures (`x`) is frozen by the time the function is referenced
const onChange = (e) => {
maybeMutate(x, e.target.value);
};
if (props.cond) {
<div>{x}</div>;
}
// ideally this call would be outside the memoization block for `x`
onChange();
return <Foo value={x} />;
}