Index: pkg/compiler/lib/src/cps_ir/type_mask_system.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart |
index 58d7330cc754175d428d52499d86a7e1c60d0ad0..a0da73e51282875c0c5004737d4d991fd609b624 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart |
@@ -11,17 +11,13 @@ import '../dart_types.dart' as types; |
import '../elements/elements.dart'; |
import '../js_backend/backend_helpers.dart' show BackendHelpers; |
import '../js_backend/js_backend.dart' show JavaScriptBackend; |
+import '../types/abstract_value_domain.dart'; |
import '../types/types.dart'; |
import '../types/constants.dart' show computeTypeMask; |
import '../universe/selector.dart' show Selector; |
-import '../universe/call_structure.dart' show CallStructure; |
import '../world.dart' show World; |
-enum AbstractBool { |
- True, False, Maybe, Nothing |
-} |
- |
-class TypeMaskSystem { |
+class TypeMaskSystem implements AbstractValueDomain { |
final TypesTask inferrer; |
final World classWorld; |
final JavaScriptBackend backend; |
@@ -33,27 +29,62 @@ class TypeMaskSystem { |
TypeMask __indexableTypeTest; |
+ @override |
TypeMask get dynamicType => inferrer.dynamicType; |
+ |
+ @override |
TypeMask get typeType => inferrer.typeType; |
+ |
+ @override |
TypeMask get functionType => inferrer.functionType; |
+ |
+ @override |
TypeMask get boolType => inferrer.boolType; |
+ |
+ @override |
TypeMask get intType => inferrer.intType; |
+ |
+ @override |
TypeMask get doubleType => inferrer.doubleType; |
+ |
+ @override |
TypeMask get numType => inferrer.numType; |
+ |
+ @override |
TypeMask get stringType => inferrer.stringType; |
+ |
+ @override |
TypeMask get listType => inferrer.listType; |
+ |
+ @override |
TypeMask get mapType => inferrer.mapType; |
+ |
+ @override |
TypeMask get nonNullType => inferrer.nonNullType; |
+ |
+ @override |
TypeMask get nullType => inferrer.nullType; |
+ |
+ @override |
TypeMask get extendableArrayType => backend.extendableArrayType; |
+ |
+ @override |
TypeMask get fixedArrayType => backend.fixedArrayType; |
+ |
+ @override |
TypeMask get arrayType => |
new TypeMask.nonNullSubclass(helpers.jsArrayClass, classWorld); |
+ @override |
TypeMask get uint31Type => inferrer.uint31Type; |
+ |
+ @override |
TypeMask get uint32Type => inferrer.uint32Type; |
+ |
+ @override |
TypeMask get uintType => inferrer.positiveIntType; |
+ @override |
TypeMask get numStringBoolType { |
if (_numStringBoolType == null) { |
// Build the number+string+bool type. To make containment tests more |
@@ -72,6 +103,7 @@ class TypeMaskSystem { |
return _numStringBoolType; |
} |
+ @override |
TypeMask get fixedLengthType { |
if (_fixedLengthType == null) { |
List<TypeMask> fixedLengthTypes = |
@@ -84,6 +116,7 @@ class TypeMaskSystem { |
return _fixedLengthType; |
} |
+ @override |
TypeMask get interceptorType { |
if (_interceptorType == null) { |
_interceptorType = |
@@ -92,6 +125,7 @@ class TypeMaskSystem { |
return _interceptorType; |
} |
+ @override |
TypeMask get interceptedTypes { // Does not include null. |
if (_interceptedTypes == null) { |
// We redundantly include subtypes of num/string/bool as intercepted |
@@ -130,6 +164,7 @@ class TypeMaskSystem { |
backend = compiler.backend { |
} |
+ @override |
bool methodUsesReceiverArgument(FunctionElement function) { |
assert(backend.isInterceptedMethod(function)); |
ClassElement clazz = function.enclosingClass.declaration; |
@@ -137,18 +172,22 @@ class TypeMaskSystem { |
classWorld.isUsedAsMixin(clazz); |
} |
+ @override |
Element locateSingleElement(TypeMask mask, Selector selector) { |
return mask.locateSingleElement(selector, mask, classWorld.compiler); |
} |
+ @override |
ClassElement singleClass(TypeMask mask) { |
return mask.singleClass(classWorld); |
} |
+ @override |
bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) { |
return mask.needsNoSuchMethodHandling(selector, classWorld); |
} |
+ @override |
TypeMask getReceiverType(MethodElement method) { |
assert(method.isInstanceMember); |
if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) { |
@@ -161,14 +200,17 @@ class TypeMaskSystem { |
} |
} |
+ @override |
TypeMask getParameterType(ParameterElement parameter) { |
return inferrer.getGuaranteedTypeOfElement(parameter); |
} |
+ @override |
TypeMask getReturnType(FunctionElement function) { |
return inferrer.getGuaranteedReturnTypeOfElement(function); |
} |
+ @override |
TypeMask getInvokeReturnType(Selector selector, TypeMask mask) { |
TypeMask result = inferrer.getGuaranteedTypeOfSelector(selector, mask); |
// Tearing off .call from a function returns the function itself. |
@@ -180,26 +222,29 @@ class TypeMaskSystem { |
return result; |
} |
+ @override |
TypeMask getFieldType(FieldElement field) { |
return inferrer.getGuaranteedTypeOfElement(field); |
} |
+ @override |
TypeMask join(TypeMask a, TypeMask b) { |
return a.union(b, classWorld); |
} |
+ @override |
TypeMask intersection(TypeMask a, TypeMask b) { |
if (a == null) return b; |
if (b == null) return a; |
return a.intersection(b, classWorld); |
} |
+ @override |
TypeMask getTypeOf(ConstantValue constant) { |
return computeTypeMask(inferrer.compiler, constant); |
} |
- // Returns the constant value if a TypeMask represents a single value. |
- // Returns `null` if [mask] is not a constant. |
+ @override |
ConstantValue getConstantOf(TypeMask mask) { |
if (!mask.isValue) return null; |
if (mask.isNullable) return null; // e.g. 'true or null'. |
@@ -209,7 +254,9 @@ class TypeMaskSystem { |
return null; |
} |
+ @override |
TypeMask nonNullExact(ClassElement element) { |
+ // TODO(johnniwinther): I don't think the follow is valid anymore. |
// The class world does not know about classes created by |
// closure conversion, so just treat those as a subtypes of Function. |
// TODO(asgerf): Maybe closure conversion should create a new ClassWorld? |
@@ -217,36 +264,43 @@ class TypeMaskSystem { |
return new TypeMask.nonNullExact(element.declaration, classWorld); |
} |
+ @override |
TypeMask nonNullSubclass(ClassElement element) { |
if (element.isClosure) return functionType; |
return new TypeMask.nonNullSubclass(element.declaration, classWorld); |
} |
+ @override |
TypeMask nonNullSubtype(ClassElement element) { |
if (element.isClosure) return functionType; |
return new TypeMask.nonNullSubtype(element.declaration, classWorld); |
} |
+ @override |
bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().containsOnlyBool(classWorld); |
} |
+ @override |
bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().containsOnlyNum(classWorld); |
} |
+ @override |
bool isDefinitelyString(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().containsOnlyString(classWorld); |
} |
+ @override |
bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return numStringBoolType.containsMask(t.nonNullable(), classWorld); |
} |
+ @override |
bool isDefinitelyNotNumStringBool(TypeMask t) { |
return areDisjoint(t, numStringBoolType); |
} |
@@ -255,6 +309,7 @@ class TypeMaskSystem { |
/// |
/// This does not imply that the value is an integer, since most other values |
/// such as null are also not a non-integer double. |
+ @override |
bool isDefinitelyNotNonIntegerDouble(TypeMask t) { |
// Even though int is a subclass of double in the JS type system, we can |
// still check this with disjointness, because [doubleType] is the *exact* |
@@ -265,69 +320,82 @@ class TypeMaskSystem { |
return areDisjoint(t, doubleType); |
} |
+ @override |
bool isDefinitelyNonNegativeInt(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
// The JSPositiveInt class includes zero, despite the name. |
return t.satisfies(helpers.jsPositiveIntClass, classWorld); |
} |
+ @override |
bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().containsOnlyInt(classWorld); |
} |
+ @override |
bool isDefinitelyUint31(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.satisfies(helpers.jsUInt31Class, classWorld); |
} |
+ @override |
bool isDefinitelyUint32(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.satisfies(helpers.jsUInt32Class, classWorld); |
} |
+ @override |
bool isDefinitelyUint(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.satisfies(helpers.jsPositiveIntClass, classWorld); |
} |
+ @override |
bool isDefinitelyArray(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().satisfies(helpers.jsArrayClass, classWorld); |
} |
+ @override |
bool isDefinitelyMutableArray(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().satisfies(helpers.jsMutableArrayClass, classWorld); |
} |
+ @override |
bool isDefinitelyFixedArray(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().satisfies(helpers.jsFixedArrayClass, classWorld); |
} |
+ @override |
bool isDefinitelyExtendableArray(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().satisfies(helpers.jsExtendableArrayClass, |
classWorld); |
} |
+ @override |
bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return _indexableTypeTest.containsMask(t.nonNullable(), classWorld); |
} |
+ @override |
bool isDefinitelyMutableIndexable(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().satisfies(helpers.jsMutableIndexableClass, |
classWorld); |
} |
+ @override |
bool isDefinitelyFixedLengthIndexable(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return fixedLengthType.containsMask(t.nonNullable(), classWorld); |
} |
+ @override |
bool isDefinitelyIntercepted(TypeMask t, {bool allowNull}) { |
assert(allowNull != null); |
if (!allowNull && t.isNullable) return false; |
@@ -336,6 +404,7 @@ class TypeMaskSystem { |
/// Given a class from the interceptor hierarchy, returns a [TypeMask] |
/// matching all values with that interceptor (or a subtype thereof). |
+ @override |
TypeMask getInterceptorSubtypes(ClassElement class_) { |
if (class_ == helpers.jsInterceptorClass) { |
return interceptorType.nullable(); |
@@ -346,15 +415,18 @@ class TypeMaskSystem { |
} |
} |
+ @override |
bool areDisjoint(TypeMask leftType, TypeMask rightType) { |
TypeMask intersected = intersection(leftType, rightType); |
return intersected.isEmpty && !intersected.isNullable; |
} |
+ @override |
bool isMorePreciseOrEqual(TypeMask t1, TypeMask t2) { |
return t2.containsMask(t1, classWorld); |
} |
+ @override |
AbstractBool isSubtypeOf(TypeMask value, |
types.DartType type, |
{bool allowNull}) { |
@@ -390,6 +462,7 @@ class TypeMaskSystem { |
/// Returns whether [type] is one of the falsy values: false, 0, -0, NaN, |
/// the empty string, or null. |
+ @override |
AbstractBool boolify(TypeMask type) { |
if (isDefinitelyNotNumStringBool(type) && !type.isNullable) { |
return AbstractBool.True; |
@@ -397,12 +470,14 @@ class TypeMaskSystem { |
return AbstractBool.Maybe; |
} |
+ @override |
AbstractBool strictBoolify(TypeMask type) { |
if (areDisjoint(type, boolType)) return AbstractBool.False; |
return AbstractBool.Maybe; |
} |
/// Create a type mask containing at least all subtypes of [type]. |
+ @override |
TypeMask subtypesOf(types.DartType type) { |
if (type is types.InterfaceType) { |
ClassElement element = type.element; |
@@ -435,12 +510,14 @@ class TypeMaskSystem { |
/// Returns a subset of [mask] containing at least the types |
/// that can respond to [selector] without throwing. |
+ @override |
TypeMask receiverTypeFor(Selector selector, TypeMask mask) { |
return classWorld.allFunctions.receiverType(selector, mask); |
} |
/// The result of an index operation on something of [type], or the dynamic |
/// type if unknown. |
+ @override |
TypeMask elementTypeOfIndexable(TypeMask type) { |
if (type is UnionTypeMask) { |
return new TypeMask.unionOf( |
@@ -462,6 +539,7 @@ class TypeMaskSystem { |
} |
/// The length of something of [type], or `null` if unknown. |
+ @override |
int getContainerLength(TypeMask type) { |
if (type is ContainerTypeMask) { |
return type.length; |