@@ -6,6 +6,12 @@ part of 'masks.dart';
66
77enum FlatTypeMaskKind { empty, exact, subclass, subtype }
88
9+ // The flags encode not only the powerset, but also the [FlatTypeMaskKind]. If
10+ // we type both flags and powersets as [Bitset]s, we risk accidentally passing
11+ // the wrong one when the other is expected. We can get type safety against this
12+ // by introducing this extension type.
13+ extension type _Flags (Bitset bitset) {}
14+
915/// A flat type mask is a type mask that has been flattened to contain a
1016/// base type.
1117class FlatTypeMask extends TypeMask {
@@ -22,15 +28,22 @@ class FlatTypeMask extends TypeMask {
2228
2329 final ClassEntity ? base ;
2430
25- final Bitset flags;
31+ final _Flags _flags;
32+
33+ static _Flags _computeFlags (FlatTypeMaskKind kind, Bitset powerset) =>
34+ _Flags (Bitset (kind.index << _powersetDomains.bitWidth | powerset.bits));
35+
36+ static Bitset _powersetOfFlagsUnion (_Flags a, _Flags b) =>
37+ _getPowerset (_Flags (a.bitset.union (b.bitset)));
2638
27- static Bitset _computeFlags ( FlatTypeMaskKind kind, Bitset powerset ) =>
28- Bitset (kind.index << _powersetDomains.bitWidth | powerset.bits );
39+ static Bitset _powersetOfFlagsIntersection ( _Flags a, _Flags b ) =>
40+ _getPowerset ( _Flags (a.bitset. intersection (b.bitset)) );
2941
30- static FlatTypeMaskKind _getKind (Bitset flags) =>
31- FlatTypeMaskKind .values[flags.bits >> _powersetDomains.bitWidth];
42+ static FlatTypeMaskKind _getKind (_Flags flags) =>
43+ FlatTypeMaskKind .values[flags.bitset. bits >> _powersetDomains.bitWidth];
3244
33- static Bitset _getPowerset (Bitset flags) => _powersetDomains.restrict (flags);
45+ static Bitset _getPowerset (_Flags flags) =>
46+ _powersetDomains.restrict (flags.bitset);
3447
3548 static EnumSet <TypeMaskSpecialValue > _composeSpecialValues ({
3649 required bool isNullable,
@@ -166,13 +179,13 @@ class FlatTypeMask extends TypeMask {
166179 return FlatTypeMask ._cached (base , _computeFlags (kind, powerset), domain);
167180 }
168181
169- const FlatTypeMask ._(this .base , this .flags );
182+ const FlatTypeMask ._(this .base , this ._flags );
170183
171184 factory FlatTypeMask ._cached (
172185 ClassEntity ? base ,
173- Bitset flags,
186+ _Flags flags,
174187 CommonMasks domain,
175- ) => domain.getCachedMask (base , flags, () {
188+ ) => domain._getCachedMask (base , flags, () {
176189 final mask = FlatTypeMask ._(base , flags);
177190 // Since this is the only place [FlatTypeMask]s are allocated, it is an
178191 // invariant that every [FlatTypeMask] is normalized.
@@ -220,7 +233,7 @@ class FlatTypeMask extends TypeMask {
220233 ) {
221234 source.begin (tag);
222235 final base = source.readClassOrNull ();
223- final flags = Bitset (source.readInt ());
236+ final flags = _Flags ( Bitset (source.readInt () ));
224237 source.end (tag);
225238 return FlatTypeMask ._cached (base , flags, domain);
226239 }
@@ -231,40 +244,44 @@ class FlatTypeMask extends TypeMask {
231244 sink.writeEnum (TypeMaskKind .flat);
232245 sink.begin (tag);
233246 sink.writeClassOrNull (base );
234- sink.writeInt (flags .bits);
247+ sink.writeInt (_flags.bitset .bits);
235248 sink.end (tag);
236249 }
237250
238- FlatTypeMaskKind get _kind => _getKind (flags );
251+ FlatTypeMaskKind get _kind => _getKind (_flags );
239252
240253 @override
241- Bitset get powerset => _getPowerset (flags );
254+ Bitset get powerset => _getPowerset (_flags );
242255
243256 ClassQuery get _classQuery =>
244257 isExact
245258 ? ClassQuery .exact
246259 : (isSubclass ? ClassQuery .subclass : ClassQuery .subtype);
247260
248261 @override
249- bool get isEmpty => isEmptyOrSpecial && _specialValueDomain.isEmpty (flags);
262+ bool get isEmpty =>
263+ isEmptyOrSpecial && _specialValueDomain.isEmpty (_flags.bitset);
250264 @override
251265 bool get isNull =>
252- isEmptyOrSpecial && _specialValueDomain.restrict (flags) == _nullBit;
266+ isEmptyOrSpecial &&
267+ _specialValueDomain.restrict (_flags.bitset) == _nullBit;
253268 @override
254269 bool get isEmptyOrSpecial => _kind == FlatTypeMaskKind .empty;
255270 @override
256271 bool get isExact => _kind == FlatTypeMaskKind .exact;
257272 @override
258273 bool get isNullable =>
259- _specialValueDomain.contains (flags , TypeMaskSpecialValue .null_);
274+ _specialValueDomain.contains (_flags.bitset , TypeMaskSpecialValue .null_);
260275 @override
261- bool get hasLateSentinel =>
262- _specialValueDomain.contains (flags, TypeMaskSpecialValue .lateSentinel);
276+ bool get hasLateSentinel => _specialValueDomain.contains (
277+ _flags.bitset,
278+ TypeMaskSpecialValue .lateSentinel,
279+ );
263280 @override
264281 AbstractBool get isLateSentinel {
265282 if (! hasLateSentinel) return AbstractBool .false_;
266283 if (isEmptyOrSpecial &&
267- _specialValueDomain.restrict (flags ) == _lateSentinelBit) {
284+ _specialValueDomain.restrict (_flags.bitset ) == _lateSentinelBit) {
268285 return AbstractBool .true_;
269286 }
270287 return AbstractBool .maybe;
@@ -279,7 +296,7 @@ class FlatTypeMask extends TypeMask {
279296 @override
280297 FlatTypeMask withPowerset (Bitset powerset, CommonMasks domain) {
281298 final newFlags = _computeFlags (_kind, powerset);
282- if (newFlags == flags ) return this ;
299+ if (newFlags == _flags ) return this ;
283300 return FlatTypeMask ._cached (base , newFlags, domain);
284301 }
285302
@@ -436,7 +453,7 @@ class FlatTypeMask extends TypeMask {
436453 TypeMask union (TypeMask other, CommonMasks domain) {
437454 JClosedWorld closedWorld = domain.closedWorld;
438455 if (other is ! FlatTypeMask ) return other.union (this , domain);
439- final powerset = this .powerset. union ( other.powerset );
456+ final powerset = _powersetOfFlagsUnion (_flags, other._flags );
440457 if (isEmptyOrSpecial) {
441458 return other.withPowerset (powerset, domain);
442459 } else if (other.isEmptyOrSpecial) {
@@ -464,13 +481,14 @@ class FlatTypeMask extends TypeMask {
464481 // The two masks share the base type, so we must chose the least
465482 // constraining kind (the highest) of the two. As both masks are normalized,
466483 // the result will be, too.
467- final combined =
468- (flags.bits > other.flags.bits)
469- ? flags.union (other.powerset)
470- : other.flags.union (powerset);
471- if (flags == combined) {
484+ final combined = _Flags (
485+ (_flags.bitset.bits > other._flags.bitset.bits)
486+ ? _flags.bitset.union (other.powerset)
487+ : other._flags.bitset.union (powerset),
488+ );
489+ if (_flags == combined) {
472490 return this ;
473- } else if (other.flags == combined) {
491+ } else if (other._flags == combined) {
474492 return other;
475493 } else {
476494 return FlatTypeMask ._cached (base , combined, domain);
@@ -481,25 +499,21 @@ class FlatTypeMask extends TypeMask {
481499 assert (base != other.base );
482500 assert (domain.closedWorld.classHierarchy.isSubclassOf (other.base ! , base ! ));
483501 final FlatTypeMaskKind combinedKind;
484- final Bitset combinedPowerset;
502+ final Bitset combinedPowerset = _powersetOfFlagsUnion (_flags, other._flags) ;
485503 if ((isExact && other.isExact) ||
486504 base == domain.commonElements.objectClass) {
487505 // Since the other mask is a subclass of this mask, we need the
488506 // resulting union to be a subclass too.
489507 combinedKind = FlatTypeMaskKind .subclass;
490- combinedPowerset = powerset.union (other.powerset);
491508 if (combinedKind == _kind && combinedPowerset == powerset) {
492509 return this ;
493510 }
494511 } else {
495512 // Both masks are at least subclass masks, so we pick the least
496513 // constraining kind (the highest) of the two.
497- final combined =
498- (flags.bits > other.flags.bits)
499- ? flags.union (other.powerset)
500- : other.flags.union (powerset);
501- combinedKind = _getKind (combined);
502- combinedPowerset = _getPowerset (combined);
514+ combinedKind = _getKind (
515+ _flags.bitset.bits > other._flags.bitset.bits ? _flags : other._flags,
516+ );
503517 }
504518 // If we weaken the constraint on this type, we have to make sure that
505519 // the result is normalized.
@@ -518,7 +532,7 @@ class FlatTypeMask extends TypeMask {
518532 // Since the other mask is a subtype of this mask, we need the
519533 // resulting union to be a subtype too.
520534 final combinedKind = FlatTypeMaskKind .subtype;
521- final combinedPowerset = powerset. union ( other.powerset );
535+ final combinedPowerset = _powersetOfFlagsUnion (_flags, other._flags );
522536 return combinedKind == _kind && combinedPowerset == powerset
523537 ? this
524538 // If we weaken the constraint on this type, we have to make sure that
@@ -538,7 +552,7 @@ class FlatTypeMask extends TypeMask {
538552 if (other is ! FlatTypeMask ) return other.intersection (this , domain);
539553
540554 final otherBase = other.base ;
541- final powerset = this .powerset. intersection ( other.powerset );
555+ final powerset = _powersetOfFlagsIntersection (_flags, other._flags );
542556 final includeNull = _specialValueDomain.contains (
543557 powerset,
544558 TypeMaskSpecialValue .null_,
@@ -683,14 +697,19 @@ class FlatTypeMask extends TypeMask {
683697 // The two masks share the base type, so we must chose the most
684698 // constraining kind (the lowest) of the two. The result will be normalized,
685699 // as the two inputs are normalized, too.
686- final combined =
687- (flags.bits < other.flags.bits)
688- ? flags.intersection (other.flags.union (_powersetDomains.notMask))
689- : other.flags.intersection (flags.union (_powersetDomains.notMask));
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+ );
690709
691- if (flags == combined) {
710+ if (_flags == combined) {
692711 return this ;
693- } else if (other.flags == combined) {
712+ } else if (other._flags == combined) {
694713 return other;
695714 } else {
696715 return FlatTypeMask ._cached (base , combined, domain);
@@ -706,10 +725,12 @@ class FlatTypeMask extends TypeMask {
706725 // Only the other mask puts constraints on the intersection mask,
707726 // so base the combined flags on the other mask. The result is guaranteed to
708727 // be normalized, as the other type was normalized.
709- final combined = other.flags.intersection (
710- flags.union (_powersetDomains.notMask),
728+ final combined = _Flags (
729+ other._flags.bitset.intersection (
730+ _flags.bitset.union (_powersetDomains.notMask),
731+ ),
711732 );
712- if (other.flags == combined) {
733+ if (other._flags == combined) {
713734 return other;
714735 } else {
715736 return FlatTypeMask ._cached (other.base , combined, domain);
@@ -868,12 +889,12 @@ class FlatTypeMask extends TypeMask {
868889 if (identical (this , other)) return true ;
869890 if (other is ! FlatTypeMask ) return false ;
870891 FlatTypeMask otherMask = other;
871- return (flags == otherMask.flags ) && (base == otherMask.base );
892+ return (_flags == otherMask._flags ) && (base == otherMask.base );
872893 }
873894
874895 @override
875896 int get hashCode {
876- return (base == null ? 0 : base .hashCode) + 31 * flags .hashCode;
897+ return (base == null ? 0 : base .hashCode) + 31 * _flags .hashCode;
877898 }
878899
879900 @override
0 commit comments