Use AbstractValue/AbstractValueDomain in function_set.dart

Change-Id: I8c2e80d7d6722254eec2c8753c2f37a495a9026a
Reviewed-on: https://dart-review.googlesource.com/55899
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index 4b2849d..6b35ca4 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -6,6 +6,7 @@
 
 import '../constants/values.dart' show ConstantValue;
 import '../elements/entities.dart';
+import '../universe/selector.dart';
 
 /// A value in an abstraction of runtime values.
 abstract class AbstractValue {}
@@ -255,4 +256,16 @@
   /// Returns the value type of [value] if it represents a map value at runtime.
   /// Returns [dynamicType] otherwise.
   AbstractValue getMapValueType(AbstractValue value);
+
+  /// Compute the type of all potential receivers of the set of live [members].
+  AbstractValue computeReceiver(Iterable<MemberEntity> members);
+
+  /// Returns whether [member] is a potential target when being
+  /// invoked on a [receiver]. [selector] is used to ensure library privacy is
+  /// taken into account.
+  bool canHit(AbstractValue receiver, MemberEntity member, Selector selector);
+
+  /// Returns whether [selector] invoked on a [receiver] can hit a
+  /// [noSuchMethod].
+  bool needsNoSuchMethodHandling(AbstractValue receiver, Selector selector);
 }
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
index 22a39b0..8e4916c 100644
--- a/pkg/compiler/lib/src/types/masks.dart
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -409,4 +409,37 @@
     }
     return result;
   }
+
+  @override
+  AbstractValue computeReceiver(Iterable<MemberEntity> members) {
+    assert(_closedWorld
+        .hasAnyStrictSubclass(_closedWorld.commonElements.objectClass));
+    return new TypeMask.unionOf(
+        members.expand((MemberEntity element) {
+          ClassEntity cls = element.enclosingClass;
+          return [cls]..addAll(_closedWorld.mixinUsesOf(cls));
+        }).map((cls) {
+          if (_closedWorld.commonElements.jsNullClass == cls) {
+            return const TypeMask.empty();
+          } else if (_closedWorld.isInstantiated(cls)) {
+            return new TypeMask.nonNullSubclass(cls, _closedWorld);
+          } else {
+            // TODO(johnniwinther): Avoid the need for this case.
+            return const TypeMask.empty();
+          }
+        }),
+        _closedWorld);
+  }
+
+  @override
+  bool canHit(
+      covariant TypeMask receiver, MemberEntity member, Selector selector) {
+    return receiver.canHit(member, selector, _closedWorld);
+  }
+
+  @override
+  bool needsNoSuchMethodHandling(
+      covariant TypeMask receiver, Selector selector) {
+    return receiver.needsNoSuchMethodHandling(selector, _closedWorld);
+  }
 }
diff --git a/pkg/compiler/lib/src/universe/function_set.dart b/pkg/compiler/lib/src/universe/function_set.dart
index 4d64297..aee80f5 100644
--- a/pkg/compiler/lib/src/universe/function_set.dart
+++ b/pkg/compiler/lib/src/universe/function_set.dart
@@ -6,11 +6,9 @@
 
 import '../common/names.dart' show Identifiers, Selectors;
 import '../elements/entities.dart';
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../util/util.dart' show Hashing, Setlet;
-import '../world.dart' show ClosedWorld;
 import 'selector.dart' show Selector;
-import 'world_builder.dart' show ReceiverConstraint;
 
 // TODO(kasperl): This actually holds getters and setters just fine
 // too and stricly they aren't functions. Maybe this needs a better
@@ -41,9 +39,9 @@
   /// receiver with the given [constraint]. The returned elements may include
   /// noSuchMethod handlers that are potential targets indirectly through the
   /// noSuchMethod mechanism.
