@samitouri / QOS-React / commits / 0a7f4427f1

Fix invariant on mutable context values

ghstack-source-id: cb105318bf66d876a546b1c52e28286839d30032 Pull Request resolved: https://github.com/facebook/react-forget/pull/2904

Joe Savona committed Apr 25, 2024 at 08:00 UTC 0a7f4427f13d70cd4cafe0388eb7d6b44ef1832e
4 files changed +79 -62
compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts
-11
@@ -1640,17 +1640,6 @@ function inferBlock(
1640 const lvalue = instr.lvalue;
1641 lvalue.effect = Effect.ConditionallyMutate;
1642 const valueKind = state.kind(instrValue.place);
1643 - CompilerError.invariant(
1644 - valueKind.kind === ValueKind.Mutable ||
1645 - valueKind.kind === ValueKind.Context,
1646 - {
1647 - reason:
1648 - "[InferReferenceEffects] Context variables are always mutable.",
1649 - description: null,
1650 - loc: instrValue.loc,
1651 - suggestions: null,
1652 - }
1653 - );
1643 state.initialize(instrValue, valueKind);
1644 state.define(lvalue, instrValue);
1645 continue;
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-multiple-calls-to-hoisted-callback-from-other-callback.expect.md deleted
-46
@@ -1,46 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
6 -function Component(props) {
7 - const [_state, setState] = useState();
8 - const a = () => {
9 - return b();
10 - };
11 - const b = () => {
12 - return (
13 - <>
14 - <div onClick={() => onClick(true)} />
15 - <div onClick={() => onClick(false)} />
16 - </>
17 - );
18 - };
19 - const onClick = (value) => {
20 - setState(value);
21 - };
22 -
23 - return <div>{a()}</div>;
24 -}
25 -
26 -export const FIXTURE_ENTRYPONT = {
27 - fn: Component,
28 - props: [{}],
29 -};
30 -
31 -```
32 -
33 -
34 -## Error
35 -
36 -```
37 - 9 | <>
38 - 10 | <div onClick={() => onClick(true)} />
39 -> 11 | <div onClick={() => onClick(false)} />
40 - | ^^^^^^^ Invariant: [InferReferenceEffects] Context variables are always mutable. (11:11)
41 - 12 | </>
42 - 13 | );
43 - 14 | };
44 -```
45 -
46 -
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/multiple-calls-to-hoisted-callback-from-other-callback.expect.md new
+73
@@ -0,0 +1,73 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import { useState } from "react";
6 +
7 +function Component(props) {
8 + const [_state, setState] = useState();
9 + const a = () => {
10 + return b();
11 + };
12 + const b = () => {
13 + return (
14 + <>
15 + <div onClick={() => onClick(true)}>a</div>
16 + <div onClick={() => onClick(false)}>b</div>
17 + </>
18 + );
19 + };
20 + const onClick = (value) => {
21 + setState(value);
22 + };
23 +
24 + return <div>{a()}</div>;
25 +}
26 +
27 +export const FIXTURE_ENTRYPOINT = {
28 + fn: Component,
29 + params: [{}],
30 +};
31 +
32 +```
33 +
34 +## Code
35 +
36 +```javascript
37 +import { useState, unstable_useMemoCache as useMemoCache } from "react";
38 +
39 +function Component(props) {
40 + const $ = useMemoCache(1);
41 + const [_state, setState] = useState();
42 + let t0;
43 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
44 + const a = () => b();
45 +
46 + const b = () => (
47 + <>
48 + <div onClick={() => onClick(true)}>a</div>
49 + <div onClick={() => onClick(false)}>b</div>
50 + </>
51 + );
52 +
53 + const onClick = (value) => {
54 + setState(value);
55 + };
56 +
57 + t0 = <div>{a()}</div>;
58 + $[0] = t0;
59 + } else {
60 + t0 = $[0];
61 + }
62 + return t0;
63 +}
64 +
65 +export const FIXTURE_ENTRYPOINT = {
66 + fn: Component,
67 + params: [{}],
68 +};
69 +
70 +```
71 +
72 +### Eval output
73 +(kind: ok) <div><div>a</div><div>b</div></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/multiple-calls-to-hoisted-callback-from-other-callback.js renamed
+6 -5
@@ -1,4 +1,5 @@
1 -// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
1 +import { useState } from "react";
2 +
3 function Component(props) {
4 const [_state, setState] = useState();
5 const a = () => {
@@ -7,8 +8,8 @@ function Component(props) {
8 const b = () => {
9 return (
10 <>
10 - <div onClick={() => onClick(true)} />
11 - <div onClick={() => onClick(false)} />
11 + <div onClick={() => onClick(true)}>a</div>
12 + <div onClick={() => onClick(false)}>b</div>
13 </>
14 );
15 };
@@ -19,7 +20,7 @@ function Component(props) {
20 return <div>{a()}</div>;
21 }
22
22 -export const FIXTURE_ENTRYPONT = {
23 +export const FIXTURE_ENTRYPOINT = {
24 fn: Component,
24 - props: [{}],
25 + params: [{}],
26 };