[compiler] Upstream experimental flow integration (#34121)
all credit on the Flood/ code goes to @mvitousek and @jbrown215, i'm just the one upstreaming it
Joseph Savona committed
Aug 6, 2025 at 15:58 UTC
c403a7c54805e1198bfdad7fc97f33a792359a77
8 files changed
+2232
-3
compiler/packages/babel-plugin-react-compiler/src/Flood/FlowTypes.ts
new
+752
@@ -0,0 +1,752 @@
1
+/**
2
+ * TypeScript definitions for Flow type JSON representations
3
+ * Based on the output of /data/sandcastle/boxes/fbsource/fbcode/flow/src/typing/convertTypes.ml
4
+ */
5
+
6
+// Base type for all Flow types with a kind field
7
+export interface BaseFlowType {
8
+ kind: string;
9
+}
10
+
11
+// Type for representing polarity
12
+export type Polarity = 'positive' | 'negative' | 'neutral';
13
+
14
+// Type for representing a name that might be null
15
+export type OptionalName = string | null;
16
+
17
+// Open type
18
+export interface OpenType extends BaseFlowType {
19
+ kind: 'Open';
20
+}
21
+
22
+// Def type
23
+export interface DefType extends BaseFlowType {
24
+ kind: 'Def';
25
+ def: DefT;
26
+}
27
+
28
+// Eval type
29
+export interface EvalType extends BaseFlowType {
30
+ kind: 'Eval';
31
+ type: FlowType;
32
+ destructor: Destructor;
33
+}
34
+
35
+// Generic type
36
+export interface GenericType extends BaseFlowType {
37
+ kind: 'Generic';
38
+ name: string;
39
+ bound: FlowType;
40
+ no_infer: boolean;
41
+}
42
+
43
+// ThisInstance type
44
+export interface ThisInstanceType extends BaseFlowType {
45
+ kind: 'ThisInstance';
46
+ instance: InstanceT;
47
+ is_this: boolean;
48
+ name: string;
49
+}
50
+
51
+// ThisTypeApp type
52
+export interface ThisTypeAppType extends BaseFlowType {
53
+ kind: 'ThisTypeApp';
54
+ t1: FlowType;
55
+ t2: FlowType;
56
+ t_list?: Array<FlowType>;
57
+}
58
+
59
+// TypeApp type
60
+export interface TypeAppType extends BaseFlowType {
61
+ kind: 'TypeApp';
62
+ type: FlowType;
63
+ targs: Array<FlowType>;
64
+ from_value: boolean;
65
+ use_desc: boolean;
66
+}
67
+
68
+// FunProto type
69
+export interface FunProtoType extends BaseFlowType {
70
+ kind: 'FunProto';
71
+}
72
+
73
+// ObjProto type
74
+export interface ObjProtoType extends BaseFlowType {
75
+ kind: 'ObjProto';
76
+}
77
+
78
+// NullProto type
79
+export interface NullProtoType extends BaseFlowType {
80
+ kind: 'NullProto';
81
+}
82
+
83
+// FunProtoBind type
84
+export interface FunProtoBindType extends BaseFlowType {
85
+ kind: 'FunProtoBind';
86
+}
87
+
88
+// Intersection type
89
+export interface IntersectionType extends BaseFlowType {
90
+ kind: 'Intersection';
91
+ members: Array<FlowType>;
92
+}
93
+
94
+// Union type
95
+export interface UnionType extends BaseFlowType {
96
+ kind: 'Union';
97
+ members: Array<FlowType>;
98
+}
99
+
100
+// Maybe type
101
+export interface MaybeType extends BaseFlowType {
102
+ kind: 'Maybe';
103
+ type: FlowType;
104
+}
105
+
106
+// Optional type
107
+export interface OptionalType extends BaseFlowType {
108
+ kind: 'Optional';
109
+ type: FlowType;
110
+ use_desc: boolean;
111
+}
112
+
113
+// Keys type
114
+export interface KeysType extends BaseFlowType {
115
+ kind: 'Keys';
116
+ type: FlowType;
117
+}
118
+
119
+// Annot type
120
+export interface AnnotType extends BaseFlowType {
121
+ kind: 'Annot';
122
+ type: FlowType;
123
+ use_desc: boolean;
124
+}
125
+
126
+// Opaque type
127
+export interface OpaqueType extends BaseFlowType {
128
+ kind: 'Opaque';
129
+ opaquetype: {
130
+ opaque_id: string;
131
+ underlying_t: FlowType | null;
132
+ super_t: FlowType | null;
133
+ opaque_type_args: Array<{
134
+ name: string;
135
+ type: FlowType;
136
+ polarity: Polarity;
137
+ }>;
138
+ opaque_name: string;
139
+ };
140
+}
141
+
142
+// Namespace type
143
+export interface NamespaceType extends BaseFlowType {
144
+ kind: 'Namespace';
145
+ namespace_symbol: {
146
+ symbol: string;
147
+ };
148
+ values_type: FlowType;
149
+ types_tmap: PropertyMap;
150
+}
151
+
152
+// Any type
153
+export interface AnyType extends BaseFlowType {
154
+ kind: 'Any';
155
+}
156
+
157
+// StrUtil type
158
+export interface StrUtilType extends BaseFlowType {
159
+ kind: 'StrUtil';
160
+ op: 'StrPrefix' | 'StrSuffix';
161
+ prefix?: string;
162
+ suffix?: string;
163
+ remainder?: FlowType;
164
+}
165
+
166
+// TypeParam definition
167
+export interface TypeParam {
168
+ name: string;
169
+ bound: FlowType;
170
+ polarity: Polarity;
171
+ default: FlowType | null;
172
+}
173
+
174
+// EnumInfo types
175
+export type EnumInfo = ConcreteEnum | AbstractEnum;
176
+
177
+export interface ConcreteEnum {
178
+ kind: 'ConcreteEnum';
179
+ enum_name: string;
180
+ enum_id: string;
181
+ members: Array<string>;
182
+ representation_t: FlowType;
183
+ has_unknown_members: boolean;
184
+}
185
+
186
+export interface AbstractEnum {
187
+ kind: 'AbstractEnum';
188
+ representation_t: FlowType;
189
+}
190
+
191
+// CanonicalRendersForm types
192
+export type CanonicalRendersForm =
193
+ | InstrinsicRenders
194
+ | NominalRenders
195
+ | StructuralRenders
196
+ | DefaultRenders;
197
+
198
+export interface InstrinsicRenders {
199
+ kind: 'InstrinsicRenders';
200
+ name: string;
201
+}
202
+
203
+export interface NominalRenders {
204
+ kind: 'NominalRenders';
205
+ renders_id: string;
206
+ renders_name: string;
207
+ renders_super: FlowType;
208
+}
209
+
210
+export interface StructuralRenders {
211
+ kind: 'StructuralRenders';
212
+ renders_variant: 'RendersNormal' | 'RendersMaybe' | 'RendersStar';
213
+ renders_structural_type: FlowType;
214
+}
215
+
216
+export interface DefaultRenders {
217
+ kind: 'DefaultRenders';
218
+}
219
+
220
+// InstanceT definition
221
+export interface InstanceT {
222
+ inst: InstType;
223
+ static: FlowType;
224
+ super: FlowType;
225
+ implements: Array<FlowType>;
226
+}
227
+
228
+// InstType definition
229
+export interface InstType {
230
+ class_name: string | null;
231
+ class_id: string;
232
+ type_args: Array<{
233
+ name: string;
234
+ type: FlowType;
235
+ polarity: Polarity;
236
+ }>;
237
+ own_props: PropertyMap;
238
+ proto_props: PropertyMap;
239
+ call_t: null | {
240
+ id: number;
241
+ call: FlowType;
242
+ };
243
+}
244
+
245
+// DefT types
246
+export type DefT =
247
+ | NumGeneralType
248
+ | StrGeneralType
249
+ | BoolGeneralType
250
+ | BigIntGeneralType
251
+ | EmptyType
252
+ | MixedType
253
+ | NullType
254
+ | VoidType
255
+ | SymbolType
256
+ | FunType
257
+ | ObjType
258
+ | ArrType
259
+ | ClassType
260
+ | InstanceType
261
+ | SingletonStrType
262
+ | NumericStrKeyType
263
+ | SingletonNumType
264
+ | SingletonBoolType
265
+ | SingletonBigIntType
266
+ | TypeType
267
+ | PolyType
268
+ | ReactAbstractComponentType
269
+ | RendersType
270
+ | EnumValueType
271
+ | EnumObjectType;
272
+
273
+export interface NumGeneralType extends BaseFlowType {
274
+ kind: 'NumGeneral';
275
+}
276
+
277
+export interface StrGeneralType extends BaseFlowType {
278
+ kind: 'StrGeneral';
279
+}
280
+
281
+export interface BoolGeneralType extends BaseFlowType {
282
+ kind: 'BoolGeneral';
283
+}
284
+
285
+export interface BigIntGeneralType extends BaseFlowType {
286
+ kind: 'BigIntGeneral';
287
+}
288
+
289
+export interface EmptyType extends BaseFlowType {
290
+ kind: 'Empty';
291
+}
292
+
293
+export interface MixedType extends BaseFlowType {
294
+ kind: 'Mixed';
295
+}
296
+
297
+export interface NullType extends BaseFlowType {
298
+ kind: 'Null';
299
+}
300
+
301
+export interface VoidType extends BaseFlowType {
302
+ kind: 'Void';
303
+}
304
+
305
+export interface SymbolType extends BaseFlowType {
306
+ kind: 'Symbol';
307
+}
308
+
309
+export interface FunType extends BaseFlowType {
310
+ kind: 'Fun';
311
+ static: FlowType;
312
+ funtype: FunTypeObj;
313
+}
314
+
315
+export interface ObjType extends BaseFlowType {
316
+ kind: 'Obj';
317
+ objtype: ObjTypeObj;
318
+}
319
+
320
+export interface ArrType extends BaseFlowType {
321
+ kind: 'Arr';
322
+ arrtype: ArrTypeObj;
323
+}
324
+
325
+export interface ClassType extends BaseFlowType {
326
+ kind: 'Class';
327
+ type: FlowType;
328
+}
329
+
330
+export interface InstanceType extends BaseFlowType {
331
+ kind: 'Instance';
332
+ instance: InstanceT;
333
+}
334
+
335
+export interface SingletonStrType extends BaseFlowType {
336
+ kind: 'SingletonStr';
337
+ from_annot: boolean;
338
+ value: string;
339
+}
340
+
341
+export interface NumericStrKeyType extends BaseFlowType {
342
+ kind: 'NumericStrKey';
343
+ number: string;
344
+ string: string;
345
+}
346
+
347
+export interface SingletonNumType extends BaseFlowType {
348
+ kind: 'SingletonNum';
349
+ from_annot: boolean;
350
+ number: string;
351
+ string: string;
352
+}
353
+
354
+export interface SingletonBoolType extends BaseFlowType {
355
+ kind: 'SingletonBool';
356
+ from_annot: boolean;
357
+ value: boolean;
358
+}
359
+
360
+export interface SingletonBigIntType extends BaseFlowType {
361
+ kind: 'SingletonBigInt';
362
+ from_annot: boolean;
363
+ value: string;
364
+}
365
+
366
+export interface TypeType extends BaseFlowType {
367
+ kind: 'Type';
368
+ type_kind: TypeTKind;
369
+ type: FlowType;
370
+}
371
+
372
+export type TypeTKind =
373
+ | 'TypeAliasKind'
374
+ | 'TypeParamKind'
375
+ | 'OpaqueKind'
376
+ | 'ImportTypeofKind'
377
+ | 'ImportClassKind'
378
+ | 'ImportEnumKind'
379
+ | 'InstanceKind'
380
+ | 'RenderTypeKind';
381
+
382
+export interface PolyType extends BaseFlowType {
383
+ kind: 'Poly';
384
+ tparams: Array<TypeParam>;
385
+ t_out: FlowType;
386
+ id: string;
387
+}
388
+
389
+export interface ReactAbstractComponentType extends BaseFlowType {
390
+ kind: 'ReactAbstractComponent';
391
+ config: FlowType;
392
+ renders: FlowType;
393
+ instance: ComponentInstance;
394
+ component_kind: ComponentKind;
395
+}
396
+
397
+export type ComponentInstance =
398
+ | {kind: 'RefSetterProp'; type: FlowType}
399
+ | {kind: 'Omitted'};
400
+
401
+export type ComponentKind =
402
+ | {kind: 'Structural'}
403
+ | {kind: 'Nominal'; id: string; name: string; types: Array<FlowType> | null};
404
+
405
+export interface RendersType extends BaseFlowType {
406
+ kind: 'Renders';
407
+ form: CanonicalRendersForm;
408
+}
409
+
410
+export interface EnumValueType extends BaseFlowType {
411
+ kind: 'EnumValue';
412
+ enum_info: EnumInfo;
413
+}
414
+
415
+export interface EnumObjectType extends BaseFlowType {
416
+ kind: 'EnumObject';
417
+ enum_value_t: FlowType;
418
+ enum_info: EnumInfo;
419
+}
420
+
421
+// ObjKind types
422
+export type ObjKind =
423
+ | {kind: 'Exact'}
424
+ | {kind: 'Inexact'}
425
+ | {kind: 'Indexed'; dicttype: DictType};
426
+
427
+// DictType definition
428
+export interface DictType {
429
+ dict_name: string | null;
430
+ key: FlowType;
431
+ value: FlowType;
432
+ dict_polarity: Polarity;
433
+}
434
+
435
+// ArrType types
436
+export type ArrTypeObj = ArrayAT | TupleAT | ROArrayAT;
437
+
438
+export interface ArrayAT {
439
+ kind: 'ArrayAT';
440
+ elem_t: FlowType;
441
+}
442
+
443
+export interface TupleAT {
444
+ kind: 'TupleAT';
445
+ elem_t: FlowType;
446
+ elements: Array<TupleElement>;
447
+ min_arity: number;
448
+ max_arity: number;
449
+ inexact: boolean;
450
+}
451
+
452
+export interface ROArrayAT {
453
+ kind: 'ROArrayAT';
454
+ elem_t: FlowType;
455
+}
456
+
457
+// TupleElement definition
458
+export interface TupleElement {
459
+ name: string | null;
460
+ t: FlowType;
461
+ polarity: Polarity;
462
+ optional: boolean;
463
+}
464
+
465
+// Flags definition
466
+export interface Flags {
467
+ obj_kind: ObjKind;
468
+}
469
+
470
+// Property types
471
+export type Property =
472
+ | FieldProperty
473
+ | GetProperty
474
+ | SetProperty
475
+ | GetSetProperty
476
+ | MethodProperty;
477
+
478
+export interface FieldProperty {
479
+ kind: 'Field';
480
+ type: FlowType;
481
+ polarity: Polarity;
482
+}
483
+
484
+export interface GetProperty {
485
+ kind: 'Get';
486
+ type: FlowType;
487
+}
488
+
489
+export interface SetProperty {
490
+ kind: 'Set';
491
+ type: FlowType;
492
+}
493
+
494
+export interface GetSetProperty {
495
+ kind: 'GetSet';
496
+ get_type: FlowType;
497
+ set_type: FlowType;
498
+}
499
+
500
+export interface MethodProperty {
501
+ kind: 'Method';
502
+ type: FlowType;
503
+}
504
+
505
+// PropertyMap definition
506
+export interface PropertyMap {
507
+ [key: string]: Property; // For other properties in the map
508
+}
509
+
510
+// ObjType definition
511
+export interface ObjTypeObj {
512
+ flags: Flags;
513
+ props: PropertyMap;
514
+ proto_t: FlowType;
515
+ call_t: number | null;
516
+}
517
+
518
+// FunType definition
519
+export interface FunTypeObj {
520
+ this_t: {
521
+ type: FlowType;
522
+ status: ThisStatus;
523
+ };
524
+ params: Array<{
525
+ name: string | null;
526
+ type: FlowType;
527
+ }>;
528
+ rest_param: null | {
529
+ name: string | null;
530
+ type: FlowType;
531
+ };
532
+ return_t: FlowType;
533
+ type_guard: null | {
534
+ inferred: boolean;
535
+ param_name: string;
536
+ type_guard: FlowType;
537
+ one_sided: boolean;
538
+ };
539
+ effect: Effect;
540
+}
541
+
542
+// ThisStatus types
543
+export type ThisStatus =
544
+ | {kind: 'This_Method'; unbound: boolean}
545
+ | {kind: 'This_Function'};
546
+
547
+// Effect types
548
+export type Effect =
549
+ | {kind: 'HookDecl'; id: string}
550
+ | {kind: 'HookAnnot'}
551
+ | {kind: 'ArbitraryEffect'}
552
+ | {kind: 'AnyEffect'};
553
+
554
+// Destructor types
555
+export type Destructor =
556
+ | NonMaybeTypeDestructor
557
+ | PropertyTypeDestructor
558
+ | ElementTypeDestructor
559
+ | OptionalIndexedAccessNonMaybeTypeDestructor
560
+ | OptionalIndexedAccessResultTypeDestructor
561
+ | ExactTypeDestructor
562
+ | ReadOnlyTypeDestructor
563
+ | PartialTypeDestructor
564
+ | RequiredTypeDestructor
565
+ | SpreadTypeDestructor
566
+ | SpreadTupleTypeDestructor
567
+ | RestTypeDestructor
568
+ | ValuesTypeDestructor
569
+ | ConditionalTypeDestructor
570
+ | TypeMapDestructor
571
+ | ReactElementPropsTypeDestructor
572
+ | ReactElementConfigTypeDestructor
573
+ | ReactCheckComponentConfigDestructor
574
+ | ReactDRODestructor
575
+ | MakeHooklikeDestructor
576
+ | MappedTypeDestructor
577
+ | EnumTypeDestructor;
578
+
579
+export interface NonMaybeTypeDestructor {
580
+ kind: 'NonMaybeType';
581
+}
582
+
583
+export interface PropertyTypeDestructor {
584
+ kind: 'PropertyType';
585
+ name: string;
586
+}
587
+
588
+export interface ElementTypeDestructor {
589
+ kind: 'ElementType';
590
+ index_type: FlowType;
591
+}
592
+
593
+export interface OptionalIndexedAccessNonMaybeTypeDestructor {
594
+ kind: 'OptionalIndexedAccessNonMaybeType';
595
+ index: OptionalIndexedAccessIndex;
596
+}
597
+
598
+export type OptionalIndexedAccessIndex =
599
+ | {kind: 'StrLitIndex'; name: string}
600
+ | {kind: 'TypeIndex'; type: FlowType};
601
+
602
+export interface OptionalIndexedAccessResultTypeDestructor {
603
+ kind: 'OptionalIndexedAccessResultType';
604
+}
605
+
606
+export interface ExactTypeDestructor {
607
+ kind: 'ExactType';
608
+}
609
+
610
+export interface ReadOnlyTypeDestructor {
611
+ kind: 'ReadOnlyType';
612
+}
613
+
614
+export interface PartialTypeDestructor {
615
+ kind: 'PartialType';
616
+}
617
+
618
+export interface RequiredTypeDestructor {
619
+ kind: 'RequiredType';
620
+}
621
+
622
+export interface SpreadTypeDestructor {
623
+ kind: 'SpreadType';
624
+ target: SpreadTarget;
625
+ operands: Array<SpreadOperand>;
626
+ operand_slice: Slice | null;
627
+}
628
+
629
+export type SpreadTarget =
630
+ | {kind: 'Value'; make_seal: 'Sealed' | 'Frozen' | 'As_Const'}
631
+ | {kind: 'Annot'; make_exact: boolean};
632
+
633
+export type SpreadOperand = {kind: 'Type'; type: FlowType} | Slice;
634
+
635
+export interface Slice {
636
+ kind: 'Slice';
637
+ prop_map: PropertyMap;
638
+ generics: Array<string>;
639
+ dict: DictType | null;
640
+ reachable_targs: Array<{
641
+ type: FlowType;
642
+ polarity: Polarity;
643
+ }>;
644
+}
645
+
646
+export interface SpreadTupleTypeDestructor {
647
+ kind: 'SpreadTupleType';
648
+ inexact: boolean;
649
+ resolved_rev: string;
650
+ unresolved: string;
651
+}
652
+
653
+export interface RestTypeDestructor {
654
+ kind: 'RestType';
655
+ merge_mode: RestMergeMode;
656
+ type: FlowType;
657
+}
658
+
659
+export type RestMergeMode =
660
+ | {kind: 'SpreadReversal'}
661
+ | {kind: 'ReactConfigMerge'; polarity: Polarity}
662
+ | {kind: 'Omit'};
663
+
664
+export interface ValuesTypeDestructor {
665
+ kind: 'ValuesType';
666
+}
667
+
668
+export interface ConditionalTypeDestructor {
669
+ kind: 'ConditionalType';
670
+ distributive_tparam_name: string | null;
671
+ infer_tparams: string;
672
+ extends_t: FlowType;
673
+ true_t: FlowType;
674
+ false_t: FlowType;
675
+}
676
+
677
+export interface TypeMapDestructor {
678
+ kind: 'ObjectKeyMirror';
679
+}
680
+
681
+export interface ReactElementPropsTypeDestructor {
682
+ kind: 'ReactElementPropsType';
683
+}
684
+
685
+export interface ReactElementConfigTypeDestructor {
686
+ kind: 'ReactElementConfigType';
687
+}
688
+
689
+export interface ReactCheckComponentConfigDestructor {
690
+ kind: 'ReactCheckComponentConfig';
691
+ props: {
692
+ [key: string]: Property;
693
+ };
694
+}
695
+
696
+export interface ReactDRODestructor {
697
+ kind: 'ReactDRO';
698
+ dro_type:
699
+ | 'HookReturn'
700
+ | 'HookArg'
701
+ | 'Props'
702
+ | 'ImmutableAnnot'
703
+ | 'DebugAnnot';
704
+}
705
+
706
+export interface MakeHooklikeDestructor {
707
+ kind: 'MakeHooklike';
708
+}
709
+
710
+export interface MappedTypeDestructor {
711
+ kind: 'MappedType';
712
+ homomorphic: Homomorphic;
713
+ distributive_tparam_name: string | null;
714
+ property_type: FlowType;
715
+ mapped_type_flags: {
716
+ variance: Polarity;
717
+ optional: 'MakeOptional' | 'RemoveOptional' | 'KeepOptionality';
718
+ };
719
+}
720
+
721
+export type Homomorphic =
722
+ | {kind: 'Homomorphic'}
723
+ | {kind: 'Unspecialized'}
724
+ | {kind: 'SemiHomomorphic'; type: FlowType};
725
+
726
+export interface EnumTypeDestructor {
727
+ kind: 'EnumType';
728
+}
729
+
730
+// Union of all possible Flow types
731
+export type FlowType =
732
+ | OpenType
733
+ | DefType
734
+ | EvalType
735
+ | GenericType
736
+ | ThisInstanceType
737
+ | ThisTypeAppType
738
+ | TypeAppType
739
+ | FunProtoType
740
+ | ObjProtoType
741
+ | NullProtoType
742
+ | FunProtoBindType
743
+ | IntersectionType
744
+ | UnionType
745
+ | MaybeType
746
+ | OptionalType
747
+ | KeysType
748
+ | AnnotType
749
+ | OpaqueType
750
+ | NamespaceType
751
+ | AnyType
752
+ | StrUtilType;
compiler/packages/babel-plugin-react-compiler/src/Flood/TypeErrors.ts
new
+131
@@ -0,0 +1,131 @@
1
+import {CompilerError, SourceLocation} from '..';
2
+import {
3
+ ConcreteType,
4
+ printConcrete,
5
+ printType,
6
+ StructuralValue,
7
+ Type,
8
+ VariableId,
9
+} from './Types';
10
+
11
+export function unsupportedLanguageFeature(
12
+ desc: string,
13
+ loc: SourceLocation,
14
+): never {
15
+ CompilerError.throwInvalidJS({
16
+ reason: `Typedchecker does not currently support language feature: ${desc}`,
17
+ loc,
18
+ });
19
+}
20
+
21
+export type UnificationError =
22
+ | {
23
+ kind: 'TypeUnification';
24
+ left: ConcreteType<Type>;
25
+ right: ConcreteType<Type>;
26
+ }
27
+ | {
28
+ kind: 'StructuralUnification';
29
+ left: StructuralValue;
30
+ right: ConcreteType<Type>;
31
+ };
32
+
33
+function printUnificationError(err: UnificationError): string {
34
+ if (err.kind === 'TypeUnification') {
35
+ return `${printConcrete(err.left, printType)} is incompatible with ${printConcrete(err.right, printType)}`;
36
+ } else {
37
+ return `structural ${err.left.kind} is incompatible with ${printConcrete(err.right, printType)}`;
38
+ }
39
+}
40
+
41
+export function raiseUnificationErrors(
42
+ errs: null | Array<UnificationError>,
43
+ loc: SourceLocation,
44
+): void {
45
+ if (errs != null) {
46
+ if (errs.length === 0) {
47
+ CompilerError.invariant(false, {
48
+ reason: 'Should not have array of zero errors',
49
+ loc,
50
+ });
51
+ } else if (errs.length === 1) {
52
+ CompilerError.throwInvalidJS({
53
+ reason: `Unable to unify types because ${printUnificationError(errs[0])}`,
54
+ loc,
55
+ });
56
+ } else {
57
+ const messages = errs
58
+ .map(err => `\t* ${printUnificationError(err)}`)
59
+ .join('\n');
60
+ CompilerError.throwInvalidJS({
61
+ reason: `Unable to unify types because:\n${messages}`,
62
+ loc,
63
+ });
64
+ }
65
+ }
66
+}
67
+
68
+export function unresolvableTypeVariable(
69
+ id: VariableId,
70
+ loc: SourceLocation,
71
+): never {
72
+ CompilerError.throwInvalidJS({
73
+ reason: `Unable to resolve free variable ${id} to a concrete type`,
74
+ loc,
75
+ });
76
+}
77
+
78
+export function cannotAddVoid(explicit: boolean, loc: SourceLocation): never {
79
+ if (explicit) {
80
+ CompilerError.throwInvalidJS({
81
+ reason: `Undefined is not a valid operand of \`+\``,
82
+ loc,
83
+ });
84
+ } else {
85
+ CompilerError.throwInvalidJS({
86
+ reason: `Value may be undefined, which is not a valid operand of \`+\``,
87
+ loc,
88
+ });
89
+ }
90
+}
91
+
92
+export function unsupportedTypeAnnotation(
93
+ desc: string,
94
+ loc: SourceLocation,
95
+): never {
96
+ CompilerError.throwInvalidJS({
97
+ reason: `Typedchecker does not currently support type annotation: ${desc}`,
98
+ loc,
99
+ });
100
+}
101
+
102
+export function checkTypeArgumentArity(
103
+ desc: string,
104
+ expected: number,
105
+ actual: number,
106
+ loc: SourceLocation,
107
+): void {
108
+ if (expected !== actual) {
109
+ CompilerError.throwInvalidJS({
110
+ reason: `Expected ${desc} to have ${expected} type parameters, got ${actual}`,
111
+ loc,
112
+ });
113
+ }
114
+}
115
+
116
+export function notAFunction(desc: string, loc: SourceLocation): void {
117
+ CompilerError.throwInvalidJS({
118
+ reason: `Cannot call ${desc} because it is not a function`,
119
+ loc,
120
+ });
121
+}
122
+
123
+export function notAPolymorphicFunction(
124
+ desc: string,
125
+ loc: SourceLocation,
126
+): void {
127
+ CompilerError.throwInvalidJS({
128
+ reason: `Cannot call ${desc} with type arguments because it is not a polymorphic function`,
129
+ loc,
130
+ });
131
+}
compiler/packages/babel-plugin-react-compiler/src/Flood/TypeUtils.ts
new
+312
@@ -0,0 +1,312 @@
1
+import {GeneratedSource} from '../HIR';
2
+import {assertExhaustive} from '../Utils/utils';
3
+import {unsupportedLanguageFeature} from './TypeErrors';
4
+import {
5
+ ConcreteType,
6
+ ResolvedType,
7
+ TypeParameter,
8
+ TypeParameterId,
9
+ DEBUG,
10
+ printConcrete,
11
+ printType,
12
+} from './Types';
13
+
14
+export function substitute(
15
+ type: ConcreteType<ResolvedType>,
16
+ typeParameters: Array<TypeParameter<ResolvedType>>,
17
+ typeArguments: Array<ResolvedType>,
18
+): ResolvedType {
19
+ const substMap = new Map<TypeParameterId, ResolvedType>();
20
+ for (let i = 0; i < typeParameters.length; i++) {
21
+ // TODO: Length checks to make sure type params match up with args
22
+ const typeParameter = typeParameters[i];
23
+ const typeArgument = typeArguments[i];
24
+ substMap.set(typeParameter.id, typeArgument);
25
+ }
26
+ const substitutionFunction = (t: ResolvedType): ResolvedType => {
27
+ // TODO: We really want a stateful mapper or visitor here so that we can model nested polymorphic types
28
+ if (t.type.kind === 'Generic' && substMap.has(t.type.id)) {
29
+ const substitutedType = substMap.get(t.type.id)!;
30
+ return substitutedType;
31
+ }
32
+
33
+ return {
34
+ kind: 'Concrete',
35
+ type: mapType(substitutionFunction, t.type),
36
+ platform: t.platform,
37
+ };
38
+ };
39
+
40
+ const substituted = mapType(substitutionFunction, type);
41
+
42
+ if (DEBUG) {
43
+ let substs = '';
44
+ for (let i = 0; i < typeParameters.length; i++) {
45
+ const typeParameter = typeParameters[i];
46
+ const typeArgument = typeArguments[i];
47
+ substs += `[${typeParameter.name}${typeParameter.id} := ${printType(typeArgument)}]`;
48
+ }
49
+ console.log(
50
+ `${printConcrete(type, printType)}${substs} = ${printConcrete(substituted, printType)}`,
51
+ );
52
+ }
53
+
54
+ return {kind: 'Concrete', type: substituted, platform: /* TODO */ 'shared'};
55
+}
56
+
57
+export function mapType<T, U>(
58
+ f: (t: T) => U,
59
+ type: ConcreteType<T>,
60
+): ConcreteType<U> {
61
+ switch (type.kind) {
62
+ case 'Mixed':
63
+ case 'Number':
64
+ case 'String':
65
+ case 'Boolean':
66
+ case 'Void':
67
+ return type;
68
+
69
+ case 'Nullable':
70
+ return {
71
+ kind: 'Nullable',
72
+ type: f(type.type),
73
+ };
74
+
75
+ case 'Array':
76
+ return {
77
+ kind: 'Array',
78
+ element: f(type.element),
79
+ };
80
+
81
+ case 'Set':
82
+ return {
83
+ kind: 'Set',
84
+ element: f(type.element),
85
+ };
86
+
87
+ case 'Map':
88
+ return {
89
+ kind: 'Map',
90
+ key: f(type.key),
91
+ value: f(type.value),
92
+ };
93
+
94
+ case 'Function':
95
+ return {
96
+ kind: 'Function',
97
+ typeParameters:
98
+ type.typeParameters?.map(param => ({
99
+ id: param.id,
100
+ name: param.name,
101
+ bound: f(param.bound),
102
+ })) ?? null,
103
+ params: type.params.map(f),
104
+ returnType: f(type.returnType),
105
+ };
106
+
107
+ case 'Component': {
108
+ return {
109
+ kind: 'Component',
110
+ children: type.children != null ? f(type.children) : null,
111
+ props: new Map([...type.props.entries()].map(([k, v]) => [k, f(v)])),
112
+ };
113
+ }
114
+
115
+ case 'Generic':
116
+ return {
117
+ kind: 'Generic',
118
+ id: type.id,
119
+ bound: f(type.bound),
120
+ };
121
+
122
+ case 'Object':
123
+ return type;
124
+
125
+ case 'Tuple':
126
+ return {
127
+ kind: 'Tuple',
128
+ id: type.id,
129
+ members: type.members.map(f),
130
+ };
131
+
132
+ case 'Structural':
133
+ return type;
134
+
135
+ case 'Enum':
136
+ case 'Union':
137
+ case 'Instance':
138
+ unsupportedLanguageFeature(type.kind, GeneratedSource);
139
+
140
+ default:
141
+ assertExhaustive(type, 'Unknown type kind');
142
+ }
143
+}
144
+
145
+export function diff<R, T>(
146
+ a: ConcreteType<T>,
147
+ b: ConcreteType<T>,
148
+ onChild: (a: T, b: T) => R,
149
+ onChildMismatch: (child: R, cur: R) => R,
150
+ onMismatch: (a: ConcreteType<T>, b: ConcreteType<T>, cur: R) => R,
151
+ init: R,
152
+): R {
153
+ let errors = init;
154
+
155
+ // Check if kinds match
156
+ if (a.kind !== b.kind) {
157
+ errors = onMismatch(a, b, errors);
158
+ return errors;
159
+ }
160
+
161
+ // Based on kind, check other properties
162
+ switch (a.kind) {
163
+ case 'Mixed':
164
+ case 'Number':
165
+ case 'String':
166
+ case 'Boolean':
167
+ case 'Void':
168
+ // Simple types, no further checks needed
169
+ break;
170
+
171
+ case 'Nullable':
172
+ // Check the nested type
173
+ errors = onChildMismatch(onChild(a.type, (b as typeof a).type), errors);
174
+ break;
175
+
176
+ case 'Array':
177
+ case 'Set':
178
+ // Check the element type
179
+ errors = onChildMismatch(
180
+ onChild(a.element, (b as typeof a).element),
181
+ errors,
182
+ );
183
+ break;
184
+
185
+ case 'Map':
186
+ // Check both key and value types
187
+ errors = onChildMismatch(onChild(a.key, (b as typeof a).key), errors);
188
+ errors = onChildMismatch(onChild(a.value, (b as typeof a).value), errors);
189
+ break;
190
+
191
+ case 'Function': {
192
+ const bFunc = b as typeof a;
193
+
194
+ // Check type parameters
195
+ if ((a.typeParameters == null) !== (bFunc.typeParameters == null)) {
196
+ errors = onMismatch(a, b, errors);
197
+ }
198
+
199
+ if (a.typeParameters != null && bFunc.typeParameters != null) {
200
+ if (a.typeParameters.length !== bFunc.typeParameters.length) {
201
+ errors = onMismatch(a, b, errors);
202
+ }
203
+
204
+ // Type parameters are just numbers, so we can compare them directly
205
+ for (let i = 0; i < a.typeParameters.length; i++) {
206
+ if (a.typeParameters[i] !== bFunc.typeParameters[i]) {
207
+ errors = onMismatch(a, b, errors);
208
+ }
209
+ }
210
+ }
211
+
212
+ // Check parameters
213
+ if (a.params.length !== bFunc.params.length) {
214
+ errors = onMismatch(a, b, errors);
215
+ }
216
+
217
+ for (let i = 0; i < a.params.length; i++) {
218
+ errors = onChildMismatch(onChild(a.params[i], bFunc.params[i]), errors);
219
+ }
220
+
221
+ // Check return type
222
+ errors = onChildMismatch(onChild(a.returnType, bFunc.returnType), errors);
223
+ break;
224
+ }
225
+
226
+ case 'Component': {
227
+ const bComp = b as typeof a;
228
+
229
+ // Check children
230
+ if (a.children !== bComp.children) {
231
+ errors = onMismatch(a, b, errors);
232
+ }
233
+
234
+ // Check props
235
+ if (a.props.size !== bComp.props.size) {
236
+ errors = onMismatch(a, b, errors);
237
+ }
238
+
239
+ for (const [k, v] of a.props) {
240
+ const bProp = bComp.props.get(k);
241
+ if (bProp == null) {
242
+ errors = onMismatch(a, b, errors);
243
+ } else {
244
+ errors = onChildMismatch(onChild(v, bProp), errors);
245
+ }
246
+ }
247
+
248
+ break;
249
+ }
250
+
251
+ case 'Generic': {
252
+ // Check that the type parameter IDs match
253
+ if (a.id !== (b as typeof a).id) {
254
+ errors = onMismatch(a, b, errors);
255
+ }
256
+ break;
257
+ }
258
+ case 'Structural': {
259
+ const bStruct = b as typeof a;
260
+
261
+ // Check that the structural IDs match
262
+ if (a.id !== bStruct.id) {
263
+ errors = onMismatch(a, b, errors);
264
+ }
265
+ break;
266
+ }
267
+ case 'Object': {
268
+ const bNom = b as typeof a;
269
+
270
+ // Check that the nominal IDs match
271
+ if (a.id !== bNom.id) {
272
+ errors = onMismatch(a, b, errors);
273
+ }
274
+ break;
275
+ }
276
+
277
+ case 'Tuple': {
278
+ const bTuple = b as typeof a;
279
+
280
+ // Check that the tuple IDs match
281
+ if (a.id !== bTuple.id) {
282
+ errors = onMismatch(a, b, errors);
283
+ }
284
+ for (let i = 0; i < a.members.length; i++) {
285
+ errors = onChildMismatch(
286
+ onChild(a.members[i], bTuple.members[i]),
287
+ errors,
288
+ );
289
+ }
290
+
291
+ break;
292
+ }
293
+
294
+ case 'Enum':
295
+ case 'Instance':
296
+ case 'Union': {
297
+ unsupportedLanguageFeature(a.kind, GeneratedSource);
298
+ }
299
+
300
+ default:
301
+ assertExhaustive(a, 'Unknown type kind');
302
+ }
303
+
304
+ return errors;
305
+}
306
+
307
+export function filterOptional(t: ResolvedType): ResolvedType {
308
+ if (t.kind === 'Concrete' && t.type.kind === 'Nullable') {
309
+ return t.type.type;
310
+ }
311
+ return t;
312
+}
compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts
new
+1001
@@ -0,0 +1,1001 @@
1
+import {CompilerError, SourceLocation} from '..';
2
+import {
3
+ Environment,
4
+ GeneratedSource,
5
+ HIRFunction,
6
+ Identifier,
7
+ IdentifierId,
8
+} from '../HIR';
9
+import * as t from '@babel/types';
10
+import * as TypeErrors from './TypeErrors';
11
+import {assertExhaustive} from '../Utils/utils';
12
+
13
+export const DEBUG = false;
14
+
15
+export type Type =
16
+ | {kind: 'Concrete'; type: ConcreteType<Type>; platform: Platform}
17
+ | {kind: 'Variable'; id: VariableId};
18
+
19
+export type ResolvedType = {
20
+ kind: 'Concrete';
21
+ type: ConcreteType<ResolvedType>;
22
+ platform: Platform;
23
+};
24
+
25
+export type ComponentType<T> = {
26
+ kind: 'Component';
27
+ props: Map<string, T>;
28
+ children: null | T;
29
+};
30
+export type ConcreteType<T> =
31
+ | {kind: 'Enum'}
32
+ | {kind: 'Mixed'}
33
+ | {kind: 'Number'}
34
+ | {kind: 'String'}
35
+ | {kind: 'Boolean'}
36
+ | {kind: 'Void'}
37
+ | {kind: 'Nullable'; type: T}
38
+ | {kind: 'Array'; element: T}
39
+ | {kind: 'Set'; element: T}
40
+ | {kind: 'Map'; key: T; value: T}
41
+ | {
42
+ kind: 'Function';
43
+ typeParameters: null | Array<TypeParameter<T>>;
44
+ params: Array<T>;
45
+ returnType: T;
46
+ }
47
+ | ComponentType<T>
48
+ | {kind: 'Generic'; id: TypeParameterId; bound: T}
49
+ | {
50
+ kind: 'Object';
51
+ id: NominalId;
52
+ members: Map<string, ResolvedType>;
53
+ }
54
+ | {
55
+ kind: 'Tuple';
56
+ id: NominalId;
57
+ members: Array<T>;
58
+ }
59
+ | {kind: 'Structural'; id: LinearId}
60
+ | {kind: 'Union'; members: Array<T>}
61
+ | {kind: 'Instance'; name: string; members: Map<string, ResolvedType>};
62
+
63
+export type StructuralValue =
64
+ | {
65
+ kind: 'Function';
66
+ fn: HIRFunction;
67
+ }
68
+ | {
69
+ kind: 'Object';
70
+ members: Map<string, ResolvedType>;
71
+ }
72
+ | {
73
+ kind: 'Array';
74
+ elementType: ResolvedType;
75
+ };
76
+
77
+export type Structural = {
78
+ type: StructuralValue;
79
+ consumed: boolean;
80
+};
81
+// TODO: create a kind: "Alias"
82
+
83
+// type T<X> = { foo: X}
84
+
85
+/**
86
+ *
87
+ * function apply<A, B>(x: A, f: A => B): B { }
88
+ *
89
+ * apply(42, x => String(x));
90
+ *
91
+ * f({foo: 42})
92
+ *
93
+ * f([HOLE]) -----> {foo: 42} with context NominalType
94
+ *
95
+ * $0 = Object {foo: 42}
96
+ * $1 = LoadLocal "f"
97
+ * $2 = Call $1, [$0]
98
+ *
99
+ * ContextMap:
100
+ * $2 => ??
101
+ * $1 => [HOLE]($0)
102
+ * $0 => $1([HOLE])
103
+ */
104
+
105
+/*
106
+ *const g = {foo: 42} as NominalType // ok
107
+ *
108
+ *
109
+ *function f(x: NominalType) { ... }
110
+ *f()
111
+ *
112
+ *const y: NominalType = {foo: 42}
113
+ *
114
+ *
115
+ */
116
+
117
+/**
118
+ * // Mike: maybe this could be the ideal?
119
+ *type X = nominal('registryNameX', {
120
+ *value: number,
121
+ *});
122
+ *
123
+ * // For now:
124
+ *opaque type X = { // creates a new nominal type
125
+ *value: number,
126
+ *};
127
+ *
128
+ *type Y = X; // creates a type alias
129
+ *
130
+ *type Z = number; // creates a type alias
131
+ *
132
+ *
133
+ * // (todo: disallowed)
134
+ *type X' = {
135
+ *value: number,
136
+ *}
137
+ */
138
+
139
+export type TypeParameter<T> = {
140
+ name: string;
141
+ id: TypeParameterId;
142
+ bound: T;
143
+};
144
+
145
+const opaqueLinearId = Symbol();
146
+export type LinearId = number & {
147
+ [opaqueLinearId]: 'LinearId';
148
+};
149
+
150
+export function makeLinearId(id: number): LinearId {
151
+ CompilerError.invariant(id >= 0 && Number.isInteger(id), {
152
+ reason: 'Expected LinearId id to be a non-negative integer',
153
+ description: null,
154
+ loc: null,
155
+ suggestions: null,
156
+ });
157
+ return id as LinearId;
158
+}
159
+
160
+const opaqueTypeParameterId = Symbol();
161
+export type TypeParameterId = number & {
162
+ [opaqueTypeParameterId]: 'TypeParameterId';
163
+};
164
+
165
+export function makeTypeParameterId(id: number): TypeParameterId {
166
+ CompilerError.invariant(id >= 0 && Number.isInteger(id), {
167
+ reason: 'Expected TypeParameterId to be a non-negative integer',
168
+ description: null,
169
+ loc: null,
170
+ suggestions: null,
171
+ });
172
+ return id as TypeParameterId;
173
+}
174
+
175
+const opaqueNominalId = Symbol();
176
+export type NominalId = number & {
177
+ [opaqueNominalId]: 'NominalId';
178
+};
179
+
180
+export function makeNominalId(id: number): NominalId {
181
+ return id as NominalId;
182
+}
183
+
184
+const opaqueVariableId = Symbol();
185
+export type VariableId = number & {
186
+ [opaqueVariableId]: 'VariableId';
187
+};
188
+
189
+export function makeVariableId(id: number): VariableId {
190
+ CompilerError.invariant(id >= 0 && Number.isInteger(id), {
191
+ reason: 'Expected VariableId id to be a non-negative integer',
192
+ description: null,
193
+ loc: null,
194
+ suggestions: null,
195
+ });
196
+ return id as VariableId;
197
+}
198
+
199
+import {inspect} from 'util';
200
+import {FlowType} from './FlowTypes';
201
+export function printConcrete<T>(
202
+ type: ConcreteType<T>,
203
+ printType: (_: T) => string,
204
+): string {
205
+ switch (type.kind) {
206
+ case 'Mixed':
207
+ return 'mixed';
208
+ case 'Number':
209
+ return 'number';
210
+ case 'String':
211
+ return 'string';
212
+ case 'Boolean':
213
+ return 'boolean';
214
+ case 'Void':
215
+ return 'void';
216
+ case 'Nullable':
217
+ return `${printType(type.type)} | void`;
218
+ case 'Array':
219
+ return `Array<${printType(type.element)}>`;
220
+ case 'Set':
221
+ return `Set<${printType(type.element)}>`;
222
+ case 'Map':
223
+ return `Map<${printType(type.key)}, ${printType(type.value)}>`;
224
+ case 'Function': {
225
+ const typeParams = type.typeParameters
226
+ ? `<${type.typeParameters.map(tp => `T${tp}`).join(', ')}>`
227
+ : '';
228
+ const params = type.params.map(printType).join(', ');
229
+ const returnType = printType(type.returnType);
230
+ return `${typeParams}(${params}) => ${returnType}`;
231
+ }
232
+ case 'Component': {
233
+ const params = [...type.props.entries()]
234
+ .map(([k, v]) => `${k}: ${printType(v)}`)
235
+ .join(', ');
236
+ const comma = type.children != null && type.props.size > 0 ? ', ' : '';
237
+ const children =
238
+ type.children != null ? `children: ${printType(type.children)}` : '';
239
+ return `component (${params}${comma}${children})`;
240
+ }
241
+ case 'Generic':
242
+ return `T${type.id}`;
243
+ case 'Object': {
244
+ const name = `Object ${inspect([...type.members.keys()])}`;
245
+ return `${name}`;
246
+ }
247
+ case 'Tuple': {
248
+ const name = `Tuple ${type.members}`;
249
+ return `${name}`;
250
+ }
251
+ case 'Structural': {
252
+ const name = `Structural ${type.id}`;
253
+ return `${name}`;
254
+ }
255
+ case 'Enum': {
256
+ return 'TODO enum printing';
257
+ }
258
+ case 'Union': {
259
+ return type.members.map(printType).join(' | ');
260
+ }
261
+ case 'Instance': {
262
+ return type.name;
263
+ }
264
+ default:
265
+ assertExhaustive(type, `Unknown type: ${JSON.stringify(type)}`);
266
+ }
267
+}
268
+
269
+export function printType(type: Type): string {
270
+ switch (type.kind) {
271
+ case 'Concrete':
272
+ return printConcrete(type.type, printType);
273
+ case 'Variable':
274
+ return `$${type.id}`;
275
+ default:
276
+ assertExhaustive(type, `Unknown type: ${JSON.stringify(type)}`);
277
+ }
278
+}
279
+
280
+export function printResolved(type: ResolvedType): string {
281
+ return printConcrete(type.type, printResolved);
282
+}
283
+
284
+type Platform = 'client' | 'server' | 'shared';
285
+
286
+const DUMMY_NOMINAL = makeNominalId(0);
287
+
288
+function convertFlowType(flowType: FlowType, loc: string): ResolvedType {
289
+ let nextGenericId = 0;
290
+ function convertFlowTypeImpl(
291
+ flowType: FlowType,
292
+ loc: string,
293
+ genericEnv: Map<string, TypeParameterId>,
294
+ platform: Platform,
295
+ poly: null | Array<TypeParameter<ResolvedType>> = null,
296
+ ): ResolvedType {
297
+ switch (flowType.kind) {
298
+ case 'TypeApp': {
299
+ if (
300
+ flowType.type.kind === 'Def' &&
301
+ flowType.type.def.kind === 'Poly' &&
302
+ flowType.type.def.t_out.kind === 'Def' &&
303
+ flowType.type.def.t_out.def.kind === 'Type' &&
304
+ flowType.type.def.t_out.def.type.kind === 'Opaque' &&
305
+ flowType.type.def.t_out.def.type.opaquetype.opaque_name ===
306
+ 'Client' &&
307
+ flowType.targs.length === 1
308
+ ) {
309
+ return convertFlowTypeImpl(
310
+ flowType.targs[0],
311
+ loc,
312
+ genericEnv,
313
+ 'client',
314
+ );
315
+ } else if (
316
+ flowType.type.kind === 'Def' &&
317
+ flowType.type.def.kind === 'Poly' &&
318
+ flowType.type.def.t_out.kind === 'Def' &&
319
+ flowType.type.def.t_out.def.kind === 'Type' &&
320
+ flowType.type.def.t_out.def.type.kind === 'Opaque' &&
321
+ flowType.type.def.t_out.def.type.opaquetype.opaque_name ===
322
+ 'Server' &&
323
+ flowType.targs.length === 1
324
+ ) {
325
+ return convertFlowTypeImpl(
326
+ flowType.targs[0],
327
+ loc,
328
+ genericEnv,
329
+ 'server',
330
+ );
331
+ }
332
+ return Resolved.todo(platform);
333
+ }
334
+ case 'Open':
335
+ return Resolved.mixed(platform);
336
+ case 'Any':
337
+ return Resolved.todo(platform);
338
+ case 'Annot':
339
+ return convertFlowTypeImpl(
340
+ flowType.type,
341
+ loc,
342
+ genericEnv,
343
+ platform,
344
+ poly,
345
+ );
346
+ case 'Opaque': {
347
+ if (
348
+ flowType.opaquetype.opaque_name === 'Client' &&
349
+ flowType.opaquetype.super_t != null
350
+ ) {
351
+ return convertFlowTypeImpl(
352
+ flowType.opaquetype.super_t,
353
+ loc,
354
+ genericEnv,
355
+ 'client',
356
+ );
357
+ }
358
+ if (
359
+ flowType.opaquetype.opaque_name === 'Server' &&
360
+ flowType.opaquetype.super_t != null
361
+ ) {
362
+ return convertFlowTypeImpl(
363
+ flowType.opaquetype.super_t,
364
+ loc,
365
+ genericEnv,
366
+ 'server',
367
+ );
368
+ }
369
+ const t =
370
+ flowType.opaquetype.underlying_t ?? flowType.opaquetype.super_t;
371
+ if (t != null) {
372
+ return convertFlowTypeImpl(t, loc, genericEnv, platform, poly);
373
+ } else {
374
+ return Resolved.todo(platform);
375
+ }
376
+ }
377
+ case 'Def': {
378
+ switch (flowType.def.kind) {
379
+ case 'EnumValue':
380
+ return convertFlowTypeImpl(
381
+ flowType.def.enum_info.representation_t,
382
+ loc,
383
+ genericEnv,
384
+ platform,
385
+ poly,
386
+ );
387
+ case 'EnumObject':
388
+ return Resolved.enum(platform);
389
+ case 'Empty':
390
+ return Resolved.todo(platform);
391
+ case 'Instance': {
392
+ const members = new Map<string, ResolvedType>();
393
+ for (const key in flowType.def.instance.inst.own_props) {
394
+ const prop = flowType.def.instance.inst.own_props[key];
395
+ if (prop.kind === 'Field') {
396
+ members.set(
397
+ key,
398
+ convertFlowTypeImpl(prop.type, loc, genericEnv, platform),
399
+ );
400
+ } else {
401
+ CompilerError.invariant(false, {
402
+ reason: `Unsupported property kind ${prop.kind}`,
403
+ loc: GeneratedSource,
404
+ });
405
+ }
406
+ }
407
+ return Resolved.class(
408
+ flowType.def.instance.inst.class_name ?? '[anonymous class]',
409
+ members,
410
+ platform,
411
+ );
412
+ }
413
+ case 'Type':
414
+ return convertFlowTypeImpl(
415
+ flowType.def.type,
416
+ loc,
417
+ genericEnv,
418
+ platform,
419
+ poly,
420
+ );
421
+ case 'NumGeneral':
422
+ case 'SingletonNum':
423
+ return Resolved.number(platform);
424
+ case 'StrGeneral':
425
+ case 'SingletonStr':
426
+ return Resolved.string(platform);
427
+ case 'BoolGeneral':
428
+ case 'SingletonBool':
429
+ return Resolved.boolean(platform);
430
+ case 'Void':
431
+ return Resolved.void(platform);
432
+ case 'Null':
433
+ return Resolved.void(platform);
434
+ case 'Mixed':
435
+ return Resolved.mixed(platform);
436
+ case 'Arr': {
437
+ if (
438
+ flowType.def.arrtype.kind === 'ArrayAT' ||
439
+ flowType.def.arrtype.kind === 'ROArrayAT'
440
+ ) {
441
+ return Resolved.array(
442
+ convertFlowTypeImpl(
443
+ flowType.def.arrtype.elem_t,
444
+ loc,
445
+ genericEnv,
446
+ platform,
447
+ ),
448
+ platform,
449
+ );
450
+ } else {
451
+ return Resolved.tuple(
452
+ DUMMY_NOMINAL,
453
+ flowType.def.arrtype.elements.map(t =>
454
+ convertFlowTypeImpl(t.t, loc, genericEnv, platform),
455
+ ),
456
+ platform,
457
+ );
458
+ }
459
+ }
460
+ case 'Obj': {
461
+ const members = new Map<string, ResolvedType>();
462
+ for (const key in flowType.def.objtype.props) {
463
+ const prop = flowType.def.objtype.props[key];
464
+ if (prop.kind === 'Field') {
465
+ members.set(
466
+ key,
467
+ convertFlowTypeImpl(prop.type, loc, genericEnv, platform),
468
+ );
469
+ } else {
470
+ CompilerError.invariant(false, {
471
+ reason: `Unsupported property kind ${prop.kind}`,
472
+ loc: GeneratedSource,
473
+ });
474
+ }
475
+ }
476
+ return Resolved.object(DUMMY_NOMINAL, members, platform);
477
+ }
478
+ case 'Class': {
479
+ if (flowType.def.type.kind === 'ThisInstance') {
480
+ const members = new Map<string, ResolvedType>();
481
+ for (const key in flowType.def.type.instance.inst.own_props) {
482
+ const prop = flowType.def.type.instance.inst.own_props[key];
483
+ if (prop.kind === 'Field') {
484
+ members.set(
485
+ key,
486
+ convertFlowTypeImpl(prop.type, loc, genericEnv, platform),
487
+ );
488
+ } else {
489
+ CompilerError.invariant(false, {
490
+ reason: `Unsupported property kind ${prop.kind}`,
491
+ loc: GeneratedSource,
492
+ });
493
+ }
494
+ }
495
+ return Resolved.class(
496
+ flowType.def.type.instance.inst.class_name ??
497
+ '[anonymous class]',
498
+ members,
499
+ platform,
500
+ );
501
+ }
502
+ CompilerError.invariant(false, {
503
+ reason: `Unsupported class instance type ${flowType.def.type.kind}`,
504
+ loc: GeneratedSource,
505
+ });
506
+ }
507
+ case 'Fun':
508
+ return Resolved.function(
509
+ poly,
510
+ flowType.def.funtype.params.map(p =>
511
+ convertFlowTypeImpl(p.type, loc, genericEnv, platform),
512
+ ),
513
+ convertFlowTypeImpl(
514
+ flowType.def.funtype.return_t,
515
+ loc,
516
+ genericEnv,
517
+ platform,
518
+ ),
519
+ platform,
520
+ );
521
+ case 'Poly': {
522
+ let newEnv = genericEnv;
523
+ const poly = flowType.def.tparams.map(p => {
524
+ const id = makeTypeParameterId(nextGenericId++);
525
+ const bound = convertFlowTypeImpl(p.bound, loc, newEnv, platform);
526
+ newEnv = new Map(newEnv);
527
+ newEnv.set(p.name, id);
528
+ return {
529
+ name: p.name,
530
+ id,
531
+ bound,
532
+ };
533
+ });
534
+ return convertFlowTypeImpl(
535
+ flowType.def.t_out,
536
+ loc,
537
+ newEnv,
538
+ platform,
539
+ poly,
540
+ );
541
+ }
542
+ case 'ReactAbstractComponent': {
543
+ const props = new Map<string, ResolvedType>();
544
+ let children: ResolvedType | null = null;
545
+ const propsType = convertFlowTypeImpl(
546
+ flowType.def.config,
547
+ loc,
548
+ genericEnv,
549
+ platform,
550
+ );
551
+
552
+ if (propsType.type.kind === 'Object') {
553
+ propsType.type.members.forEach((v, k) => {
554
+ if (k === 'children') {
555
+ children = v;
556
+ } else {
557
+ props.set(k, v);
558
+ }
559
+ });
560
+ } else {
561
+ CompilerError.invariant(false, {
562
+ reason: `Unsupported component props type ${propsType.type.kind}`,
563
+ loc: GeneratedSource,
564
+ });
565
+ }
566
+
567
+ return Resolved.component(props, children, platform);
568
+ }
569
+ case 'Renders':
570
+ return Resolved.todo(platform);
571
+ default:
572
+ TypeErrors.unsupportedTypeAnnotation('Renders', GeneratedSource);
573
+ }
574
+ }
575
+ case 'Generic': {
576
+ const id = genericEnv.get(flowType.name);
577
+ if (id == null) {
578
+ TypeErrors.unsupportedTypeAnnotation(flowType.name, GeneratedSource);
579
+ }
580
+ return Resolved.generic(
581
+ id,
582
+ platform,
583
+ convertFlowTypeImpl(flowType.bound, loc, genericEnv, platform),
584
+ );
585
+ }
586
+ case 'Union': {
587
+ const members = flowType.members.map(t =>
588
+ convertFlowTypeImpl(t, loc, genericEnv, platform),
589
+ );
590
+ if (members.length === 1) {
591
+ return members[0];
592
+ }
593
+ if (
594
+ members[0].type.kind === 'Number' ||
595
+ members[0].type.kind === 'String' ||
596
+ members[0].type.kind === 'Boolean'
597
+ ) {
598
+ const dupes = members.filter(
599
+ t => t.type.kind === members[0].type.kind,
600
+ );
601
+ if (dupes.length === members.length) {
602
+ return members[0];
603
+ }
604
+ }
605
+ if (
606
+ members[0].type.kind === 'Array' &&
607
+ (members[0].type.element.type.kind === 'Number' ||
608
+ members[0].type.element.type.kind === 'String' ||
609
+ members[0].type.element.type.kind === 'Boolean')
610
+ ) {
611
+ const first = members[0].type.element;
612
+ const dupes = members.filter(
613
+ t =>
614
+ t.type.kind === 'Array' &&
615
+ t.type.element.type.kind === first.type.kind,
616
+ );
617
+ if (dupes.length === members.length) {
618
+ return members[0];
619
+ }
620
+ }
621
+ return Resolved.union(members, platform);
622
+ }
623
+ case 'Eval': {
624
+ if (
625
+ flowType.destructor.kind === 'ReactDRO' ||
626
+ flowType.destructor.kind === 'ReactCheckComponentConfig'
627
+ ) {
628
+ return convertFlowTypeImpl(
629
+ flowType.type,
630
+ loc,
631
+ genericEnv,
632
+ platform,
633
+ poly,
634
+ );
635
+ }
636
+ TypeErrors.unsupportedTypeAnnotation(
637
+ `EvalT(${flowType.destructor.kind})`,
638
+ GeneratedSource,
639
+ );
640
+ }
641
+ case 'Optional': {
642
+ return Resolved.union(
643
+ [
644
+ convertFlowTypeImpl(flowType.type, loc, genericEnv, platform),
645
+ Resolved.void(platform),
646
+ ],
647
+ platform,
648
+ );
649
+ }
650
+ default:
651
+ TypeErrors.unsupportedTypeAnnotation(flowType.kind, GeneratedSource);
652
+ }
653
+ }
654
+ return convertFlowTypeImpl(flowType, loc, new Map(), 'shared');
655
+}
656
+
657
+export interface ITypeEnv {
658
+ popGeneric(name: string): void;
659
+ getGeneric(name: string): null | TypeParameter<ResolvedType>;
660
+ pushGeneric(
661
+ name: string,
662
+ binding: {name: string; id: TypeParameterId; bound: ResolvedType},
663
+ ): void;
664
+ getType(id: Identifier): ResolvedType;
665
+ getTypeOrNull(id: Identifier): ResolvedType | null;
666
+ setType(id: Identifier, type: ResolvedType): void;
667
+ nextNominalId(): NominalId;
668
+ nextTypeParameterId(): TypeParameterId;
669
+ moduleEnv: Map<string, ResolvedType>;
670
+ addBinding(bindingIdentifier: t.Identifier, type: ResolvedType): void;
671
+ resolveBinding(bindingIdentifier: t.Identifier): ResolvedType | null;
672
+}
673
+
674
+function serializeLoc(location: t.SourceLocation): string {
675
+ return `${location.start.line}:${location.start.column}-${location.end.line}:${location.end.column}`;
676
+}
677
+
678
+function buildTypeEnvironment(
679
+ flowOutput: Array<{loc: t.SourceLocation; type: string}>,
680
+): Map<string, string> {
681
+ const result: Map<string, string> = new Map();
682
+ for (const item of flowOutput) {
683
+ const loc: t.SourceLocation = {
684
+ start: {
685
+ line: item.loc.start.line,
686
+ column: item.loc.start.column - 1,
687
+ index: item.loc.start.index,
688
+ },
689
+ end: item.loc.end,
690
+ filename: item.loc.filename,
691
+ identifierName: item.loc.identifierName,
692
+ };
693
+
694
+ result.set(serializeLoc(loc), item.type);
695
+ }
696
+ return result;
697
+}
698
+
699
+let lastFlowSource: string | null = null;
700
+let lastFlowResult: any = null;
701
+
702
+export class FlowTypeEnv implements ITypeEnv {
703
+ moduleEnv: Map<string, ResolvedType> = new Map();
704
+ #nextNominalId: number = 0;
705
+ #nextTypeParameterId: number = 0;
706
+
707
+ #types: Map<IdentifierId, ResolvedType> = new Map();
708
+ #bindings: Map<t.Identifier, ResolvedType> = new Map();
709
+ #generics: Array<[string, TypeParameter<ResolvedType>]> = [];
710
+ #flowTypes: Map<string, ResolvedType> = new Map();
711
+
712
+ init(env: Environment, source: string): void {
713
+ // TODO: use flow-js only for web environments (e.g. playground)
714
+ CompilerError.invariant(env.config.flowTypeProvider != null, {
715
+ reason: 'Expected flowDumpTypes to be defined in environment config',
716
+ loc: GeneratedSource,
717
+ });
718
+ let stdout: any;
719
+ if (source === lastFlowSource) {
720
+ stdout = lastFlowResult;
721
+ } else {
722
+ lastFlowSource = source;
723
+ lastFlowResult = env.config.flowTypeProvider(source);
724
+ stdout = lastFlowResult;
725
+ }
726
+ const flowTypes = buildTypeEnvironment(stdout);
727
+ const resolvedFlowTypes = new Map<string, ResolvedType>();
728
+ for (const [loc, type] of flowTypes) {
729
+ if (typeof loc === 'symbol') continue;
730
+ resolvedFlowTypes.set(loc, convertFlowType(JSON.parse(type), loc));
731
+ }
732
+ // =console.log(resolvedFlowTypes);
733
+ this.#flowTypes = resolvedFlowTypes;
734
+ }
735
+
736
+ setType(identifier: Identifier, type: ResolvedType): void {
737
+ if (
738
+ typeof identifier.loc !== 'symbol' &&
739
+ this.#flowTypes.has(serializeLoc(identifier.loc))
740
+ ) {
741
+ return;
742
+ }
743
+ this.#types.set(identifier.id, type);
744
+ }
745
+
746
+ getType(identifier: Identifier): ResolvedType {
747
+ const result = this.getTypeOrNull(identifier);
748
+ if (result == null) {
749
+ throw new Error(
750
+ `Type not found for ${identifier.id}, ${typeof identifier.loc === 'symbol' ? 'generated loc' : serializeLoc(identifier.loc)}`,
751
+ );
752
+ }
753
+ return result;
754
+ }
755
+
756
+ getTypeOrNull(identifier: Identifier): ResolvedType | null {
757
+ const result = this.#types.get(identifier.id) ?? null;
758
+ if (result == null && typeof identifier.loc !== 'symbol') {
759
+ const flowType = this.#flowTypes.get(serializeLoc(identifier.loc));
760
+ return flowType ?? null;
761
+ }
762
+ return result;
763
+ }
764
+
765
+ getTypeByLoc(loc: SourceLocation): ResolvedType | null {
766
+ if (typeof loc === 'symbol') {
767
+ return null;
768
+ }
769
+ const flowType = this.#flowTypes.get(serializeLoc(loc));
770
+ return flowType ?? null;
771
+ }
772
+
773
+ nextNominalId(): NominalId {
774
+ return makeNominalId(this.#nextNominalId++);
775
+ }
776
+
777
+ nextTypeParameterId(): TypeParameterId {
778
+ return makeTypeParameterId(this.#nextTypeParameterId++);
779
+ }
780
+
781
+ addBinding(bindingIdentifier: t.Identifier, type: ResolvedType): void {
782
+ this.#bindings.set(bindingIdentifier, type);
783
+ }
784
+
785
+ resolveBinding(bindingIdentifier: t.Identifier): ResolvedType | null {
786
+ return this.#bindings.get(bindingIdentifier) ?? null;
787
+ }
788
+
789
+ pushGeneric(name: string, generic: TypeParameter<ResolvedType>): void {
790
+ this.#generics.unshift([name, generic]);
791
+ }
792
+
793
+ popGeneric(name: string): void {
794
+ for (let i = 0; i < this.#generics.length; i++) {
795
+ if (this.#generics[i][0] === name) {
796
+ this.#generics.splice(i, 1);
797
+ return;
798
+ }
799
+ }
800
+ }
801
+
802
+ /**
803
+ * Look up bound polymorphic types
804
+ * @param name
805
+ * @returns
806
+ */
807
+ getGeneric(name: string): null | TypeParameter<ResolvedType> {
808
+ for (const [eltName, param] of this.#generics) {
809
+ if (name === eltName) {
810
+ return param;
811
+ }
812
+ }
813
+ return null;
814
+ }
815
+}
816
+const Primitives = {
817
+ number(platform: Platform): Type & ResolvedType {
818
+ return {kind: 'Concrete', type: {kind: 'Number'}, platform};
819
+ },
820
+ string(platform: Platform): Type & ResolvedType {
821
+ return {kind: 'Concrete', type: {kind: 'String'}, platform};
822
+ },
823
+ boolean(platform: Platform): Type & ResolvedType {
824
+ return {kind: 'Concrete', type: {kind: 'Boolean'}, platform};
825
+ },
826
+ void(platform: Platform): Type & ResolvedType {
827
+ return {kind: 'Concrete', type: {kind: 'Void'}, platform};
828
+ },
829
+ mixed(platform: Platform): Type & ResolvedType {
830
+ return {kind: 'Concrete', type: {kind: 'Mixed'}, platform};
831
+ },
832
+ enum(platform: Platform): Type & ResolvedType {
833
+ return {kind: 'Concrete', type: {kind: 'Enum'}, platform};
834
+ },
835
+ todo(platform: Platform): Type & ResolvedType {
836
+ return {kind: 'Concrete', type: {kind: 'Mixed'}, platform};
837
+ },
838
+};
839
+
840
+export const Resolved = {
841
+ ...Primitives,
842
+ nullable(type: ResolvedType, platform: Platform): ResolvedType {
843
+ return {kind: 'Concrete', type: {kind: 'Nullable', type}, platform};
844
+ },
845
+ array(element: ResolvedType, platform: Platform): ResolvedType {
846
+ return {kind: 'Concrete', type: {kind: 'Array', element}, platform};
847
+ },
848
+ set(element: ResolvedType, platform: Platform): ResolvedType {
849
+ return {kind: 'Concrete', type: {kind: 'Set', element}, platform};
850
+ },
851
+ map(
852
+ key: ResolvedType,
853
+ value: ResolvedType,
854
+ platform: Platform,
855
+ ): ResolvedType {
856
+ return {kind: 'Concrete', type: {kind: 'Map', key, value}, platform};
857
+ },
858
+ function(
859
+ typeParameters: null | Array<TypeParameter<ResolvedType>>,
860
+ params: Array<ResolvedType>,
861
+ returnType: ResolvedType,
862
+ platform: Platform,
863
+ ): ResolvedType {
864
+ return {
865
+ kind: 'Concrete',
866
+ type: {kind: 'Function', typeParameters, params, returnType},
867
+ platform,
868
+ };
869
+ },
870
+ component(
871
+ props: Map<string, ResolvedType>,
872
+ children: ResolvedType | null,
873
+ platform: Platform,
874
+ ): ResolvedType {
875
+ return {
876
+ kind: 'Concrete',
877
+ type: {kind: 'Component', props, children},
878
+ platform,
879
+ };
880
+ },
881
+ object(
882
+ id: NominalId,
883
+ members: Map<string, ResolvedType>,
884
+ platform: Platform,
885
+ ): ResolvedType {
886
+ return {
887
+ kind: 'Concrete',
888
+ type: {
889
+ kind: 'Object',
890
+ id,
891
+ members,
892
+ },
893
+ platform,
894
+ };
895
+ },
896
+ class(
897
+ name: string,
898
+ members: Map<string, ResolvedType>,
899
+ platform: Platform,
900
+ ): ResolvedType {
901
+ return {
902
+ kind: 'Concrete',
903
+ type: {
904
+ kind: 'Instance',
905
+ name,
906
+ members,
907
+ },
908
+ platform,
909
+ };
910
+ },
911
+ tuple(
912
+ id: NominalId,
913
+ members: Array<ResolvedType>,
914
+ platform: Platform,
915
+ ): ResolvedType {
916
+ return {
917
+ kind: 'Concrete',
918
+ type: {
919
+ kind: 'Tuple',
920
+ id,
921
+ members,
922
+ },
923
+ platform,
924
+ };
925
+ },
926
+ generic(
927
+ id: TypeParameterId,
928
+ platform: Platform,
929
+ bound = Primitives.mixed(platform),
930
+ ): ResolvedType {
931
+ return {
932
+ kind: 'Concrete',
933
+ type: {
934
+ kind: 'Generic',
935
+ id,
936
+ bound,
937
+ },
938
+ platform,
939
+ };
940
+ },
941
+ union(members: Array<ResolvedType>, platform: Platform): ResolvedType {
942
+ return {
943
+ kind: 'Concrete',
944
+ type: {
945
+ kind: 'Union',
946
+ members,
947
+ },
948
+ platform,
949
+ };
950
+ },
951
+};
952
+
953
+/*
954
+ * export const Types = {
955
+ * ...Primitives,
956
+ * variable(env: TypeEnv): Type {
957
+ * return env.nextTypeVariable();
958
+ * },
959
+ * nullable(type: Type): Type {
960
+ * return {kind: 'Concrete', type: {kind: 'Nullable', type}};
961
+ * },
962
+ * array(element: Type): Type {
963
+ * return {kind: 'Concrete', type: {kind: 'Array', element}};
964
+ * },
965
+ * set(element: Type): Type {
966
+ * return {kind: 'Concrete', type: {kind: 'Set', element}};
967
+ * },
968
+ * map(key: Type, value: Type): Type {
969
+ * return {kind: 'Concrete', type: {kind: 'Map', key, value}};
970
+ * },
971
+ * function(
972
+ * typeParameters: null | Array<TypeParameter<Type>>,
973
+ * params: Array<Type>,
974
+ * returnType: Type,
975
+ * ): Type {
976
+ * return {
977
+ * kind: 'Concrete',
978
+ * type: {kind: 'Function', typeParameters, params, returnType},
979
+ * };
980
+ * },
981
+ * component(
982
+ * props: Map<string, ResolvedType>,
983
+ * children: Type | null,
984
+ * ): Type {
985
+ * return {
986
+ * kind: 'Concrete',
987
+ * type: {kind: 'Component', props, children},
988
+ * };
989
+ * },
990
+ * object(id: NominalId, members: Map<string, ResolvedType>): Type {
991
+ * return {
992
+ * kind: 'Concrete',
993
+ * type: {
994
+ * kind: 'Object',
995
+ * id,
996
+ * members,
997
+ * },
998
+ * };
999
+ * },
1000
+ * };
1001
+ */
compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
+29
@@ -49,6 +49,7 @@ import {
49
} from './ObjectShape';
50
import {Scope as BabelScope, NodePath} from '@babel/traverse';
51
import {TypeSchema} from './TypeSchema';
52
+import {FlowTypeEnv} from '../Flood/Types';
53
54
export const ReactElementSymbolSchema = z.object({
55
elementSymbol: z.union([
@@ -243,6 +244,12 @@ export const EnvironmentConfigSchema = z.object({
244
*/
245
enableUseTypeAnnotations: z.boolean().default(false),
246
247
+ /**
248
+ * Allows specifying a function that can populate HIR with type information from
249
+ * Flow
250
+ */
251
+ flowTypeProvider: z.nullable(z.function().args(z.string())).default(null),
252
+
253
/**
254
* Enable a new model for mutability and aliasing inference
255
*/
@@ -697,6 +704,8 @@ export class Environment {
704
#hoistedIdentifiers: Set<t.Identifier>;
705
parentFunction: NodePath<t.Function>;
706
707
+ #flowTypeEnvironment: FlowTypeEnv | null;
708
+
709
constructor(
710
scope: BabelScope,
711
fnType: ReactFunctionType,
@@ -765,6 +774,26 @@ export class Environment {
774
this.parentFunction = parentFunction;
775
this.#contextIdentifiers = contextIdentifiers;
776
this.#hoistedIdentifiers = new Set();
777
+
778
+ if (config.flowTypeProvider != null) {
779
+ this.#flowTypeEnvironment = new FlowTypeEnv();
780
+ CompilerError.invariant(code != null, {
781
+ reason:
782
+ 'Expected Environment to be initialized with source code when a Flow type provider is specified',
783
+ loc: null,
784
+ });
785
+ this.#flowTypeEnvironment.init(this, code);
786
+ } else {
787
+ this.#flowTypeEnvironment = null;
788
+ }
789
+ }
790
+
791
+ get typeContext(): FlowTypeEnv {
792
+ CompilerError.invariant(this.#flowTypeEnvironment != null, {
793
+ reason: 'Flow type environment not initialized',
794
+ loc: null,
795
+ });
796
+ return this.#flowTypeEnvironment;
797
}
798
799
get isInferredMemoEnabled(): boolean {
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts
+1
-1
@@ -504,7 +504,7 @@ function canMergeScopes(
504
return false;
505
}
506
507
-function isAlwaysInvalidatingType(type: Type): boolean {
507
+export function isAlwaysInvalidatingType(type: Type): boolean {
508
switch (type.kind) {
509
case 'Object': {
510
switch (type.shapeId) {
compiler/packages/babel-plugin-react-compiler/src/Utils/DisjointSet.ts
+4
@@ -78,6 +78,10 @@ export default class DisjointSet<T> {
78
return root;
79
}
80
81
+ has(item: T): boolean {
82
+ return this.#entries.has(item);
83
+ }
84
+
85
/*
86
* Forces the set into canonical form, ie with all items pointing directly to
87
* their root, and returns a Map representing the mapping of items to their roots.
compiler/packages/babel-plugin-react-compiler/src/Utils/utils.ts
+2
-2
@@ -33,12 +33,12 @@ export function assertExhaustive(_: never, errorMsg: string): never {
33
// Modifies @param array in place, retaining only the items where the predicate returns true.
34
export function retainWhere<T>(
35
array: Array<T>,
36
- predicate: (item: T) => boolean,
36
+ predicate: (item: T, index: number) => boolean,
37
): void {
38
let writeIndex = 0;
39
for (let readIndex = 0; readIndex < array.length; readIndex++) {
40
const item = array[readIndex];
41
- if (predicate(item) === true) {
41
+ if (predicate(item, readIndex) === true) {
42
array[writeIndex++] = item;
43
}
44
}