Pop receiver last in unsupported feature rewriting.

This CL moves the legacy invokepolymorphic test to the new test
infrastructure. The old test failed to distinguish the expected error
from the internal compiler error due to type mismatch.

Bug: b/238175192
Change-Id: I02d68f4a99b02ed8da36be26f6a8f955236577ca
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java b/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java
index 50cf2b0..0500ac5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java
@@ -219,10 +219,10 @@
                   dexItemFactory) -> {
                 report(context);
                 Builder<CfInstruction> replacement = ImmutableList.builder();
+                pop(invoke.getMethod().getProto(), replacement);
                 if (!invoke.isInvokeStatic()) {
                   pop(dexItemFactory.objectType, replacement);
                 }
-                pop(invoke.getMethod().getProto(), replacement);
                 localStackAllocator.allocateLocalStack(1);
                 invokeThrowingStub(methodProcessingContext, eventConsumer, context, replacement);
                 pushReturnValue(invoke.getMethod().getReturnType(), replacement);
diff --git a/src/test/examplesAndroidO/invokepolymorphic/InvokePolymorphic.java b/src/test/examplesAndroidO/invokepolymorphic/InvokePolymorphic.java
deleted file mode 100644
index 90cb064..0000000
--- a/src/test/examplesAndroidO/invokepolymorphic/InvokePolymorphic.java
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2017, the R8 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.
-package invokepolymorphic;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-
-class Data {
-}
-
-public class InvokePolymorphic {
-
-  public String buildString(Integer i1, int i2, String s) {
-    return (i1 == null ? "N" : "!N") + "-" + i2 + "-" + s;
-  }
-
-  public void testInvokePolymorphic() {
-    MethodType mt = MethodType.methodType(String.class, Integer.class, int.class, String.class);
-    MethodHandles.Lookup lk = MethodHandles.lookup();
-
-    try {
-      MethodHandle mh = lk.findVirtual(getClass(), "buildString", mt);
-      System.out.println(mh.invoke(this, null, 1, "string"));
-    } catch (Throwable t) {
-      t.printStackTrace();
-    }
-  }
-
-  public String buildString(
-      byte b, char c, short s, float f, double d, long l, Integer i1, int i2, String str) {
-    return b + "-" + c + "-" + s + "-" + f + "-" + d + "-" + l + "-" + (i1 == null ? "N" : "!N")
-        + "-" + i2 + "-" + str;
-  }
-
-  public void testInvokePolymorphicRange() {
-    MethodType mt = MethodType.methodType(String.class, byte.class, char.class, short.class,
-        float.class, double.class, long.class, Integer.class, int.class, String.class);
-    MethodHandles.Lookup lk = MethodHandles.lookup();
-
-    try {
-      MethodHandle mh = lk.findVirtual(getClass(), "buildString", mt);
-      System.out.println(
-          mh.invoke(this, (byte) 2, 'a', (short) 0xFFFF, 1.1f, 2.24d, 12345678L, null,
-              1, "string"));
-    } catch (Throwable t) {
-      t.printStackTrace();
-    }
-  }
-
-  public static void testWithAllTypes(
-      boolean z, char a, short b, int c, long d, float e, double f, String g, Object h) {
-    System.out.println(z);
-    System.out.println(a);
-    System.out.println(b);
-    System.out.println(c);
-    System.out.println(d);
-    System.out.println(e);
-    System.out.println(f);
-    System.out.println(g);
-    System.out.println(h);
-  }
-
-  public void testInvokePolymorphicWithAllTypes() {
-    try {
-      MethodHandle mth =
-          MethodHandles.lookup()
-              .findStatic(
-                  InvokePolymorphic.class,
-                  "testWithAllTypes",
-                  MethodType.methodType(
-                      void.class, boolean.class, char.class, short.class, int.class, long.class,
-                      float.class, double.class, String.class, Object.class));
-      mth.invokeExact(false,'h', (short) 56, 72, Integer.MAX_VALUE + 42l,
-          0.56f, 100.0d, "hello", (Object) "goodbye");
-    } catch (Throwable t) {
-      t.printStackTrace();
-    }
-  }
-
-  public MethodHandle testInvokePolymorphicWithConstructor() {
-    MethodHandle mh = null;
-    MethodType mt = MethodType.methodType(void.class);
-    MethodHandles.Lookup lk = MethodHandles.lookup();
-
-    try {
-      mh = lk.findConstructor(Data.class, mt);
-      System.out.println(mh.invoke().getClass() == Data.class);
-    } catch (Throwable t) {
-      t.printStackTrace();
-    }
-
-    return mh;
-  }
-
-  public static void main(String[] args) {
-    InvokePolymorphic invokePolymorphic = new InvokePolymorphic();
-    invokePolymorphic.testInvokePolymorphic();
-    invokePolymorphic.testInvokePolymorphicRange();
-    invokePolymorphic.testInvokePolymorphicWithAllTypes();
-    invokePolymorphic.testInvokePolymorphicWithConstructor();
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 7fe1ae0..572fb1c 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -214,8 +214,7 @@
   }
 
   private static List<String> minSdkErrorExpected =
-      ImmutableList.of(
-          "invokepolymorphic-error-due-to-min-sdk", "invokecustom-error-due-to-min-sdk");
+      ImmutableList.of("invokecustom-error-due-to-min-sdk");
 
   private static Map<DexVm.Version, List<String>> failsOn;
 
@@ -229,7 +228,6 @@
                 "paramnames",
                 "repeat_annotations_new_api",
                 // Dex version not supported
-                "invokepolymorphic",
                 "invokecustom",
                 "invokecustom2",
                 "DefaultMethodInAndroidJar25",
@@ -244,7 +242,6 @@
                 "paramnames",
                 "repeat_annotations_new_api",
                 // Dex version not supported
-                "invokepolymorphic",
                 "invokecustom",
                 "invokecustom2",
                 "DefaultMethodInAndroidJar25",
@@ -259,7 +256,6 @@
                 "paramnames",
                 "repeat_annotations_new_api",
                 // Dex version not supported
-                "invokepolymorphic",
                 "invokecustom",
                 "invokecustom2",
                 "DefaultMethodInAndroidJar25",
@@ -274,7 +270,6 @@
                 "paramnames",
                 "repeat_annotations_new_api",
                 // Dex version not supported
-                "invokepolymorphic",
                 "invokecustom",
                 "invokecustom2",
                 "DefaultMethodInAndroidJar25",
@@ -288,7 +283,6 @@
                 // API not supported
                 "paramnames",
                 // Dex version not supported
-                "invokepolymorphic",
                 "invokecustom",
                 "invokecustom2",
                 "testMissingInterfaceDesugared2AndroidO",
@@ -378,22 +372,6 @@
   }
 
   @Test
-  public void invokePolymorphic() throws Throwable {
-    test("invokepolymorphic", "invokepolymorphic", "InvokePolymorphic")
-        .withMinApiLevel(AndroidApiLevel.O)
-        .withKeepAll()
-        .run();
-  }
-
-  @Test
-  public void invokePolymorphicErrorDueToMinSdk() throws Throwable {
-    test("invokepolymorphic-error-due-to-min-sdk", "invokepolymorphic", "InvokePolymorphic")
-        .withMinApiLevel(AndroidApiLevel.N_MR1)
-        .withKeepAll()
-        .run();
-  }
-
-  @Test
   public void lambdaDesugaring() throws Throwable {
     test("lambdadesugaring", "lambdadesugaring", "LambdaDesugaring")
         .withMinApiLevel(ToolHelper.getMinApiLevelForDexVmNoHigherThan(AndroidApiLevel.K))
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
index caed567..c8b6cc4 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
@@ -176,8 +176,7 @@
   }
 
   private static List<String> minSdkErrorExpected =
-      ImmutableList.of(
-          "invokepolymorphic-error-due-to-min-sdk", "invokecustom-error-due-to-min-sdk");
+      ImmutableList.of("invokecustom-error-due-to-min-sdk");
 
   private static Map<DexVm.Version, List<String>> failsOn =
       ImmutableMap.<DexVm.Version, List<String>>builder()
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/InvokePolymorphicTypesTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/InvokePolymorphicTypesTest.java
new file mode 100644
index 0000000..b218c6f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/InvokePolymorphicTypesTest.java
@@ -0,0 +1,282 @@
+// Copyright (c) 2022, the R8 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.
+package com.android.tools.r8.cf.methodhandles;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * This test is a refactoring of the InvokePolymorphic test code run by the various AndroidOTest
+ * runners.
+ */
+@RunWith(Parameterized.class)
+public class InvokePolymorphicTypesTest extends TestBase {
+
+  static final String EXPECTED =
+      StringUtils.lines(
+          "N-1-string",
+          "2-a--1-1.1-2.24-12345678-N-1-string",
+          "false",
+          "h",
+          "56",
+          "72",
+          "2147483689",
+          "0.56",
+          "100.0",
+          "hello",
+          "goodbye",
+          "true");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+  }
+
+  public InvokePolymorphicTypesTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    boolean hasCompileSupport =
+        parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevelWithInvokePolymorphicSupport());
+    boolean hasRuntimeSupport =
+        parameters.isCfRuntime()
+            || parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V8_1_0);
+    testForD8(parameters.getBackend())
+        .addProgramClasses(Data.class, TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .mapUnsupportedFeaturesToWarnings()
+        .run(parameters.getRuntime(), TestClass.class)
+        .applyIf(
+            hasCompileSupport,
+            r -> r.assertSuccessWithOutput(EXPECTED),
+            hasRuntimeSupport,
+            r ->
+                r.assertSuccess()
+                    .assertStderrMatches(
+                        containsString(
+                            "Instruction is unrepresentable in DEX V35: invoke-polymorphic")),
+            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeTrue(parameters.isDexRuntime() || parameters.getApiLevel().equals(AndroidApiLevel.B));
+    boolean hasCompileSupport =
+        parameters.isCfRuntime()
+            || parameters
+                .getApiLevel()
+                .isGreaterThanOrEqualTo(apiLevelWithInvokePolymorphicSupport());
+    boolean hasRuntimeSupport =
+        parameters.isCfRuntime()
+            || parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V8_1_0);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Data.class, TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .applyIf(
+            !hasCompileSupport,
+            b ->
+                b.addDontWarn(
+                    MethodType.class,
+                    MethodHandle.class,
+                    MethodHandles.class,
+                    MethodHandles.Lookup.class))
+        .addKeepMainRule(TestClass.class)
+        .addKeepMethodRules(
+            Reference.methodFromMethod(Data.class.getDeclaredConstructor()),
+            Reference.methodFromMethod(
+                TestClass.class.getDeclaredMethod(
+                    "buildString", Integer.class, int.class, String.class)),
+            Reference.methodFromMethod(
+                TestClass.class.getDeclaredMethod(
+                    "buildString",
+                    byte.class,
+                    char.class,
+                    short.class,
+                    float.class,
+                    double.class,
+                    long.class,
+                    Integer.class,
+                    int.class,
+                    String.class)),
+            Reference.methodFromMethod(
+                TestClass.class.getDeclaredMethod(
+                    "testWithAllTypes",
+                    boolean.class,
+                    char.class,
+                    short.class,
+                    int.class,
+                    long.class,
+                    float.class,
+                    double.class,
+                    String.class,
+                    Object.class)))
+        .mapUnsupportedFeaturesToWarnings()
+        .allowDiagnosticMessages()
+        .run(parameters.getRuntime(), TestClass.class)
+        .applyIf(
+            hasCompileSupport,
+            r -> r.assertSuccessWithOutput(EXPECTED),
+            hasRuntimeSupport,
+            r ->
+                r.assertSuccess()
+                    .assertStderrMatches(
+                        containsString(
+                            "Instruction is unrepresentable in DEX V35: invoke-polymorphic")),
+            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+  }
+
+  static class Data {}
+
+  static class TestClass {
+
+    public String buildString(Integer i1, int i2, String s) {
+      return (i1 == null ? "N" : "!N") + "-" + i2 + "-" + s;
+    }
+
+    public void testInvokePolymorphic() {
+      MethodType mt = MethodType.methodType(String.class, Integer.class, int.class, String.class);
+      MethodHandles.Lookup lk = MethodHandles.lookup();
+
+      try {
+        MethodHandle mh = lk.findVirtual(getClass(), "buildString", mt);
+        System.out.println(mh.invoke(this, null, 1, "string"));
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+    }
+
+    public String buildString(
+        byte b, char c, short s, float f, double d, long l, Integer i1, int i2, String str) {
+      return b
+          + "-"
+          + c
+          + "-"
+          + s
+          + "-"
+          + f
+          + "-"
+          + d
+          + "-"
+          + l
+          + "-"
+          + (i1 == null ? "N" : "!N")
+          + "-"
+          + i2
+          + "-"
+          + str;
+    }
+
+    public void testInvokePolymorphicRange() {
+      MethodType mt =
+          MethodType.methodType(
+              String.class,
+              byte.class,
+              char.class,
+              short.class,
+              float.class,
+              double.class,
+              long.class,
+              Integer.class,
+              int.class,
+              String.class);
+      MethodHandles.Lookup lk = MethodHandles.lookup();
+
+      try {
+        MethodHandle mh = lk.findVirtual(getClass(), "buildString", mt);
+        System.out.println(
+            mh.invoke(
+                this, (byte) 2, 'a', (short) 0xFFFF, 1.1f, 2.24d, 12345678L, null, 1, "string"));
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+    }
+
+    public static void testWithAllTypes(
+        boolean z, char a, short b, int c, long d, float e, double f, String g, Object h) {
+      System.out.println(z);
+      System.out.println(a);
+      System.out.println(b);
+      System.out.println(c);
+      System.out.println(d);
+      System.out.println(e);
+      System.out.println(f);
+      System.out.println(g);
+      System.out.println(h);
+    }
+
+    public void testInvokePolymorphicWithAllTypes() {
+      try {
+        MethodHandle mth =
+            MethodHandles.lookup()
+                .findStatic(
+                    TestClass.class,
+                    "testWithAllTypes",
+                    MethodType.methodType(
+                        void.class,
+                        boolean.class,
+                        char.class,
+                        short.class,
+                        int.class,
+                        long.class,
+                        float.class,
+                        double.class,
+                        String.class,
+                        Object.class));
+        mth.invokeExact(
+            false,
+            'h',
+            (short) 56,
+            72,
+            Integer.MAX_VALUE + 42l,
+            0.56f,
+            100.0d,
+            "hello",
+            (Object) "goodbye");
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+    }
+
+    public MethodHandle testInvokePolymorphicWithConstructor() {
+      MethodHandle mh = null;
+      MethodType mt = MethodType.methodType(void.class);
+      MethodHandles.Lookup lk = MethodHandles.lookup();
+
+      try {
+        mh = lk.findConstructor(Data.class, mt);
+        System.out.println(mh.invoke().getClass() == Data.class);
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+
+      return mh;
+    }
+
+    public static void main(String[] args) {
+      TestClass invokePolymorphic = new TestClass();
+      invokePolymorphic.testInvokePolymorphic();
+      invokePolymorphic.testInvokePolymorphicRange();
+      invokePolymorphic.testInvokePolymorphicWithAllTypes();
+      invokePolymorphic.testInvokePolymorphicWithConstructor();
+    }
+  }
+}