[vm/aot] Attach unboxing info to unreachable members

Unreachable members could be used as interface targets of dispatch
table calls, so they should have correct unboxing metadata.
This change fixes attaching unboxing info to such members.

TEST=runtime/tests/vm/dart/regress_44563_test.dart

Fixes https://github.com/dart-lang/sdk/issues/44563

Change-Id: I5da6a8d07048904eb94b05bfba11bdf72d655e12
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/177621
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 2ea1325..02ffe47 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -313,13 +313,6 @@
     if (_typeFlowAnalysis.isMemberUsed(member)) {
       if (member is Field) {
         _setInferredType(member, _typeFlowAnalysis.fieldType(member));
-
-        final unboxingInfoMetadata =
-            _unboxingInfo.getUnboxingInfoOfMember(member);
-        if (unboxingInfoMetadata != null &&
-            !unboxingInfoMetadata.isFullyBoxed) {
-          _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata;
-        }
       } else {
         Args<Type> argTypes = _typeFlowAnalysis.argumentTypes(member);
         final uncheckedParameters =
@@ -350,36 +343,41 @@
               skipCheck: uncheckedParameters.contains(param));
         }
 
-        final unboxingInfoMetadata =
-            _unboxingInfo.getUnboxingInfoOfMember(member);
-        if (unboxingInfoMetadata != null &&
-            !unboxingInfoMetadata.isFullyBoxed) {
-          _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata;
-        }
-
         // TODO(alexmarkov): figure out how to pass receiver type.
       }
-    } else if (!member.isAbstract &&
-        !fieldMorpher.isExtraMemberWithReachableBody(member)) {
-      _setUnreachable(member);
-    } else if (member is! Field) {
+
       final unboxingInfoMetadata =
           _unboxingInfo.getUnboxingInfoOfMember(member);
-      if (unboxingInfoMetadata != null) {
-        // Check for partitions that only have abstract methods should be marked as boxed.
-        if (unboxingInfoMetadata.returnInfo ==
-            UnboxingInfoMetadata.kUnboxingCandidate) {
-          unboxingInfoMetadata.returnInfo = UnboxingInfoMetadata.kBoxed;
-        }
-        for (int i = 0; i < unboxingInfoMetadata.unboxedArgsInfo.length; i++) {
-          if (unboxingInfoMetadata.unboxedArgsInfo[i] ==
+      if (unboxingInfoMetadata != null && !unboxingInfoMetadata.isFullyBoxed) {
+        _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata;
+      }
+    } else {
+      if (!member.isAbstract &&
+          !fieldMorpher.isExtraMemberWithReachableBody(member)) {
+        _setUnreachable(member);
+      }
+
+      if (member is! Field) {
+        final unboxingInfoMetadata =
+            _unboxingInfo.getUnboxingInfoOfMember(member);
+        if (unboxingInfoMetadata != null) {
+          // Check for partitions that only have abstract methods should be marked as boxed.
+          if (unboxingInfoMetadata.returnInfo ==
               UnboxingInfoMetadata.kUnboxingCandidate) {
-            unboxingInfoMetadata.unboxedArgsInfo[i] =
-                UnboxingInfoMetadata.kBoxed;
+            unboxingInfoMetadata.returnInfo = UnboxingInfoMetadata.kBoxed;
           }
-        }
-        if (!unboxingInfoMetadata.isFullyBoxed) {
-          _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata;
+          for (int i = 0;
+              i < unboxingInfoMetadata.unboxedArgsInfo.length;
+              i++) {
+            if (unboxingInfoMetadata.unboxedArgsInfo[i] ==
+                UnboxingInfoMetadata.kUnboxingCandidate) {
+              unboxingInfoMetadata.unboxedArgsInfo[i] =
+                  UnboxingInfoMetadata.kBoxed;
+            }
+          }
+          if (!unboxingInfoMetadata.isFullyBoxed) {
+            _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata;
+          }
         }
       }
     }
diff --git a/runtime/tests/vm/dart/regress_44563_test.dart b/runtime/tests/vm/dart/regress_44563_test.dart
new file mode 100644
index 0000000..6b1baa6
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_44563_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verifies that unboxing info is attached to a member with unreachable body,
+// which is still used as an interface target.
+// Regression test for https://github.com/dart-lang/sdk/issues/44563.
+
+import 'package:expect/expect.dart';
+
+class BaseClass {
+  int get value => 0;
+}
+
+class Class1 extends BaseClass {
+  @pragma('vm:never-inline')
+  int get value => 1;
+}
+
+class Class2 extends BaseClass {
+  @pragma('vm:never-inline')
+  int get value => 2;
+}
+
+bool nonConstantCondition = int.parse("1") == 1;
+
+void main() {
+  BaseClass obj = BaseClass();
+  obj = nonConstantCondition ? Class1() : Class2();
+  Expect.equals(1, obj.value);
+}
diff --git a/runtime/tests/vm/dart_2/regress_44563_test.dart b/runtime/tests/vm/dart_2/regress_44563_test.dart
new file mode 100644
index 0000000..6b1baa6
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_44563_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verifies that unboxing info is attached to a member with unreachable body,
+// which is still used as an interface target.
+// Regression test for https://github.com/dart-lang/sdk/issues/44563.
+
+import 'package:expect/expect.dart';
+
+class BaseClass {
+  int get value => 0;
+}
+
+class Class1 extends BaseClass {
+  @pragma('vm:never-inline')
+  int get value => 1;
+}
+
+class Class2 extends BaseClass {
+  @pragma('vm:never-inline')
+  int get value => 2;
+}
+
+bool nonConstantCondition = int.parse("1") == 1;
+
+void main() {
+  BaseClass obj = BaseClass();
+  obj = nonConstantCondition ? Class1() : Class2();
+  Expect.equals(1, obj.value);
+}