Add a DYNAMIC_Constant ICCE regression test

A DYNAMIC_Constant test where the bootstrap method handle
does not have the interface bit but targets a bootstrap method on an
interface.

Bug: 178172809
Change-Id: I729de5ad20c38cec77fea25b6f8ac4b3018598be
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index a332828..48dca2d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -162,7 +162,11 @@
       synthesizeConstantDynamicClass(builder);
     } else {
       // Unconditionally throw as the RI.
-      behaviour = resolution.isFailedResolution() ? THROW_NSME : THROW_ICCE;
+      behaviour =
+          resolution.isNoSuchMethodErrorResult(
+                  context.getContextClass(), appView.appInfoForDesugaring())
+              ? THROW_NSME
+              : THROW_ICCE;
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
index d458f22..c5c6480 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
@@ -109,9 +109,9 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", A.class, "myConstant", "constantName", Object.class)
+            "condy1", A.class, "myConstant", false, "constantName", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy2", A.class, "myConstant", "constantName", Object.class)
+            "condy2", A.class, "myConstant", false, "constantName", Object.class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
index 7b204ac..4cea83c 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
@@ -102,7 +102,7 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", A.class, "methodNotFound", "constantName", Object.class)
+            "condy1", A.class, "methodNotFound", false, "constantName", Object.class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
index 5f7e125..169a85d 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
@@ -101,7 +101,7 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", A.class, "myConstant", "constantName", Object.class)
+            "condy1", A.class, "myConstant", false, "constantName", Object.class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
index 3f9a957..a693c21 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
@@ -101,7 +101,7 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", A.class, "myConstant", "constantName", Object.class)
+            "condy1", A.class, "myConstant", false, "constantName", Object.class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
index 4810b1d..7deff9c 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
@@ -126,7 +126,7 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy", A.class, "myConstant", "constantName", Object.class)
+            "condy", A.class, "myConstant", false, "constantName", Object.class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java
new file mode 100644
index 0000000..feff719
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java
@@ -0,0 +1,141 @@
+// 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.desugar.constantdynamic;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.DesugarTestConfiguration;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ConstantDynamicInDefaultInterfaceMethodICCETest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+  }
+
+  private static final Class<?> MAIN_CLASS = A.class;
+
+  @Test
+  public void testReference() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
+    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+
+    testForJvm()
+        .addProgramClasses(MAIN_CLASS)
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    testForDesugaring(parameters)
+        .addProgramClasses(MAIN_CLASS)
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .applyIf(
+            // When not desugaring the CF code requires JDK 11.
+            DesugarTestConfiguration::isNotDesugared,
+            r -> {
+              if (parameters.isCfRuntime()
+                  && parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)) {
+                r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
+              } else {
+                r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class);
+              }
+            })
+        .applyIf(
+            DesugarTestConfiguration::isDesugared,
+            r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeTrue(parameters.isDexRuntime() || parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+
+    testForR8(parameters.getBackend())
+        .addProgramClasses(MAIN_CLASS)
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(MAIN_CLASS)
+        // TODO(b/198142625): Support CONSTANT_Dynamic output for class files.
+        .applyIf(
+            parameters.isCfRuntime(),
+            b -> {
+              assertThrows(
+                  CompilationFailedException.class,
+                  () ->
+                      b.compileWithExpectedDiagnostics(
+                          diagnostics -> {
+                            diagnostics.assertOnlyErrors();
+                            diagnostics.assertErrorsMatch(
+                                diagnosticMessage(
+                                    containsString(
+                                        "Unsupported dynamic constant (not desugaring)")));
+                          }));
+            },
+            b ->
+                b.run(parameters.getRuntime(), MAIN_CLASS)
+                    .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class));
+  }
+
+  // Create a constant dynamic without the interface bit targeting an interface bootstrap method.
+  private byte[] getTransformedClasses() throws Exception {
+    return transformer(I.class)
+        .setVersion(CfVersion.V11)
+        .transformConstStringToConstantDynamic(
+            "condy1", I.class, "myConstant", false, "constantName", Object.class)
+        .transformConstStringToConstantDynamic(
+            "condy2", I.class, "myConstant", false, "constantName", Object.class)
+        .setPrivate(
+            I.class.getDeclaredMethod(
+                "myConstant", MethodHandles.Lookup.class, String.class, Class.class))
+        .transform();
+  }
+
+  public interface I {
+
+    default Object f() {
+      return "condy1"; // Will be transformed to Constant_DYNAMIC.
+    }
+
+    default Object g() {
+      return "condy2"; // Will be transformed to Constant_DYNAMIC.
+    }
+
+    /* private */ static Object myConstant(
+        MethodHandles.Lookup lookup, String name, Class<?> type) {
+      return new Object();
+    }
+  }
+
+  public static class A implements I {
+    public static void main(String[] args) {
+      A a = new A();
+      System.out.println(a.f() != null);
+      System.out.println(a.f() == a.g());
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
index a09ae6a..ad46d90 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
@@ -116,9 +116,9 @@
     return transformer(I.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", I.class, "myConstant", "constantName", Object.class)
+            "condy1", I.class, "myConstant", true, "constantName", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy2", I.class, "myConstant", "constantName", Object.class)
+            "condy2", I.class, "myConstant", true, "constantName", Object.class)
         .setPrivate(
             I.class.getDeclaredMethod(
                 "myConstant", MethodHandles.Lookup.class, String.class, Class.class))
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
index edc3cab..b7e540b 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
@@ -102,12 +102,12 @@
         transformer(A.class)
             .setVersion(CfVersion.V11)
             .transformConstStringToConstantDynamic(
-                "condy1", A.class, "myConstant", "constantName", Object.class)
+                "condy1", A.class, "myConstant", false, "constantName", Object.class)
             .transform(),
         transformer(B.class)
             .setVersion(CfVersion.V11)
             .transformConstStringToConstantDynamic(
-                "condy1", B.class, "myConstant", "constantName", Object.class)
+                "condy1", B.class, "myConstant", false, "constantName", Object.class)
             .transform());
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
index b3f900a..a7df375 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
@@ -110,13 +110,13 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", A.class, "myConstant1", "constantName", Object.class)
+            "condy1", A.class, "myConstant1", false, "constantName", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy2", A.class, "myConstant1", "constantName", Object.class)
+            "condy2", A.class, "myConstant1", false, "constantName", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy3", A.class, "myConstant2", "constantName", Object.class)
+            "condy3", A.class, "myConstant2", false, "constantName", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy4", A.class, "myConstant2", "constantName", Object.class)
+            "condy4", A.class, "myConstant2", false, "constantName", Object.class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
index 667473e..5ebc8da 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
@@ -112,13 +112,13 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", A.class, "myConstant", "constantF", Object.class)
+            "condy1", A.class, "myConstant", false, "constantF", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy2", A.class, "myConstant", "constantF", Object.class)
+            "condy2", A.class, "myConstant", false, "constantF", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy3", A.class, "myConstant", "constantG", Object.class)
+            "condy3", A.class, "myConstant", false, "constantG", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy4", A.class, "myConstant", "constantG", Object.class)
+            "condy4", A.class, "myConstant", false, "constantG", Object.class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
index 48e0aab..fab07ce 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
@@ -111,13 +111,13 @@
     return transformer(A.class)
         .setVersion(CfVersion.V11)
         .transformConstStringToConstantDynamic(
-            "condy1", A.class, "myConstant", "constantName", Object.class)
+            "condy1", A.class, "myConstant", false, "constantName", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy2", A.class, "myConstant", "constantName", Object.class)
+            "condy2", A.class, "myConstant", false, "constantName", Object.class)
         .transformConstStringToConstantDynamic(
-            "condy3", A.class, "myConstant", "constantName", boolean[].class)
+            "condy3", A.class, "myConstant", false, "constantName", boolean[].class)
         .transformConstStringToConstantDynamic(
-            "condy4", A.class, "myConstant", "constantName", boolean[].class)
+            "condy4", A.class, "myConstant", false, "constantName", boolean[].class)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
index bff5968..1ae1ccf 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
@@ -123,16 +123,16 @@
         transformer(A.class)
             .setVersion(CfVersion.V11)
             .transformConstStringToConstantDynamic(
-                "condy1", A.class, "myConstant", "constantName", Object.class)
+                "condy1", A.class, "myConstant", false, "constantName", Object.class)
             .transformConstStringToConstantDynamic(
-                "condy2", A.class, "myConstant", "constantName", Object.class)
+                "condy2", A.class, "myConstant", false, "constantName", Object.class)
             .transform(),
         transformer(B.class)
             .setVersion(CfVersion.V11)
             .transformConstStringToConstantDynamic(
-                "condy3", A.class, "myConstant", "constantName", Object.class)
+                "condy3", A.class, "myConstant", false, "constantName", Object.class)
             .transformConstStringToConstantDynamic(
-                "condy4", A.class, "myConstant", "constantName", Object.class)
+                "condy4", A.class, "myConstant", false, "constantName", Object.class)
             .transform());
   }
 
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index 8644e9a..d8557a0 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -978,6 +978,7 @@
       String constantName,
       Class<?> bootstrapMethodHolder,
       String bootstrapMethodName,
+      boolean isInterfaceInvoke,
       String name,
       Class<?> type) {
     return addMethodTransformer(
@@ -996,7 +997,7 @@
                           DescriptorUtils.getClassBinaryName(bootstrapMethodHolder),
                           bootstrapMethodName,
                           bootstrapMethodSignature,
-                          bootstrapMethodHolder.isInterface()),
+                          isInterfaceInvoke),
                       new Object[] {}));
             } else {
               super.visitLdcInsn(value);