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