Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
index 5ef491bd3195c94721de5189ef157bd044c059f2..d59a717da9dabbfcaed82bde628b410fb82f1682 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
@@ -30,248 +30,7 @@ import '../universe/universe.dart'; |
import '../world.dart' show World; |
import 'cps_fragment.dart'; |
import 'cps_ir_nodes.dart'; |
-import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier; |
- |
-enum AbstractBool { |
- True, False, Maybe, Nothing |
-} |
- |
-class TypeMaskSystem { |
- final TypesTask inferrer; |
- final World classWorld; |
- final JavaScriptBackend backend; |
- |
- TypeMask get dynamicType => inferrer.dynamicType; |
- TypeMask get typeType => inferrer.typeType; |
- TypeMask get functionType => inferrer.functionType; |
- TypeMask get boolType => inferrer.boolType; |
- TypeMask get intType => inferrer.intType; |
- TypeMask get doubleType => inferrer.doubleType; |
- TypeMask get numType => inferrer.numType; |
- TypeMask get stringType => inferrer.stringType; |
- TypeMask get listType => inferrer.listType; |
- TypeMask get mapType => inferrer.mapType; |
- TypeMask get nonNullType => inferrer.nonNullType; |
- TypeMask get extendableNativeListType => backend.extendableArrayType; |
- |
- TypeMask numStringBoolType; |
- |
- ClassElement get jsNullClass => backend.jsNullClass; |
- |
- // TODO(karlklose): remove compiler here. |
- TypeMaskSystem(dart2js.Compiler compiler) |
- : inferrer = compiler.typesTask, |
- classWorld = compiler.world, |
- backend = compiler.backend { |
- |
- // Build the number+string+bool type. To make containment tests more |
- // inclusive, we use the num, String, bool types for this, not |
- // the JSNumber, JSString, JSBool subclasses. |
- TypeMask anyNum = |
- new TypeMask.nonNullSubtype(classWorld.numClass, classWorld); |
- TypeMask anyString = |
- new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld); |
- TypeMask anyBool = |
- new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld); |
- numStringBoolType = |
- new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool], |
- classWorld); |
- } |
- |
- bool methodUsesReceiverArgument(FunctionElement function) { |
- assert(backend.isInterceptedMethod(function)); |
- ClassElement clazz = function.enclosingClass.declaration; |
- return clazz.isSubclassOf(backend.jsInterceptorClass) || |
- classWorld.isUsedAsMixin(clazz); |
- } |
- |
- Element locateSingleElement(TypeMask mask, Selector selector) { |
- return mask.locateSingleElement(selector, mask, classWorld.compiler); |
- } |
- |
- ClassElement singleClass(TypeMask mask) { |
- return mask.singleClass(classWorld); |
- } |
- |
- bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) { |
- return mask.needsNoSuchMethodHandling(selector, classWorld); |
- } |
- |
- TypeMask getReceiverType(MethodElement method) { |
- assert(method.isInstanceMember); |
- if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) { |
- // If used as a mixin, the receiver could be any of the classes that mix |
- // in the class, and these are not considered subclasses. |
- // TODO(asgerf): Exclude the subtypes that only `implement` the class. |
- return nonNullSubtype(method.enclosingClass); |
- } else { |
- return nonNullSubclass(method.enclosingClass); |
- } |
- } |
- |
- TypeMask getParameterType(ParameterElement parameter) { |
- return inferrer.getGuaranteedTypeOfElement(parameter); |
- } |
- |
- TypeMask getReturnType(FunctionElement function) { |
- return inferrer.getGuaranteedReturnTypeOfElement(function); |
- } |
- |
- TypeMask getInvokeReturnType(Selector selector, TypeMask mask) { |
- return inferrer.getGuaranteedTypeOfSelector(selector, mask); |
- } |
- |
- TypeMask getFieldType(FieldElement field) { |
- return inferrer.getGuaranteedTypeOfElement(field); |
- } |
- |
- TypeMask join(TypeMask a, TypeMask b) { |
- return a.union(b, classWorld); |
- } |
- |
- TypeMask getTypeOf(ConstantValue constant) { |
- return computeTypeMask(inferrer.compiler, constant); |
- } |
- |
- TypeMask nonNullExact(ClassElement element) { |
- // 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? |
- if (element.isClosure) return functionType; |
- return new TypeMask.nonNullExact(element.declaration, classWorld); |
- } |
- |
- TypeMask nonNullSubclass(ClassElement element) { |
- if (element.isClosure) return functionType; |
- return new TypeMask.nonNullSubclass(element.declaration, classWorld); |
- } |
- |
- TypeMask nonNullSubtype(ClassElement element) { |
- if (element.isClosure) return functionType; |
- return new TypeMask.nonNullSubtype(element.declaration, classWorld); |
- } |
- |
- bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().containsOnlyBool(classWorld); |
- } |
- |
- bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().containsOnlyNum(classWorld); |
- } |
- |
- bool isDefinitelyString(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().containsOnlyString(classWorld); |
- } |
- |
- bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return numStringBoolType.containsMask(t.nonNullable(), classWorld); |
- } |
- |
- bool isDefinitelyNotNumStringBool(TypeMask t) { |
- return areDisjoint(t, numStringBoolType); |
- } |
- |
- /// True if all values of [t] are either integers or not numbers at all. |
- /// |
- /// This does not imply that the value is an integer, since most other values |
- /// such as null are also not a non-integer double. |
- 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* |
- // double class, so this excludes things that are known to be instances of a |
- // more specific class. |
- // We currently exploit that there are no subclasses of double that are |
- // not integers (e.g. there is no UnsignedDouble class or whatever). |
- return areDisjoint(t, doubleType); |
- } |
- |
- bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.satisfies(backend.jsIntClass, classWorld); |
- } |
- |
- bool isDefinitelyNativeList(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().satisfies(backend.jsArrayClass, classWorld); |
- } |
- |
- bool isDefinitelyMutableNativeList(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().satisfies(backend.jsMutableArrayClass, classWorld); |
- } |
- |
- bool isDefinitelyFixedNativeList(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().satisfies(backend.jsFixedArrayClass, classWorld); |
- } |
- |
- bool isDefinitelyExtendableNativeList(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().satisfies(backend.jsExtendableArrayClass, |
- classWorld); |
- } |
- |
- bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) { |
- if (!allowNull && t.isNullable) return false; |
- return t.nonNullable().satisfies(backend.jsIndexableClass, classWorld); |
- } |
- |
- bool areDisjoint(TypeMask leftType, TypeMask rightType) { |
- TypeMask intersection = leftType.intersection(rightType, classWorld); |
- return intersection.isEmpty && !intersection.isNullable; |
- } |
- |
- AbstractBool isSubtypeOf(TypeMask value, |
- types.DartType type, |
- {bool allowNull}) { |
- assert(allowNull != null); |
- if (type is types.DynamicType) { |
- return AbstractBool.True; |
- } |
- if (type is types.InterfaceType) { |
- TypeMask typeAsMask = allowNull |
- ? new TypeMask.subtype(type.element, classWorld) |
- : new TypeMask.nonNullSubtype(type.element, classWorld); |
- if (areDisjoint(value, typeAsMask)) { |
- // Disprove the subtype relation based on the class alone. |
- return AbstractBool.False; |
- } |
- if (!type.treatAsRaw) { |
- // If there are type arguments, we cannot prove the subtype relation, |
- // because the type arguments are unknown on both the value and type. |
- return AbstractBool.Maybe; |
- } |
- if (typeAsMask.containsMask(value, classWorld)) { |
- // All possible values are contained in the set of allowed values. |
- // Note that we exploit the fact that [typeAsMask] is an exact |
- // representation of [type], not an approximation. |
- return AbstractBool.True; |
- } |
- // The value is neither contained in the type, nor disjoint from the type. |
- return AbstractBool.Maybe; |
- } |
- // TODO(asgerf): Support function types, and what else might be missing. |
- return AbstractBool.Maybe; |
- } |
- |
- /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN, |
- /// the empty string, or null. |
- AbstractBool boolify(TypeMask type) { |
- if (isDefinitelyNotNumStringBool(type) && !type.isNullable) { |
- return AbstractBool.True; |
- } |
- return AbstractBool.Maybe; |
- } |
- |
- AbstractBool strictBoolify(TypeMask type) { |
- if (areDisjoint(type, boolType)) return AbstractBool.False; |
- return AbstractBool.Maybe; |
- } |
-} |
+import 'type_mask_system.dart'; |
class ConstantPropagationLattice { |
final TypeMaskSystem typeSystem; |
@@ -575,17 +334,17 @@ class TypePropagator extends Pass { |
final dart2js.Compiler _compiler; |
final CpsFunctionCompiler _functionCompiler; |
- // The constant system is used for evaluation of expressions with constant |
- // arguments. |
final ConstantPropagationLattice _lattice; |
final dart2js.InternalErrorFunction _internalError; |
final Map<Definition, AbstractValue> _values = <Definition, AbstractValue>{}; |
- TypePropagator(dart2js.Compiler compiler, this._functionCompiler) |
+ TypePropagator(dart2js.Compiler compiler, |
+ TypeMaskSystem typeSystem, |
+ this._functionCompiler) |
: _compiler = compiler, |
_internalError = compiler.internalError, |
_lattice = new ConstantPropagationLattice( |
- new TypeMaskSystem(compiler), |
+ typeSystem, |
compiler.backend.constantSystem, |
compiler.types); |
@@ -2572,13 +2331,10 @@ class TypePropagationVisitor implements Visitor { |
case AbstractBool.Maybe: |
setReachable(cont); |
- TypeMask type = input.type; |
- if (node.type.element is ClassElement) { |
- // Narrow type of output to those that survive the cast. |
- type = type.intersection( |
- new TypeMask.subtype(node.type.element, classWorld), |
- classWorld); |
- } |
+ // Narrow type of output to those that survive the cast. |
+ TypeMask type = input.type.intersection( |
+ typeSystem.subtypesOf(node.type), |
+ classWorld); |
setValue(cont.parameters.single, nonConstant(type)); |
break; |
} |