Skip to content

Commit 4f1d2dd

Browse files
committed
[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: 1c81e21 Pull Request resolved: #33077
1 parent 73d7e81 commit 4f1d2dd

File tree

7 files changed

+570
-1
lines changed

7 files changed

+570
-1
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import {
2525
BuiltInUseRefId,
2626
BuiltInUseStateId,
2727
BuiltInUseTransitionId,
28+
BuiltInWeakMapId,
29+
BuiltInWeakSetId,
30+
ReanimatedSharedValueId,
2831
ShapeRegistry,
2932
addFunction,
3033
addHook,
@@ -491,6 +494,38 @@ const TYPED_GLOBALS: Array<[string, BuiltInType]> = [
491494
true,
492495
),
493496
],
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+
],
494529
// TODO: rest of Global objects
495530
];
496531

@@ -908,7 +943,7 @@ export function getReanimatedModuleType(registry: ShapeRegistry): ObjectType {
908943
addHook(registry, {
909944
positionalParams: [],
910945
restParam: Effect.Freeze,
911-
returnType: {kind: 'Poly'},
946+
returnType: {kind: 'Object', shapeId: ReanimatedSharedValueId},
912947
returnValueKind: ValueKind.Mutable,
913948
noAlias: true,
914949
calleeEffect: Effect.Read,

compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,18 @@ export function isRefOrRefValue(id: Identifier): boolean {
17251725
return isUseRefType(id) || isRefValueType(id);
17261726
}
17271727

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+
17281740
export function isSetStateType(id: Identifier): boolean {
17291741
return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetState';
17301742
}

compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ export const BuiltInPropsId = 'BuiltInProps';
203203
export const BuiltInArrayId = 'BuiltInArray';
204204
export const BuiltInSetId = 'BuiltInSet';
205205
export const BuiltInMapId = 'BuiltInMap';
206+
export const BuiltInWeakSetId = 'BuiltInWeakSet';
207+
export const BuiltInWeakMapId = 'BuiltInWeakMap';
206208
export const BuiltInFunctionId = 'BuiltInFunction';
207209
export const BuiltInJsxId = 'BuiltInJsx';
208210
export const BuiltInObjectId = 'BuiltInObject';
@@ -225,6 +227,9 @@ export const BuiltInStartTransitionId = 'BuiltInStartTransition';
225227
export const BuiltInFireId = 'BuiltInFire';
226228
export const BuiltInFireFunctionId = 'BuiltInFireFunction';
227229

230+
// See getReanimatedModuleType() in Globals.ts — this is part of supporting Reanimated's ref-like types
231+
export const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
232+
228233
// ShapeRegistry with default definitions for built-ins.
229234
export const BUILTIN_SHAPES: ShapeRegistry = new Map();
230235

@@ -764,6 +769,101 @@ addObject(BUILTIN_SHAPES, BuiltInMapId, [
764769
],
765770
]);
766771

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+
767867
addObject(BUILTIN_SHAPES, BuiltInUseStateId, [
768868
['0', {kind: 'Poly'}],
769869
[
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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>

0 commit comments

Comments
 (0)