@@ -37,7 +37,7 @@ class FlatTypeMask extends TypeMask {
3737 _getPowerset (_Flags (a.bitset.union (b.bitset)));
3838
3939 static Bitset _powersetOfFlagsIntersection (_Flags a, _Flags b) =>
40- _getPowerset (_Flags (a.bitset. intersection ( b.bitset)));
40+ _getPowerset (_Flags (_intersectPowersets ( a.bitset, b.bitset)));
4141
4242 static FlatTypeMaskKind _getKind (_Flags flags) =>
4343 FlatTypeMaskKind .values[flags.bitset.bits >> _powersetDomains.bitWidth];
@@ -92,6 +92,15 @@ class FlatTypeMask extends TypeMask {
9292 domain,
9393 );
9494
95+ factory FlatTypeMask ._emptyOrSpecial (CommonMasks domain, Bitset powerset) {
96+ assert (_isEmptyOrSpecialPowerset (powerset));
97+ return FlatTypeMask ._cached (
98+ null ,
99+ _computeFlags (FlatTypeMaskKind .empty, powerset),
100+ domain,
101+ );
102+ }
103+
95104 factory FlatTypeMask .nonNullEmpty (
96105 CommonMasks domain, {
97106 bool hasLateSentinel = false ,
@@ -100,11 +109,8 @@ class FlatTypeMask extends TypeMask {
100109 hasLateSentinel
101110 ? _specialValueDomain.fromValue (TypeMaskSpecialValue .lateSentinel)
102111 : Bitset .empty ();
103- return FlatTypeMask ._cached (
104- null ,
105- _computeFlags (FlatTypeMaskKind .empty, powerset),
106- domain,
107- );
112+
113+ return FlatTypeMask ._emptyOrSpecial (domain, powerset);
108114 }
109115
110116 factory FlatTypeMask .empty (
@@ -115,13 +121,9 @@ class FlatTypeMask extends TypeMask {
115121 hasLateSentinel
116122 ? _specialValueDomain.allValues
117123 : _specialValueDomain.fromValue (TypeMaskSpecialValue .null_);
118- return FlatTypeMask ._cached (
119- null ,
120- _computeFlags (FlatTypeMaskKind .empty, powerset),
121- domain,
122- );
123- }
124124
125+ return FlatTypeMask ._emptyOrSpecial (domain, powerset);
126+ }
125127 factory FlatTypeMask .nonNullExact (
126128 ClassEntity base ,
127129 CommonMasks domain, {
@@ -175,7 +177,16 @@ class FlatTypeMask extends TypeMask {
175177 ),
176178 );
177179 }
178- var powerset = _specialValueDomain.fromEnumSet (specialValues);
180+
181+ final probe = domain._powersetCache[base ];
182+ final powerset = switch (kind) {
183+ FlatTypeMaskKind .empty =>
184+ throw StateError ('Unexpected empty kind with base $base ' ),
185+ FlatTypeMaskKind .exact => probe.exact,
186+ FlatTypeMaskKind .subclass => probe.subclass,
187+ FlatTypeMaskKind .subtype => probe.subtype,
188+ }.union (_specialValueDomain.fromEnumSet (specialValues));
189+
179190 return FlatTypeMask ._cached (base , _computeFlags (kind, powerset), domain);
180191 }
181192
@@ -196,11 +207,13 @@ class FlatTypeMask extends TypeMask {
196207 /// Ensures that the generated mask is normalized, i.e., a call to
197208 /// [TypeMask.assertIsNormalized] with the factory's result returns `true` .
198209 factory FlatTypeMask .normalized (
199- ClassEntity ? base ,
210+ ClassEntity base ,
200211 FlatTypeMaskKind kind,
201212 Bitset powerset,
202213 CommonMasks domain,
203214 ) {
215+ assert (kind != FlatTypeMaskKind .empty);
216+ assert (! _isEmptyOrSpecialPowerset (powerset));
204217 if (base == domain.commonElements.nullClass) {
205218 return FlatTypeMask .empty (
206219 domain,
@@ -210,16 +223,16 @@ class FlatTypeMask extends TypeMask {
210223 ),
211224 );
212225 }
213- if (kind == FlatTypeMaskKind .empty || kind == FlatTypeMaskKind . exact) {
226+ if (kind == FlatTypeMaskKind .exact) {
214227 return FlatTypeMask ._cached (base , _computeFlags (kind, powerset), domain);
215228 }
216229 if (kind == FlatTypeMaskKind .subtype) {
217- if (! domain.closedWorld.classHierarchy.hasAnyStrictSubtype (base ! ) ||
230+ if (! domain.closedWorld.classHierarchy.hasAnyStrictSubtype (base ) ||
218231 domain.closedWorld.classHierarchy.hasOnlySubclasses (base )) {
219232 kind = FlatTypeMaskKind .subclass;
220233 }
221234 } else if (kind == FlatTypeMaskKind .subclass &&
222- ! domain.closedWorld.classHierarchy.hasAnyStrictSubclass (base ! )) {
235+ ! domain.closedWorld.classHierarchy.hasAnyStrictSubclass (base )) {
223236 kind = FlatTypeMaskKind .exact;
224237 }
225238 final flags = _computeFlags (kind, powerset);
@@ -518,7 +531,7 @@ class FlatTypeMask extends TypeMask {
518531 // If we weaken the constraint on this type, we have to make sure that
519532 // the result is normalized.
520533 return FlatTypeMask .normalized (
521- base ,
534+ base ! ,
522535 combinedKind,
523536 combinedPowerset,
524537 domain,
@@ -537,11 +550,16 @@ class FlatTypeMask extends TypeMask {
537550 ? this
538551 // If we weaken the constraint on this type, we have to make sure that
539552 // the result is normalized.
540- : FlatTypeMask .normalized (base , combinedKind, combinedPowerset, domain);
553+ : FlatTypeMask .normalized (
554+ base ! ,
555+ combinedKind,
556+ combinedPowerset,
557+ domain,
558+ );
541559 }
542560
543561 @override
544- TypeMask intersection (TypeMask other, CommonMasks domain) {
562+ TypeMask _nonEmptyIntersection (TypeMask other, CommonMasks domain) {
545563 return (domain._intersectionCache[this ] ?? = {})[other] ?? = _intersection (
546564 other,
547565 domain,
@@ -551,8 +569,10 @@ class FlatTypeMask extends TypeMask {
551569 TypeMask _intersection (TypeMask other, CommonMasks domain) {
552570 if (other is ! FlatTypeMask ) return other.intersection (this , domain);
553571
554- final otherBase = other.base ;
555572 final powerset = _powersetOfFlagsIntersection (_flags, other._flags);
573+ assert (! isEmptyOrSpecial);
574+ assert (! other.isEmptyOrSpecial);
575+
556576 final includeNull = _specialValueDomain.contains (
557577 powerset,
558578 TypeMaskSpecialValue .null_,
@@ -562,16 +582,10 @@ class FlatTypeMask extends TypeMask {
562582 TypeMaskSpecialValue .lateSentinel,
563583 );
564584
565- if (isEmptyOrSpecial) {
566- return withPowerset (powerset, domain);
567- } else if (other.isEmptyOrSpecial) {
568- return other.withPowerset (powerset, domain);
569- }
570-
571585 SubclassResult result = domain.closedWorld.classHierarchy.commonSubclasses (
572586 base ! ,
573587 _classQuery,
574- otherBase ! ,
588+ other. base ! ,
575589 other._classQuery,
576590 );
577591
@@ -637,20 +651,18 @@ class FlatTypeMask extends TypeMask {
637651 }
638652
639653 @override
640- bool isDisjoint (TypeMask other, JClosedWorld closedWorld) {
641- if (other is ! FlatTypeMask ) return other.isDisjoint (this , closedWorld);
642- FlatTypeMask flatOther = other;
643-
644- if (isNullable && flatOther.isNullable) return false ;
645- if (hasLateSentinel && flatOther.hasLateSentinel) return false ;
646- if (isEmptyOrSpecial || flatOther.isEmptyOrSpecial) return true ;
647- if (base == flatOther.base ) return false ;
648- if (isExact && flatOther.isExact) return true ;
649-
650- if (isExact) return ! flatOther.contains (base ! , closedWorld);
651- if (flatOther.isExact) return ! contains (flatOther.base ! , closedWorld);
654+ bool _isNonTriviallyDisjoint (TypeMask other, JClosedWorld closedWorld) {
655+ if (other is ! FlatTypeMask ) {
656+ return other._isNonTriviallyDisjoint (this , closedWorld);
657+ }
658+
659+ if (base == other.base ) return false ;
660+ if (isExact && other.isExact) return true ;
661+
662+ if (isExact) return ! other.contains (base ! , closedWorld);
663+ if (other.isExact) return ! contains (other.base ! , closedWorld);
652664 final thisBase = base ! ;
653- final otherBase = flatOther .base ! ;
665+ final otherBase = other .base ! ;
654666
655667 // Normalization guarantees that isExact === !isSubclass && !isSubtype.
656668 // Both are subclass or subtype masks, so if there is a subclass
@@ -664,9 +676,9 @@ class FlatTypeMask extends TypeMask {
664676
665677 // Two different base classes have no common subclass unless one is a
666678 // subclass of the other (checked above).
667- if (isSubclass && flatOther .isSubclass) return true ;
679+ if (isSubclass && other .isSubclass) return true ;
668680
669- return _isDisjointHelper (this , flatOther , closedWorld);
681+ return _isDisjointHelper (this , other , closedWorld);
670682 }
671683
672684 static bool _isDisjointHelper (
@@ -692,59 +704,6 @@ class FlatTypeMask extends TypeMask {
692704 return true ;
693705 }
694706
695- TypeMask intersectionSame (FlatTypeMask other, CommonMasks domain) {
696- assert (base == other.base );
697- // The two masks share the base type, so we must chose the most
698- // constraining kind (the lowest) of the two. The result will be normalized,
699- // as the two inputs are normalized, too.
700- final combined = _Flags (
701- (_flags.bitset.bits < other._flags.bitset.bits)
702- ? _flags.bitset.intersection (
703- other._flags.bitset.union (_powersetDomains.notMask),
704- )
705- : other._flags.bitset.intersection (
706- _flags.bitset.union (_powersetDomains.notMask),
707- ),
708- );
709-
710- if (_flags == combined) {
711- return this ;
712- } else if (other._flags == combined) {
713- return other;
714- } else {
715- return FlatTypeMask ._cached (base , combined, domain);
716- }
717- }
718-
719- TypeMask intersectionStrictSubclass (FlatTypeMask other, CommonMasks domain) {
720- assert (base != other.base );
721- assert (domain.closedWorld.classHierarchy.isSubclassOf (other.base ! , base ! ));
722- // If this mask isn't at least a subclass mask, then the
723- // intersection with the other mask is empty.
724- if (isExact) return intersectionEmpty (other, domain);
725- // Only the other mask puts constraints on the intersection mask,
726- // so base the combined flags on the other mask. The result is guaranteed to
727- // be normalized, as the other type was normalized.
728- final combined = _Flags (
729- other._flags.bitset.intersection (
730- _flags.bitset.union (_powersetDomains.notMask),
731- ),
732- );
733- if (other._flags == combined) {
734- return other;
735- } else {
736- return FlatTypeMask ._cached (other.base , combined, domain);
737- }
738- }
739-
740- TypeMask intersectionEmpty (FlatTypeMask other, CommonMasks domain) {
741- bool isNullable = this .isNullable && other.isNullable;
742- bool hasLateSentinel = this .hasLateSentinel && other.hasLateSentinel;
743- return isNullable
744- ? TypeMask .empty (domain, hasLateSentinel: hasLateSentinel)
745- : TypeMask .nonNullEmpty (domain, hasLateSentinel: hasLateSentinel);
746- }
747-
748707 @override
749708 bool canHit (MemberEntity element, Name name, CommonMasks domain) {
750709 final closedWorld = domain.closedWorld;
@@ -913,3 +872,44 @@ class FlatTypeMask extends TypeMask {
913872 return buffer.toString ();
914873 }
915874}
875+
876+ typedef _CachedPowersets = ({Bitset exact, Bitset subclass, Bitset subtype});
877+
878+ class _PowersetCache {
879+ final ClassHierarchy _classHierarchy;
880+ final Set <ClassEntity > _interceptorCone;
881+ final Map <ClassEntity , _CachedPowersets > _cache = {};
882+
883+ _PowersetCache (JClosedWorld closedWorld)
884+ : _classHierarchy = closedWorld.classHierarchy,
885+ _interceptorCone =
886+ closedWorld.classHierarchy
887+ .subclassesOf (closedWorld.commonElements.jsInterceptorClass)
888+ .toSet ();
889+
890+ _CachedPowersets operator [](ClassEntity cls) => _cache.putIfAbsent (cls, () {
891+ var exactPowerset = Bitset .empty ();
892+ exactPowerset = _interceptorDomain.add (
893+ exactPowerset,
894+ _interceptorCone.contains (cls)
895+ ? TypeMaskInterceptorProperty .interceptor
896+ : TypeMaskInterceptorProperty .notInterceptor,
897+ );
898+
899+ var subclassPowerset = exactPowerset;
900+ for (final subclass in _classHierarchy.strictSubclassesOf (cls)) {
901+ subclassPowerset = subclassPowerset.union (this [subclass].subclass);
902+ }
903+
904+ var subtypePowerset = exactPowerset;
905+ for (final subtype in _classHierarchy.strictSubtypesOf (cls)) {
906+ subtypePowerset = subtypePowerset.union (this [subtype].subtype);
907+ }
908+
909+ return (
910+ exact: exactPowerset,
911+ subclass: subclassPowerset,
912+ subtype: subtypePowerset,
913+ );
914+ });
915+ }
0 commit comments