[VM/AOT/TFA] Do not attribute calls via fields/getters with inference results

MethodInvocation nodes which have field or getter as interface target
actually correspond to 2 calls: 1) getter; 2) implicit call() on the result
of the getter.

While this was correctly modeled in summaries in TFA, it is not correct
to attribute such MethodInvocation nodes with results of the inference,
as results correspond to an each distinct call. To fix this, Call
statements in summaries are created without attaching them to a
corresponding kernel AST node.

Change-Id: I3ea28ed85550192f8b592a926cac0eae23810811
Reviewed-on: https://dart-review.googlesource.com/c/88424
Commit-Queue: Martin Kustermann <kustermann@google.com>
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 1e71390..483ca7f 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -918,16 +918,19 @@
       return _makeCall(
           node, new DynamicSelector(CallKind.Method, node.name), args);
     }
+    // TODO(dartbug.com/34497): Once front-end desugars calls via
+    // fields/getters, handling of field and getter targets here
+    // can be turned into assertions.
     if ((target is Field) || ((target is Procedure) && target.isGetter)) {
-      // Call via field.
-      final fieldValue = _makeCall(
-          node,
+      // Call via field/getter.
+      final value = _makeCall(
+          null,
           (node.receiver is ThisExpression)
               ? new VirtualSelector(target, callKind: CallKind.PropertyGet)
               : new InterfaceSelector(target, callKind: CallKind.PropertyGet),
           new Args<TypeExpr>([receiver]));
       _makeCall(
-          null, DynamicSelector.kCall, new Args.withReceiver(args, fieldValue));
+          null, DynamicSelector.kCall, new Args.withReceiver(args, value));
       return _staticType(node);
     } else {
       // TODO(alexmarkov): overloaded arithmetic operators
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
index e206d89..d0dc0ad 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
@@ -114,7 +114,7 @@
 [@vm.inferred-type.metadata=dart.core::_Closure?]static field core::Function unknown4 = () → dynamic => self::bb4;
 static method test1() → void {
   self::B1 bb = new self::B1::•();
-  [@vm.inferred-type.metadata=#lib::A1 (skip check)] bb.{self::B1::aa1}(1, 2, 3, 4, new self::T1::•());
+  bb.{self::B1::aa1}(1, 2, 3, 4, new self::T1::•());
   self::ok = false;
   [@vm.direct-call.metadata=#lib::T1::doTest1??] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=#lib::A1::foo] [@vm.inferred-type.metadata=#lib::T1?] [@vm.direct-call.metadata=#lib::B1::aa1] [@vm.inferred-type.metadata=#lib::A1] bb.{self::B1::aa1}.{self::A1::foo}.{self::T1::doTest1}();
   exp::Expect::isTrue([@vm.inferred-type.metadata=dart.core::bool?] self::ok);
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
index 4dbe283..2c96882 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
@@ -18,7 +18,7 @@
 [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic bazz;
   constructor •(dynamic arg) → self::TearOffDynamicMethod
     : self::TearOffDynamicMethod::bazz = arg.foo, super core::Object::•() {
-    [@vm.inferred-type.metadata=!? (skip check)] this.{self::TearOffDynamicMethod::bazz}();
+    this.{self::TearOffDynamicMethod::bazz}();
   }
 }
 static method knownResult() → dynamic
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 83de6a2..c05b7ff 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
@@ -26,5 +26,5 @@
 static method knownResult() → dynamic
   return new self::B::•();
 static method main(core::List<core::String> args) → dynamic {
-  [@vm.inferred-type.metadata=!? (skip check)] new self::TearOffInterfaceMethod::•(new self::B::•()).{self::TearOffInterfaceMethod::bazz}();
+  new self::TearOffInterfaceMethod::•(new self::B::•()).{self::TearOffInterfaceMethod::bazz}();
 }
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 73ff36d..8bcbb49 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -3639,6 +3639,9 @@
   const Function* interface_target = &Function::null_function();
   const NameIndex itarget_name =
       ReadCanonicalNameReference();  // read interface_target_reference.
+  // TODO(dartbug.com/34497): Once front-end desugars calls via
+  // fields/getters, filtering of field and getter interface targets here
+  // can be turned into assertions.
   if (!H.IsRoot(itarget_name) && !H.IsField(itarget_name) &&
       !H.IsGetter(itarget_name)) {
     interface_target = &Function::ZoneHandle(
diff --git a/tests/language_2/vm/type_of_call_via_getter_test.dart b/tests/language_2/vm/type_of_call_via_getter_test.dart
index bd246bb..4a6c445 100644
--- a/tests/language_2/vm/type_of_call_via_getter_test.dart
+++ b/tests/language_2/vm/type_of_call_via_getter_test.dart
@@ -18,13 +18,34 @@
 
 var box = new Box();
 
-void foo() {
+void test1() {
   Expect.isFalse(box.fun(42) is Function);
   Expect.isTrue(box.fun(42) is String);
 }
 
+class Callable {
+  String call(int i) => 'qwe';
+}
+
+class Box2 {
+  Callable get fun => new Callable();
+}
+
+var box2 = new Box2();
+
+void test2() {
+  Expect.isFalse(box2.fun is Function);
+  Expect.isTrue(box2.fun is Callable);
+  Expect.isFalse(box2.fun(42) is Function);
+  Expect.isFalse(box2.fun(42) is Callable);
+  Expect.isTrue(box2.fun(42) is String);
+}
+
 void main() {
   for (int i = 0; i < 20; ++i) {
-    foo();
+    test1();
+  }
+  for (int i = 0; i < 20; ++i) {
+    test2();
   }
 }