[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:
Nate Biggs 2022-09-22 00:29:47 +00:00 committed by Commit Bot
parent 48b2cb6ea2
commit 182742a61c
26 changed files with 568 additions and 738 deletions

View file

@ -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);
}

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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();

View file

@ -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) {

View file

@ -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);

View file

@ -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(' | ');

View file

@ -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);

View file

@ -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);
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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(

View file

@ -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);
}

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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();

View file

@ -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) {

View file

@ -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);

View file

@ -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(' | ');

View file

@ -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);

View file

@ -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);
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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(