@@ -146,6 +146,41 @@ class UnionType extends DeclarationType {
146
146
}
147
147
}
148
148
149
+ class IntersectionType extends DeclarationType {
150
+ final List <Type > types;
151
+
152
+ @override
153
+ bool isNullable = false ;
154
+
155
+ @override
156
+ String declarationName;
157
+
158
+ IntersectionType ({required this .types, required String name})
159
+ : declarationName = name;
160
+
161
+ @override
162
+ ID get id => ID (type: 'type' , name: types.map ((t) => t.id.name).join ('&' ));
163
+
164
+ @override
165
+ Declaration get declaration =>
166
+ _IntersectionDeclaration (name: declarationName, types: types);
167
+
168
+ @override
169
+ Reference emit ([TypeOptions ? options]) {
170
+ return TypeReference ((t) => t
171
+ ..symbol = declarationName
172
+ ..isNullable = (options? .nullable ?? false ) || isNullable);
173
+ }
174
+
175
+ @override
176
+ int get hashCode => Object .hashAllUnordered (types);
177
+
178
+ @override
179
+ bool operator == (Object other) {
180
+ return other is TupleType && other.types.every (types.contains);
181
+ }
182
+ }
183
+
149
184
class HomogenousEnumType <T extends LiteralType , D extends Declaration >
150
185
extends UnionType implements DeclarationType {
151
186
final List <T > _types;
@@ -557,25 +592,27 @@ class _ConstructorDeclaration extends CallableDeclaration
557
592
}
558
593
}
559
594
560
- // TODO: Merge properties/methods of related types
561
- class _UnionDeclaration extends NamedDeclaration
595
+ sealed class _UnionOrIntersectionDeclaration extends NamedDeclaration
562
596
implements ExportableDeclaration {
563
597
@override
564
598
bool get exported => true ;
565
599
566
600
@override
567
- ID get id => ID (type: 'union' , name: name);
568
-
569
- bool isNullable;
601
+ ID get id;
570
602
571
603
List <Type > types;
572
604
573
605
List <GenericType > typeParameters;
574
606
575
- _UnionDeclaration (
607
+ @override
608
+ String name;
609
+
610
+ @override
611
+ String ? dartName;
612
+
613
+ _UnionOrIntersectionDeclaration (
576
614
{required this .name,
577
615
this .types = const [],
578
- this .isNullable = false ,
579
616
List <GenericType >? typeParams})
580
617
: typeParameters = typeParams ?? [] {
581
618
if (typeParams == null ) {
@@ -588,26 +625,42 @@ class _UnionDeclaration extends NamedDeclaration
588
625
}
589
626
}
590
627
591
- @override
592
- String ? dartName;
593
-
594
- @override
595
- String name;
596
-
597
- @override
598
- Spec emit ([covariant DeclarationOptions ? options]) {
628
+ Spec _emit (
629
+ {covariant DeclarationOptions ? options,
630
+ bool extendTypes = false ,
631
+ bool isNullable = false }) {
599
632
options ?? = DeclarationOptions ();
600
633
601
634
final repType =
602
635
getLowestCommonAncestorOfTypes (types, isNullable: isNullable);
603
636
637
+ final extendees = < Type > [];
638
+ if (extendTypes) {
639
+ // check if any types are primitive
640
+ // TODO: We can be much smarter about this, but this works best so far
641
+ if (types.any ((t) {
642
+ final jsAltType = getJSTypeAlternative (t);
643
+ return jsAltType is BuiltinType &&
644
+ _nonObjectRepTypeTypes.contains (jsAltType.name);
645
+ }) ||
646
+ (repType is BuiltinType && repType.name == 'JSAny' )) {
647
+ extendees.add (
648
+ BuiltinType .primitiveType (PrimitiveType .any, isNullable: false ));
649
+ } else {
650
+ extendees.addAll (types.map (getJSTypeAlternative));
651
+ }
652
+ } else {
653
+ extendees.add (repType);
654
+ }
655
+
604
656
return ExtensionType ((e) => e
605
657
..name = name
606
658
..primaryConstructorName = '_'
607
659
..representationDeclaration = RepresentationDeclaration ((r) => r
608
660
..name = '_'
609
661
..declaredRepresentationType = repType.emit (options? .toTypeOptions ()))
610
- ..implements .addAll ([repType.emit (options? .toTypeOptions ())])
662
+ ..implements
663
+ .addAll (extendees.map ((e) => e.emit (options? .toTypeOptions ())))
611
664
..types
612
665
.addAll (typeParameters.map ((t) => t.emit (options? .toTypeOptions ())))
613
666
..methods.addAll (types.map ((t) {
@@ -719,3 +772,45 @@ class _EnumObjDeclaration extends NamedDeclaration
719
772
@override
720
773
ID get id => ID (type: 'enum-rep' , name: name);
721
774
}
775
+
776
+ List <String > _nonObjectRepTypeTypes = [
777
+ 'JSAny' ,
778
+ 'JSString' ,
779
+ 'JSBoolean' ,
780
+ 'JSNumber' ,
781
+ 'JSSymbol' ,
782
+ 'JSBigInt'
783
+ ];
784
+
785
+ class _IntersectionDeclaration extends _UnionOrIntersectionDeclaration {
786
+ @override
787
+ bool get exported => true ;
788
+
789
+ @override
790
+ ID get id => ID (type: 'intersection' , name: name);
791
+
792
+ _IntersectionDeclaration ({required super .name, super .types}) : super ();
793
+
794
+ @override
795
+ Spec emit ([covariant DeclarationOptions ? options]) {
796
+ return super ._emit (options: options, extendTypes: true );
797
+ }
798
+ }
799
+
800
+ class _UnionDeclaration extends _UnionOrIntersectionDeclaration {
801
+ @override
802
+ bool get exported => true ;
803
+
804
+ @override
805
+ ID get id => ID (type: 'union' , name: name);
806
+
807
+ bool isNullable;
808
+
809
+ _UnionDeclaration ({required super .name, super .types, this .isNullable = false })
810
+ : super ();
811
+
812
+ @override
813
+ Spec emit ([covariant DeclarationOptions ? options]) {
814
+ return super ._emit (options: options, isNullable: isNullable);
815
+ }
816
+ }
0 commit comments