Desugare nest based access for invoke-special instructions.

Bug: 145775365
Change-Id: I696cf095f4353845e6ed87a994da4a31f0694747
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index 68a8bd4..e4af36c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -62,7 +62,7 @@
       InstructionListIterator instructions = block.listIterator(code);
       while (instructions.hasNext()) {
         Instruction instruction = instructions.next();
-        if (instruction.isInvokeMethod() && !instruction.isInvokeSuper()) {
+        if (instruction.isInvokeMethod()) {
           InvokeMethod invokeMethod = instruction.asInvokeMethod();
           DexMethod methodCalled = invokeMethod.getInvokedMethod();
           DexEncodedMethod encodedMethodCalled =
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index f286bac..6170af1 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
@@ -90,6 +91,15 @@
     return self();
   }
 
+  public RR assertFailureWithErrorThatThrows(Class<? extends Throwable> expectedError) {
+    assertFailure();
+    assertThat(
+        errorMessage("Run stderr incorrect.", expectedError.getName()),
+        result.stderr,
+        containsString(expectedError.getName() + ":"));
+    return self();
+  }
+
   public RR assertStderrMatches(Matcher<String> matcher) {
     assertThat(errorMessage("Run stderr incorrect.", matcher.toString()), result.stderr, matcher);
     return self();
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
index d0d4398..9d9b8c5 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.resolution.access;
 
 import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
-import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -192,29 +191,20 @@
   private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
     if (isR8 && parameters.isDexRuntime() && inSameNest && symbolicReferenceIsDefiningType) {
       // TODO(b/145187969): Incorrect nest desugaring.
-      result.assertFailureWithErrorThatMatches(containsString(VerifyError.class.getName()));
+      result.assertFailureWithErrorThatThrows(VerifyError.class);
       return;
     }
 
     if (!symbolicReferenceIsDefiningType) {
-      result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
-      return;
-    }
-
-    if (isDesugaring()) {
-      // TODO(b/145775365): Desugaring results in an incorrect program.
-      result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
+      result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
       return;
     }
 
     if (!inSameNest) {
-      result.assertFailureWithErrorThatMatches(containsString(IllegalAccessError.class.getName()));
-      return;
-    }
-
-    if (parameters.isDexRuntime()) {
-      // TODO(b/145187969): Incorrect nest desugaring.
-      result.assertFailureWithErrorThatMatches(containsString(IllegalAccessError.class.getName()));
+      // TODO(b/145775365): Desugaring causes change to reported error.
+      // The default method desugar will target $default$bar, but the definition is $private$bar.
+      result.assertFailureWithErrorThatThrows(
+          isDesugaring() ? NoSuchMethodError.class : IllegalAccessError.class);
       return;
     }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
index 8d54c3a..508e851 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.resolution.access;
 
 import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
-import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -166,19 +165,14 @@
 
   private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
     if (inSameNest) {
-      if (parameters.isDexRuntime()) {
-        // TODO(b/145187969): D8/R8 incorrectly compiles the nest based access away.
-        if (isR8) {
-          result.assertFailureWithErrorThatMatches(containsString(VerifyError.class.getName()));
-        } else {
-          result.assertFailureWithErrorThatMatches(
-              containsString(IllegalAccessError.class.getName()));
-        }
+      if (isR8 && parameters.isDexRuntime()) {
+        // TODO(b/145187969): R8 incorrectly compiles the nest based access away.
+        result.assertFailureWithErrorThatThrows(VerifyError.class);
       } else {
         result.assertSuccessWithOutput(EXPECTED);
       }
     } else {
-      result.assertFailureWithErrorThatMatches(containsString(IllegalAccessError.class.getName()));
+      result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
index 3f5efb9..d5f612d 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.resolution.access;
 
 import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
-import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -194,18 +193,35 @@
   }
 
   private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
-    if (inSameNest && parameters.isCfRuntime()) {
-      if (isR8) {
-        // TODO(b/145775365): R8 incorrectly compiles the input.
-        result.assertSuccessWithOutput(EXPECTED);
-      } else if (symbolicReferenceIsDefiningType) {
-        result.assertSuccessWithOutput(EXPECTED);
-      } else {
-        result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
-      }
-    } else {
-      result.assertFailureWithErrorThatMatches(containsString(IllegalAccessError.class.getName()));
+    // If not in the same nest, the error is always illegal access.
+    if (!inSameNest) {
+      result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+      return;
     }
+
+    // If in the same nest but the reference is not exact, the error is always no such method.
+    if (!symbolicReferenceIsDefiningType) {
+      // TODO(b/145775365): R8/CF incorrectly compiles the input to a working program.
+      if (isR8 && parameters.isCfRuntime()) {
+        result.assertSuccessWithOutput(EXPECTED);
+        return;
+      }
+      // TODO(b/145775365): D8/R8 does not preserve the thrown error.
+      if (parameters.isDexRuntime()) {
+        result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+        return;
+      }
+      result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+      return;
+    }
+
+    // Finally, if in the same nest and the reference is exact match the program runs successfully.
+    // TODO(b/145775365): R8/DEX incorrectly compiles the input to a non-working program.
+    if (isR8 && parameters.isDexRuntime()) {
+      result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+      return;
+    }
+    result.assertSuccessWithOutput(EXPECTED);
   }
 
   static class A {
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
index c45ec8b..49426c4 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
@@ -145,7 +145,7 @@
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), Main.class)
-        .apply(result -> checkExpectedResult(result, false));
+        .apply(this::checkExpectedResult);
   }
 
   @Test
@@ -156,10 +156,10 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Main.class)
         .run(parameters.getRuntime(), Main.class)
-        .apply(result -> checkExpectedResult(result, true));
+        .apply(this::checkExpectedResult);
   }
 
-  private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
+  private void checkExpectedResult(TestRunResult<?> result) {
     result.assertSuccessWithOutput(EXPECTED);
   }