[vm/tfa] Streamline handling of tear-offs in TFA

When building a summary, instead of adding a raw call for a torn off
method immediatelly, add a call with PropertyGet kind.
Calls of methods with PropertyGet kind are already handled as
they could appear from dynamic calls.

This has the following advantages:

* Duplicated handling of tear-offs is removed. Now only
  _DirectInvocation._processFunction handles tear-offs, both from
  dynamic and non-dynamic calls.

* This change allow us to more accurately figure out whether the
  tear-off was taken from a particular method, as tear-offs of
  interface methods are now routed through a dispatchable call which
  figures out targets.

Change-Id: I49692577728c03285cb22863c53e4ea3cdd2ab5e
Reviewed-on: https://dart-review.googlesource.com/75386
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/calls.dart b/pkg/vm/lib/transformations/type_flow/calls.dart
index ac69128..958de82 100644
--- a/pkg/vm/lib/transformations/type_flow/calls.dart
+++ b/pkg/vm/lib/transformations/type_flow/calls.dart
@@ -118,9 +118,7 @@
   final Member member;
 
   InterfaceSelector(this.member, {CallKind callKind = CallKind.Method})
-      : super(callKind) {
-    assertx(memberAgreesToCallKind(member));
-  }
+      : super(callKind);
 
   @override
   int get hashCode => (super.hashCode ^ member.hashCode + 31) & kHashMask;
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 4aaa33d..984521d 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -632,17 +632,8 @@
     final receiver = _visit(node.receiver);
     final args = new Args<TypeExpr>([receiver]);
     final target = node.target;
-    if ((target is Field) || ((target is Procedure) && target.isGetter)) {
-      return _makeCall(node,
-          new DirectSelector(target, callKind: CallKind.PropertyGet), args);
-    } else {
-      // Tear-off.
-      // TODO(alexmarkov): Consider cleaning up this code as it duplicates
-      // processing in DirectInvocation.
-      // TODO(alexmarkov): capture receiver type
-      _entryPointsListener.addRawCall(new DirectSelector(target));
-      return _staticType(node);
-    }
+    return _makeCall(
+        node, new DirectSelector(target, callKind: CallKind.PropertyGet), args);
   }
 
   @override
@@ -768,15 +759,8 @@
       return _makeCall(
           node, new DynamicSelector(CallKind.PropertyGet, node.name), args);
     }
-    if ((target is Field) || ((target is Procedure) && target.isGetter)) {
-      return _makeCall(node,
-          new InterfaceSelector(target, callKind: CallKind.PropertyGet), args);
-    } else {
-      // Tear-off.
-      // TODO(alexmarkov): capture receiver type
-      _entryPointsListener.addRawCall(new InterfaceSelector(target));
-      return _staticType(node);
-    }
+    return _makeCall(node,
+        new InterfaceSelector(target, callKind: CallKind.PropertyGet), args);
   }
 
   @override
@@ -835,17 +819,8 @@
     if (target == null) {
       return new Type.empty();
     } else {
-      if ((target is Field) || ((target is Procedure) && target.isGetter)) {
-        return _makeCall(node,
-            new DirectSelector(target, callKind: CallKind.PropertyGet), args);
-      } else {
-        // Tear-off.
-        // TODO(alexmarkov): Consider cleaning up this code as it duplicates
-        // processing in DirectInvocation.
-        // TODO(alexmarkov): capture receiver type
-        _entryPointsListener.addRawCall(new DirectSelector(target));
-        return _staticType(node);
-      }
+      return _makeCall(node,
+          new DirectSelector(target, callKind: CallKind.PropertyGet), args);
     }
   }
 
@@ -886,14 +861,8 @@
   TypeExpr visitStaticGet(StaticGet node) {
     final args = new Args<TypeExpr>(const <TypeExpr>[]);
     final target = node.target;
-    if ((target is Field) || (target is Procedure) && target.isGetter) {
-      return _makeCall(node,
-          new DirectSelector(target, callKind: CallKind.PropertyGet), args);
-    } else {
-      // Tear-off.
-      _entryPointsListener.addRawCall(new DirectSelector(target));
-      return _staticType(node);
-    }
+    return _makeCall(
+        node, new DirectSelector(target, callKind: CallKind.PropertyGet), args);
   }
 
   @override
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
index deb849c..e5c30ed 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
@@ -39,8 +39,9 @@
 t7* = _Call get [#lib::A::foo2] (%aa)
 t8 = _Narrow (t7 to _T (dart.core::int)+?)
 t9 = _Call set [#lib::A::foo3] (%aa, t8)
-t10* = _Call get [#lib::A::foo2] (%aa)
-t11 = _Call dynamic [call] (t10, %a2, %a3, _T ANY?)
+t10* = _Call get [#lib::A::foo1] (%aa)
+t11* = _Call get [#lib::A::foo2] (%aa)
+t12 = _Call dynamic [call] (t11, %a2, %a3, t10)
 a4 = _Join [dart.core::Object] (%a4, _T ANY?)
 RESULT: a4
 ------------ #lib::C::dynamicCalls ------------
@@ -71,8 +72,9 @@
 t6* = _Call direct get [#lib::B::bar4] (%this)
 t7 = _Call direct set [#lib::B::bar3] (%this, t6)
 t8* = _Call direct get [#lib::B::bar2] (%this)
-t9* = _Call dynamic [call] (t8, %a2, %a3, _T ANY?)
-a4 = _Join [dart.core::Object] (%a4, t9)
+t9* = _Call direct get [#lib::B::bar1] (%this)
+t10* = _Call dynamic [call] (t8, %a2, %a3, t9)
+a4 = _Join [dart.core::Object] (%a4, t10)
 RESULT: a4
 ------------ #lib::main ------------
 
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart
index db52bf0..5ce46d8 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart
@@ -11,11 +11,12 @@
 }
 
 class B extends A {
-  int foo() => 1 + knownResult().foo(); // Should have metadata.
+  int foo() => 1 + knownResult().bar(); // Should have metadata.
+  int bar() => 3;
 }
 
 class C implements A {
-  int foo() => 2 + knownResult().foo(); // Should be unreachable.
+  int foo() => 2 + knownResult().bar(); // Should be unreachable.
 }
 
 class TearOffInterfaceMethod {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
index 18c3870..4cf2073 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
@@ -13,7 +13,9 @@
     : super self::A::•()
     ;
   method foo() → core::int
-    return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+    return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::bar] [@vm.inferred-type.metadata=int] [@vm.inferred-type.metadata=#lib::B] self::knownResult().bar() as{TypeError} core::num) as{TypeError} core::int;
+  method bar() → core::int
+    return 3;
 }
 class TearOffInterfaceMethod extends core::Object {
   field dynamic bazz;