-  Iterable<MemberEntity> filter(Selector selector,
-      ReceiverConstraint constraint, ClosedWorld closedWorld) {
-    return query(selector, constraint, closedWorld).functions;
+  Iterable<MemberEntity> filter(
+      Selector selector, AbstractValue receiver, AbstractValueDomain domain) {
+    return query(selector, receiver, domain).functions;
   }
 
   /// Returns the mask for the potential receivers of a dynamic call to
@@ -52,43 +50,38 @@
   /// This will narrow the constraints of [constraint] to a [TypeMask] of the
   /// set of classes that actually implement the selected member or implement
   /// the handling 'noSuchMethod' where the selected member is unimplemented.
-  TypeMask receiverType(Selector selector, ReceiverConstraint constraint,
-      ClosedWorld closedWorld) {
-    return query(selector, constraint, closedWorld).computeMask(closedWorld);
+  AbstractValue receiverType(
+      Selector selector, AbstractValue receiver, AbstractValueDomain domain) {
+    return query(selector, receiver, domain).computeMask(domain);
   }
 
-  SelectorMask _createSelectorMask(Selector selector,
-      ReceiverConstraint constraint, ClosedWorld closedWorld) {
-    return constraint != null
-        ? new SelectorMask(selector, constraint)
-        : new SelectorMask(
-            selector,
-            new TypeMask.subclass(
-                closedWorld.commonElements.objectClass, closedWorld));
+  SelectorMask _createSelectorMask(
+      Selector selector, AbstractValue receiver, AbstractValueDomain domain) {
+    return receiver != null
+        ? new SelectorMask(selector, receiver)
+        : new SelectorMask(selector, domain.dynamicType);
   }
 
   /// Returns the set of functions that can be the target of a call to
   /// [selector] on a receiver constrained by [constraint] including
   /// 'noSuchMethod' methods where applicable.
-  FunctionSetQuery query(Selector selector, ReceiverConstraint constraint,
-      ClosedWorld closedWorld) {
+  FunctionSetQuery query(
+      Selector selector, AbstractValue receiver, AbstractValueDomain domain) {
     String name = selector.name;
-    SelectorMask selectorMask =
-        _createSelectorMask(selector, constraint, closedWorld);
+    SelectorMask selectorMask = _createSelectorMask(selector, receiver, domain);
     SelectorMask noSuchMethodMask =
-        new SelectorMask(Selectors.noSuchMethod_, selectorMask.constraint);
+        new SelectorMask(Selectors.noSuchMethod_, selectorMask.receiver);
     FunctionSetNode node = _nodes[name];
     FunctionSetNode noSuchMethods = _nodes[Identifiers.noSuchMethod_];
     if (node != null) {
-      return node.query(
-          selectorMask, closedWorld, noSuchMethods, noSuchMethodMask);
+      return node.query(selectorMask, domain, noSuchMethods, noSuchMethodMask);
     }
     // If there is no method that matches [selector] we know we can
     // only hit [:noSuchMethod:].
     if (noSuchMethods == null) {
       return const EmptyFunctionSetQuery();
     }
-    return noSuchMethods.query(noSuchMethodMask, closedWorld);
+    return noSuchMethods.query(noSuchMethodMask, domain);
   }
 
   void forEach(void action(MemberEntity member)) {
@@ -102,34 +95,32 @@
 /// on a receiver constrained by [constraint].
 class SelectorMask {
   final Selector selector;
-  final ReceiverConstraint constraint;
+  final AbstractValue receiver;
   final int hashCode;
 
-  SelectorMask(Selector selector, ReceiverConstraint constraint)
-      : this.selector = selector,
-        this.constraint = constraint,
-        this.hashCode =
-            Hashing.mixHashCodeBits(selector.hashCode, constraint.hashCode) {
-    assert(constraint != null);
+  SelectorMask(this.selector, this.receiver)
+      : this.hashCode =
+            Hashing.mixHashCodeBits(selector.hashCode, receiver.hashCode) {
+    assert(receiver != null);
   }
 
   String get name => selector.name;
 
-  bool applies(MemberEntity element, ClosedWorld closedWorld) {
+  bool applies(MemberEntity element, AbstractValueDomain domain) {
     if (!selector.appliesUnnamed(element)) return false;
-    return constraint.canHit(element, selector, closedWorld);
+    return domain.canHit(receiver, element, selector);
   }
 
-  bool needsNoSuchMethodHandling(ClosedWorld closedWorld) {
-    return constraint.needsNoSuchMethodHandling(selector, closedWorld);
+  bool needsNoSuchMethodHandling(AbstractValueDomain domain) {
+    return domain.needsNoSuchMethodHandling(receiver, selector);
   }
 
   bool operator ==(other) {
     if (identical(this, other)) return true;
-    return selector == other.selector && constraint == other.constraint;
+    return selector == other.selector && receiver == other.receiver;
   }
 
-  String toString() => '($selector,$constraint)';
+  String toString() => '($selector,$receiver)';
 }
 
 /// A node in the [FunctionSet] caching all [FunctionSetQuery] object for
@@ -202,7 +193,7 @@
 
   /// Returns the set of functions that can be the target of [selectorMask]
   /// including no such method handling where applicable.
-  FunctionSetQuery query(SelectorMask selectorMask, ClosedWorld closedWorld,
+  FunctionSetQuery query(SelectorMask selectorMask, AbstractValueDomain domain,
       [FunctionSetNode noSuchMethods, SelectorMask noSuchMethodMask]) {
     assert(selectorMask.name == name);
     FunctionSetQuery result = cache[selectorMask];
@@ -210,7 +201,7 @@
 
     Setlet<MemberEntity> functions;
     for (MemberEntity element in elements) {
-      if (selectorMask.applies(element, closedWorld)) {
+      if (selectorMask.applies(element, domain)) {
         if (functions == null) {
           // Defer the allocation of the functions set until we are
           // sure we need it. This allows us to return immutable empty
@@ -225,9 +216,9 @@
     // add [noSuchMethod] implementations that apply to [mask] as
     // potential targets.
     if (noSuchMethods != null &&
-        selectorMask.needsNoSuchMethodHandling(closedWorld)) {
+        selectorMask.needsNoSuchMethodHandling(domain)) {
       FunctionSetQuery noSuchMethodQuery =
-          noSuchMethods.query(noSuchMethodMask, closedWorld);
+          noSuchMethods.query(noSuchMethodMask, domain);
       if (!noSuchMethodQuery.functions.isEmpty) {
         if (functions == null) {
           functions =
@@ -263,7 +254,7 @@
   const FunctionSetQuery();
 
   /// Compute the type of all potential receivers of this function set.
-  TypeMask computeMask(ClosedWorld closedWorld);
+  AbstractValue computeMask(AbstractValueDomain domain);
 
   /// Returns all potential targets of this function set.
   Iterable<MemberEntity> get functions;
@@ -273,8 +264,7 @@
   const EmptyFunctionSetQuery();
 
   @override
-  TypeMask computeMask(ClosedWorld closedWorld) =>
-      const TypeMask.nonNullEmpty();
+  AbstractValue computeMask(AbstractValueDomain domain) => domain.emptyType;
 
   @override
   Iterable<MemberEntity> get functions => const <MemberEntity>[];
@@ -286,31 +276,14 @@
   @override
   final Iterable<MemberEntity> functions;
 
-  TypeMask _mask;
+  AbstractValue _receiver;
 
   FullFunctionSetQuery(this.functions);
 
   @override
-  TypeMask computeMask(ClosedWorld closedWorld) {
-    assert(closedWorld
-        .hasAnyStrictSubclass(closedWorld.commonElements.objectClass));
-    if (_mask != null) return _mask;
-    return _mask = new TypeMask.unionOf(
-        functions.expand((MemberEntity element) {
-          ClassEntity cls = element.enclosingClass;
-          return [cls]..addAll(closedWorld.mixinUsesOf(cls));
-        }).map((cls) {
-          if (closedWorld.commonElements.jsNullClass == cls) {
-            return const TypeMask.empty();
-          } else if (closedWorld.isInstantiated(cls)) {
-            return new TypeMask.nonNullSubclass(cls, closedWorld);
-          } else {
-            // TODO(johnniwinther): Avoid the need for this case.
-            return const TypeMask.empty();
-          }
-        }),
-        closedWorld);
+  AbstractValue computeMask(AbstractValueDomain domain) {
+    return _receiver ??= domain.computeReceiver(functions);
   }
 
-  String toString() => '$_mask:$functions';
+  String toString() => '$_receiver:$functions';
 }
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 91a7d5b..523bca7 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -1054,18 +1054,18 @@
     if (includesClosureCall(selector, mask)) {
       return abstractValueDomain.dynamicType;
     }
-    return _allFunctions.receiverType(selector, mask, this);
+    return _allFunctions.receiverType(selector, mask, abstractValueDomain);
   }
 
   Iterable<MemberEntity> locateMembers(Selector selector, TypeMask mask) {
     _ensureFunctionSet();
-    return _allFunctions.filter(selector, mask, this);
+    return _allFunctions.filter(selector, mask, abstractValueDomain);
   }
 
   bool hasAnyUserDefinedGetter(Selector selector, TypeMask mask) {
     _ensureFunctionSet();
     return _allFunctions
-        .filter(selector, mask, this)
+        .filter(selector, mask, abstractValueDomain)
         .any((each) => each.isGetter);
   }
 
@@ -1117,7 +1117,8 @@
     }
     SideEffects sideEffects = new SideEffects.empty();
     _ensureFunctionSet();
-    for (MemberEntity e in _allFunctions.filter(selector, mask, this)) {
+    for (MemberEntity e
+        in _allFunctions.filter(selector, mask, abstractValueDomain)) {
       if (e.isField) {
         if (selector.isGetter) {
           if (!fieldNeverChanges(e)) {