Use AbstractValue in KernelToTypeInferenceMap and KernelTypeGraphBuilder

Change-Id: I0af69d10223364256852248228cdbbcbca3f83fa
Reviewed-on: https://dart-review.googlesource.com/56484
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index bb5ebdb..afa3b0a 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -18,7 +18,7 @@
 import '../native/behavior.dart';
 import '../options.dart';
 import '../types/constants.dart';
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../types/types.dart';
 import '../universe/selector.dart';
 import '../universe/side_effects.dart';
@@ -125,7 +125,7 @@
   /// If an instance field matched with a [selector] that is _not_ a setter, the
   /// field is considered to have been read before initialization and the field
   /// is assumed to be potentially `null`.
-  void _checkIfExposesThis(Selector selector, TypeMask mask) {
+  void _checkIfExposesThis(Selector selector, AbstractValue mask) {
     if (_isThisExposed) {
       // We already consider `this` to have been exposed.
       return;
@@ -296,7 +296,7 @@
     ArgumentsTypes arguments = analyzeArguments(node.arguments);
     Selector selector = new Selector(SelectorKind.CALL, constructor.memberName,
         _elementMap.getCallStructure(node.arguments));
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     handleConstructorInvoke(
         node, node.arguments, selector, mask, constructor, arguments);
 
@@ -312,7 +312,7 @@
     ArgumentsTypes arguments = analyzeArguments(node.arguments);
     Selector selector = new Selector(SelectorKind.CALL, constructor.memberName,
         _elementMap.getCallStructure(node.arguments));
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     handleConstructorInvoke(
         node, node.arguments, selector, mask, constructor, arguments);
 
@@ -725,7 +725,7 @@
   @override
   TypeInformation visitMethodInvocation(ir.MethodInvocation node) {
     Selector selector = _elementMap.getSelector(node);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
 
     ir.TreeNode receiver = node.receiver;
     if (receiver is ir.VariableGet &&
@@ -767,7 +767,7 @@
       CallType callType,
       ir.Node node,
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       TypeInformation receiverType,
       ArgumentsTypes arguments) {
     assert(receiverType != null);
@@ -811,13 +811,17 @@
   }
 
   TypeInformation handleDynamicGet(ir.Node node, Selector selector,
-      TypeMask mask, TypeInformation receiverType) {
+      AbstractValue mask, TypeInformation receiverType) {
     return _handleDynamic(
         CallType.access, node, selector, mask, receiverType, null);
   }
 
-  TypeInformation handleDynamicSet(ir.Node node, Selector selector,
-      TypeMask mask, TypeInformation receiverType, TypeInformation rhsType) {
+  TypeInformation handleDynamicSet(
+      ir.Node node,
+      Selector selector,
+      AbstractValue mask,
+      TypeInformation receiverType,
+      TypeInformation rhsType) {
     ArgumentsTypes arguments = new ArgumentsTypes([rhsType], null);
     return _handleDynamic(
         CallType.access, node, selector, mask, receiverType, arguments);
@@ -827,7 +831,7 @@
       CallType callType,
       ir.Node node,
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       TypeInformation receiverType,
       ArgumentsTypes arguments) {
     return _handleDynamic(
@@ -896,8 +900,8 @@
       _markThisAsExposed();
     }
 
-    TypeMask currentMask;
-    TypeMask moveNextMask;
+    AbstractValue currentMask;
+    AbstractValue moveNextMask;
     TypeInformation iteratorType;
     if (node.isAsync) {
       TypeInformation expressionType = visit(node.iterable);
@@ -914,7 +918,7 @@
     } else {
       TypeInformation expressionType = visit(node.iterable);
       Selector iteratorSelector = Selectors.iterator;
-      TypeMask iteratorMask = _memberData.typeOfIterator(node);
+      AbstractValue iteratorMask = _memberData.typeOfIterator(node);
       currentMask = _memberData.typeOfIteratorCurrent(node);
       moveNextMask = _memberData.typeOfIteratorMoveNext(node);
 
@@ -998,7 +1002,7 @@
     ConstructorEntity constructor = _elementMap.getConstructor(node.target);
     ArgumentsTypes arguments = analyzeArguments(node.arguments);
     Selector selector = _elementMap.getSelector(node);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     return handleConstructorInvoke(
         node, node.arguments, selector, mask, constructor, arguments);
   }
@@ -1038,7 +1042,7 @@
       ir.Node node,
       ir.Arguments arguments,
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       ConstructorEntity constructor,
       ArgumentsTypes argumentsTypes) {
     TypeInformation returnType =
@@ -1089,13 +1093,13 @@
   }
 
   TypeInformation handleStaticInvoke(ir.Node node, Selector selector,
-      TypeMask mask, MemberEntity element, ArgumentsTypes arguments) {
+      AbstractValue mask, MemberEntity element, ArgumentsTypes arguments) {
     return _inferrer.registerCalledMember(node, selector, mask, _analyzedMember,
         element, arguments, _sideEffectsBuilder, inLoop);
   }
 
   TypeInformation handleClosureCall(ir.Node node, Selector selector,
-      TypeMask mask, MemberEntity member, ArgumentsTypes arguments) {
+      AbstractValue mask, MemberEntity member, ArgumentsTypes arguments) {
     return _inferrer.registerCalledClosure(
         node,
         selector,
@@ -1112,7 +1116,7 @@
       FunctionEntity function,
       ArgumentsTypes arguments,
       Selector selector,
-      TypeMask mask) {
+      AbstractValue mask) {
     String name = function.name;
     handleStaticInvoke(node, selector, mask, function, arguments);
     if (name == JavaScriptBackend.JS) {
@@ -1143,7 +1147,7 @@
     MemberEntity member = _elementMap.getMember(node.target);
     ArgumentsTypes arguments = analyzeArguments(node.arguments);
     Selector selector = _elementMap.getSelector(node);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     if (_closedWorld.commonElements.isForeign(member)) {
       return handleForeignInvoke(node, member, arguments, selector, mask);
     } else if (member.isConstructor) {
@@ -1165,7 +1169,7 @@
   @override
   TypeInformation visitStaticGet(ir.StaticGet node) {
     MemberEntity member = _elementMap.getMember(node.target);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     return handleStaticInvoke(
         node, new Selector.getter(member.memberName), mask, member, null);
   }
@@ -1177,7 +1181,7 @@
       _markThisAsExposed();
     }
     MemberEntity member = _elementMap.getMember(node.target);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     handleStaticInvoke(node, new Selector.setter(member.memberName), mask,
         member, new ArgumentsTypes([rhsType], null));
     return rhsType;
@@ -1187,7 +1191,7 @@
   TypeInformation visitPropertyGet(ir.PropertyGet node) {
     TypeInformation receiverType = visit(node.receiver);
     Selector selector = _elementMap.getSelector(node);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     // TODO(johnniwinther): Use `node.interfaceTarget` to narrow the receiver
     // type for --trust-type-annotations/strong-mode.
     if (node.receiver is ir.ThisExpression) {
@@ -1201,7 +1205,7 @@
   TypeInformation visitDirectPropertyGet(ir.DirectPropertyGet node) {
     TypeInformation receiverType = thisType;
     MemberEntity member = _elementMap.getMember(node.target);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     // TODO(johnniwinther): Use `node.target` to narrow the receiver type.
     Selector selector = new Selector.getter(member.memberName);
     _checkIfExposesThis(selector, _types.newTypedSelector(receiverType, mask));
@@ -1212,7 +1216,7 @@
   TypeInformation visitPropertySet(ir.PropertySet node) {
     TypeInformation receiverType = visit(node.receiver);
     Selector selector = _elementMap.getSelector(node);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
 
     TypeInformation rhsType = visit(node.value);
     if (node.value is ir.ThisExpression) {
@@ -1220,7 +1224,7 @@
     }
 
     if (_inGenerativeConstructor && node.receiver is ir.ThisExpression) {
-      TypeMask typedMask = _types.newTypedSelector(receiverType, mask);
+      AbstractValue typedMask = _types.newTypedSelector(receiverType, mask);
       if (!_closedWorld.includesClosureCall(selector, typedMask)) {
         Iterable<MemberEntity> targets =
             _closedWorld.locateMembers(selector, typedMask);
@@ -1608,7 +1612,7 @@
   }
 
   TypeInformation handleSuperNoSuchMethod(ir.Node node, Selector selector,
-      TypeMask mask, ArgumentsTypes arguments) {
+      AbstractValue mask, ArgumentsTypes arguments) {
     // Ensure we create a node, to make explicit the call to the
     // `noSuchMethod` handler.
     FunctionEntity noSuchMethod =
@@ -1624,7 +1628,7 @@
 
     MemberEntity member = _elementMap.getSuperMember(
         _analyzedMember, node.name, node.interfaceTarget);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     Selector selector = new Selector.getter(_elementMap.getName(node.name));
     if (member == null) {
       return handleSuperNoSuchMethod(node, selector, mask, null);
@@ -1643,7 +1647,7 @@
     MemberEntity member = _elementMap.getSuperMember(
         _analyzedMember, node.name, node.interfaceTarget,
         setter: true);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     Selector selector = new Selector.setter(_elementMap.getName(node.name));
     ArgumentsTypes arguments = new ArgumentsTypes([rhsType], null);
     if (member == null) {
@@ -1664,7 +1668,7 @@
         _analyzedMember, node.name, node.interfaceTarget);
     ArgumentsTypes arguments = analyzeArguments(node.arguments);
     Selector selector = _elementMap.getSelector(node);
-    TypeMask mask = _memberData.typeOfSend(node);
+    AbstractValue mask = _memberData.typeOfSend(node);
     if (member == null) {
       return handleSuperNoSuchMethod(node, selector, mask, arguments);
     } else if (member.isFunction) {
@@ -1720,7 +1724,7 @@
 
 class Refinement {
   final Selector selector;
-  final TypeMask mask;
+  final AbstractValue mask;
 
   Refinement(this.selector, this.mask);
 }
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index 13adcc4..7c90a63 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -20,7 +20,7 @@
 import '../js_model/elements.dart' show JGeneratorBody;
 import '../native/native.dart' as native;
 import '../ssa/type_builder.dart';
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../universe/call_structure.dart';
 import '../universe/selector.dart';
 import '../world.dart';
@@ -369,58 +369,55 @@
 /// Interface for type inference results for kernel IR nodes.
 abstract class KernelToTypeInferenceMap {
   /// Returns the inferred return type of [function].
-  TypeMask getReturnTypeOf(FunctionEntity function);
+  AbstractValue getReturnTypeOf(FunctionEntity function);
 
   /// Returns the inferred receiver type of the dynamic [invocation].
-  TypeMask receiverTypeOfInvocation(
-      ir.MethodInvocation invocation, ClosedWorld closedWorld);
+  AbstractValue receiverTypeOfInvocation(
+      ir.MethodInvocation invocation, AbstractValueDomain abstractValueDomain);
 
   /// Returns the inferred receiver type of the dynamic [read].
-  TypeMask receiverTypeOfGet(ir.PropertyGet read);
+  AbstractValue receiverTypeOfGet(ir.PropertyGet read);
 
   /// Returns the inferred receiver type of the direct [read].
-  TypeMask receiverTypeOfDirectGet(ir.DirectPropertyGet read);
+  AbstractValue receiverTypeOfDirectGet(ir.DirectPropertyGet read);
 
   /// Returns the inferred receiver type of the dynamic [write].
-  TypeMask receiverTypeOfSet(ir.PropertySet write, ClosedWorld closedWorld);
+  AbstractValue receiverTypeOfSet(
+      ir.PropertySet write, AbstractValueDomain abstractValueDomain);
 
   /// Returns the inferred type of [listLiteral].
-  TypeMask typeOfListLiteral(covariant MemberEntity owner,
-      ir.ListLiteral listLiteral, ClosedWorld closedWorld);
+  AbstractValue typeOfListLiteral(MemberEntity owner,
+      ir.ListLiteral listLiteral, AbstractValueDomain abstractValueDomain);
 
   /// Returns the inferred type of iterator in [forInStatement].
-  TypeMask typeOfIterator(ir.ForInStatement forInStatement);
+  AbstractValue typeOfIterator(ir.ForInStatement forInStatement);
 
   /// Returns the inferred type of `current` in [forInStatement].
-  TypeMask typeOfIteratorCurrent(ir.ForInStatement forInStatement);
+  AbstractValue typeOfIteratorCurrent(ir.ForInStatement forInStatement);
 
   /// Returns the inferred type of `moveNext` in [forInStatement].
-  TypeMask typeOfIteratorMoveNext(ir.ForInStatement forInStatement);
+  AbstractValue typeOfIteratorMoveNext(ir.ForInStatement forInStatement);
 
   /// Returns `true` if [forInStatement] is inferred to be a JavaScript
   /// indexable iterator.
-  bool isJsIndexableIterator(
-      ir.ForInStatement forInStatement, ClosedWorld closedWorld);
-
-  /// Returns `true` if [mask] is inferred to have a JavaScript `length`
-  /// property.
-  bool isFixedLength(TypeMask mask, ClosedWorld closedWorld);
+  bool isJsIndexableIterator(ir.ForInStatement forInStatement,
+      AbstractValueDomain abstractValueDomain);
 
   /// Returns the inferred index type of [forInStatement].
-  TypeMask inferredIndexType(ir.ForInStatement forInStatement);
+  AbstractValue inferredIndexType(ir.ForInStatement forInStatement);
 
   /// Returns the inferred type of [member].
-  TypeMask getInferredTypeOf(MemberEntity member);
+  AbstractValue getInferredTypeOf(MemberEntity member);
 
   /// Returns the inferred type of the [parameter].
-  TypeMask getInferredTypeOfParameter(Local parameter);
+  AbstractValue getInferredTypeOfParameter(Local parameter);
 
-  /// Returns the inferred type of a dynamic [selector] access on a receiver of
-  /// type [mask].
-  TypeMask selectorTypeOf(Selector selector, TypeMask mask);
+  /// Returns the inferred type of a dynamic [selector] access on the
+  /// [receiver].
+  AbstractValue selectorTypeOf(Selector selector, AbstractValue receiver);
 
   /// Returns the returned type annotation in the [nativeBehavior].
-  TypeMask typeFromNativeBehavior(
+  AbstractValue typeFromNativeBehavior(
       native.NativeBehavior nativeBehavior, ClosedWorld closedWorld);
 }
 
diff --git a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
index ae1b004..b0487db 100644
--- a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
@@ -25,7 +25,7 @@
 import '../ssa/nodes.dart';
 import '../ssa/ssa.dart';
 import '../ssa/types.dart';
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../types/types.dart';
 import '../universe/selector.dart';
 import '../universe/world_impact.dart';
@@ -125,92 +125,74 @@
       _globalInferenceResults
           .resultOfMember(e is ConstructorBodyEntity ? e.constructor : e);
 
-  TypeMask getReturnTypeOf(FunctionEntity function) {
+  AbstractValue getReturnTypeOf(FunctionEntity function) {
     return TypeMaskFactory.inferredReturnTypeForElement(
         function, _globalInferenceResults);
   }
 
-  TypeMask receiverTypeOfInvocation(
-      ir.MethodInvocation node, ClosedWorld closedWorld) {
+  AbstractValue receiverTypeOfInvocation(
+      ir.MethodInvocation node, AbstractValueDomain abstractValueDomain) {
     return _targetResults.typeOfSend(node);
   }
 
-  TypeMask receiverTypeOfGet(ir.PropertyGet node) {
+  AbstractValue receiverTypeOfGet(ir.PropertyGet node) {
     return _targetResults.typeOfSend(node);
   }
 
-  TypeMask receiverTypeOfDirectGet(ir.DirectPropertyGet node) {
+  AbstractValue receiverTypeOfDirectGet(ir.DirectPropertyGet node) {
     return _targetResults.typeOfSend(node);
   }
 
-  TypeMask receiverTypeOfSet(ir.PropertySet node, ClosedWorld closedWorld) {
+  AbstractValue receiverTypeOfSet(
+      ir.PropertySet node, AbstractValueDomain abstractValueDomain) {
     return _targetResults.typeOfSend(node);
   }
 
-  TypeMask typeOfListLiteral(
-      MemberEntity owner, ir.ListLiteral listLiteral, ClosedWorld closedWorld) {
+  AbstractValue typeOfListLiteral(MemberEntity owner,
+      ir.ListLiteral listLiteral, AbstractValueDomain abstractValueDomain) {
     return _resultOf(owner).typeOfListLiteral(listLiteral) ??
-        closedWorld.abstractValueDomain.dynamicType;
+        abstractValueDomain.dynamicType;
   }
 
-  TypeMask typeOfIterator(ir.ForInStatement node) {
+  AbstractValue typeOfIterator(ir.ForInStatement node) {
     return _targetResults.typeOfIterator(node);
   }
 
-  TypeMask typeOfIteratorCurrent(ir.ForInStatement node) {
+  AbstractValue typeOfIteratorCurrent(ir.ForInStatement node) {
     return _targetResults.typeOfIteratorCurrent(node);
   }
 
-  TypeMask typeOfIteratorMoveNext(ir.ForInStatement node) {
+  AbstractValue typeOfIteratorMoveNext(ir.ForInStatement node) {
     return _targetResults.typeOfIteratorMoveNext(node);
   }
 
-  bool isJsIndexableIterator(ir.ForInStatement node, ClosedWorld closedWorld) {
-    TypeMask mask = typeOfIterator(node);
-    return mask != null &&
-        mask.satisfies(
-            closedWorld.commonElements.jsIndexableClass, closedWorld) &&
-        // String is indexable but not iterable.
-        !mask.satisfies(closedWorld.commonElements.jsStringClass, closedWorld);
+  bool isJsIndexableIterator(
+      ir.ForInStatement node, AbstractValueDomain abstractValueDomain) {
+    AbstractValue mask = typeOfIterator(node);
+    return abstractValueDomain.isJsIndexableAndIterable(mask);
   }
 
-  bool isFixedLength(covariant TypeMask mask, ClosedWorld closedWorld) {
-    if (mask.isContainer && (mask as ContainerTypeMask).length != null) {
-      // A container on which we have inferred the length.
-      return true;
-    }
-    // TODO(sra): Recognize any combination of fixed length indexables.
-    if (mask.containsOnly(closedWorld.commonElements.jsFixedArrayClass) ||
-        mask.containsOnly(
-            closedWorld.commonElements.jsUnmodifiableArrayClass) ||
-        mask.containsOnlyString(closedWorld) ||
-        closedWorld.abstractValueDomain.isTypedArray(mask)) {
-      return true;
-    }
-    return false;
-  }
-
-  TypeMask inferredIndexType(ir.ForInStatement node) {
+  AbstractValue inferredIndexType(ir.ForInStatement node) {
     return TypeMaskFactory.inferredTypeForSelector(
         new Selector.index(), typeOfIterator(node), _globalInferenceResults);
   }
 
-  TypeMask getInferredTypeOf(MemberEntity member) {
+  AbstractValue getInferredTypeOf(MemberEntity member) {
     return TypeMaskFactory.inferredTypeForMember(
         member, _globalInferenceResults);
   }
 
-  TypeMask getInferredTypeOfParameter(Local parameter) {
+  AbstractValue getInferredTypeOfParameter(Local parameter) {
     return TypeMaskFactory.inferredTypeForParameter(
         parameter, _globalInferenceResults);
   }
 
-  TypeMask selectorTypeOf(Selector selector, covariant TypeMask mask) {
+  AbstractValue selectorTypeOf(Selector selector, AbstractValue mask) {
     return TypeMaskFactory.inferredTypeForSelector(
         selector, mask, _globalInferenceResults);
   }
 
-  TypeMask typeFromNativeBehavior(
+  AbstractValue typeFromNativeBehavior(
       NativeBehavior nativeBehavior, ClosedWorld closedWorld) {
     return TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
   }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 65e1636..df419aa 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1494,7 +1494,8 @@
   void visitForInStatement(ir.ForInStatement node) {
     if (node.isAsync) {
       _buildAsyncForIn(node);
-    } else if (_typeInferenceMap.isJsIndexableIterator(node, closedWorld)) {
+    } else if (_typeInferenceMap.isJsIndexableIterator(
+        node, abstractValueDomain)) {
       // If the expression being iterated over is a JS indexable type, we can
       // generate an optimized version of for-in that uses indexing.
       _buildForInIndexable(node);
@@ -1561,7 +1562,7 @@
       node.iterable.accept(this);
       array = pop();
       isFixed =
-          _typeInferenceMap.isFixedLength(array.instructionType, closedWorld);
+          abstractValueDomain.isFixedLengthJsIndexable(array.instructionType);
       localsHandler.updateLocal(
           indexVariable, graph.addConstantInt(0, closedWorld),
           sourceInformation: sourceInformation);
@@ -2686,8 +2687,8 @@
           listInstruction, type, sourceInformation);
     }
 
-    TypeMask type =
-        _typeInferenceMap.typeOfListLiteral(targetElement, node, closedWorld);
+    TypeMask type = _typeInferenceMap.typeOfListLiteral(
+        targetElement, node, abstractValueDomain);
     if (!type.containsAll(closedWorld)) {
       listInstruction.instructionType = type;
     }
@@ -2926,7 +2927,7 @@
 
     _pushDynamicInvocation(
         node,
-        _typeInferenceMap.receiverTypeOfSet(node, closedWorld),
+        _typeInferenceMap.receiverTypeOfSet(node, abstractValueDomain),
         new Selector.setter(_elementMap.getName(node.name)),
         <HInstruction>[receiver, value],
         const <DartType>[],
@@ -4234,7 +4235,7 @@
         _fillDynamicTypeArguments(selector, node.arguments, typeArguments);
     _pushDynamicInvocation(
         node,
-        _typeInferenceMap.receiverTypeOfInvocation(node, closedWorld),
+        _typeInferenceMap.receiverTypeOfInvocation(node, abstractValueDomain),
         selector,
         <HInstruction>[receiver]..addAll(_visitArgumentsForDynamicTarget(
             selector, node.arguments, typeArguments)),
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index de04b3d..1130029 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -278,4 +278,14 @@
   ///
   /// Returns `null` if 0 or more than 1 member can be hit at runtime.
   MemberEntity locateSingleMember(AbstractValue receiver, Selector selector);
+
+  /// Returns `true` if [value] is a indexable and iterable JavaScript value at
+  /// runtime.
+  ///
+  /// JavaScript arrays are both indexable and iterable whereas JavaScript
+  /// strings are indexable but not iterable.
+  bool isJsIndexableAndIterable(AbstractValue value);
+
+  /// Returns `true` if [value] is an JavaScript indexable of fixed length.
+  bool isFixedLengthJsIndexable(AbstractValue value);
 }
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
index 19455cc..c8a17fb 100644
--- a/pkg/compiler/lib/src/types/masks.dart
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -453,4 +453,31 @@
       covariant TypeMask receiver, Selector selector) {
     return receiver.locateSingleMember(selector, _closedWorld);
   }
+
+  @override
+  bool isJsIndexableAndIterable(covariant TypeMask mask) {
+    return mask != null &&
+        mask.satisfies(
+            _closedWorld.commonElements.jsIndexableClass, _closedWorld) &&
+        // String is indexable but not iterable.
+        !mask.satisfies(
+            _closedWorld.commonElements.jsStringClass, _closedWorld);
+  }
+
+  @override
+  bool isFixedLengthJsIndexable(covariant TypeMask mask) {
+    if (mask.isContainer && (mask as ContainerTypeMask).length != null) {
+      // A container on which we have inferred the length.
+      return true;
+    }
+    // TODO(sra): Recognize any combination of fixed length indexables.
+    if (mask.containsOnly(_closedWorld.commonElements.jsFixedArrayClass) ||
+        mask.containsOnly(
+            _closedWorld.commonElements.jsUnmodifiableArrayClass) ||
+        mask.containsOnlyString(_closedWorld) ||
+        _closedWorld.abstractValueDomain.isTypedArray(mask)) {
+      return true;
+    }
+    return false;
+  }
 }
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 9bd4e8a..46a6d583 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -461,7 +461,7 @@
   final Set<FunctionEntity> _functionsThatMightBePassedToApply =
       new Set<FunctionEntity>();
 
-  CommonMasks _commonMasks;
+  AbstractValueDomain _abstractValueDomain;
 
   final ElementEnvironment elementEnvironment;
   final DartTypes dartTypes;
@@ -500,14 +500,14 @@
       : this._implementedClasses = implementedClasses,
         this._classHierarchyNodes = classHierarchyNodes,
         this._classSets = classSets {
-    _commonMasks = new CommonMasks(this);
+    _abstractValueDomain = new CommonMasks(this);
   }
 
   @override
   ClosedWorld get closedWorld => this;
 
-  CommonMasks get abstractValueDomain {
-    return _commonMasks;
+  AbstractValueDomain get abstractValueDomain {
+    return _abstractValueDomain;
   }
 
   bool checkEntity(covariant Entity element);