@samitouri / QOS-React / commits / 4f1d2ddf95

[compiler] Add types for WeakMap, WeakSet, and reanimated shared values

Building on mofeiz's recent work to type constructors. Also, types for reanimated values which are useful in the next PR. ghstack-source-id: 1c81e213a11337ac7e9c85a429ecf3f1d1adef66 Pull Request resolved: https://github.com/facebook/react/pull/33077

Joe Savona committed May 3, 2025 at 09:15 UTC 4f1d2ddf95906e9a3436552c524410e9d39f48ca
7 files changed +570 -1
compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts
+36 -1
@@ -25,6 +25,9 @@ import {
25 BuiltInUseRefId,
26 BuiltInUseStateId,
27 BuiltInUseTransitionId,
28 + BuiltInWeakMapId,
29 + BuiltInWeakSetId,
30 + ReanimatedSharedValueId,
31 ShapeRegistry,
32 addFunction,
33 addHook,
@@ -491,6 +494,38 @@ const TYPED_GLOBALS: Array<[string, BuiltInType]> = [
494 true,
495 ),
496 ],
497 + [
498 + 'WeakMap',
499 + addFunction(
500 + DEFAULT_SHAPES,
501 + [],
502 + {
503 + positionalParams: [Effect.ConditionallyMutateIterator],
504 + restParam: null,
505 + returnType: {kind: 'Object', shapeId: BuiltInWeakMapId},
506 + calleeEffect: Effect.Read,
507 + returnValueKind: ValueKind.Mutable,
508 + },
509 + null,
510 + true,
511 + ),
512 + ],
513 + [
514 + 'WeakSet',
515 + addFunction(
516 + DEFAULT_SHAPES,
517 + [],
518 + {
519 + positionalParams: [Effect.ConditionallyMutateIterator],
520 + restParam: null,
521 + returnType: {kind: 'Object', shapeId: BuiltInWeakSetId},
522 + calleeEffect: Effect.Read,
523 + returnValueKind: ValueKind.Mutable,
524 + },
525 + null,
526 + true,
527 + ),
528 + ],
529 // TODO: rest of Global objects
530 ];
531
@@ -908,7 +943,7 @@ export function getReanimatedModuleType(registry: ShapeRegistry): ObjectType {
943 addHook(registry, {
944 positionalParams: [],
945 restParam: Effect.Freeze,
911 - returnType: {kind: 'Poly'},
946 + returnType: {kind: 'Object', shapeId: ReanimatedSharedValueId},
947 returnValueKind: ValueKind.Mutable,
948 noAlias: true,
949 calleeEffect: Effect.Read,
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
+12
@@ -1725,6 +1725,18 @@ export function isRefOrRefValue(id: Identifier): boolean {
1725 return isUseRefType(id) || isRefValueType(id);
1726 }
1727
1728 +/*
1729 + * Returns true if the type is a Ref or a custom user type that acts like a ref when it
1730 + * shouldn't. For now the only other case of this is Reanimated's shared values.
1731 + */
1732 +export function isRefOrRefLikeMutableType(type: Type): boolean {
1733 + return (
1734 + type.kind === 'Object' &&
1735 + (type.shapeId === 'BuiltInUseRefId' ||
1736 + type.shapeId == 'ReanimatedSharedValueId')
1737 + );
1738 +}
1739 +
1740 export function isSetStateType(id: Identifier): boolean {
1741 return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetState';
1742 }
compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
+100
@@ -203,6 +203,8 @@ export const BuiltInPropsId = 'BuiltInProps';
203 export const BuiltInArrayId = 'BuiltInArray';
204 export const BuiltInSetId = 'BuiltInSet';
205 export const BuiltInMapId = 'BuiltInMap';
206 +export const BuiltInWeakSetId = 'BuiltInWeakSet';
207 +export const BuiltInWeakMapId = 'BuiltInWeakMap';
208 export const BuiltInFunctionId = 'BuiltInFunction';
209 export const BuiltInJsxId = 'BuiltInJsx';
210 export const BuiltInObjectId = 'BuiltInObject';
@@ -225,6 +227,9 @@ export const BuiltInStartTransitionId = 'BuiltInStartTransition';
227 export const BuiltInFireId = 'BuiltInFire';
228 export const BuiltInFireFunctionId = 'BuiltInFireFunction';
229
230 +// See getReanimatedModuleType() in Globals.ts — this is part of supporting Reanimated's ref-like types
231 +export const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
232 +
233 // ShapeRegistry with default definitions for built-ins.
234 export const BUILTIN_SHAPES: ShapeRegistry = new Map();
235
@@ -764,6 +769,101 @@ addObject(BUILTIN_SHAPES, BuiltInMapId, [
769 ],
770 ]);
771
772 +addObject(BUILTIN_SHAPES, BuiltInWeakSetId, [
773 + [
774 + /**
775 + * add(value)
776 + * Parameters
777 + * value: the value of the element to add to the Set object.
778 + * Returns the Set object with added value.
779 + */
780 + 'add',
781 + addFunction(BUILTIN_SHAPES, [], {
782 + positionalParams: [Effect.Capture],
783 + restParam: null,
784 + returnType: {kind: 'Object', shapeId: BuiltInWeakSetId},
785 + calleeEffect: Effect.Store,
786 + // returnValueKind is technically dependent on the ValueKind of the set itself
787 + returnValueKind: ValueKind.Mutable,
788 + }),
789 + ],
790 + [
791 + /**
792 + * setInstance.delete(value)
793 + * Returns true if value was already in Set; otherwise false.
794 + */
795 + 'delete',
796 + addFunction(BUILTIN_SHAPES, [], {
797 + positionalParams: [Effect.Read],
798 + restParam: null,
799 + returnType: PRIMITIVE_TYPE,
800 + calleeEffect: Effect.Store,
801 + returnValueKind: ValueKind.Primitive,
802 + }),
803 + ],
804 + [
805 + 'has',
806 + addFunction(BUILTIN_SHAPES, [], {
807 + positionalParams: [Effect.Read],
808 + restParam: null,
809 + returnType: PRIMITIVE_TYPE,
810 + calleeEffect: Effect.Read,
811 + returnValueKind: ValueKind.Primitive,
812 + }),
813 + ],
814 +]);
815 +
816 +addObject(BUILTIN_SHAPES, BuiltInWeakMapId, [
817 + [
818 + 'delete',
819 + addFunction(BUILTIN_SHAPES, [], {
820 + positionalParams: [Effect.Read],
821 + restParam: null,
822 + returnType: PRIMITIVE_TYPE,
823 + calleeEffect: Effect.Store,
824 + returnValueKind: ValueKind.Primitive,
825 + }),
826 + ],
827 + [
828 + 'get',
829 + addFunction(BUILTIN_SHAPES, [], {
830 + positionalParams: [Effect.Read],
831 + restParam: null,
832 + returnType: {kind: 'Poly'},
833 + calleeEffect: Effect.Capture,
834 + returnValueKind: ValueKind.Mutable,
835 + }),
836 + ],
837 + [
838 + 'has',
839 + addFunction(BUILTIN_SHAPES, [], {
840 + positionalParams: [Effect.Read],
841 + restParam: null,
842 + returnType: PRIMITIVE_TYPE,
843 + calleeEffect: Effect.Read,
844 + returnValueKind: ValueKind.Primitive,
845 + }),
846 + ],
847 + [
848 + /**
849 + * Params
850 + * key: the key of the element to add to the Map object. The key may be
851 + * any JavaScript type (any primitive value or any type of JavaScript
852 + * object).
853 + * value: the value of the element to add to the Map object.
854 + * Returns the Map object.
855 + */
856 + 'set',
857 + addFunction(BUILTIN_SHAPES, [], {
858 + positionalParams: [Effect.Capture, Effect.Capture],
859 + restParam: null,
860 + returnType: {kind: 'Object', shapeId: BuiltInWeakMapId},
861 + calleeEffect: Effect.Store,
862 + returnValueKind: ValueKind.Mutable,
863 + }),
864 + ],
865 +]);
866 +
867 addObject(BUILTIN_SHAPES, BuiltInUseStateId, [
868 ['0', {kind: 'Poly'}],
869 [
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/weakmap-constructor.expect.md new
+176
@@ -0,0 +1,176 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import {ValidateMemoization} from 'shared-runtime';
6 +
7 +function Component({a, b, c}) {
8 + const map = new WeakMap();
9 + const mapAlias = map.set(a, 0);
10 + mapAlias.set(c, 0);
11 +
12 + const hasB = map.has(b);
13 +
14 + return (
15 + <>
16 + <ValidateMemoization inputs={[a, c]} output={map} />
17 + <ValidateMemoization inputs={[a, c]} output={mapAlias} />
18 + <ValidateMemoization inputs={[b]} output={[hasB]} />
19 + </>
20 + );
21 +}
22 +
23 +const v1 = {value: 1};
24 +const v2 = {value: 2};
25 +const v3 = {value: 3};
26 +export const FIXTURE_ENTRYPOINT = {
27 + fn: Component,
28 + params: [{a: v1, b: v1, c: v1}],
29 + sequentialRenders: [
30 + {a: v1, b: v1, c: v1},
31 + {a: v2, b: v1, c: v1},
32 + {a: v1, b: v1, c: v1},
33 + {a: v1, b: v2, c: v1},
34 + {a: v1, b: v1, c: v1},
35 + {a: v3, b: v3, c: v1},
36 + {a: v3, b: v3, c: v1},
37 + {a: v1, b: v1, c: v1},
38 + ],
39 +};
40 +
41 +```
42 +
43 +## Code
44 +
45 +```javascript
46 +import { c as _c } from "react/compiler-runtime";
47 +import { ValidateMemoization } from "shared-runtime";
48 +
49 +function Component(t0) {
50 + const $ = _c(27);
51 + const { a, b, c } = t0;
52 + let map;
53 + let mapAlias;
54 + if ($[0] !== a || $[1] !== c) {
55 + map = new WeakMap();
56 + mapAlias = map.set(a, 0);
57 + mapAlias.set(c, 0);
58 + $[0] = a;
59 + $[1] = c;
60 + $[2] = map;
61 + $[3] = mapAlias;
62 + } else {
63 + map = $[2];
64 + mapAlias = $[3];
65 + }
66 +
67 + const hasB = map.has(b);
68 + let t1;
69 + if ($[4] !== a || $[5] !== c) {
70 + t1 = [a, c];
71 + $[4] = a;
72 + $[5] = c;
73 + $[6] = t1;
74 + } else {
75 + t1 = $[6];
76 + }
77 + let t2;
78 + if ($[7] !== map || $[8] !== t1) {
79 + t2 = <ValidateMemoization inputs={t1} output={map} />;
80 + $[7] = map;
81 + $[8] = t1;
82 + $[9] = t2;
83 + } else {
84 + t2 = $[9];
85 + }
86 + let t3;
87 + if ($[10] !== a || $[11] !== c) {
88 + t3 = [a, c];
89 + $[10] = a;
90 + $[11] = c;
91 + $[12] = t3;
92 + } else {
93 + t3 = $[12];
94 + }
95 + let t4;
96 + if ($[13] !== mapAlias || $[14] !== t3) {
97 + t4 = <ValidateMemoization inputs={t3} output={mapAlias} />;
98 + $[13] = mapAlias;
99 + $[14] = t3;
100 + $[15] = t4;
101 + } else {
102 + t4 = $[15];
103 + }
104 + let t5;
105 + if ($[16] !== b) {
106 + t5 = [b];
107 + $[16] = b;
108 + $[17] = t5;
109 + } else {
110 + t5 = $[17];
111 + }
112 + let t6;
113 + if ($[18] !== hasB) {
114 + t6 = [hasB];
115 + $[18] = hasB;
116 + $[19] = t6;
117 + } else {
118 + t6 = $[19];
119 + }
120 + let t7;
121 + if ($[20] !== t5 || $[21] !== t6) {
122 + t7 = <ValidateMemoization inputs={t5} output={t6} />;
123 + $[20] = t5;
124 + $[21] = t6;
125 + $[22] = t7;
126 + } else {
127 + t7 = $[22];
128 + }
129 + let t8;
130 + if ($[23] !== t2 || $[24] !== t4 || $[25] !== t7) {
131 + t8 = (
132 + <>
133 + {t2}
134 + {t4}
135 + {t7}
136 + </>
137 + );
138 + $[23] = t2;
139 + $[24] = t4;
140 + $[25] = t7;
141 + $[26] = t8;
142 + } else {
143 + t8 = $[26];
144 + }
145 + return t8;
146 +}
147 +
148 +const v1 = { value: 1 };
149 +const v2 = { value: 2 };
150 +const v3 = { value: 3 };
151 +export const FIXTURE_ENTRYPOINT = {
152 + fn: Component,
153 + params: [{ a: v1, b: v1, c: v1 }],
154 + sequentialRenders: [
155 + { a: v1, b: v1, c: v1 },
156 + { a: v2, b: v1, c: v1 },
157 + { a: v1, b: v1, c: v1 },
158 + { a: v1, b: v2, c: v1 },
159 + { a: v1, b: v1, c: v1 },
160 + { a: v3, b: v3, c: v1 },
161 + { a: v3, b: v3, c: v1 },
162 + { a: v1, b: v1, c: v1 },
163 + ],
164 +};
165 +
166 +```
167 +
168 +### Eval output
169 +(kind: ok) <div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
170 +<div>{"inputs":[{"value":2},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":2},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
171 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
172 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":2}],"output":[false]}</div>
173 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
174 +<div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3}],"output":[true]}</div>
175 +<div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3}],"output":[true]}</div>
176 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/weakmap-constructor.js new
+35
@@ -0,0 +1,35 @@
1 +import {ValidateMemoization} from 'shared-runtime';
2 +
3 +function Component({a, b, c}) {
4 + const map = new WeakMap();
5 + const mapAlias = map.set(a, 0);
6 + mapAlias.set(c, 0);
7 +
8 + const hasB = map.has(b);
9 +
10 + return (
11 + <>
12 + <ValidateMemoization inputs={[a, c]} output={map} />
13 + <ValidateMemoization inputs={[a, c]} output={mapAlias} />
14 + <ValidateMemoization inputs={[b]} output={[hasB]} />
15 + </>
16 + );
17 +}
18 +
19 +const v1 = {value: 1};
20 +const v2 = {value: 2};
21 +const v3 = {value: 3};
22 +export const FIXTURE_ENTRYPOINT = {
23 + fn: Component,
24 + params: [{a: v1, b: v1, c: v1}],
25 + sequentialRenders: [
26 + {a: v1, b: v1, c: v1},
27 + {a: v2, b: v1, c: v1},
28 + {a: v1, b: v1, c: v1},
29 + {a: v1, b: v2, c: v1},
30 + {a: v1, b: v1, c: v1},
31 + {a: v3, b: v3, c: v1},
32 + {a: v3, b: v3, c: v1},
33 + {a: v1, b: v1, c: v1},
34 + ],
35 +};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/weakset-constructor.expect.md new
+176
@@ -0,0 +1,176 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import {ValidateMemoization} from 'shared-runtime';
6 +
7 +function Component({a, b, c}) {
8 + const set = new WeakSet();
9 + const setAlias = set.add(a);
10 + setAlias.add(c);
11 +
12 + const hasB = set.has(b);
13 +
14 + return (
15 + <>
16 + <ValidateMemoization inputs={[a, c]} output={set} />
17 + <ValidateMemoization inputs={[a, c]} output={setAlias} />
18 + <ValidateMemoization inputs={[b]} output={[hasB]} />
19 + </>
20 + );
21 +}
22 +
23 +const v1 = {value: 1};
24 +const v2 = {value: 2};
25 +const v3 = {value: 3};
26 +export const FIXTURE_ENTRYPOINT = {
27 + fn: Component,
28 + params: [{a: v1, b: v1, c: v1}],
29 + sequentialRenders: [
30 + {a: v1, b: v1, c: v1},
31 + {a: v2, b: v1, c: v1},
32 + {a: v1, b: v1, c: v1},
33 + {a: v1, b: v2, c: v1},
34 + {a: v1, b: v1, c: v1},
35 + {a: v3, b: v3, c: v1},
36 + {a: v3, b: v3, c: v1},
37 + {a: v1, b: v1, c: v1},
38 + ],
39 +};
40 +
41 +```
42 +
43 +## Code
44 +
45 +```javascript
46 +import { c as _c } from "react/compiler-runtime";
47 +import { ValidateMemoization } from "shared-runtime";
48 +
49 +function Component(t0) {
50 + const $ = _c(27);
51 + const { a, b, c } = t0;
52 + let set;
53 + let setAlias;
54 + if ($[0] !== a || $[1] !== c) {
55 + set = new WeakSet();
56 + setAlias = set.add(a);
57 + setAlias.add(c);
58 + $[0] = a;
59 + $[1] = c;
60 + $[2] = set;
61 + $[3] = setAlias;
62 + } else {
63 + set = $[2];
64 + setAlias = $[3];
65 + }
66 +
67 + const hasB = set.has(b);
68 + let t1;
69 + if ($[4] !== a || $[5] !== c) {
70 + t1 = [a, c];
71 + $[4] = a;
72 + $[5] = c;
73 + $[6] = t1;
74 + } else {
75 + t1 = $[6];
76 + }
77 + let t2;
78 + if ($[7] !== set || $[8] !== t1) {
79 + t2 = <ValidateMemoization inputs={t1} output={set} />;
80 + $[7] = set;
81 + $[8] = t1;
82 + $[9] = t2;
83 + } else {
84 + t2 = $[9];
85 + }
86 + let t3;
87 + if ($[10] !== a || $[11] !== c) {
88 + t3 = [a, c];
89 + $[10] = a;
90 + $[11] = c;
91 + $[12] = t3;
92 + } else {
93 + t3 = $[12];
94 + }
95 + let t4;
96 + if ($[13] !== setAlias || $[14] !== t3) {
97 + t4 = <ValidateMemoization inputs={t3} output={setAlias} />;
98 + $[13] = setAlias;
99 + $[14] = t3;
100 + $[15] = t4;
101 + } else {
102 + t4 = $[15];
103 + }
104 + let t5;
105 + if ($[16] !== b) {
106 + t5 = [b];
107 + $[16] = b;
108 + $[17] = t5;
109 + } else {
110 + t5 = $[17];
111 + }
112 + let t6;
113 + if ($[18] !== hasB) {
114 + t6 = [hasB];
115 + $[18] = hasB;
116 + $[19] = t6;
117 + } else {
118 + t6 = $[19];
119 + }
120 + let t7;
121 + if ($[20] !== t5 || $[21] !== t6) {
122 + t7 = <ValidateMemoization inputs={t5} output={t6} />;
123 + $[20] = t5;
124 + $[21] = t6;
125 + $[22] = t7;
126 + } else {
127 + t7 = $[22];
128 + }
129 + let t8;
130 + if ($[23] !== t2 || $[24] !== t4 || $[25] !== t7) {
131 + t8 = (
132 + <>
133 + {t2}
134 + {t4}
135 + {t7}
136 + </>
137 + );
138 + $[23] = t2;
139 + $[24] = t4;
140 + $[25] = t7;
141 + $[26] = t8;
142 + } else {
143 + t8 = $[26];
144 + }
145 + return t8;
146 +}
147 +
148 +const v1 = { value: 1 };
149 +const v2 = { value: 2 };
150 +const v3 = { value: 3 };
151 +export const FIXTURE_ENTRYPOINT = {
152 + fn: Component,
153 + params: [{ a: v1, b: v1, c: v1 }],
154 + sequentialRenders: [
155 + { a: v1, b: v1, c: v1 },
156 + { a: v2, b: v1, c: v1 },
157 + { a: v1, b: v1, c: v1 },
158 + { a: v1, b: v2, c: v1 },
159 + { a: v1, b: v1, c: v1 },
160 + { a: v3, b: v3, c: v1 },
161 + { a: v3, b: v3, c: v1 },
162 + { a: v1, b: v1, c: v1 },
163 + ],
164 +};
165 +
166 +```
167 +
168 +### Eval output
169 +(kind: ok) <div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
170 +<div>{"inputs":[{"value":2},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":2},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
171 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
172 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":2}],"output":[false]}</div>
173 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
174 +<div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3}],"output":[true]}</div>
175 +<div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3},{"value":1}],"output":{}}</div><div>{"inputs":[{"value":3}],"output":[true]}</div>
176 +<div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1},"[[ cyclic ref *2 ]]"],"output":{}}</div><div>{"inputs":[{"value":1}],"output":[true]}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/weakset-constructor.js new
+35
@@ -0,0 +1,35 @@
1 +import {ValidateMemoization} from 'shared-runtime';
2 +
3 +function Component({a, b, c}) {
4 + const set = new WeakSet();
5 + const setAlias = set.add(a);
6 + setAlias.add(c);
7 +
8 + const hasB = set.has(b);
9 +
10 + return (
11 + <>
12 + <ValidateMemoization inputs={[a, c]} output={set} />
13 + <ValidateMemoization inputs={[a, c]} output={setAlias} />
14 + <ValidateMemoization inputs={[b]} output={[hasB]} />
15 + </>
16 + );
17 +}
18 +
19 +const v1 = {value: 1};
20 +const v2 = {value: 2};
21 +const v3 = {value: 3};
22 +export const FIXTURE_ENTRYPOINT = {
23 + fn: Component,
24 + params: [{a: v1, b: v1, c: v1}],
25 + sequentialRenders: [
26 + {a: v1, b: v1, c: v1},
27 + {a: v2, b: v1, c: v1},
28 + {a: v1, b: v1, c: v1},
29 + {a: v1, b: v2, c: v1},
30 + {a: v1, b: v1, c: v1},
31 + {a: v3, b: v3, c: v1},
32 + {a: v3, b: v3, c: v1},
33 + {a: v1, b: v1, c: v1},
34 + ],
35 +};