mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:57:58 +00:00
[dart2js] Migrate masks.dart (and associated part files) to null safety
The changes between inferrer/ and inferrer_experimental/ are identical. The changes were made in one and then the files were re-copied into the other. Change-Id: I2bb9d54ee39e8b9acba55e5e4c83392e5ab59586 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/260320 Reviewed-by: Mayank Patke <fishythefish@google.com> Commit-Queue: Nate Biggs <natebiggs@google.com>
This commit is contained in:
parent
48b2cb6ea2
commit
182742a61c
|
@ -363,7 +363,8 @@ class TrivialAbstractValueDomain implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValueWithPrecision createFromStaticType(DartType type,
|
||||
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
|
||||
{ClassRelation classRelation = ClassRelation.subtype,
|
||||
/* required */ bool nullable}) {
|
||||
assert(nullable != null);
|
||||
return const AbstractValueWithPrecision(TrivialAbstractValue(), false);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
library types.constants;
|
||||
|
||||
import '../../constants/constant_system.dart' as constant_system;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [TypeMask] for a specific allocation site of a container (currently only
|
||||
|
@ -17,18 +15,18 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
@override
|
||||
final TypeMask forwardTo;
|
||||
|
||||
final ir.Node /*?*/ _allocationNode;
|
||||
final ir.Node? _allocationNode;
|
||||
@override
|
||||
ir.Node get allocationNode => _allocationNode /*!*/;
|
||||
ir.Node? get allocationNode => _allocationNode;
|
||||
|
||||
@override
|
||||
final MemberEntity allocationElement;
|
||||
final MemberEntity? allocationElement;
|
||||
|
||||
// The element type of this container.
|
||||
final TypeMask elementType;
|
||||
|
||||
// The length of the container.
|
||||
final int length;
|
||||
final int? length;
|
||||
|
||||
const ContainerTypeMask(this.forwardTo, this._allocationNode,
|
||||
this.allocationElement, this.elementType, this.length);
|
||||
|
@ -37,10 +35,10 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
factory ContainerTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask elementType = TypeMask.readFromDataSource(source, domain);
|
||||
int length = source.readIntOrNull();
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final elementType = TypeMask.readFromDataSource(source, domain);
|
||||
final length = source.readIntOrNull();
|
||||
source.end(tag);
|
||||
return ContainerTypeMask(
|
||||
forwardTo, null, allocationElement, elementType, length);
|
||||
|
@ -59,7 +57,7 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ContainerTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
ContainerTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -79,16 +77,12 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
bool get isExact => true;
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
if (other is ContainerTypeMask &&
|
||||
elementType != null &&
|
||||
other.elementType != null) {
|
||||
TypeMask newElementType = elementType.union(other.elementType, domain);
|
||||
int newLength = (length == other.length) ? length : null;
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is ContainerTypeMask) {
|
||||
final newElementType = elementType.union(other.elementType, domain);
|
||||
final newLength = (length == other.length) ? length : null;
|
||||
final newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
return ContainerTypeMask(
|
||||
newForwardTo,
|
||||
allocationNode == other.allocationNode ? allocationNode : null,
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [DictionaryTypeMask] is a [TypeMask] for a specific allocation
|
||||
|
@ -20,25 +18,19 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
// The underlying key/value map of this dictionary.
|
||||
final Map<String, TypeMask> _typeMap;
|
||||
|
||||
const DictionaryTypeMask(
|
||||
TypeMask forwardTo,
|
||||
ir.Node allocationNode,
|
||||
MemberEntity allocationElement,
|
||||
TypeMask keyType,
|
||||
TypeMask valueType,
|
||||
this._typeMap)
|
||||
: super(forwardTo, allocationNode, allocationElement, keyType, valueType);
|
||||
const DictionaryTypeMask(super.forwardTo, super._allocationNode,
|
||||
super.allocationElement, super.keyType, super.valueType, this._typeMap);
|
||||
|
||||
/// Deserializes a [DictionaryTypeMask] object from [source].
|
||||
factory DictionaryTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask keyType = TypeMask.readFromDataSource(source, domain);
|
||||
TypeMask valueType = TypeMask.readFromDataSource(source, domain);
|
||||
Map<String, TypeMask> typeMap =
|
||||
source.readStringMap(() => TypeMask.readFromDataSource(source, domain));
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final keyType = TypeMask.readFromDataSource(source, domain);
|
||||
final valueType = TypeMask.readFromDataSource(source, domain);
|
||||
final typeMap = source
|
||||
.readStringMap(() => TypeMask.readFromDataSource(source, domain))!;
|
||||
source.end(tag);
|
||||
return DictionaryTypeMask(
|
||||
forwardTo, null, allocationElement, keyType, valueType, typeMap);
|
||||
|
@ -60,7 +52,7 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
DictionaryTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
DictionaryTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -82,13 +74,11 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
|
||||
bool containsKey(String key) => _typeMap.containsKey(key);
|
||||
|
||||
TypeMask getValueForKey(String key) => _typeMap[key];
|
||||
TypeMask? getValueForKey(String key) => _typeMap[key];
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is DictionaryTypeMask) {
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
TypeMask newKeyType = keyType.union(other.keyType, domain);
|
||||
|
@ -101,7 +91,7 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
});
|
||||
other._typeMap.forEach((k, v) {
|
||||
if (_typeMap.containsKey(k)) {
|
||||
mappings[k] = v.union(_typeMap[k], domain);
|
||||
mappings[k] = v.union(_typeMap[k]!, domain);
|
||||
} else {
|
||||
mappings[k] = v.nullable();
|
||||
}
|
||||
|
@ -109,9 +99,7 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
return DictionaryTypeMask(
|
||||
newForwardTo, null, null, newKeyType, newValueType, mappings);
|
||||
}
|
||||
if (other is MapTypeMask &&
|
||||
(other.keyType != null) &&
|
||||
(other.valueType != null)) {
|
||||
if (other is MapTypeMask) {
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
TypeMask newKeyType = keyType.union(other.keyType, domain);
|
||||
TypeMask newValueType = valueType.union(other.valueType, domain);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
enum _FlatTypeMaskKind { empty, exact, subclass, subtype }
|
||||
|
@ -24,7 +22,7 @@ class FlatTypeMask extends TypeMask {
|
|||
static const int _LATE_SENTINEL_MASK = 1 << _LATE_SENTINEL_INDEX;
|
||||
static const int _ALL_MASK = (1 << _USED_INDICES) - 1;
|
||||
|
||||
final ClassEntity base;
|
||||
final ClassEntity? base;
|
||||
final int flags;
|
||||
|
||||
static int _computeFlags(_FlatTypeMaskKind kind,
|
||||
|
@ -98,7 +96,7 @@ class FlatTypeMask extends TypeMask {
|
|||
/// Ensures that the generated mask is normalized, i.e., a call to
|
||||
/// [TypeMask.assertIsNormalized] with the factory's result returns `true`.
|
||||
factory FlatTypeMask.normalized(
|
||||
ClassEntity base, int flags, CommonMasks domain) {
|
||||
ClassEntity? base, int flags, CommonMasks domain) {
|
||||
bool isNullable = _hasNullableFlag(flags);
|
||||
bool hasLateSentinel = _hasLateSentinelFlag(flags);
|
||||
if (base == domain.commonElements.nullClass) {
|
||||
|
@ -109,14 +107,14 @@ class FlatTypeMask extends TypeMask {
|
|||
return FlatTypeMask._(base, flags);
|
||||
}
|
||||
if (kind == _FlatTypeMaskKind.subtype) {
|
||||
if (!domain._closedWorld.classHierarchy.hasAnyStrictSubtype(base) ||
|
||||
if (!domain._closedWorld.classHierarchy.hasAnyStrictSubtype(base!) ||
|
||||
domain._closedWorld.classHierarchy.hasOnlySubclasses(base)) {
|
||||
flags = _computeFlags(_FlatTypeMaskKind.subclass,
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
}
|
||||
if (kind == _FlatTypeMaskKind.subclass &&
|
||||
!domain._closedWorld.classHierarchy.hasAnyStrictSubclass(base)) {
|
||||
!domain._closedWorld.classHierarchy.hasAnyStrictSubclass(base!)) {
|
||||
flags = _computeFlags(_FlatTypeMaskKind.exact,
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
|
@ -127,7 +125,7 @@ class FlatTypeMask extends TypeMask {
|
|||
factory FlatTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
ClassEntity base = source.readClassOrNull();
|
||||
final base = source.readClassOrNull();
|
||||
int flags = source.readInt();
|
||||
source.end(tag);
|
||||
return domain.getCachedMask(base, flags, () => FlatTypeMask._(base, flags));
|
||||
|
@ -179,7 +177,7 @@ class FlatTypeMask extends TypeMask {
|
|||
bool get isSubtype => _kind == _FlatTypeMaskKind.subtype;
|
||||
|
||||
@override
|
||||
FlatTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
FlatTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
int newFlags = _computeFlags(_kind,
|
||||
isNullable: isNullable ?? this.isNullable,
|
||||
hasLateSentinel: hasLateSentinel ?? this.hasLateSentinel);
|
||||
|
@ -196,10 +194,10 @@ class FlatTypeMask extends TypeMask {
|
|||
} else if (isExact) {
|
||||
return false;
|
||||
} else if (isSubclass) {
|
||||
return closedWorld.classHierarchy.isSubclassOf(other, base);
|
||||
return closedWorld.classHierarchy.isSubclassOf(other, base!);
|
||||
} else {
|
||||
assert(isSubtype);
|
||||
return closedWorld.classHierarchy.isSubtypeOf(other, base);
|
||||
return closedWorld.classHierarchy.isSubtypeOf(other, base!);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,12 +241,12 @@ class FlatTypeMask extends TypeMask {
|
|||
if (other is! FlatTypeMask) return other.containsMask(this, closedWorld);
|
||||
// The other must be flat, so compare base and flags.
|
||||
FlatTypeMask flatOther = other;
|
||||
ClassEntity otherBase = flatOther.base;
|
||||
final otherBase = flatOther.base;
|
||||
// If other is exact, it only contains its base.
|
||||
// TODO(herhut): Get rid of _isSingleImplementationOf.
|
||||
if (flatOther.isExact) {
|
||||
return (isExact && base == otherBase) ||
|
||||
_isSingleImplementationOf(otherBase, closedWorld);
|
||||
_isSingleImplementationOf(otherBase!, closedWorld);
|
||||
}
|
||||
// If other is subclass, this has to be subclass, as well. Unless
|
||||
// flatOther.base covers all subtypes of this. Currently, we only
|
||||
|
@ -258,11 +256,11 @@ class FlatTypeMask extends TypeMask {
|
|||
if (flatOther.isSubclass) {
|
||||
if (isSubtype)
|
||||
return (otherBase == closedWorld.commonElements.objectClass);
|
||||
return closedWorld.classHierarchy.isSubclassOf(base, otherBase);
|
||||
return closedWorld.classHierarchy.isSubclassOf(base!, otherBase!);
|
||||
}
|
||||
assert(flatOther.isSubtype);
|
||||
// Check whether this TypeMask satisfies otherBase's interface.
|
||||
return satisfies(otherBase, closedWorld);
|
||||
return satisfies(otherBase!, closedWorld);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -309,19 +307,19 @@ class FlatTypeMask extends TypeMask {
|
|||
@override
|
||||
bool satisfies(ClassEntity cls, JClosedWorld closedWorld) {
|
||||
if (isEmptyOrFlagged) return false;
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(base, cls)) return true;
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(base!, cls)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
ClassEntity singleClass(JClosedWorld closedWorld) {
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld) {
|
||||
if (isEmptyOrFlagged) return null;
|
||||
if (isNullable) return null; // It is Null and some other class.
|
||||
if (hasLateSentinel) return null;
|
||||
if (isExact) {
|
||||
return base;
|
||||
} else if (isSubclass) {
|
||||
return closedWorld.classHierarchy.hasAnyStrictSubclass(base)
|
||||
return closedWorld.classHierarchy.hasAnyStrictSubclass(base!)
|
||||
? null
|
||||
: base;
|
||||
} else {
|
||||
|
@ -339,7 +337,6 @@ class FlatTypeMask extends TypeMask {
|
|||
@override
|
||||
TypeMask union(TypeMask other, CommonMasks domain) {
|
||||
JClosedWorld closedWorld = domain._closedWorld;
|
||||
assert(other != null);
|
||||
assert(TypeMask.assertIsNormalized(this, closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, closedWorld));
|
||||
if (other is! FlatTypeMask) return other.union(this, domain);
|
||||
|
@ -354,18 +351,21 @@ class FlatTypeMask extends TypeMask {
|
|||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
} else if (base == flatOther.base) {
|
||||
return unionSame(flatOther, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
|
||||
} else if (closedWorld.classHierarchy
|
||||
.isSubclassOf(flatOther.base!, base!)) {
|
||||
return unionStrictSubclass(flatOther, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
|
||||
} else if (closedWorld.classHierarchy
|
||||
.isSubclassOf(base!, flatOther.base!)) {
|
||||
return flatOther.unionStrictSubclass(this, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(flatOther.base, base)) {
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(flatOther.base!, base!)) {
|
||||
return unionStrictSubtype(flatOther, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(base, flatOther.base)) {
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(base!, flatOther.base!)) {
|
||||
return flatOther.unionStrictSubtype(this, domain);
|
||||
} else {
|
||||
return UnionTypeMask._internal(
|
||||
<FlatTypeMask>[withoutFlags(), flatOther.withoutFlags()],
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
return UnionTypeMask._internal([
|
||||
withoutFlags() as FlatTypeMask,
|
||||
flatOther.withoutFlags() as FlatTypeMask
|
||||
], isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,13 +384,13 @@ class FlatTypeMask extends TypeMask {
|
|||
} else if (other.flags == combined) {
|
||||
return other;
|
||||
} else {
|
||||
return FlatTypeMask.normalized(base, combined, domain);
|
||||
return FlatTypeMask.normalized(base!, combined, domain);
|
||||
}
|
||||
}
|
||||
|
||||
TypeMask unionStrictSubclass(FlatTypeMask other, CommonMasks domain) {
|
||||
assert(base != other.base);
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base!, base!));
|
||||
assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
|
||||
int combined;
|
||||
|
@ -417,8 +417,9 @@ class FlatTypeMask extends TypeMask {
|
|||
|
||||
TypeMask unionStrictSubtype(FlatTypeMask other, CommonMasks domain) {
|
||||
assert(base != other.base);
|
||||
assert(!domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
|
||||
assert(domain._closedWorld.classHierarchy.isSubtypeOf(other.base, base));
|
||||
assert(
|
||||
!domain._closedWorld.classHierarchy.isSubclassOf(other.base!, base!));
|
||||
assert(domain._closedWorld.classHierarchy.isSubtypeOf(other.base!, base!));
|
||||
assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
|
||||
// Since the other mask is a subtype of this mask, we need the
|
||||
|
@ -435,13 +436,12 @@ class FlatTypeMask extends TypeMask {
|
|||
|
||||
@override
|
||||
TypeMask intersection(TypeMask other, CommonMasks domain) {
|
||||
assert(other != null);
|
||||
if (other is! FlatTypeMask) return other.intersection(this, domain);
|
||||
assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
|
||||
FlatTypeMask flatOther = other;
|
||||
|
||||
ClassEntity otherBase = flatOther.base;
|
||||
final otherBase = flatOther.base;
|
||||
|
||||
bool includeNull = isNullable && flatOther.isNullable;
|
||||
bool includeLateSentinel = hasLateSentinel && flatOther.hasLateSentinel;
|
||||
|
@ -454,8 +454,8 @@ class FlatTypeMask extends TypeMask {
|
|||
isNullable: includeNull, hasLateSentinel: includeLateSentinel);
|
||||
}
|
||||
|
||||
SubclassResult result = domain._closedWorld.classHierarchy
|
||||
.commonSubclasses(base, _classQuery, otherBase, flatOther._classQuery);
|
||||
SubclassResult result = domain._closedWorld.classHierarchy.commonSubclasses(
|
||||
base!, _classQuery, otherBase!, flatOther._classQuery);
|
||||
|
||||
switch (result.kind) {
|
||||
case SubclassResultKind.EMPTY:
|
||||
|
@ -525,16 +525,18 @@ class FlatTypeMask extends TypeMask {
|
|||
if (base == flatOther.base) return false;
|
||||
if (isExact && flatOther.isExact) return true;
|
||||
|
||||
if (isExact) return !flatOther.contains(base, closedWorld);
|
||||
if (flatOther.isExact) return !contains(flatOther.base, closedWorld);
|
||||
if (isExact) return !flatOther.contains(base!, closedWorld);
|
||||
if (flatOther.isExact) return !contains(flatOther.base!, closedWorld);
|
||||
final thisBase = base!;
|
||||
final otherBase = flatOther.base!;
|
||||
|
||||
// Normalization guarantees that isExact === !isSubclass && !isSubtype.
|
||||
// Both are subclass or subtype masks, so if there is a subclass
|
||||
// relationship, they are not disjoint.
|
||||
if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(otherBase, thisBase)) {
|
||||
return false;
|
||||
}
|
||||
if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(thisBase, otherBase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -552,11 +554,14 @@ class FlatTypeMask extends TypeMask {
|
|||
}
|
||||
assert(a.isSubclass || a.isSubtype);
|
||||
assert(b.isSubtype);
|
||||
final aBase = a.base!;
|
||||
var elements = a.isSubclass
|
||||
? closedWorld.classHierarchy.strictSubclassesOf(a.base)
|
||||
: closedWorld.classHierarchy.strictSubtypesOf(a.base);
|
||||
? closedWorld.classHierarchy.strictSubclassesOf(aBase)
|
||||
: closedWorld.classHierarchy.strictSubtypesOf(aBase);
|
||||
for (var element in elements) {
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(element, b.base)) return false;
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(element, b.base!)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -581,7 +586,7 @@ class FlatTypeMask extends TypeMask {
|
|||
|
||||
TypeMask intersectionStrictSubclass(FlatTypeMask other, CommonMasks domain) {
|
||||
assert(base != other.base);
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base!, base!));
|
||||
// If this mask isn't at least a subclass mask, then the
|
||||
// intersection with the other mask is empty.
|
||||
if (isExact) return intersectionEmpty(other);
|
||||
|
@ -615,25 +620,26 @@ class FlatTypeMask extends TypeMask {
|
|||
closedWorld.hasElementIn(commonElements.jsNullClass, name, element);
|
||||
}
|
||||
|
||||
ClassEntity other = element.enclosingClass;
|
||||
final other = element.enclosingClass;
|
||||
final thisBase = base!;
|
||||
if (other == commonElements.jsNullClass) {
|
||||
return isNullable;
|
||||
} else if (isExact) {
|
||||
return closedWorld.hasElementIn(base, name, element);
|
||||
return closedWorld.hasElementIn(thisBase, name, element);
|
||||
} else if (isSubclass) {
|
||||
return closedWorld.hasElementIn(base, name, element) ||
|
||||
closedWorld.classHierarchy.isSubclassOf(other, base) ||
|
||||
closedWorld.hasAnySubclassThatMixes(base, other);
|
||||
return closedWorld.hasElementIn(thisBase, name, element) ||
|
||||
closedWorld.classHierarchy.isSubclassOf(other!, thisBase) ||
|
||||
closedWorld.hasAnySubclassThatMixes(thisBase, other);
|
||||
} else {
|
||||
assert(isSubtype);
|
||||
bool result = closedWorld.hasElementIn(base, name, element) ||
|
||||
closedWorld.classHierarchy.isSubtypeOf(other, base) ||
|
||||
closedWorld.hasAnySubclassThatImplements(other, base) ||
|
||||
closedWorld.hasAnySubclassOfMixinUseThatImplements(other, base);
|
||||
bool result = closedWorld.hasElementIn(thisBase, name, element) ||
|
||||
closedWorld.classHierarchy.isSubtypeOf(other!, thisBase) ||
|
||||
closedWorld.hasAnySubclassThatImplements(other, thisBase) ||
|
||||
closedWorld.hasAnySubclassOfMixinUseThatImplements(other, thisBase);
|
||||
if (result) return true;
|
||||
// If the class is used as a mixin, we have to check if the element
|
||||
// can be hit from any of the mixin applications.
|
||||
Iterable<ClassEntity> mixinUses = closedWorld.mixinUsesOf(base);
|
||||
Iterable<ClassEntity> mixinUses = closedWorld.mixinUsesOf(thisBase);
|
||||
return mixinUses.any((mixinApplication) =>
|
||||
closedWorld.hasElementIn(mixinApplication, name, element) ||
|
||||
closedWorld.classHierarchy.isSubclassOf(other, mixinApplication) ||
|
||||
|
@ -651,13 +657,14 @@ class FlatTypeMask extends TypeMask {
|
|||
// TODO(johnniwinther): A type mask cannot be abstract. Remove the need
|
||||
// for this noise (currently used for super-calls in inference and mirror
|
||||
// usage).
|
||||
if (isExact && base.isAbstract) return false;
|
||||
final thisBase = base!;
|
||||
if (isExact && thisBase.isAbstract) return false;
|
||||
|
||||
return closedWorld.needsNoSuchMethod(base, selector, _classQuery);
|
||||
return closedWorld.needsNoSuchMethod(thisBase, selector, _classQuery);
|
||||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
if (isEmptyOrFlagged) return null;
|
||||
JClosedWorld closedWorld = domain._closedWorld;
|
||||
if (closedWorld.includesClosureCallInDomain(selector, this, domain))
|
||||
|
@ -666,23 +673,26 @@ class FlatTypeMask extends TypeMask {
|
|||
closedWorld.locateMembersInDomain(selector, this, domain);
|
||||
if (targets.length != 1) return null;
|
||||
MemberEntity result = targets.first;
|
||||
ClassEntity enclosing = result.enclosingClass;
|
||||
final enclosing = result.enclosingClass!;
|
||||
final thisBase = base!;
|
||||
// We only return the found element if it is guaranteed to be implemented on
|
||||
// all classes in the receiver type [this]. It could be found only in a
|
||||
// subclass or in an inheritance-wise unrelated class in case of subtype
|
||||
// selectors.
|
||||
if (isSubtype) {
|
||||
// if (closedWorld.isUsedAsMixin(enclosing)) {
|
||||
if (closedWorld.everySubtypeIsSubclassOfOrMixinUseOf(base, enclosing)) {
|
||||
if (closedWorld.everySubtypeIsSubclassOfOrMixinUseOf(
|
||||
thisBase, enclosing)) {
|
||||
return result;
|
||||
}
|
||||
//}
|
||||
return null;
|
||||
} else {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(base, enclosing)) {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(thisBase, enclosing)) {
|
||||
return result;
|
||||
}
|
||||
if (closedWorld.isSubclassOfMixinUseOf(base, enclosing)) return result;
|
||||
if (closedWorld.isSubclassOfMixinUseOf(thisBase, enclosing))
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -707,9 +717,9 @@ class FlatTypeMask extends TypeMask {
|
|||
if (isEmpty) 'empty',
|
||||
if (isNullable) 'null',
|
||||
if (hasLateSentinel) 'sentinel',
|
||||
if (isExact) 'exact=${base.name}',
|
||||
if (isSubclass) 'subclass=${base.name}',
|
||||
if (isSubtype) 'subtype=${base.name}',
|
||||
if (isExact) 'exact=${base!.name}',
|
||||
if (isSubclass) 'subclass=${base!.name}',
|
||||
if (isSubtype) 'subtype=${base!.name}',
|
||||
], '|');
|
||||
buffer.write(']');
|
||||
return buffer.toString();
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A type mask that wraps another one, and delegates all its
|
||||
|
@ -79,7 +77,7 @@ abstract class ForwardingTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ClassEntity singleClass(JClosedWorld closedWorld) {
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld) {
|
||||
return forwardTo.singleClass(closedWorld);
|
||||
}
|
||||
|
||||
|
@ -103,8 +101,8 @@ abstract class ForwardingTypeMask extends TypeMask {
|
|||
forwardTo.union(other, domain);
|
||||
}
|
||||
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) =>
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) =>
|
||||
null;
|
||||
|
||||
@override
|
||||
|
@ -133,7 +131,7 @@ abstract class ForwardingTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
return forwardTo.locateSingleMember(selector, domain);
|
||||
}
|
||||
|
||||
|
@ -153,12 +151,11 @@ abstract class AllocationTypeMask extends ForwardingTypeMask {
|
|||
|
||||
// The [ir.Node] where this type mask was created. This value is not used
|
||||
// after type inference and therefore does not need to be serialized by
|
||||
// subclasses. Using it outside of type inference may cause an exception to be
|
||||
// thrown.
|
||||
ir.Node /*?*/ get allocationNode;
|
||||
// subclasses. It will always be null outside of the global inference phase.
|
||||
ir.Node? get allocationNode;
|
||||
|
||||
// The [Entity] where this type mask was created.
|
||||
MemberEntity get allocationElement;
|
||||
MemberEntity? get allocationElement;
|
||||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [MapTypeMask] is a [TypeMask] for a specific allocation
|
||||
|
@ -17,12 +15,12 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
@override
|
||||
final TypeMask forwardTo;
|
||||
|
||||
final ir.Node /*?*/ _allocationNode;
|
||||
final ir.Node? _allocationNode;
|
||||
@override
|
||||
ir.Node get allocationNode => _allocationNode /*!*/;
|
||||
ir.Node? get allocationNode => _allocationNode;
|
||||
|
||||
@override
|
||||
final MemberEntity allocationElement;
|
||||
final MemberEntity? allocationElement;
|
||||
|
||||
// The value type of this map.
|
||||
final TypeMask valueType;
|
||||
|
@ -37,10 +35,10 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
factory MapTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask keyType = TypeMask.readFromDataSource(source, domain);
|
||||
TypeMask valueType = TypeMask.readFromDataSource(source, domain);
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final keyType = TypeMask.readFromDataSource(source, domain);
|
||||
final valueType = TypeMask.readFromDataSource(source, domain);
|
||||
source.end(tag);
|
||||
return MapTypeMask(forwardTo, null, allocationElement, keyType, valueType);
|
||||
}
|
||||
|
@ -58,7 +56,7 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
MapTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
MapTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -78,15 +76,9 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
bool get isExact => true;
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
if (other is MapTypeMask &&
|
||||
keyType != null &&
|
||||
other.keyType != null &&
|
||||
valueType != null &&
|
||||
other.valueType != null) {
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is MapTypeMask) {
|
||||
TypeMask newKeyType = keyType.union(other.keyType, domain);
|
||||
TypeMask newValueType = valueType.union(other.valueType, domain);
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
library masks;
|
||||
|
||||
import 'package:kernel/ast.dart' as ir;
|
||||
|
@ -47,150 +45,121 @@ class CommonMasks implements AbstractValueDomain {
|
|||
CommonElements get commonElements => _closedWorld.commonElements;
|
||||
DartTypes get dartTypes => _closedWorld.dartTypes;
|
||||
|
||||
TypeMask _internalTopType;
|
||||
TypeMask _dynamicType;
|
||||
TypeMask _nonNullType;
|
||||
TypeMask _nullType;
|
||||
TypeMask _intType;
|
||||
TypeMask _uint32Type;
|
||||
TypeMask _uint31Type;
|
||||
TypeMask _positiveIntType;
|
||||
TypeMask _numNotIntType;
|
||||
TypeMask _numType;
|
||||
TypeMask _boolType;
|
||||
TypeMask _functionType;
|
||||
TypeMask _listType;
|
||||
TypeMask _constListType;
|
||||
TypeMask _fixedListType;
|
||||
TypeMask _growableListType;
|
||||
TypeMask _setType;
|
||||
TypeMask _constSetType;
|
||||
TypeMask _mapType;
|
||||
TypeMask _constMapType;
|
||||
TypeMask _stringType;
|
||||
TypeMask _typeType;
|
||||
TypeMask _syncStarIterableType;
|
||||
TypeMask _asyncFutureType;
|
||||
TypeMask _asyncStarStreamType;
|
||||
TypeMask _indexablePrimitiveType;
|
||||
TypeMask _readableArrayType;
|
||||
TypeMask _mutableArrayType;
|
||||
TypeMask _unmodifiableArrayType;
|
||||
TypeMask _interceptorType;
|
||||
|
||||
/// Cache of [FlatTypeMask]s grouped by the possible values of the
|
||||
/// `FlatTypeMask.flags` property.
|
||||
final List<Map<ClassEntity, TypeMask>> _canonicalizedTypeMasks = List.filled(
|
||||
final List<Map<ClassEntity, TypeMask>?> _canonicalizedTypeMasks = List.filled(
|
||||
_FlatTypeMaskKind.values.length << FlatTypeMask._USED_INDICES, null);
|
||||
|
||||
/// Return the cached mask for [base] with the given flags, or
|
||||
/// calls [createMask] to create the mask and cache it.
|
||||
TypeMask getCachedMask(ClassEntity base, int flags, TypeMask createMask()) {
|
||||
Map<ClassEntity, TypeMask> cachedMasks =
|
||||
_canonicalizedTypeMasks[flags] ??= <ClassEntity, TypeMask>{};
|
||||
return cachedMasks.putIfAbsent(base, createMask);
|
||||
T getCachedMask<T extends TypeMask>(
|
||||
ClassEntity? base, int flags, T createMask()) {
|
||||
// `null` is a valid base so we allow it as a key in the map.
|
||||
final Map<ClassEntity?, TypeMask> cachedMasks =
|
||||
_canonicalizedTypeMasks[flags] ??= {};
|
||||
return cachedMasks.putIfAbsent(base, createMask) as T;
|
||||
}
|
||||
|
||||
@override
|
||||
TypeMask get internalTopType => _internalTopType ??= TypeMask.subclass(
|
||||
late final TypeMask internalTopType = TypeMask.subclass(
|
||||
_closedWorld.commonElements.objectClass, _closedWorld,
|
||||
hasLateSentinel: true);
|
||||
|
||||
@override
|
||||
TypeMask get dynamicType => _dynamicType ??=
|
||||
late final TypeMask dynamicType =
|
||||
TypeMask.subclass(_closedWorld.commonElements.objectClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get nonNullType => _nonNullType ??= TypeMask.nonNullSubclass(
|
||||
late final TypeMask nonNullType = TypeMask.nonNullSubclass(
|
||||
_closedWorld.commonElements.objectClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get intType => _intType ??=
|
||||
late final TypeMask intType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsIntClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get uint32Type => _uint32Type ??=
|
||||
late final TypeMask uint32Type =
|
||||
TypeMask.nonNullSubclass(commonElements.jsUInt32Class, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get uint31Type => _uint31Type ??=
|
||||
late final TypeMask uint31Type =
|
||||
TypeMask.nonNullExact(commonElements.jsUInt31Class, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get positiveIntType => _positiveIntType ??=
|
||||
late final TypeMask positiveIntType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsPositiveIntClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get numNotIntType => _numNotIntType ??=
|
||||
late final TypeMask numNotIntType =
|
||||
TypeMask.nonNullExact(commonElements.jsNumNotIntClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get numType => _numType ??=
|
||||
late final TypeMask numType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsNumberClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get boolType => _boolType ??=
|
||||
late final TypeMask boolType =
|
||||
TypeMask.nonNullExact(commonElements.jsBoolClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get functionType => _functionType ??=
|
||||
late final TypeMask functionType =
|
||||
TypeMask.nonNullSubtype(commonElements.functionClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get listType => _listType ??=
|
||||
late final TypeMask listType =
|
||||
TypeMask.nonNullSubtype(commonElements.jsArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get constListType => _constListType ??= TypeMask.nonNullExact(
|
||||
late final TypeMask constListType = TypeMask.nonNullExact(
|
||||
commonElements.jsUnmodifiableArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get fixedListType => _fixedListType ??=
|
||||
late final TypeMask fixedListType =
|
||||
TypeMask.nonNullExact(commonElements.jsFixedArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get growableListType => _growableListType ??= TypeMask.nonNullExact(
|
||||
late final TypeMask growableListType = TypeMask.nonNullExact(
|
||||
commonElements.jsExtendableArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get setType => _setType ??=
|
||||
late final TypeMask setType =
|
||||
TypeMask.nonNullSubtype(commonElements.setLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get constSetType => _constSetType ??= TypeMask.nonNullSubtype(
|
||||
late final TypeMask constSetType = TypeMask.nonNullSubtype(
|
||||
commonElements.constSetLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get mapType => _mapType ??=
|
||||
late final TypeMask mapType =
|
||||
TypeMask.nonNullSubtype(commonElements.mapLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get constMapType => _constMapType ??= TypeMask.nonNullSubtype(
|
||||
late final TypeMask constMapType = TypeMask.nonNullSubtype(
|
||||
commonElements.constMapLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get stringType => _stringType ??=
|
||||
late final TypeMask stringType =
|
||||
TypeMask.nonNullExact(commonElements.jsStringClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get typeType => _typeType ??=
|
||||
late final TypeMask typeType =
|
||||
TypeMask.nonNullExact(commonElements.typeLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get syncStarIterableType => _syncStarIterableType ??=
|
||||
late final TypeMask syncStarIterableType =
|
||||
TypeMask.nonNullExact(commonElements.syncStarIterable, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get asyncFutureType => _asyncFutureType ??=
|
||||
late final TypeMask asyncFutureType =
|
||||
TypeMask.nonNullExact(commonElements.futureImplementation, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get asyncStarStreamType => _asyncStarStreamType ??=
|
||||
late final TypeMask asyncStarStreamType =
|
||||
TypeMask.nonNullExact(commonElements.controllerStream, _closedWorld);
|
||||
|
||||
// TODO(johnniwinther): Assert that the null type has been resolved.
|
||||
@override
|
||||
TypeMask get nullType => _nullType ??= TypeMask.empty();
|
||||
late final TypeMask nullType = TypeMask.empty();
|
||||
|
||||
@override
|
||||
TypeMask get lateSentinelType => TypeMask.nonNullEmpty(hasLateSentinel: true);
|
||||
|
@ -198,22 +167,20 @@ class CommonMasks implements AbstractValueDomain {
|
|||
@override
|
||||
TypeMask get emptyType => TypeMask.nonNullEmpty();
|
||||
|
||||
TypeMask get indexablePrimitiveType => _indexablePrimitiveType ??=
|
||||
late final TypeMask indexablePrimitiveType =
|
||||
TypeMask.nonNullSubtype(commonElements.jsIndexableClass, _closedWorld);
|
||||
|
||||
TypeMask get readableArrayType => _readableArrayType ??=
|
||||
late final TypeMask readableArrayType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get mutableArrayType =>
|
||||
_mutableArrayType ??= TypeMask.nonNullSubclass(
|
||||
commonElements.jsMutableArrayClass, _closedWorld);
|
||||
late final TypeMask mutableArrayType = TypeMask.nonNullSubclass(
|
||||
commonElements.jsMutableArrayClass, _closedWorld);
|
||||
|
||||
TypeMask get unmodifiableArrayType =>
|
||||
_unmodifiableArrayType ??= TypeMask.nonNullExact(
|
||||
commonElements.jsUnmodifiableArrayClass, _closedWorld);
|
||||
late final TypeMask unmodifiableArrayType = TypeMask.nonNullExact(
|
||||
commonElements.jsUnmodifiableArrayClass, _closedWorld);
|
||||
|
||||
TypeMask get interceptorType => _interceptorType ??=
|
||||
late final TypeMask interceptorType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsInterceptorClass, _closedWorld);
|
||||
|
||||
@override
|
||||
|
@ -222,11 +189,12 @@ class CommonMasks implements AbstractValueDomain {
|
|||
// class any user-defined class can implement. So we also check for the
|
||||
// interface `JavaScriptIndexingBehavior`.
|
||||
ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
|
||||
return AbstractBool.trueOrMaybe(typedDataClass != null &&
|
||||
return AbstractBool.trueOrMaybe(
|
||||
_closedWorld.classHierarchy.isInstantiated(typedDataClass) &&
|
||||
mask.satisfies(typedDataClass, _closedWorld) &&
|
||||
mask.satisfies(_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld));
|
||||
mask.satisfies(typedDataClass, _closedWorld) &&
|
||||
mask.satisfies(
|
||||
_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -236,14 +204,14 @@ class CommonMasks implements AbstractValueDomain {
|
|||
// TODO(herhut): Maybe cache the TypeMask for typedDataClass and
|
||||
// jsIndexingBehaviourInterface.
|
||||
ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
|
||||
return AbstractBool.maybeOrFalse(typedDataClass != null &&
|
||||
return AbstractBool.maybeOrFalse(
|
||||
_closedWorld.classHierarchy.isInstantiated(typedDataClass) &&
|
||||
intersects(mask, TypeMask.subtype(typedDataClass, _closedWorld)) &&
|
||||
intersects(
|
||||
mask,
|
||||
TypeMask.subtype(
|
||||
_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld)));
|
||||
intersects(mask, TypeMask.subtype(typedDataClass, _closedWorld)) &&
|
||||
intersects(
|
||||
mask,
|
||||
TypeMask.subtype(
|
||||
_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld)));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -273,9 +241,8 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValueWithPrecision createFromStaticType(DartType type,
|
||||
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
|
||||
assert(nullable != null);
|
||||
|
||||
{ClassRelation classRelation = ClassRelation.subtype,
|
||||
required bool nullable}) {
|
||||
if ((classRelation == ClassRelation.subtype ||
|
||||
classRelation == ClassRelation.thisExpression) &&
|
||||
dartTypes.isTopType(type)) {
|
||||
|
@ -311,8 +278,6 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
AbstractValueWithPrecision _createFromStaticType(
|
||||
DartType type, ClassRelation classRelation, bool nullable) {
|
||||
assert(nullable != null);
|
||||
|
||||
AbstractValueWithPrecision finish(TypeMask value, bool isPrecise) {
|
||||
return AbstractValueWithPrecision(
|
||||
nullable ? value.nullable() : value, isPrecise);
|
||||
|
@ -440,7 +405,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
@override
|
||||
AbstractBool isInstanceOf(
|
||||
covariant TypeMask expressionMask, ClassEntity cls) {
|
||||
AbstractValue typeMask = (cls == commonElements.nullClass)
|
||||
final typeMask = (cls == commonElements.nullClass)
|
||||
? nullType
|
||||
: createNonNullSubtype(cls);
|
||||
if (expressionMask.union(typeMask, this) == typeMask) {
|
||||
|
@ -461,7 +426,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
value.isExact && !value.isNullable && !value.hasLateSentinel);
|
||||
|
||||
@override
|
||||
ClassEntity getExactClass(TypeMask mask) {
|
||||
ClassEntity? getExactClass(TypeMask mask) {
|
||||
return mask.singleClass(_closedWorld);
|
||||
}
|
||||
|
||||
|
@ -469,7 +434,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
bool isPrimitiveValue(TypeMask value) => value is ValueTypeMask;
|
||||
|
||||
@override
|
||||
PrimitiveConstantValue getPrimitiveValue(TypeMask mask) {
|
||||
PrimitiveConstantValue? getPrimitiveValue(TypeMask mask) {
|
||||
if (mask is ValueTypeMask) {
|
||||
return mask.value;
|
||||
}
|
||||
|
@ -717,42 +682,35 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValue getMapValueType(AbstractValue value) {
|
||||
if (value is MapTypeMask) {
|
||||
// TODO(johnniwinther): Assert the `value.valueType` is not null.
|
||||
return value.valueType ?? dynamicType;
|
||||
}
|
||||
return dynamicType;
|
||||
return value is MapTypeMask ? value.valueType : dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getContainerElementType(AbstractValue value) {
|
||||
if (value is ContainerTypeMask) {
|
||||
return value.elementType ?? dynamicType;
|
||||
}
|
||||
return dynamicType;
|
||||
return value is ContainerTypeMask ? value.elementType : dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
int getContainerLength(AbstractValue value) {
|
||||
int? getContainerLength(AbstractValue value) {
|
||||
return value is ContainerTypeMask ? value.length : null;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createContainerValue(
|
||||
AbstractValue forwardTo,
|
||||
Object allocationNode,
|
||||
MemberEntity allocationElement,
|
||||
AbstractValue elementType,
|
||||
int length) {
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask elementType,
|
||||
int? length) {
|
||||
return ContainerTypeMask(
|
||||
forwardTo, allocationNode, allocationElement, elementType, length);
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue unionOfMany(Iterable<AbstractValue> values) {
|
||||
TypeMask result = TypeMask.nonNullEmpty();
|
||||
for (TypeMask value in values) {
|
||||
result = result.union(value, this);
|
||||
var result = TypeMask.nonNullEmpty();
|
||||
for (final value in values) {
|
||||
result = result.union(value as TypeMask, this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -763,7 +721,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
.hasAnyStrictSubclass(_closedWorld.commonElements.objectClass));
|
||||
return TypeMask.unionOf(
|
||||
members.expand((MemberEntity element) {
|
||||
ClassEntity cls = element.enclosingClass;
|
||||
final cls = element.enclosingClass!;
|
||||
return [cls]..addAll(_closedWorld.mixinUsesOf(cls));
|
||||
}).map((cls) {
|
||||
if (_closedWorld.commonElements.jsNullClass == cls) {
|
||||
|
@ -798,7 +756,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(
|
||||
MemberEntity? locateSingleMember(
|
||||
covariant TypeMask receiver, Selector selector) {
|
||||
return receiver.locateSingleMember(selector, this);
|
||||
}
|
||||
|
@ -878,42 +836,48 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValue getDictionaryValueForKey(AbstractValue value, String key) {
|
||||
if (value is DictionaryTypeMask) return value.getValueForKey(key);
|
||||
return dynamicType;
|
||||
final result =
|
||||
value is DictionaryTypeMask ? value.getValueForKey(key) : null;
|
||||
return result ?? dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createMapValue(AbstractValue forwardTo, Object allocationNode,
|
||||
MemberEntity allocationElement, AbstractValue key, AbstractValue value) {
|
||||
AbstractValue createMapValue(
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask key,
|
||||
covariant TypeMask value) {
|
||||
return MapTypeMask(
|
||||
forwardTo, allocationNode, allocationElement, key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createDictionaryValue(
|
||||
AbstractValue forwardTo,
|
||||
Object allocationNode,
|
||||
MemberEntity allocationElement,
|
||||
AbstractValue key,
|
||||
AbstractValue value,
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask key,
|
||||
covariant TypeMask value,
|
||||
Map<String, AbstractValue> mappings) {
|
||||
return DictionaryTypeMask(forwardTo, allocationNode, allocationElement, key,
|
||||
value, Map.from(mappings));
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createSetValue(AbstractValue forwardTo, Object allocationNode,
|
||||
MemberEntity allocationElement, AbstractValue elementType) {
|
||||
AbstractValue createSetValue(
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask elementType) {
|
||||
return SetTypeMask(
|
||||
forwardTo, allocationNode, allocationElement, elementType);
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getSetElementType(AbstractValue value) {
|
||||
if (value is SetTypeMask) {
|
||||
return value.elementType ?? dynamicType;
|
||||
}
|
||||
return dynamicType;
|
||||
final result = value is SetTypeMask ? value.elementType : null;
|
||||
return result ?? dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -924,31 +888,22 @@ class CommonMasks implements AbstractValueDomain {
|
|||
}
|
||||
|
||||
@override
|
||||
Object getAllocationNode(AbstractValue value) {
|
||||
if (value is AllocationTypeMask) {
|
||||
return value.allocationNode;
|
||||
}
|
||||
return null;
|
||||
Object? getAllocationNode(AbstractValue value) {
|
||||
return value is AllocationTypeMask ? value.allocationNode : null;
|
||||
}
|
||||
|
||||
@override
|
||||
MemberEntity getAllocationElement(AbstractValue value) {
|
||||
if (value is AllocationTypeMask) {
|
||||
return value.allocationElement;
|
||||
}
|
||||
return null;
|
||||
MemberEntity? getAllocationElement(AbstractValue value) {
|
||||
return value is AllocationTypeMask ? value.allocationElement : null;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getGeneralization(AbstractValue value) {
|
||||
if (value is AllocationTypeMask) {
|
||||
return value.forwardTo;
|
||||
}
|
||||
return null;
|
||||
AbstractValue? getGeneralization(AbstractValue value) {
|
||||
return value is AllocationTypeMask ? value.forwardTo : null;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getAbstractValueForNativeMethodParameterType(DartType type) {
|
||||
AbstractValue? getAbstractValueForNativeMethodParameterType(DartType type) {
|
||||
if (type is InterfaceType) {
|
||||
if (type.typeArguments.isNotEmpty) return null;
|
||||
// TODO(sra): Consider using a strengthened type check to avoid passing
|
||||
|
@ -962,7 +917,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
}
|
||||
|
||||
@override
|
||||
String getCompactText(AbstractValue value) {
|
||||
String getCompactText(covariant TypeMask value) {
|
||||
return formatType(dartTypes, value);
|
||||
}
|
||||
|
||||
|
@ -1005,7 +960,7 @@ String formatType(DartTypes dartTypes, TypeMask type) {
|
|||
? '+'
|
||||
: '*';
|
||||
String sentinelFlag = type.hasLateSentinel ? '\$' : '';
|
||||
return '${type.base.name}$nullFlag$subFlag$sentinelFlag';
|
||||
return '${type.base!.name}$nullFlag$subFlag$sentinelFlag';
|
||||
}
|
||||
if (type is UnionTypeMask) {
|
||||
return type.disjointMasks.map((m) => formatType(dartTypes, m)).join(' | ');
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [SetTypeMask] is a [TypeMask] for a specific allocation site of a set
|
||||
|
@ -17,12 +15,12 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
@override
|
||||
final TypeMask forwardTo;
|
||||
|
||||
final ir.Node /*?*/ _allocationNode;
|
||||
final ir.Node? _allocationNode;
|
||||
@override
|
||||
ir.Node get allocationNode => _allocationNode /*!*/;
|
||||
ir.Node? get allocationNode => _allocationNode;
|
||||
|
||||
@override
|
||||
final MemberEntity allocationElement;
|
||||
final MemberEntity? allocationElement;
|
||||
|
||||
// The element type of this set.
|
||||
final TypeMask elementType;
|
||||
|
@ -34,9 +32,9 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
factory SetTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask elementType = TypeMask.readFromDataSource(source, domain);
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final elementType = TypeMask.readFromDataSource(source, domain);
|
||||
source.end(tag);
|
||||
return SetTypeMask(forwardTo, null, allocationElement, elementType);
|
||||
}
|
||||
|
@ -53,7 +51,7 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
SetTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
SetTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -72,13 +70,9 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
bool get isExact => true;
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
if (other is SetTypeMask &&
|
||||
elementType != null &&
|
||||
other.elementType != null) {
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is SetTypeMask) {
|
||||
TypeMask newElementType = elementType.union(other.elementType, domain);
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
return SetTypeMask(newForwardTo, null, null, newElementType);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// An implementation of a [UniverseSelectorConstraints] that is consists if an
|
||||
|
@ -11,13 +9,13 @@ part of masks;
|
|||
/// be removed.
|
||||
class IncreasingTypeMaskSet extends UniverseSelectorConstraints {
|
||||
bool isAll = false;
|
||||
Set<TypeMask> _masks;
|
||||
Set<TypeMask>? _masks;
|
||||
|
||||
@override
|
||||
bool canHit(MemberEntity element, Name name, JClosedWorld world) {
|
||||
if (isAll) return true;
|
||||
if (_masks == null) return false;
|
||||
for (TypeMask mask in _masks) {
|
||||
for (TypeMask mask in _masks!) {
|
||||
if (mask.canHit(element, name, world)) return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -30,7 +28,7 @@ class IncreasingTypeMaskSet extends UniverseSelectorConstraints {
|
|||
TypeMask.subclass(world.commonElements.objectClass, world);
|
||||
return mask.needsNoSuchMethodHandling(selector, world);
|
||||
}
|
||||
for (TypeMask mask in _masks) {
|
||||
for (TypeMask mask in _masks!) {
|
||||
if (mask.needsNoSuchMethodHandling(selector, world)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -39,15 +37,14 @@ class IncreasingTypeMaskSet extends UniverseSelectorConstraints {
|
|||
}
|
||||
|
||||
@override
|
||||
bool addReceiverConstraint(TypeMask mask) {
|
||||
bool addReceiverConstraint(TypeMask? mask) {
|
||||
if (isAll) return false;
|
||||
if (mask == null) {
|
||||
isAll = true;
|
||||
_masks = null;
|
||||
return true;
|
||||
}
|
||||
_masks ??= {};
|
||||
return _masks.add(mask);
|
||||
return (_masks ??= {}).add(mask);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -81,7 +78,7 @@ class TypeMaskSelectorStrategy implements SelectorConstraintsStrategy {
|
|||
|
||||
@override
|
||||
UniverseSelectorConstraints createSelectorConstraints(
|
||||
Selector selector, Object initialConstraint) {
|
||||
Selector selector, covariant TypeMask? initialConstraint) {
|
||||
return IncreasingTypeMaskSet()..addReceiverConstraint(initialConstraint);
|
||||
}
|
||||
|
||||
|
@ -89,7 +86,7 @@ class TypeMaskSelectorStrategy implements SelectorConstraintsStrategy {
|
|||
bool appliedUnnamed(DynamicUse dynamicUse, MemberEntity member,
|
||||
covariant JClosedWorld world) {
|
||||
Selector selector = dynamicUse.selector;
|
||||
TypeMask mask = dynamicUse.receiverConstraint;
|
||||
final mask = dynamicUse.receiverConstraint as TypeMask?;
|
||||
return selector.appliesUnnamed(member) &&
|
||||
(mask == null || mask.canHit(member, selector.memberName, world));
|
||||
}
|
||||
|
@ -120,7 +117,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create exact type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
return FlatTypeMask.exact(base, closedWorld,
|
||||
|
@ -141,10 +138,10 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create subclass type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.empty(hasLateSentinel: hasLateSentinel);
|
||||
} else if (closedWorld.classHierarchy.hasAnyStrictSubclass(topmost)) {
|
||||
|
@ -158,7 +155,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
factory TypeMask.subtype(ClassEntity base, JClosedWorld closedWorld,
|
||||
{bool hasLateSentinel = false}) {
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.empty(hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
|
@ -183,7 +180,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create exact type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
return FlatTypeMask.nonNullExact(base, closedWorld,
|
||||
|
@ -205,10 +202,10 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create subclass type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.nonNullEmpty(hasLateSentinel: hasLateSentinel);
|
||||
} else if (closedWorld.classHierarchy.hasAnyStrictSubclass(topmost)) {
|
||||
|
@ -222,7 +219,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
factory TypeMask.nonNullSubtype(ClassEntity base, JClosedWorld closedWorld,
|
||||
{bool hasLateSentinel = false}) {
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.nonNullEmpty(hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
|
@ -263,7 +260,6 @@ abstract class TypeMask implements AbstractValue {
|
|||
case TypeMaskKind.value:
|
||||
return ValueTypeMask.readFromDataSource(source, domain);
|
||||
}
|
||||
throw UnsupportedError("Unexpected TypeMaskKind $kind.");
|
||||
}
|
||||
|
||||
/// Serializes this [TypeMask] to [sink].
|
||||
|
@ -273,7 +269,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
/// [mask]'s forwarding chain.
|
||||
static TypeMask nonForwardingMask(TypeMask mask) {
|
||||
while (mask is ForwardingTypeMask) {
|
||||
mask = (mask as ForwardingTypeMask).forwardTo;
|
||||
mask = mask.forwardTo;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
@ -284,13 +280,13 @@ abstract class TypeMask implements AbstractValue {
|
|||
/// subclasses exist. We also normalize exact to empty if the corresponding
|
||||
/// baseclass was never instantiated.
|
||||
static bool assertIsNormalized(TypeMask mask, JClosedWorld closedWorld) {
|
||||
String reason = getNotNormalizedReason(mask, closedWorld);
|
||||
final reason = getNotNormalizedReason(mask, closedWorld);
|
||||
assert(reason == null,
|
||||
failedAt(NO_LOCATION_SPANNABLE, '$mask is not normalized: $reason'));
|
||||
return true;
|
||||
}
|
||||
|
||||
static String getNotNormalizedReason(
|
||||
static String? getNotNormalizedReason(
|
||||
TypeMask mask, JClosedWorld closedWorld) {
|
||||
mask = nonForwardingMask(mask);
|
||||
if (mask is FlatTypeMask) {
|
||||
|
@ -299,28 +295,28 @@ abstract class TypeMask implements AbstractValue {
|
|||
return 'The class ${mask.base} is not canonicalized.';
|
||||
}
|
||||
if (mask.isExact) {
|
||||
if (!closedWorld.classHierarchy.isInstantiated(mask.base)) {
|
||||
if (!closedWorld.classHierarchy.isInstantiated(mask.base!)) {
|
||||
return 'Exact ${mask.base} is not instantiated.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (mask.isSubclass) {
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubclass(mask.base)) {
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubclass(mask.base!)) {
|
||||
return 'Subclass ${mask.base} does not have any subclasses.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
assert(mask.isSubtype);
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubtype(mask.base)) {
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubtype(mask.base!)) {
|
||||
return 'Subtype ${mask.base} does not have any subclasses.';
|
||||
}
|
||||
if (closedWorld.classHierarchy.hasOnlySubclasses(mask.base)) {
|
||||
if (closedWorld.classHierarchy.hasOnlySubclasses(mask.base!)) {
|
||||
return 'Subtype ${mask.base} only has subclasses.';
|
||||
}
|
||||
return null;
|
||||
} else if (mask is UnionTypeMask) {
|
||||
for (TypeMask submask in mask.disjointMasks) {
|
||||
String submaskReason = getNotNormalizedReason(submask, closedWorld);
|
||||
final submaskReason = getNotNormalizedReason(submask, closedWorld);
|
||||
if (submaskReason != null) {
|
||||
return 'Submask $submask in $mask: $submaskReason.';
|
||||
}
|
||||
|
@ -341,7 +337,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
TypeMask withoutFlags() =>
|
||||
withFlags(isNullable: false, hasLateSentinel: false);
|
||||
|
||||
TypeMask withFlags({bool isNullable, bool hasLateSentinel});
|
||||
TypeMask withFlags({bool? isNullable, bool? hasLateSentinel});
|
||||
|
||||
/// Whether nothing matches this mask, not even null.
|
||||
bool get isEmpty;
|
||||
|
@ -402,7 +398,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
/// Returns the [ClassEntity] if this type represents a single class,
|
||||
/// otherwise returns `null`. This method is conservative.
|
||||
ClassEntity singleClass(JClosedWorld closedWorld);
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld);
|
||||
|
||||
/// Returns a type mask representing the union of [this] and [other].
|
||||
TypeMask union(TypeMask other, CommonMasks domain);
|
||||
|
@ -426,5 +422,5 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
/// Returns the [element] that is known to always be hit at runtime
|
||||
/// on this mask. Returns null if there is none.
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain);
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
class UnionTypeMask extends TypeMask {
|
||||
|
@ -31,10 +29,8 @@ class UnionTypeMask extends TypeMask {
|
|||
AbstractBool get isLateSentinel => AbstractBool.maybeOrFalse(hasLateSentinel);
|
||||
|
||||
UnionTypeMask._internal(this.disjointMasks,
|
||||
{this.isNullable, this.hasLateSentinel})
|
||||
: assert(isNullable != null),
|
||||
assert(hasLateSentinel != null),
|
||||
assert(disjointMasks.length > 1),
|
||||
{required this.isNullable, required this.hasLateSentinel})
|
||||
: assert(disjointMasks.length > 1),
|
||||
assert(disjointMasks.every((TypeMask mask) => mask is! UnionTypeMask)),
|
||||
assert(disjointMasks.every((TypeMask mask) => !mask.isNullable)),
|
||||
assert(disjointMasks.every((TypeMask mask) => !mask.hasLateSentinel));
|
||||
|
@ -43,8 +39,8 @@ class UnionTypeMask extends TypeMask {
|
|||
factory UnionTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
List<FlatTypeMask> disjointMasks =
|
||||
source.readList(() => TypeMask.readFromDataSource(source, domain));
|
||||
List<FlatTypeMask> disjointMasks = source.readList(
|
||||
() => TypeMask.readFromDataSource(source, domain) as FlatTypeMask);
|
||||
bool isNullable = source.readBool();
|
||||
bool hasLateSentinel = source.readBool();
|
||||
source.end(tag);
|
||||
|
@ -99,7 +95,7 @@ class UnionTypeMask extends TypeMask {
|
|||
} else if (mask.isEmpty) {
|
||||
continue;
|
||||
} else {
|
||||
FlatTypeMask flatMask = mask;
|
||||
var flatMask = mask as FlatTypeMask;
|
||||
int inListIndex = -1;
|
||||
bool covered = false;
|
||||
|
||||
|
@ -107,10 +103,10 @@ class UnionTypeMask extends TypeMask {
|
|||
// already covers [mask].
|
||||
for (int i = 0; i < disjoint.length; i++) {
|
||||
FlatTypeMask current = disjoint[i];
|
||||
if (current == null) continue;
|
||||
TypeMask newMask = flatMask.union(current, domain);
|
||||
// If we have found a disjoint union, continue iterating.
|
||||
if (newMask is UnionTypeMask) continue;
|
||||
newMask as FlatTypeMask;
|
||||
covered = true;
|
||||
// We found a mask that is either equal to [mask] or is a
|
||||
// supertype of [mask].
|
||||
|
@ -141,10 +137,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
static TypeMask flatten(List<FlatTypeMask> masks, CommonMasks domain,
|
||||
{bool includeNull, bool includeLateSentinel}) {
|
||||
assert(includeNull != null);
|
||||
assert(includeLateSentinel != null);
|
||||
|
||||
{required bool includeNull, required bool includeLateSentinel}) {
|
||||
// TODO(johnniwinther): Move this computation to [ClosedWorld] and use the
|
||||
// class set structures.
|
||||
if (masks.isEmpty) throw ArgumentError.value(masks, 'masks');
|
||||
|
@ -152,14 +145,14 @@ class UnionTypeMask extends TypeMask {
|
|||
// subclass type mask to represent their union.
|
||||
bool useSubclass = masks.every((e) => !e.isSubtype);
|
||||
|
||||
List<ClassEntity> masksBases = masks.map((mask) => mask.base).toList();
|
||||
final masksBases = masks.map((mask) => mask.base!).toList();
|
||||
Iterable<ClassEntity> candidates =
|
||||
domain._closedWorld.commonSupertypesOf(masksBases);
|
||||
|
||||
// Compute the best candidate and its kind.
|
||||
ClassEntity bestElement;
|
||||
_FlatTypeMaskKind bestKind;
|
||||
int bestSize;
|
||||
ClassEntity? bestElement;
|
||||
late _FlatTypeMaskKind bestKind;
|
||||
late int bestSize;
|
||||
for (ClassEntity candidate in candidates) {
|
||||
bool isInstantiatedStrictSubclass(cls) =>
|
||||
cls != candidate &&
|
||||
|
@ -194,7 +187,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
int flags = FlatTypeMask._computeFlags(bestKind,
|
||||
isNullable: includeNull, hasLateSentinel: includeLateSentinel);
|
||||
return FlatTypeMask.normalized(bestElement, flags, domain);
|
||||
return FlatTypeMask.normalized(bestElement!, flags, domain);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -222,7 +215,7 @@ class UnionTypeMask extends TypeMask {
|
|||
if (other is UnionTypeMask) {
|
||||
newList.addAll(other.disjointMasks);
|
||||
} else {
|
||||
newList.add(other);
|
||||
newList.add(other as FlatTypeMask);
|
||||
}
|
||||
TypeMask newMask = TypeMask.unionOf(newList, domain);
|
||||
return newMask.withFlags(
|
||||
|
@ -280,7 +273,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
UnionTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
UnionTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -324,16 +317,16 @@ class UnionTypeMask extends TypeMask {
|
|||
if (other.contains(closedWorld.commonElements.objectClass, closedWorld)) {
|
||||
return false;
|
||||
}
|
||||
FlatTypeMask flat = TypeMask.nonForwardingMask(other);
|
||||
final flat = TypeMask.nonForwardingMask(other) as FlatTypeMask;
|
||||
// Check we cover the base class.
|
||||
if (!contains(flat.base, closedWorld)) return false;
|
||||
if (!contains(flat.base!, closedWorld)) return false;
|
||||
// Check for other members.
|
||||
Iterable<ClassEntity> members;
|
||||
if (flat.isSubclass) {
|
||||
members = closedWorld.classHierarchy.strictSubclassesOf(flat.base);
|
||||
members = closedWorld.classHierarchy.strictSubclassesOf(flat.base!);
|
||||
} else {
|
||||
assert(flat.isSubtype);
|
||||
members = closedWorld.classHierarchy.strictSubtypesOf(flat.base);
|
||||
members = closedWorld.classHierarchy.strictSubtypesOf(flat.base!);
|
||||
}
|
||||
return members.every((ClassEntity cls) => this.contains(cls, closedWorld));
|
||||
}
|
||||
|
@ -344,7 +337,7 @@ class UnionTypeMask extends TypeMask {
|
|||
if (isNullable && !other.isNullable) return false;
|
||||
if (hasLateSentinel && !other.hasLateSentinel) return false;
|
||||
if (other is UnionTypeMask) {
|
||||
final union = other as UnionTypeMask;
|
||||
final union = other;
|
||||
return disjointMasks.every((FlatTypeMask disjointMask) {
|
||||
bool contained = union.disjointMasks.any((FlatTypeMask other) =>
|
||||
other.containsMask(disjointMask, closedWorld));
|
||||
|
@ -419,7 +412,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ClassEntity singleClass(JClosedWorld closedWorld) => null;
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld) => null;
|
||||
|
||||
@override
|
||||
bool needsNoSuchMethodHandling(Selector selector, JClosedWorld closedWorld) {
|
||||
|
@ -439,12 +432,12 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity candidate;
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity? candidate;
|
||||
for (FlatTypeMask mask in disjointMasks) {
|
||||
mask = mask.withFlags(
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
MemberEntity current = mask.locateSingleMember(selector, domain);
|
||||
final current = mask.locateSingleMember(selector, domain);
|
||||
if (current == null) {
|
||||
return null;
|
||||
} else if (candidate == null) {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
class ValueTypeMask extends ForwardingTypeMask {
|
||||
|
@ -22,7 +20,7 @@ class ValueTypeMask extends ForwardingTypeMask {
|
|||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
ConstantValue constant = source.readConstant();
|
||||
final constant = source.readConstant() as PrimitiveConstantValue;
|
||||
source.end(tag);
|
||||
return ValueTypeMask(forwardTo, constant);
|
||||
}
|
||||
|
@ -38,7 +36,7 @@ class ValueTypeMask extends ForwardingTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ValueTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
ValueTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -52,10 +50,8 @@ class ValueTypeMask extends ForwardingTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is ValueTypeMask &&
|
||||
forwardTo.withoutFlags() == other.forwardTo.withoutFlags() &&
|
||||
value == other.value) {
|
||||
|
|
|
@ -491,7 +491,8 @@ class WrappedAbstractValueDomain implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValueWithPrecision createFromStaticType(DartType type,
|
||||
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
|
||||
{ClassRelation classRelation = ClassRelation.subtype,
|
||||
/* required */ bool nullable}) {
|
||||
var unwrapped = _abstractValueDomain.createFromStaticType(type,
|
||||
classRelation: classRelation, nullable: nullable);
|
||||
return AbstractValueWithPrecision(
|
||||
|
|
|
@ -363,7 +363,8 @@ class TrivialAbstractValueDomain implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValueWithPrecision createFromStaticType(DartType type,
|
||||
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
|
||||
{ClassRelation classRelation = ClassRelation.subtype,
|
||||
/* required */ bool nullable}) {
|
||||
assert(nullable != null);
|
||||
return const AbstractValueWithPrecision(TrivialAbstractValue(), false);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
library types.constants;
|
||||
|
||||
import '../../constants/constant_system.dart' as constant_system;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [TypeMask] for a specific allocation site of a container (currently only
|
||||
|
@ -17,18 +15,18 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
@override
|
||||
final TypeMask forwardTo;
|
||||
|
||||
final ir.Node /*?*/ _allocationNode;
|
||||
final ir.Node? _allocationNode;
|
||||
@override
|
||||
ir.Node get allocationNode => _allocationNode /*!*/;
|
||||
ir.Node? get allocationNode => _allocationNode;
|
||||
|
||||
@override
|
||||
final MemberEntity allocationElement;
|
||||
final MemberEntity? allocationElement;
|
||||
|
||||
// The element type of this container.
|
||||
final TypeMask elementType;
|
||||
|
||||
// The length of the container.
|
||||
final int length;
|
||||
final int? length;
|
||||
|
||||
const ContainerTypeMask(this.forwardTo, this._allocationNode,
|
||||
this.allocationElement, this.elementType, this.length);
|
||||
|
@ -37,10 +35,10 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
factory ContainerTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask elementType = TypeMask.readFromDataSource(source, domain);
|
||||
int length = source.readIntOrNull();
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final elementType = TypeMask.readFromDataSource(source, domain);
|
||||
final length = source.readIntOrNull();
|
||||
source.end(tag);
|
||||
return ContainerTypeMask(
|
||||
forwardTo, null, allocationElement, elementType, length);
|
||||
|
@ -59,7 +57,7 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ContainerTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
ContainerTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -79,16 +77,12 @@ class ContainerTypeMask extends AllocationTypeMask {
|
|||
bool get isExact => true;
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
if (other is ContainerTypeMask &&
|
||||
elementType != null &&
|
||||
other.elementType != null) {
|
||||
TypeMask newElementType = elementType.union(other.elementType, domain);
|
||||
int newLength = (length == other.length) ? length : null;
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is ContainerTypeMask) {
|
||||
final newElementType = elementType.union(other.elementType, domain);
|
||||
final newLength = (length == other.length) ? length : null;
|
||||
final newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
return ContainerTypeMask(
|
||||
newForwardTo,
|
||||
allocationNode == other.allocationNode ? allocationNode : null,
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [DictionaryTypeMask] is a [TypeMask] for a specific allocation
|
||||
|
@ -20,25 +18,19 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
// The underlying key/value map of this dictionary.
|
||||
final Map<String, TypeMask> _typeMap;
|
||||
|
||||
const DictionaryTypeMask(
|
||||
TypeMask forwardTo,
|
||||
ir.Node allocationNode,
|
||||
MemberEntity allocationElement,
|
||||
TypeMask keyType,
|
||||
TypeMask valueType,
|
||||
this._typeMap)
|
||||
: super(forwardTo, allocationNode, allocationElement, keyType, valueType);
|
||||
const DictionaryTypeMask(super.forwardTo, super._allocationNode,
|
||||
super.allocationElement, super.keyType, super.valueType, this._typeMap);
|
||||
|
||||
/// Deserializes a [DictionaryTypeMask] object from [source].
|
||||
factory DictionaryTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask keyType = TypeMask.readFromDataSource(source, domain);
|
||||
TypeMask valueType = TypeMask.readFromDataSource(source, domain);
|
||||
Map<String, TypeMask> typeMap =
|
||||
source.readStringMap(() => TypeMask.readFromDataSource(source, domain));
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final keyType = TypeMask.readFromDataSource(source, domain);
|
||||
final valueType = TypeMask.readFromDataSource(source, domain);
|
||||
final typeMap = source
|
||||
.readStringMap(() => TypeMask.readFromDataSource(source, domain))!;
|
||||
source.end(tag);
|
||||
return DictionaryTypeMask(
|
||||
forwardTo, null, allocationElement, keyType, valueType, typeMap);
|
||||
|
@ -60,7 +52,7 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
DictionaryTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
DictionaryTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -82,13 +74,11 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
|
||||
bool containsKey(String key) => _typeMap.containsKey(key);
|
||||
|
||||
TypeMask getValueForKey(String key) => _typeMap[key];
|
||||
TypeMask? getValueForKey(String key) => _typeMap[key];
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is DictionaryTypeMask) {
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
TypeMask newKeyType = keyType.union(other.keyType, domain);
|
||||
|
@ -101,7 +91,7 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
});
|
||||
other._typeMap.forEach((k, v) {
|
||||
if (_typeMap.containsKey(k)) {
|
||||
mappings[k] = v.union(_typeMap[k], domain);
|
||||
mappings[k] = v.union(_typeMap[k]!, domain);
|
||||
} else {
|
||||
mappings[k] = v.nullable();
|
||||
}
|
||||
|
@ -109,9 +99,7 @@ class DictionaryTypeMask extends MapTypeMask {
|
|||
return DictionaryTypeMask(
|
||||
newForwardTo, null, null, newKeyType, newValueType, mappings);
|
||||
}
|
||||
if (other is MapTypeMask &&
|
||||
(other.keyType != null) &&
|
||||
(other.valueType != null)) {
|
||||
if (other is MapTypeMask) {
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
TypeMask newKeyType = keyType.union(other.keyType, domain);
|
||||
TypeMask newValueType = valueType.union(other.valueType, domain);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
enum _FlatTypeMaskKind { empty, exact, subclass, subtype }
|
||||
|
@ -24,7 +22,7 @@ class FlatTypeMask extends TypeMask {
|
|||
static const int _LATE_SENTINEL_MASK = 1 << _LATE_SENTINEL_INDEX;
|
||||
static const int _ALL_MASK = (1 << _USED_INDICES) - 1;
|
||||
|
||||
final ClassEntity base;
|
||||
final ClassEntity? base;
|
||||
final int flags;
|
||||
|
||||
static int _computeFlags(_FlatTypeMaskKind kind,
|
||||
|
@ -98,7 +96,7 @@ class FlatTypeMask extends TypeMask {
|
|||
/// Ensures that the generated mask is normalized, i.e., a call to
|
||||
/// [TypeMask.assertIsNormalized] with the factory's result returns `true`.
|
||||
factory FlatTypeMask.normalized(
|
||||
ClassEntity base, int flags, CommonMasks domain) {
|
||||
ClassEntity? base, int flags, CommonMasks domain) {
|
||||
bool isNullable = _hasNullableFlag(flags);
|
||||
bool hasLateSentinel = _hasLateSentinelFlag(flags);
|
||||
if (base == domain.commonElements.nullClass) {
|
||||
|
@ -109,14 +107,14 @@ class FlatTypeMask extends TypeMask {
|
|||
return FlatTypeMask._(base, flags);
|
||||
}
|
||||
if (kind == _FlatTypeMaskKind.subtype) {
|
||||
if (!domain._closedWorld.classHierarchy.hasAnyStrictSubtype(base) ||
|
||||
if (!domain._closedWorld.classHierarchy.hasAnyStrictSubtype(base!) ||
|
||||
domain._closedWorld.classHierarchy.hasOnlySubclasses(base)) {
|
||||
flags = _computeFlags(_FlatTypeMaskKind.subclass,
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
}
|
||||
if (kind == _FlatTypeMaskKind.subclass &&
|
||||
!domain._closedWorld.classHierarchy.hasAnyStrictSubclass(base)) {
|
||||
!domain._closedWorld.classHierarchy.hasAnyStrictSubclass(base!)) {
|
||||
flags = _computeFlags(_FlatTypeMaskKind.exact,
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
|
@ -127,7 +125,7 @@ class FlatTypeMask extends TypeMask {
|
|||
factory FlatTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
ClassEntity base = source.readClassOrNull();
|
||||
final base = source.readClassOrNull();
|
||||
int flags = source.readInt();
|
||||
source.end(tag);
|
||||
return domain.getCachedMask(base, flags, () => FlatTypeMask._(base, flags));
|
||||
|
@ -179,7 +177,7 @@ class FlatTypeMask extends TypeMask {
|
|||
bool get isSubtype => _kind == _FlatTypeMaskKind.subtype;
|
||||
|
||||
@override
|
||||
FlatTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
FlatTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
int newFlags = _computeFlags(_kind,
|
||||
isNullable: isNullable ?? this.isNullable,
|
||||
hasLateSentinel: hasLateSentinel ?? this.hasLateSentinel);
|
||||
|
@ -196,10 +194,10 @@ class FlatTypeMask extends TypeMask {
|
|||
} else if (isExact) {
|
||||
return false;
|
||||
} else if (isSubclass) {
|
||||
return closedWorld.classHierarchy.isSubclassOf(other, base);
|
||||
return closedWorld.classHierarchy.isSubclassOf(other, base!);
|
||||
} else {
|
||||
assert(isSubtype);
|
||||
return closedWorld.classHierarchy.isSubtypeOf(other, base);
|
||||
return closedWorld.classHierarchy.isSubtypeOf(other, base!);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,12 +241,12 @@ class FlatTypeMask extends TypeMask {
|
|||
if (other is! FlatTypeMask) return other.containsMask(this, closedWorld);
|
||||
// The other must be flat, so compare base and flags.
|
||||
FlatTypeMask flatOther = other;
|
||||
ClassEntity otherBase = flatOther.base;
|
||||
final otherBase = flatOther.base;
|
||||
// If other is exact, it only contains its base.
|
||||
// TODO(herhut): Get rid of _isSingleImplementationOf.
|
||||
if (flatOther.isExact) {
|
||||
return (isExact && base == otherBase) ||
|
||||
_isSingleImplementationOf(otherBase, closedWorld);
|
||||
_isSingleImplementationOf(otherBase!, closedWorld);
|
||||
}
|
||||
// If other is subclass, this has to be subclass, as well. Unless
|
||||
// flatOther.base covers all subtypes of this. Currently, we only
|
||||
|
@ -258,11 +256,11 @@ class FlatTypeMask extends TypeMask {
|
|||
if (flatOther.isSubclass) {
|
||||
if (isSubtype)
|
||||
return (otherBase == closedWorld.commonElements.objectClass);
|
||||
return closedWorld.classHierarchy.isSubclassOf(base, otherBase);
|
||||
return closedWorld.classHierarchy.isSubclassOf(base!, otherBase!);
|
||||
}
|
||||
assert(flatOther.isSubtype);
|
||||
// Check whether this TypeMask satisfies otherBase's interface.
|
||||
return satisfies(otherBase, closedWorld);
|
||||
return satisfies(otherBase!, closedWorld);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -309,19 +307,19 @@ class FlatTypeMask extends TypeMask {
|
|||
@override
|
||||
bool satisfies(ClassEntity cls, JClosedWorld closedWorld) {
|
||||
if (isEmptyOrFlagged) return false;
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(base, cls)) return true;
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(base!, cls)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
ClassEntity singleClass(JClosedWorld closedWorld) {
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld) {
|
||||
if (isEmptyOrFlagged) return null;
|
||||
if (isNullable) return null; // It is Null and some other class.
|
||||
if (hasLateSentinel) return null;
|
||||
if (isExact) {
|
||||
return base;
|
||||
} else if (isSubclass) {
|
||||
return closedWorld.classHierarchy.hasAnyStrictSubclass(base)
|
||||
return closedWorld.classHierarchy.hasAnyStrictSubclass(base!)
|
||||
? null
|
||||
: base;
|
||||
} else {
|
||||
|
@ -339,7 +337,6 @@ class FlatTypeMask extends TypeMask {
|
|||
@override
|
||||
TypeMask union(TypeMask other, CommonMasks domain) {
|
||||
JClosedWorld closedWorld = domain._closedWorld;
|
||||
assert(other != null);
|
||||
assert(TypeMask.assertIsNormalized(this, closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, closedWorld));
|
||||
if (other is! FlatTypeMask) return other.union(this, domain);
|
||||
|
@ -354,18 +351,21 @@ class FlatTypeMask extends TypeMask {
|
|||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
} else if (base == flatOther.base) {
|
||||
return unionSame(flatOther, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
|
||||
} else if (closedWorld.classHierarchy
|
||||
.isSubclassOf(flatOther.base!, base!)) {
|
||||
return unionStrictSubclass(flatOther, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
|
||||
} else if (closedWorld.classHierarchy
|
||||
.isSubclassOf(base!, flatOther.base!)) {
|
||||
return flatOther.unionStrictSubclass(this, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(flatOther.base, base)) {
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(flatOther.base!, base!)) {
|
||||
return unionStrictSubtype(flatOther, domain);
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(base, flatOther.base)) {
|
||||
} else if (closedWorld.classHierarchy.isSubtypeOf(base!, flatOther.base!)) {
|
||||
return flatOther.unionStrictSubtype(this, domain);
|
||||
} else {
|
||||
return UnionTypeMask._internal(
|
||||
<FlatTypeMask>[withoutFlags(), flatOther.withoutFlags()],
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
return UnionTypeMask._internal([
|
||||
withoutFlags() as FlatTypeMask,
|
||||
flatOther.withoutFlags() as FlatTypeMask
|
||||
], isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,13 +384,13 @@ class FlatTypeMask extends TypeMask {
|
|||
} else if (other.flags == combined) {
|
||||
return other;
|
||||
} else {
|
||||
return FlatTypeMask.normalized(base, combined, domain);
|
||||
return FlatTypeMask.normalized(base!, combined, domain);
|
||||
}
|
||||
}
|
||||
|
||||
TypeMask unionStrictSubclass(FlatTypeMask other, CommonMasks domain) {
|
||||
assert(base != other.base);
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base!, base!));
|
||||
assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
|
||||
int combined;
|
||||
|
@ -417,8 +417,9 @@ class FlatTypeMask extends TypeMask {
|
|||
|
||||
TypeMask unionStrictSubtype(FlatTypeMask other, CommonMasks domain) {
|
||||
assert(base != other.base);
|
||||
assert(!domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
|
||||
assert(domain._closedWorld.classHierarchy.isSubtypeOf(other.base, base));
|
||||
assert(
|
||||
!domain._closedWorld.classHierarchy.isSubclassOf(other.base!, base!));
|
||||
assert(domain._closedWorld.classHierarchy.isSubtypeOf(other.base!, base!));
|
||||
assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
|
||||
// Since the other mask is a subtype of this mask, we need the
|
||||
|
@ -435,13 +436,12 @@ class FlatTypeMask extends TypeMask {
|
|||
|
||||
@override
|
||||
TypeMask intersection(TypeMask other, CommonMasks domain) {
|
||||
assert(other != null);
|
||||
if (other is! FlatTypeMask) return other.intersection(this, domain);
|
||||
assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
|
||||
assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
|
||||
FlatTypeMask flatOther = other;
|
||||
|
||||
ClassEntity otherBase = flatOther.base;
|
||||
final otherBase = flatOther.base;
|
||||
|
||||
bool includeNull = isNullable && flatOther.isNullable;
|
||||
bool includeLateSentinel = hasLateSentinel && flatOther.hasLateSentinel;
|
||||
|
@ -454,8 +454,8 @@ class FlatTypeMask extends TypeMask {
|
|||
isNullable: includeNull, hasLateSentinel: includeLateSentinel);
|
||||
}
|
||||
|
||||
SubclassResult result = domain._closedWorld.classHierarchy
|
||||
.commonSubclasses(base, _classQuery, otherBase, flatOther._classQuery);
|
||||
SubclassResult result = domain._closedWorld.classHierarchy.commonSubclasses(
|
||||
base!, _classQuery, otherBase!, flatOther._classQuery);
|
||||
|
||||
switch (result.kind) {
|
||||
case SubclassResultKind.EMPTY:
|
||||
|
@ -525,16 +525,18 @@ class FlatTypeMask extends TypeMask {
|
|||
if (base == flatOther.base) return false;
|
||||
if (isExact && flatOther.isExact) return true;
|
||||
|
||||
if (isExact) return !flatOther.contains(base, closedWorld);
|
||||
if (flatOther.isExact) return !contains(flatOther.base, closedWorld);
|
||||
if (isExact) return !flatOther.contains(base!, closedWorld);
|
||||
if (flatOther.isExact) return !contains(flatOther.base!, closedWorld);
|
||||
final thisBase = base!;
|
||||
final otherBase = flatOther.base!;
|
||||
|
||||
// Normalization guarantees that isExact === !isSubclass && !isSubtype.
|
||||
// Both are subclass or subtype masks, so if there is a subclass
|
||||
// relationship, they are not disjoint.
|
||||
if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(otherBase, thisBase)) {
|
||||
return false;
|
||||
}
|
||||
if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(thisBase, otherBase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -552,11 +554,14 @@ class FlatTypeMask extends TypeMask {
|
|||
}
|
||||
assert(a.isSubclass || a.isSubtype);
|
||||
assert(b.isSubtype);
|
||||
final aBase = a.base!;
|
||||
var elements = a.isSubclass
|
||||
? closedWorld.classHierarchy.strictSubclassesOf(a.base)
|
||||
: closedWorld.classHierarchy.strictSubtypesOf(a.base);
|
||||
? closedWorld.classHierarchy.strictSubclassesOf(aBase)
|
||||
: closedWorld.classHierarchy.strictSubtypesOf(aBase);
|
||||
for (var element in elements) {
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(element, b.base)) return false;
|
||||
if (closedWorld.classHierarchy.isSubtypeOf(element, b.base!)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -581,7 +586,7 @@ class FlatTypeMask extends TypeMask {
|
|||
|
||||
TypeMask intersectionStrictSubclass(FlatTypeMask other, CommonMasks domain) {
|
||||
assert(base != other.base);
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
|
||||
assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base!, base!));
|
||||
// If this mask isn't at least a subclass mask, then the
|
||||
// intersection with the other mask is empty.
|
||||
if (isExact) return intersectionEmpty(other);
|
||||
|
@ -615,25 +620,26 @@ class FlatTypeMask extends TypeMask {
|
|||
closedWorld.hasElementIn(commonElements.jsNullClass, name, element);
|
||||
}
|
||||
|
||||
ClassEntity other = element.enclosingClass;
|
||||
final other = element.enclosingClass;
|
||||
final thisBase = base!;
|
||||
if (other == commonElements.jsNullClass) {
|
||||
return isNullable;
|
||||
} else if (isExact) {
|
||||
return closedWorld.hasElementIn(base, name, element);
|
||||
return closedWorld.hasElementIn(thisBase, name, element);
|
||||
} else if (isSubclass) {
|
||||
return closedWorld.hasElementIn(base, name, element) ||
|
||||
closedWorld.classHierarchy.isSubclassOf(other, base) ||
|
||||
closedWorld.hasAnySubclassThatMixes(base, other);
|
||||
return closedWorld.hasElementIn(thisBase, name, element) ||
|
||||
closedWorld.classHierarchy.isSubclassOf(other!, thisBase) ||
|
||||
closedWorld.hasAnySubclassThatMixes(thisBase, other);
|
||||
} else {
|
||||
assert(isSubtype);
|
||||
bool result = closedWorld.hasElementIn(base, name, element) ||
|
||||
closedWorld.classHierarchy.isSubtypeOf(other, base) ||
|
||||
closedWorld.hasAnySubclassThatImplements(other, base) ||
|
||||
closedWorld.hasAnySubclassOfMixinUseThatImplements(other, base);
|
||||
bool result = closedWorld.hasElementIn(thisBase, name, element) ||
|
||||
closedWorld.classHierarchy.isSubtypeOf(other!, thisBase) ||
|
||||
closedWorld.hasAnySubclassThatImplements(other, thisBase) ||
|
||||
closedWorld.hasAnySubclassOfMixinUseThatImplements(other, thisBase);
|
||||
if (result) return true;
|
||||
// If the class is used as a mixin, we have to check if the element
|
||||
// can be hit from any of the mixin applications.
|
||||
Iterable<ClassEntity> mixinUses = closedWorld.mixinUsesOf(base);
|
||||
Iterable<ClassEntity> mixinUses = closedWorld.mixinUsesOf(thisBase);
|
||||
return mixinUses.any((mixinApplication) =>
|
||||
closedWorld.hasElementIn(mixinApplication, name, element) ||
|
||||
closedWorld.classHierarchy.isSubclassOf(other, mixinApplication) ||
|
||||
|
@ -651,13 +657,14 @@ class FlatTypeMask extends TypeMask {
|
|||
// TODO(johnniwinther): A type mask cannot be abstract. Remove the need
|
||||
// for this noise (currently used for super-calls in inference and mirror
|
||||
// usage).
|
||||
if (isExact && base.isAbstract) return false;
|
||||
final thisBase = base!;
|
||||
if (isExact && thisBase.isAbstract) return false;
|
||||
|
||||
return closedWorld.needsNoSuchMethod(base, selector, _classQuery);
|
||||
return closedWorld.needsNoSuchMethod(thisBase, selector, _classQuery);
|
||||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
if (isEmptyOrFlagged) return null;
|
||||
JClosedWorld closedWorld = domain._closedWorld;
|
||||
if (closedWorld.includesClosureCallInDomain(selector, this, domain))
|
||||
|
@ -666,23 +673,26 @@ class FlatTypeMask extends TypeMask {
|
|||
closedWorld.locateMembersInDomain(selector, this, domain);
|
||||
if (targets.length != 1) return null;
|
||||
MemberEntity result = targets.first;
|
||||
ClassEntity enclosing = result.enclosingClass;
|
||||
final enclosing = result.enclosingClass!;
|
||||
final thisBase = base!;
|
||||
// We only return the found element if it is guaranteed to be implemented on
|
||||
// all classes in the receiver type [this]. It could be found only in a
|
||||
// subclass or in an inheritance-wise unrelated class in case of subtype
|
||||
// selectors.
|
||||
if (isSubtype) {
|
||||
// if (closedWorld.isUsedAsMixin(enclosing)) {
|
||||
if (closedWorld.everySubtypeIsSubclassOfOrMixinUseOf(base, enclosing)) {
|
||||
if (closedWorld.everySubtypeIsSubclassOfOrMixinUseOf(
|
||||
thisBase, enclosing)) {
|
||||
return result;
|
||||
}
|
||||
//}
|
||||
return null;
|
||||
} else {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(base, enclosing)) {
|
||||
if (closedWorld.classHierarchy.isSubclassOf(thisBase, enclosing)) {
|
||||
return result;
|
||||
}
|
||||
if (closedWorld.isSubclassOfMixinUseOf(base, enclosing)) return result;
|
||||
if (closedWorld.isSubclassOfMixinUseOf(thisBase, enclosing))
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -707,9 +717,9 @@ class FlatTypeMask extends TypeMask {
|
|||
if (isEmpty) 'empty',
|
||||
if (isNullable) 'null',
|
||||
if (hasLateSentinel) 'sentinel',
|
||||
if (isExact) 'exact=${base.name}',
|
||||
if (isSubclass) 'subclass=${base.name}',
|
||||
if (isSubtype) 'subtype=${base.name}',
|
||||
if (isExact) 'exact=${base!.name}',
|
||||
if (isSubclass) 'subclass=${base!.name}',
|
||||
if (isSubtype) 'subtype=${base!.name}',
|
||||
], '|');
|
||||
buffer.write(']');
|
||||
return buffer.toString();
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A type mask that wraps another one, and delegates all its
|
||||
|
@ -79,7 +77,7 @@ abstract class ForwardingTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ClassEntity singleClass(JClosedWorld closedWorld) {
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld) {
|
||||
return forwardTo.singleClass(closedWorld);
|
||||
}
|
||||
|
||||
|
@ -103,8 +101,8 @@ abstract class ForwardingTypeMask extends TypeMask {
|
|||
forwardTo.union(other, domain);
|
||||
}
|
||||
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) =>
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) =>
|
||||
null;
|
||||
|
||||
@override
|
||||
|
@ -133,7 +131,7 @@ abstract class ForwardingTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
return forwardTo.locateSingleMember(selector, domain);
|
||||
}
|
||||
|
||||
|
@ -153,12 +151,11 @@ abstract class AllocationTypeMask extends ForwardingTypeMask {
|
|||
|
||||
// The [ir.Node] where this type mask was created. This value is not used
|
||||
// after type inference and therefore does not need to be serialized by
|
||||
// subclasses. Using it outside of type inference may cause an exception to be
|
||||
// thrown.
|
||||
ir.Node /*?*/ get allocationNode;
|
||||
// subclasses. It will always be null outside of the global inference phase.
|
||||
ir.Node? get allocationNode;
|
||||
|
||||
// The [Entity] where this type mask was created.
|
||||
MemberEntity get allocationElement;
|
||||
MemberEntity? get allocationElement;
|
||||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [MapTypeMask] is a [TypeMask] for a specific allocation
|
||||
|
@ -17,12 +15,12 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
@override
|
||||
final TypeMask forwardTo;
|
||||
|
||||
final ir.Node /*?*/ _allocationNode;
|
||||
final ir.Node? _allocationNode;
|
||||
@override
|
||||
ir.Node get allocationNode => _allocationNode /*!*/;
|
||||
ir.Node? get allocationNode => _allocationNode;
|
||||
|
||||
@override
|
||||
final MemberEntity allocationElement;
|
||||
final MemberEntity? allocationElement;
|
||||
|
||||
// The value type of this map.
|
||||
final TypeMask valueType;
|
||||
|
@ -37,10 +35,10 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
factory MapTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask keyType = TypeMask.readFromDataSource(source, domain);
|
||||
TypeMask valueType = TypeMask.readFromDataSource(source, domain);
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final keyType = TypeMask.readFromDataSource(source, domain);
|
||||
final valueType = TypeMask.readFromDataSource(source, domain);
|
||||
source.end(tag);
|
||||
return MapTypeMask(forwardTo, null, allocationElement, keyType, valueType);
|
||||
}
|
||||
|
@ -58,7 +56,7 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
MapTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
MapTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -78,15 +76,9 @@ class MapTypeMask extends AllocationTypeMask {
|
|||
bool get isExact => true;
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
if (other is MapTypeMask &&
|
||||
keyType != null &&
|
||||
other.keyType != null &&
|
||||
valueType != null &&
|
||||
other.valueType != null) {
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is MapTypeMask) {
|
||||
TypeMask newKeyType = keyType.union(other.keyType, domain);
|
||||
TypeMask newValueType = valueType.union(other.valueType, domain);
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
library masks;
|
||||
|
||||
import 'package:kernel/ast.dart' as ir;
|
||||
|
@ -47,150 +45,121 @@ class CommonMasks implements AbstractValueDomain {
|
|||
CommonElements get commonElements => _closedWorld.commonElements;
|
||||
DartTypes get dartTypes => _closedWorld.dartTypes;
|
||||
|
||||
TypeMask _internalTopType;
|
||||
TypeMask _dynamicType;
|
||||
TypeMask _nonNullType;
|
||||
TypeMask _nullType;
|
||||
TypeMask _intType;
|
||||
TypeMask _uint32Type;
|
||||
TypeMask _uint31Type;
|
||||
TypeMask _positiveIntType;
|
||||
TypeMask _numNotIntType;
|
||||
TypeMask _numType;
|
||||
TypeMask _boolType;
|
||||
TypeMask _functionType;
|
||||
TypeMask _listType;
|
||||
TypeMask _constListType;
|
||||
TypeMask _fixedListType;
|
||||
TypeMask _growableListType;
|
||||
TypeMask _setType;
|
||||
TypeMask _constSetType;
|
||||
TypeMask _mapType;
|
||||
TypeMask _constMapType;
|
||||
TypeMask _stringType;
|
||||
TypeMask _typeType;
|
||||
TypeMask _syncStarIterableType;
|
||||
TypeMask _asyncFutureType;
|
||||
TypeMask _asyncStarStreamType;
|
||||
TypeMask _indexablePrimitiveType;
|
||||
TypeMask _readableArrayType;
|
||||
TypeMask _mutableArrayType;
|
||||
TypeMask _unmodifiableArrayType;
|
||||
TypeMask _interceptorType;
|
||||
|
||||
/// Cache of [FlatTypeMask]s grouped by the possible values of the
|
||||
/// `FlatTypeMask.flags` property.
|
||||
final List<Map<ClassEntity, TypeMask>> _canonicalizedTypeMasks = List.filled(
|
||||
final List<Map<ClassEntity, TypeMask>?> _canonicalizedTypeMasks = List.filled(
|
||||
_FlatTypeMaskKind.values.length << FlatTypeMask._USED_INDICES, null);
|
||||
|
||||
/// Return the cached mask for [base] with the given flags, or
|
||||
/// calls [createMask] to create the mask and cache it.
|
||||
TypeMask getCachedMask(ClassEntity base, int flags, TypeMask createMask()) {
|
||||
Map<ClassEntity, TypeMask> cachedMasks =
|
||||
_canonicalizedTypeMasks[flags] ??= <ClassEntity, TypeMask>{};
|
||||
return cachedMasks.putIfAbsent(base, createMask);
|
||||
T getCachedMask<T extends TypeMask>(
|
||||
ClassEntity? base, int flags, T createMask()) {
|
||||
// `null` is a valid base so we allow it as a key in the map.
|
||||
final Map<ClassEntity?, TypeMask> cachedMasks =
|
||||
_canonicalizedTypeMasks[flags] ??= {};
|
||||
return cachedMasks.putIfAbsent(base, createMask) as T;
|
||||
}
|
||||
|
||||
@override
|
||||
TypeMask get internalTopType => _internalTopType ??= TypeMask.subclass(
|
||||
late final TypeMask internalTopType = TypeMask.subclass(
|
||||
_closedWorld.commonElements.objectClass, _closedWorld,
|
||||
hasLateSentinel: true);
|
||||
|
||||
@override
|
||||
TypeMask get dynamicType => _dynamicType ??=
|
||||
late final TypeMask dynamicType =
|
||||
TypeMask.subclass(_closedWorld.commonElements.objectClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get nonNullType => _nonNullType ??= TypeMask.nonNullSubclass(
|
||||
late final TypeMask nonNullType = TypeMask.nonNullSubclass(
|
||||
_closedWorld.commonElements.objectClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get intType => _intType ??=
|
||||
late final TypeMask intType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsIntClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get uint32Type => _uint32Type ??=
|
||||
late final TypeMask uint32Type =
|
||||
TypeMask.nonNullSubclass(commonElements.jsUInt32Class, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get uint31Type => _uint31Type ??=
|
||||
late final TypeMask uint31Type =
|
||||
TypeMask.nonNullExact(commonElements.jsUInt31Class, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get positiveIntType => _positiveIntType ??=
|
||||
late final TypeMask positiveIntType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsPositiveIntClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get numNotIntType => _numNotIntType ??=
|
||||
late final TypeMask numNotIntType =
|
||||
TypeMask.nonNullExact(commonElements.jsNumNotIntClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get numType => _numType ??=
|
||||
late final TypeMask numType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsNumberClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get boolType => _boolType ??=
|
||||
late final TypeMask boolType =
|
||||
TypeMask.nonNullExact(commonElements.jsBoolClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get functionType => _functionType ??=
|
||||
late final TypeMask functionType =
|
||||
TypeMask.nonNullSubtype(commonElements.functionClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get listType => _listType ??=
|
||||
late final TypeMask listType =
|
||||
TypeMask.nonNullSubtype(commonElements.jsArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get constListType => _constListType ??= TypeMask.nonNullExact(
|
||||
late final TypeMask constListType = TypeMask.nonNullExact(
|
||||
commonElements.jsUnmodifiableArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get fixedListType => _fixedListType ??=
|
||||
late final TypeMask fixedListType =
|
||||
TypeMask.nonNullExact(commonElements.jsFixedArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get growableListType => _growableListType ??= TypeMask.nonNullExact(
|
||||
late final TypeMask growableListType = TypeMask.nonNullExact(
|
||||
commonElements.jsExtendableArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get setType => _setType ??=
|
||||
late final TypeMask setType =
|
||||
TypeMask.nonNullSubtype(commonElements.setLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get constSetType => _constSetType ??= TypeMask.nonNullSubtype(
|
||||
late final TypeMask constSetType = TypeMask.nonNullSubtype(
|
||||
commonElements.constSetLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get mapType => _mapType ??=
|
||||
late final TypeMask mapType =
|
||||
TypeMask.nonNullSubtype(commonElements.mapLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get constMapType => _constMapType ??= TypeMask.nonNullSubtype(
|
||||
late final TypeMask constMapType = TypeMask.nonNullSubtype(
|
||||
commonElements.constMapLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get stringType => _stringType ??=
|
||||
late final TypeMask stringType =
|
||||
TypeMask.nonNullExact(commonElements.jsStringClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get typeType => _typeType ??=
|
||||
late final TypeMask typeType =
|
||||
TypeMask.nonNullExact(commonElements.typeLiteralClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get syncStarIterableType => _syncStarIterableType ??=
|
||||
late final TypeMask syncStarIterableType =
|
||||
TypeMask.nonNullExact(commonElements.syncStarIterable, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get asyncFutureType => _asyncFutureType ??=
|
||||
late final TypeMask asyncFutureType =
|
||||
TypeMask.nonNullExact(commonElements.futureImplementation, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get asyncStarStreamType => _asyncStarStreamType ??=
|
||||
late final TypeMask asyncStarStreamType =
|
||||
TypeMask.nonNullExact(commonElements.controllerStream, _closedWorld);
|
||||
|
||||
// TODO(johnniwinther): Assert that the null type has been resolved.
|
||||
@override
|
||||
TypeMask get nullType => _nullType ??= TypeMask.empty();
|
||||
late final TypeMask nullType = TypeMask.empty();
|
||||
|
||||
@override
|
||||
TypeMask get lateSentinelType => TypeMask.nonNullEmpty(hasLateSentinel: true);
|
||||
|
@ -198,22 +167,20 @@ class CommonMasks implements AbstractValueDomain {
|
|||
@override
|
||||
TypeMask get emptyType => TypeMask.nonNullEmpty();
|
||||
|
||||
TypeMask get indexablePrimitiveType => _indexablePrimitiveType ??=
|
||||
late final TypeMask indexablePrimitiveType =
|
||||
TypeMask.nonNullSubtype(commonElements.jsIndexableClass, _closedWorld);
|
||||
|
||||
TypeMask get readableArrayType => _readableArrayType ??=
|
||||
late final TypeMask readableArrayType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsArrayClass, _closedWorld);
|
||||
|
||||
@override
|
||||
TypeMask get mutableArrayType =>
|
||||
_mutableArrayType ??= TypeMask.nonNullSubclass(
|
||||
commonElements.jsMutableArrayClass, _closedWorld);
|
||||
late final TypeMask mutableArrayType = TypeMask.nonNullSubclass(
|
||||
commonElements.jsMutableArrayClass, _closedWorld);
|
||||
|
||||
TypeMask get unmodifiableArrayType =>
|
||||
_unmodifiableArrayType ??= TypeMask.nonNullExact(
|
||||
commonElements.jsUnmodifiableArrayClass, _closedWorld);
|
||||
late final TypeMask unmodifiableArrayType = TypeMask.nonNullExact(
|
||||
commonElements.jsUnmodifiableArrayClass, _closedWorld);
|
||||
|
||||
TypeMask get interceptorType => _interceptorType ??=
|
||||
late final TypeMask interceptorType =
|
||||
TypeMask.nonNullSubclass(commonElements.jsInterceptorClass, _closedWorld);
|
||||
|
||||
@override
|
||||
|
@ -222,11 +189,12 @@ class CommonMasks implements AbstractValueDomain {
|
|||
// class any user-defined class can implement. So we also check for the
|
||||
// interface `JavaScriptIndexingBehavior`.
|
||||
ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
|
||||
return AbstractBool.trueOrMaybe(typedDataClass != null &&
|
||||
return AbstractBool.trueOrMaybe(
|
||||
_closedWorld.classHierarchy.isInstantiated(typedDataClass) &&
|
||||
mask.satisfies(typedDataClass, _closedWorld) &&
|
||||
mask.satisfies(_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld));
|
||||
mask.satisfies(typedDataClass, _closedWorld) &&
|
||||
mask.satisfies(
|
||||
_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -236,14 +204,14 @@ class CommonMasks implements AbstractValueDomain {
|
|||
// TODO(herhut): Maybe cache the TypeMask for typedDataClass and
|
||||
// jsIndexingBehaviourInterface.
|
||||
ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
|
||||
return AbstractBool.maybeOrFalse(typedDataClass != null &&
|
||||
return AbstractBool.maybeOrFalse(
|
||||
_closedWorld.classHierarchy.isInstantiated(typedDataClass) &&
|
||||
intersects(mask, TypeMask.subtype(typedDataClass, _closedWorld)) &&
|
||||
intersects(
|
||||
mask,
|
||||
TypeMask.subtype(
|
||||
_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld)));
|
||||
intersects(mask, TypeMask.subtype(typedDataClass, _closedWorld)) &&
|
||||
intersects(
|
||||
mask,
|
||||
TypeMask.subtype(
|
||||
_closedWorld.commonElements.jsIndexingBehaviorInterface,
|
||||
_closedWorld)));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -273,9 +241,8 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValueWithPrecision createFromStaticType(DartType type,
|
||||
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
|
||||
assert(nullable != null);
|
||||
|
||||
{ClassRelation classRelation = ClassRelation.subtype,
|
||||
required bool nullable}) {
|
||||
if ((classRelation == ClassRelation.subtype ||
|
||||
classRelation == ClassRelation.thisExpression) &&
|
||||
dartTypes.isTopType(type)) {
|
||||
|
@ -311,8 +278,6 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
AbstractValueWithPrecision _createFromStaticType(
|
||||
DartType type, ClassRelation classRelation, bool nullable) {
|
||||
assert(nullable != null);
|
||||
|
||||
AbstractValueWithPrecision finish(TypeMask value, bool isPrecise) {
|
||||
return AbstractValueWithPrecision(
|
||||
nullable ? value.nullable() : value, isPrecise);
|
||||
|
@ -440,7 +405,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
@override
|
||||
AbstractBool isInstanceOf(
|
||||
covariant TypeMask expressionMask, ClassEntity cls) {
|
||||
AbstractValue typeMask = (cls == commonElements.nullClass)
|
||||
final typeMask = (cls == commonElements.nullClass)
|
||||
? nullType
|
||||
: createNonNullSubtype(cls);
|
||||
if (expressionMask.union(typeMask, this) == typeMask) {
|
||||
|
@ -461,7 +426,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
value.isExact && !value.isNullable && !value.hasLateSentinel);
|
||||
|
||||
@override
|
||||
ClassEntity getExactClass(TypeMask mask) {
|
||||
ClassEntity? getExactClass(TypeMask mask) {
|
||||
return mask.singleClass(_closedWorld);
|
||||
}
|
||||
|
||||
|
@ -469,7 +434,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
bool isPrimitiveValue(TypeMask value) => value is ValueTypeMask;
|
||||
|
||||
@override
|
||||
PrimitiveConstantValue getPrimitiveValue(TypeMask mask) {
|
||||
PrimitiveConstantValue? getPrimitiveValue(TypeMask mask) {
|
||||
if (mask is ValueTypeMask) {
|
||||
return mask.value;
|
||||
}
|
||||
|
@ -717,42 +682,35 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValue getMapValueType(AbstractValue value) {
|
||||
if (value is MapTypeMask) {
|
||||
// TODO(johnniwinther): Assert the `value.valueType` is not null.
|
||||
return value.valueType ?? dynamicType;
|
||||
}
|
||||
return dynamicType;
|
||||
return value is MapTypeMask ? value.valueType : dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getContainerElementType(AbstractValue value) {
|
||||
if (value is ContainerTypeMask) {
|
||||
return value.elementType ?? dynamicType;
|
||||
}
|
||||
return dynamicType;
|
||||
return value is ContainerTypeMask ? value.elementType : dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
int getContainerLength(AbstractValue value) {
|
||||
int? getContainerLength(AbstractValue value) {
|
||||
return value is ContainerTypeMask ? value.length : null;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createContainerValue(
|
||||
AbstractValue forwardTo,
|
||||
Object allocationNode,
|
||||
MemberEntity allocationElement,
|
||||
AbstractValue elementType,
|
||||
int length) {
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask elementType,
|
||||
int? length) {
|
||||
return ContainerTypeMask(
|
||||
forwardTo, allocationNode, allocationElement, elementType, length);
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue unionOfMany(Iterable<AbstractValue> values) {
|
||||
TypeMask result = TypeMask.nonNullEmpty();
|
||||
for (TypeMask value in values) {
|
||||
result = result.union(value, this);
|
||||
var result = TypeMask.nonNullEmpty();
|
||||
for (final value in values) {
|
||||
result = result.union(value as TypeMask, this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -763,7 +721,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
.hasAnyStrictSubclass(_closedWorld.commonElements.objectClass));
|
||||
return TypeMask.unionOf(
|
||||
members.expand((MemberEntity element) {
|
||||
ClassEntity cls = element.enclosingClass;
|
||||
final cls = element.enclosingClass!;
|
||||
return [cls]..addAll(_closedWorld.mixinUsesOf(cls));
|
||||
}).map((cls) {
|
||||
if (_closedWorld.commonElements.jsNullClass == cls) {
|
||||
|
@ -798,7 +756,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(
|
||||
MemberEntity? locateSingleMember(
|
||||
covariant TypeMask receiver, Selector selector) {
|
||||
return receiver.locateSingleMember(selector, this);
|
||||
}
|
||||
|
@ -878,42 +836,48 @@ class CommonMasks implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValue getDictionaryValueForKey(AbstractValue value, String key) {
|
||||
if (value is DictionaryTypeMask) return value.getValueForKey(key);
|
||||
return dynamicType;
|
||||
final result =
|
||||
value is DictionaryTypeMask ? value.getValueForKey(key) : null;
|
||||
return result ?? dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createMapValue(AbstractValue forwardTo, Object allocationNode,
|
||||
MemberEntity allocationElement, AbstractValue key, AbstractValue value) {
|
||||
AbstractValue createMapValue(
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask key,
|
||||
covariant TypeMask value) {
|
||||
return MapTypeMask(
|
||||
forwardTo, allocationNode, allocationElement, key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createDictionaryValue(
|
||||
AbstractValue forwardTo,
|
||||
Object allocationNode,
|
||||
MemberEntity allocationElement,
|
||||
AbstractValue key,
|
||||
AbstractValue value,
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask key,
|
||||
covariant TypeMask value,
|
||||
Map<String, AbstractValue> mappings) {
|
||||
return DictionaryTypeMask(forwardTo, allocationNode, allocationElement, key,
|
||||
value, Map.from(mappings));
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue createSetValue(AbstractValue forwardTo, Object allocationNode,
|
||||
MemberEntity allocationElement, AbstractValue elementType) {
|
||||
AbstractValue createSetValue(
|
||||
covariant TypeMask forwardTo,
|
||||
covariant ir.Node? allocationNode,
|
||||
MemberEntity? allocationElement,
|
||||
covariant TypeMask elementType) {
|
||||
return SetTypeMask(
|
||||
forwardTo, allocationNode, allocationElement, elementType);
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getSetElementType(AbstractValue value) {
|
||||
if (value is SetTypeMask) {
|
||||
return value.elementType ?? dynamicType;
|
||||
}
|
||||
return dynamicType;
|
||||
final result = value is SetTypeMask ? value.elementType : null;
|
||||
return result ?? dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -924,31 +888,22 @@ class CommonMasks implements AbstractValueDomain {
|
|||
}
|
||||
|
||||
@override
|
||||
Object getAllocationNode(AbstractValue value) {
|
||||
if (value is AllocationTypeMask) {
|
||||
return value.allocationNode;
|
||||
}
|
||||
return null;
|
||||
Object? getAllocationNode(AbstractValue value) {
|
||||
return value is AllocationTypeMask ? value.allocationNode : null;
|
||||
}
|
||||
|
||||
@override
|
||||
MemberEntity getAllocationElement(AbstractValue value) {
|
||||
if (value is AllocationTypeMask) {
|
||||
return value.allocationElement;
|
||||
}
|
||||
return null;
|
||||
MemberEntity? getAllocationElement(AbstractValue value) {
|
||||
return value is AllocationTypeMask ? value.allocationElement : null;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getGeneralization(AbstractValue value) {
|
||||
if (value is AllocationTypeMask) {
|
||||
return value.forwardTo;
|
||||
}
|
||||
return null;
|
||||
AbstractValue? getGeneralization(AbstractValue value) {
|
||||
return value is AllocationTypeMask ? value.forwardTo : null;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getAbstractValueForNativeMethodParameterType(DartType type) {
|
||||
AbstractValue? getAbstractValueForNativeMethodParameterType(DartType type) {
|
||||
if (type is InterfaceType) {
|
||||
if (type.typeArguments.isNotEmpty) return null;
|
||||
// TODO(sra): Consider using a strengthened type check to avoid passing
|
||||
|
@ -962,7 +917,7 @@ class CommonMasks implements AbstractValueDomain {
|
|||
}
|
||||
|
||||
@override
|
||||
String getCompactText(AbstractValue value) {
|
||||
String getCompactText(covariant TypeMask value) {
|
||||
return formatType(dartTypes, value);
|
||||
}
|
||||
|
||||
|
@ -1005,7 +960,7 @@ String formatType(DartTypes dartTypes, TypeMask type) {
|
|||
? '+'
|
||||
: '*';
|
||||
String sentinelFlag = type.hasLateSentinel ? '\$' : '';
|
||||
return '${type.base.name}$nullFlag$subFlag$sentinelFlag';
|
||||
return '${type.base!.name}$nullFlag$subFlag$sentinelFlag';
|
||||
}
|
||||
if (type is UnionTypeMask) {
|
||||
return type.disjointMasks.map((m) => formatType(dartTypes, m)).join(' | ');
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// A [SetTypeMask] is a [TypeMask] for a specific allocation site of a set
|
||||
|
@ -17,12 +15,12 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
@override
|
||||
final TypeMask forwardTo;
|
||||
|
||||
final ir.Node /*?*/ _allocationNode;
|
||||
final ir.Node? _allocationNode;
|
||||
@override
|
||||
ir.Node get allocationNode => _allocationNode /*!*/;
|
||||
ir.Node? get allocationNode => _allocationNode;
|
||||
|
||||
@override
|
||||
final MemberEntity allocationElement;
|
||||
final MemberEntity? allocationElement;
|
||||
|
||||
// The element type of this set.
|
||||
final TypeMask elementType;
|
||||
|
@ -34,9 +32,9 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
factory SetTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
MemberEntity allocationElement = source.readMemberOrNull();
|
||||
TypeMask elementType = TypeMask.readFromDataSource(source, domain);
|
||||
final forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
final allocationElement = source.readMemberOrNull();
|
||||
final elementType = TypeMask.readFromDataSource(source, domain);
|
||||
source.end(tag);
|
||||
return SetTypeMask(forwardTo, null, allocationElement, elementType);
|
||||
}
|
||||
|
@ -53,7 +51,7 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
SetTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
SetTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -72,13 +70,9 @@ class SetTypeMask extends AllocationTypeMask {
|
|||
bool get isExact => true;
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
if (other is SetTypeMask &&
|
||||
elementType != null &&
|
||||
other.elementType != null) {
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is SetTypeMask) {
|
||||
TypeMask newElementType = elementType.union(other.elementType, domain);
|
||||
TypeMask newForwardTo = forwardTo.union(other.forwardTo, domain);
|
||||
return SetTypeMask(newForwardTo, null, null, newElementType);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
/// An implementation of a [UniverseSelectorConstraints] that is consists if an
|
||||
|
@ -11,13 +9,13 @@ part of masks;
|
|||
/// be removed.
|
||||
class IncreasingTypeMaskSet extends UniverseSelectorConstraints {
|
||||
bool isAll = false;
|
||||
Set<TypeMask> _masks;
|
||||
Set<TypeMask>? _masks;
|
||||
|
||||
@override
|
||||
bool canHit(MemberEntity element, Name name, JClosedWorld world) {
|
||||
if (isAll) return true;
|
||||
if (_masks == null) return false;
|
||||
for (TypeMask mask in _masks) {
|
||||
for (TypeMask mask in _masks!) {
|
||||
if (mask.canHit(element, name, world)) return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -30,7 +28,7 @@ class IncreasingTypeMaskSet extends UniverseSelectorConstraints {
|
|||
TypeMask.subclass(world.commonElements.objectClass, world);
|
||||
return mask.needsNoSuchMethodHandling(selector, world);
|
||||
}
|
||||
for (TypeMask mask in _masks) {
|
||||
for (TypeMask mask in _masks!) {
|
||||
if (mask.needsNoSuchMethodHandling(selector, world)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -39,15 +37,14 @@ class IncreasingTypeMaskSet extends UniverseSelectorConstraints {
|
|||
}
|
||||
|
||||
@override
|
||||
bool addReceiverConstraint(TypeMask mask) {
|
||||
bool addReceiverConstraint(TypeMask? mask) {
|
||||
if (isAll) return false;
|
||||
if (mask == null) {
|
||||
isAll = true;
|
||||
_masks = null;
|
||||
return true;
|
||||
}
|
||||
_masks ??= {};
|
||||
return _masks.add(mask);
|
||||
return (_masks ??= {}).add(mask);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -81,7 +78,7 @@ class TypeMaskSelectorStrategy implements SelectorConstraintsStrategy {
|
|||
|
||||
@override
|
||||
UniverseSelectorConstraints createSelectorConstraints(
|
||||
Selector selector, Object initialConstraint) {
|
||||
Selector selector, covariant TypeMask? initialConstraint) {
|
||||
return IncreasingTypeMaskSet()..addReceiverConstraint(initialConstraint);
|
||||
}
|
||||
|
||||
|
@ -89,7 +86,7 @@ class TypeMaskSelectorStrategy implements SelectorConstraintsStrategy {
|
|||
bool appliedUnnamed(DynamicUse dynamicUse, MemberEntity member,
|
||||
covariant JClosedWorld world) {
|
||||
Selector selector = dynamicUse.selector;
|
||||
TypeMask mask = dynamicUse.receiverConstraint;
|
||||
final mask = dynamicUse.receiverConstraint as TypeMask?;
|
||||
return selector.appliesUnnamed(member) &&
|
||||
(mask == null || mask.canHit(member, selector.memberName, world));
|
||||
}
|
||||
|
@ -120,7 +117,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create exact type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
return FlatTypeMask.exact(base, closedWorld,
|
||||
|
@ -141,10 +138,10 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create subclass type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.empty(hasLateSentinel: hasLateSentinel);
|
||||
} else if (closedWorld.classHierarchy.hasAnyStrictSubclass(topmost)) {
|
||||
|
@ -158,7 +155,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
factory TypeMask.subtype(ClassEntity base, JClosedWorld closedWorld,
|
||||
{bool hasLateSentinel = false}) {
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.empty(hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
|
@ -183,7 +180,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create exact type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
return FlatTypeMask.nonNullExact(base, closedWorld,
|
||||
|
@ -205,10 +202,10 @@ abstract class TypeMask implements AbstractValue {
|
|||
assert(
|
||||
closedWorld.classHierarchy.isInstantiated(base),
|
||||
failedAt(
|
||||
base ?? CURRENT_ELEMENT_SPANNABLE,
|
||||
base,
|
||||
"Cannot create subclass type mask for uninstantiated "
|
||||
"class $base.\n${closedWorld.classHierarchy.dump(base)}"));
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.nonNullEmpty(hasLateSentinel: hasLateSentinel);
|
||||
} else if (closedWorld.classHierarchy.hasAnyStrictSubclass(topmost)) {
|
||||
|
@ -222,7 +219,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
factory TypeMask.nonNullSubtype(ClassEntity base, JClosedWorld closedWorld,
|
||||
{bool hasLateSentinel = false}) {
|
||||
ClassEntity topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
final topmost = closedWorld.getLubOfInstantiatedSubtypes(base);
|
||||
if (topmost == null) {
|
||||
return TypeMask.nonNullEmpty(hasLateSentinel: hasLateSentinel);
|
||||
}
|
||||
|
@ -263,7 +260,6 @@ abstract class TypeMask implements AbstractValue {
|
|||
case TypeMaskKind.value:
|
||||
return ValueTypeMask.readFromDataSource(source, domain);
|
||||
}
|
||||
throw UnsupportedError("Unexpected TypeMaskKind $kind.");
|
||||
}
|
||||
|
||||
/// Serializes this [TypeMask] to [sink].
|
||||
|
@ -273,7 +269,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
/// [mask]'s forwarding chain.
|
||||
static TypeMask nonForwardingMask(TypeMask mask) {
|
||||
while (mask is ForwardingTypeMask) {
|
||||
mask = (mask as ForwardingTypeMask).forwardTo;
|
||||
mask = mask.forwardTo;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
@ -284,13 +280,13 @@ abstract class TypeMask implements AbstractValue {
|
|||
/// subclasses exist. We also normalize exact to empty if the corresponding
|
||||
/// baseclass was never instantiated.
|
||||
static bool assertIsNormalized(TypeMask mask, JClosedWorld closedWorld) {
|
||||
String reason = getNotNormalizedReason(mask, closedWorld);
|
||||
final reason = getNotNormalizedReason(mask, closedWorld);
|
||||
assert(reason == null,
|
||||
failedAt(NO_LOCATION_SPANNABLE, '$mask is not normalized: $reason'));
|
||||
return true;
|
||||
}
|
||||
|
||||
static String getNotNormalizedReason(
|
||||
static String? getNotNormalizedReason(
|
||||
TypeMask mask, JClosedWorld closedWorld) {
|
||||
mask = nonForwardingMask(mask);
|
||||
if (mask is FlatTypeMask) {
|
||||
|
@ -299,28 +295,28 @@ abstract class TypeMask implements AbstractValue {
|
|||
return 'The class ${mask.base} is not canonicalized.';
|
||||
}
|
||||
if (mask.isExact) {
|
||||
if (!closedWorld.classHierarchy.isInstantiated(mask.base)) {
|
||||
if (!closedWorld.classHierarchy.isInstantiated(mask.base!)) {
|
||||
return 'Exact ${mask.base} is not instantiated.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (mask.isSubclass) {
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubclass(mask.base)) {
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubclass(mask.base!)) {
|
||||
return 'Subclass ${mask.base} does not have any subclasses.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
assert(mask.isSubtype);
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubtype(mask.base)) {
|
||||
if (!closedWorld.classHierarchy.hasAnyStrictSubtype(mask.base!)) {
|
||||
return 'Subtype ${mask.base} does not have any subclasses.';
|
||||
}
|
||||
if (closedWorld.classHierarchy.hasOnlySubclasses(mask.base)) {
|
||||
if (closedWorld.classHierarchy.hasOnlySubclasses(mask.base!)) {
|
||||
return 'Subtype ${mask.base} only has subclasses.';
|
||||
}
|
||||
return null;
|
||||
} else if (mask is UnionTypeMask) {
|
||||
for (TypeMask submask in mask.disjointMasks) {
|
||||
String submaskReason = getNotNormalizedReason(submask, closedWorld);
|
||||
final submaskReason = getNotNormalizedReason(submask, closedWorld);
|
||||
if (submaskReason != null) {
|
||||
return 'Submask $submask in $mask: $submaskReason.';
|
||||
}
|
||||
|
@ -341,7 +337,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
TypeMask withoutFlags() =>
|
||||
withFlags(isNullable: false, hasLateSentinel: false);
|
||||
|
||||
TypeMask withFlags({bool isNullable, bool hasLateSentinel});
|
||||
TypeMask withFlags({bool? isNullable, bool? hasLateSentinel});
|
||||
|
||||
/// Whether nothing matches this mask, not even null.
|
||||
bool get isEmpty;
|
||||
|
@ -402,7 +398,7 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
/// Returns the [ClassEntity] if this type represents a single class,
|
||||
/// otherwise returns `null`. This method is conservative.
|
||||
ClassEntity singleClass(JClosedWorld closedWorld);
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld);
|
||||
|
||||
/// Returns a type mask representing the union of [this] and [other].
|
||||
TypeMask union(TypeMask other, CommonMasks domain);
|
||||
|
@ -426,5 +422,5 @@ abstract class TypeMask implements AbstractValue {
|
|||
|
||||
/// Returns the [element] that is known to always be hit at runtime
|
||||
/// on this mask. Returns null if there is none.
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain);
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
class UnionTypeMask extends TypeMask {
|
||||
|
@ -31,10 +29,8 @@ class UnionTypeMask extends TypeMask {
|
|||
AbstractBool get isLateSentinel => AbstractBool.maybeOrFalse(hasLateSentinel);
|
||||
|
||||
UnionTypeMask._internal(this.disjointMasks,
|
||||
{this.isNullable, this.hasLateSentinel})
|
||||
: assert(isNullable != null),
|
||||
assert(hasLateSentinel != null),
|
||||
assert(disjointMasks.length > 1),
|
||||
{required this.isNullable, required this.hasLateSentinel})
|
||||
: assert(disjointMasks.length > 1),
|
||||
assert(disjointMasks.every((TypeMask mask) => mask is! UnionTypeMask)),
|
||||
assert(disjointMasks.every((TypeMask mask) => !mask.isNullable)),
|
||||
assert(disjointMasks.every((TypeMask mask) => !mask.hasLateSentinel));
|
||||
|
@ -43,8 +39,8 @@ class UnionTypeMask extends TypeMask {
|
|||
factory UnionTypeMask.readFromDataSource(
|
||||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
List<FlatTypeMask> disjointMasks =
|
||||
source.readList(() => TypeMask.readFromDataSource(source, domain));
|
||||
List<FlatTypeMask> disjointMasks = source.readList(
|
||||
() => TypeMask.readFromDataSource(source, domain) as FlatTypeMask);
|
||||
bool isNullable = source.readBool();
|
||||
bool hasLateSentinel = source.readBool();
|
||||
source.end(tag);
|
||||
|
@ -99,7 +95,7 @@ class UnionTypeMask extends TypeMask {
|
|||
} else if (mask.isEmpty) {
|
||||
continue;
|
||||
} else {
|
||||
FlatTypeMask flatMask = mask;
|
||||
var flatMask = mask as FlatTypeMask;
|
||||
int inListIndex = -1;
|
||||
bool covered = false;
|
||||
|
||||
|
@ -107,10 +103,10 @@ class UnionTypeMask extends TypeMask {
|
|||
// already covers [mask].
|
||||
for (int i = 0; i < disjoint.length; i++) {
|
||||
FlatTypeMask current = disjoint[i];
|
||||
if (current == null) continue;
|
||||
TypeMask newMask = flatMask.union(current, domain);
|
||||
// If we have found a disjoint union, continue iterating.
|
||||
if (newMask is UnionTypeMask) continue;
|
||||
newMask as FlatTypeMask;
|
||||
covered = true;
|
||||
// We found a mask that is either equal to [mask] or is a
|
||||
// supertype of [mask].
|
||||
|
@ -141,10 +137,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
static TypeMask flatten(List<FlatTypeMask> masks, CommonMasks domain,
|
||||
{bool includeNull, bool includeLateSentinel}) {
|
||||
assert(includeNull != null);
|
||||
assert(includeLateSentinel != null);
|
||||
|
||||
{required bool includeNull, required bool includeLateSentinel}) {
|
||||
// TODO(johnniwinther): Move this computation to [ClosedWorld] and use the
|
||||
// class set structures.
|
||||
if (masks.isEmpty) throw ArgumentError.value(masks, 'masks');
|
||||
|
@ -152,14 +145,14 @@ class UnionTypeMask extends TypeMask {
|
|||
// subclass type mask to represent their union.
|
||||
bool useSubclass = masks.every((e) => !e.isSubtype);
|
||||
|
||||
List<ClassEntity> masksBases = masks.map((mask) => mask.base).toList();
|
||||
final masksBases = masks.map((mask) => mask.base!).toList();
|
||||
Iterable<ClassEntity> candidates =
|
||||
domain._closedWorld.commonSupertypesOf(masksBases);
|
||||
|
||||
// Compute the best candidate and its kind.
|
||||
ClassEntity bestElement;
|
||||
_FlatTypeMaskKind bestKind;
|
||||
int bestSize;
|
||||
ClassEntity? bestElement;
|
||||
late _FlatTypeMaskKind bestKind;
|
||||
late int bestSize;
|
||||
for (ClassEntity candidate in candidates) {
|
||||
bool isInstantiatedStrictSubclass(cls) =>
|
||||
cls != candidate &&
|
||||
|
@ -194,7 +187,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
int flags = FlatTypeMask._computeFlags(bestKind,
|
||||
isNullable: includeNull, hasLateSentinel: includeLateSentinel);
|
||||
return FlatTypeMask.normalized(bestElement, flags, domain);
|
||||
return FlatTypeMask.normalized(bestElement!, flags, domain);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -222,7 +215,7 @@ class UnionTypeMask extends TypeMask {
|
|||
if (other is UnionTypeMask) {
|
||||
newList.addAll(other.disjointMasks);
|
||||
} else {
|
||||
newList.add(other);
|
||||
newList.add(other as FlatTypeMask);
|
||||
}
|
||||
TypeMask newMask = TypeMask.unionOf(newList, domain);
|
||||
return newMask.withFlags(
|
||||
|
@ -280,7 +273,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
UnionTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
UnionTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -324,16 +317,16 @@ class UnionTypeMask extends TypeMask {
|
|||
if (other.contains(closedWorld.commonElements.objectClass, closedWorld)) {
|
||||
return false;
|
||||
}
|
||||
FlatTypeMask flat = TypeMask.nonForwardingMask(other);
|
||||
final flat = TypeMask.nonForwardingMask(other) as FlatTypeMask;
|
||||
// Check we cover the base class.
|
||||
if (!contains(flat.base, closedWorld)) return false;
|
||||
if (!contains(flat.base!, closedWorld)) return false;
|
||||
// Check for other members.
|
||||
Iterable<ClassEntity> members;
|
||||
if (flat.isSubclass) {
|
||||
members = closedWorld.classHierarchy.strictSubclassesOf(flat.base);
|
||||
members = closedWorld.classHierarchy.strictSubclassesOf(flat.base!);
|
||||
} else {
|
||||
assert(flat.isSubtype);
|
||||
members = closedWorld.classHierarchy.strictSubtypesOf(flat.base);
|
||||
members = closedWorld.classHierarchy.strictSubtypesOf(flat.base!);
|
||||
}
|
||||
return members.every((ClassEntity cls) => this.contains(cls, closedWorld));
|
||||
}
|
||||
|
@ -344,7 +337,7 @@ class UnionTypeMask extends TypeMask {
|
|||
if (isNullable && !other.isNullable) return false;
|
||||
if (hasLateSentinel && !other.hasLateSentinel) return false;
|
||||
if (other is UnionTypeMask) {
|
||||
final union = other as UnionTypeMask;
|
||||
final union = other;
|
||||
return disjointMasks.every((FlatTypeMask disjointMask) {
|
||||
bool contained = union.disjointMasks.any((FlatTypeMask other) =>
|
||||
other.containsMask(disjointMask, closedWorld));
|
||||
|
@ -419,7 +412,7 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ClassEntity singleClass(JClosedWorld closedWorld) => null;
|
||||
ClassEntity? singleClass(JClosedWorld closedWorld) => null;
|
||||
|
||||
@override
|
||||
bool needsNoSuchMethodHandling(Selector selector, JClosedWorld closedWorld) {
|
||||
|
@ -439,12 +432,12 @@ class UnionTypeMask extends TypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
MemberEntity locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity candidate;
|
||||
MemberEntity? locateSingleMember(Selector selector, CommonMasks domain) {
|
||||
MemberEntity? candidate;
|
||||
for (FlatTypeMask mask in disjointMasks) {
|
||||
mask = mask.withFlags(
|
||||
isNullable: isNullable, hasLateSentinel: hasLateSentinel);
|
||||
MemberEntity current = mask.locateSingleMember(selector, domain);
|
||||
final current = mask.locateSingleMember(selector, domain);
|
||||
if (current == null) {
|
||||
return null;
|
||||
} else if (candidate == null) {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart = 2.10
|
||||
|
||||
part of masks;
|
||||
|
||||
class ValueTypeMask extends ForwardingTypeMask {
|
||||
|
@ -22,7 +20,7 @@ class ValueTypeMask extends ForwardingTypeMask {
|
|||
DataSourceReader source, CommonMasks domain) {
|
||||
source.begin(tag);
|
||||
TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
|
||||
ConstantValue constant = source.readConstant();
|
||||
final constant = source.readConstant() as PrimitiveConstantValue;
|
||||
source.end(tag);
|
||||
return ValueTypeMask(forwardTo, constant);
|
||||
}
|
||||
|
@ -38,7 +36,7 @@ class ValueTypeMask extends ForwardingTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
ValueTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
|
||||
ValueTypeMask withFlags({bool? isNullable, bool? hasLateSentinel}) {
|
||||
isNullable ??= this.isNullable;
|
||||
hasLateSentinel ??= this.hasLateSentinel;
|
||||
if (isNullable == this.isNullable &&
|
||||
|
@ -52,10 +50,8 @@ class ValueTypeMask extends ForwardingTypeMask {
|
|||
}
|
||||
|
||||
@override
|
||||
TypeMask _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{bool isNullable, bool hasLateSentinel}) {
|
||||
assert(isNullable != null);
|
||||
assert(hasLateSentinel != null);
|
||||
TypeMask? _unionSpecialCases(TypeMask other, CommonMasks domain,
|
||||
{required bool isNullable, required bool hasLateSentinel}) {
|
||||
if (other is ValueTypeMask &&
|
||||
forwardTo.withoutFlags() == other.forwardTo.withoutFlags() &&
|
||||
value == other.value) {
|
||||
|
|
|
@ -491,7 +491,8 @@ class WrappedAbstractValueDomain implements AbstractValueDomain {
|
|||
|
||||
@override
|
||||
AbstractValueWithPrecision createFromStaticType(DartType type,
|
||||
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
|
||||
{ClassRelation classRelation = ClassRelation.subtype,
|
||||
/* required */ bool nullable}) {
|
||||
var unwrapped = _abstractValueDomain.createFromStaticType(type,
|
||||
classRelation: classRelation, nullable: nullable);
|
||||
return AbstractValueWithPrecision(
|
||||
|
|
Loading…
Reference in a new issue