Repro for "context variables are always mutable" error w callbacks

I haven't debugged to understand exactly why this pattern fails, but there are a 
few instances of this internally. It's especially weird because 

```javascript 

// @enableAssumeHooksFollowRulesOfReact 
@enableTransitivelyFreezeFunctionExpressions 

function Component(props) { 

const [_state, setState] = useState(); 

const a = () => { 

return b(); 

}; 

const b = () => { 

return ( 

<> 

<div onClick={() => onClick(true)} /> 

<div onClick={() => onClick(false)} /> // <---- only repros if there's a second 
call! 

</> 

); 

}; 

const onClick = (value) => { 

setState(value); 

}; 

return <div>{a()}</div>; 

} 

``` 

Here, if `b()` only had one nested function expression that called `onClick` it 
would work. Also, if we disable `@enableTransitivelyFreezeFunctionExpressions` 
then it works. 

But the combination of multiple calls plus that mode causes "context variables 
are always mutable". I'm guessing we're freezing `onClick` twice and the second 
time reports an error since it calls `setState`.
This commit is contained in:
Joe Savona
2024-03-21 21:40:02 -07:00
parent f18a01bf59
commit 3a6a2e7e4a
2 changed files with 71 additions and 0 deletions
@@ -0,0 +1,46 @@
## Input
```javascript
// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
function Component(props) {
const [_state, setState] = useState();
const a = () => {
return b();
};
const b = () => {
return (
<>
<div onClick={() => onClick(true)} />
<div onClick={() => onClick(false)} />
</>
);
};
const onClick = (value) => {
setState(value);
};
return <div>{a()}</div>;
}
export const FIXTURE_ENTRYPONT = {
fn: Component,
props: [{}],
};
```
## Error
```
9 | <>
10 | <div onClick={() => onClick(true)} />
> 11 | <div onClick={() => onClick(false)} />
| ^^^^^^^ [ReactForget] Invariant: [InferReferenceEffects] Context variables are always mutable. (11:11)
12 | </>
13 | );
14 | };
```
@@ -0,0 +1,25 @@
// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
function Component(props) {
const [_state, setState] = useState();
const a = () => {
return b();
};
const b = () => {
return (
<>
<div onClick={() => onClick(true)} />
<div onClick={() => onClick(false)} />
</>
);
};
const onClick = (value) => {
setState(value);
};
return <div>{a()}</div>;
}
export const FIXTURE_ENTRYPONT = {
fn: Component,
props: [{}],
};