Return null for invalid targets of invoke-super.

Bug: 147848950
Change-Id: If881afa3b5e5d56f51085bc6eff9c6c3b3b613df
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index fbecfef..d164bf1 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.LookupResult.LookupResultSuccess.LookupResultCollectionState;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -205,14 +204,11 @@
     @Override
     public DexEncodedMethod lookupInvokeSuperTarget(
         DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
-      // TODO(b/147848950): Investigate and remove the Compilation error. It could compile to
-      //  throw IAE.
       if (resolvedMethod.isInstanceInitializer()
-          || (appInfo.hasSubtyping()
-              && initialResolutionHolder != context
-              && !isSuperclass(initialResolutionHolder, context, appInfo.withSubtyping()))) {
-        throw new CompilationError(
-            "Illegal invoke-super to " + resolvedMethod.toSourceString(), context.getOrigin());
+          || (initialResolutionHolder != context
+              && !isSuperclass(initialResolutionHolder, context, appInfo))) {
+        // If the target is <init> or not on a super class then the call is invalid.
+        return null;
       }
       if (isAccessibleFrom(context, appInfo)) {
         return internalInvokeSpecialOrSuper(context, appInfo, (sup, sub) -> true);
@@ -341,7 +337,7 @@
 
     private static boolean isSuperclass(
         DexClass sup, DexClass sub, AppInfoWithClassHierarchy appInfo) {
-      return sup != sub && appInfo.isSubtype(sub.type, sup.type);
+      return appInfo.isStrictSubtypeOf(sub.type, sup.type);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
index a5c4e81..5ed1539 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -83,6 +83,7 @@
         DexType refinedReceiverType =
             TypeAnalysis.getRefinedReceiverType(appViewWithLiveness, this);
         assert receiverLowerBoundType.getClassType() == refinedReceiverType
+                || appView.options().testing.allowTypeErrors
                 || receiverLowerBoundType.isBasedOnMissingClass(appViewWithLiveness)
                 || upperBoundAssumedByCallSiteOptimizationAndNoLongerInstantiated(
                     appViewWithLiveness, refinedReceiverType, receiverLowerBoundType.getClassType())
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 74cff92..8ffe6af 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -981,7 +981,6 @@
                   LEGACY_RUNTIME))
           // Dex input contains an illegal InvokeSuper in Z.foo() to Y.foo()
           // that R8 will fail to compile.
-          .put("594-invoke-super", TestCondition.match(TestCondition.R8DEX_COMPILER))
           .put("974-verify-interface-super", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // R8 generates too large code in Goto.bigGoto(). b/74327727
           .put("003-omnibus-opcodes", TestCondition.match(TestCondition.D8_AFTER_R8CF_COMPILER))
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java
index f71538c..1abfea6f 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java
@@ -3,12 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -114,48 +111,42 @@
             SubClassOfInvokerClass.class)
         .addProgramClassFileData(InvokerClassDump.dumpNonVerifying())
         .run(parameters.getRuntime(), MainClassFailing.class)
-        .apply(this::checkNonVerifyingResult);
+        .apply(r -> checkNonVerifyingResult(r, false));
   }
 
-  private void checkNonVerifyingResult(TestRunResult<?> result) {
+  private void checkNonVerifyingResult(TestRunResult<?> result, boolean isR8) {
     // The input is invalid and any JVM will fail at verification time.
     if (parameters.isCfRuntime()) {
-      result.assertFailureWithErrorThatMatches(containsString(VerifyError.class.getName()));
+      result.assertFailureWithErrorThatThrows(VerifyError.class);
       return;
     }
-    // D8 cannot verify its inputs and the behavior of the compiled output differs.
-    // The failure is due to lambda desugaring on pre-7 and fails at runtime on 7+.
+    // Dex results vary wildly...
     Version version = parameters.getRuntime().asDex().getVm().getVersion();
-    if (version.isOlderThanOrEqual(Version.V6_0_1)) {
-      result.assertFailureWithErrorThatMatches(
-          allOf(containsString("java.lang.NoClassDefFoundError"), containsString("-$$Lambda$")));
-      return;
+    if (!isR8 && version.isOlderThanOrEqual(Version.V4_4_4)) {
+      result.assertFailureWithErrorThatThrows(VerifyError.class);
+    } else if (version == Version.V5_1_1 || version == Version.V6_0_1) {
+      result.assertFailure();
+    } else {
+      result.assertSuccessWithOutputThatMatches(containsString(NoSuchMethodError.class.getName()));
     }
-    result.assertSuccessWithOutputLines(NoSuchMethodError.class.getName());
   }
 
   @Test
   public void testR8NonVerifying() throws Exception {
-    try {
-      testForR8(parameters.getBackend())
-          .addProgramClasses(
-              MainClassFailing.class,
-              Consumer.class,
-              Super.class,
-              SubLevel1.class,
-              SubLevel2.class,
-              SubClassOfInvokerClass.class)
-          .addProgramClassFileData(InvokerClassDump.dumpNonVerifying())
-          .setMinApi(parameters.getApiLevel())
-          .addKeepMainRule(MainClassFailing.class)
-          .compileWithExpectedDiagnostics(
-              diagnostics -> {
-                diagnostics.assertErrorMessageThatMatches(containsString("Illegal invoke-super"));
-              });
-      fail("Expected compilation to fail");
-    } catch (CompilationFailedException e) {
-      // Expected compilation failure.
-    }
+    testForR8(parameters.getBackend())
+        .addProgramClasses(
+            MainClassFailing.class,
+            Consumer.class,
+            Super.class,
+            SubLevel1.class,
+            SubLevel2.class,
+            SubClassOfInvokerClass.class)
+        .addProgramClassFileData(InvokerClassDump.dumpNonVerifying())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(MainClassFailing.class)
+        .addOptionsModification(o -> o.testing.allowTypeErrors = true)
+        .run(parameters.getRuntime(), MainClassFailing.class)
+        .apply(r -> checkNonVerifyingResult(r, true));
   }
 
   /** Copy of {@ref java.util.function.Consumer} to allow tests to run on early versions of art. */
@@ -253,7 +244,7 @@
 
   static class MainClassFailing {
 
-    private static void tryInvoke(java.util.function.Consumer<InvokerClass> function) {
+    private static void tryInvoke(Consumer<InvokerClass> function) {
       InvokerClass invoker = new InvokerClass();
       try {
         function.accept(invoker);
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index 2438ab2..8524677 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -261,7 +261,7 @@
     assertEquals(mOnI1, appInfo.lookupSuperTarget(mOnI1, c1).method);
     assertEquals(mOnI2, appInfo.lookupSuperTarget(mOnI2, c1).method);
 
-    assertEquals(mOnI0, appInfo.lookupSuperTarget(mOnC1, c2).method);
+    assertNull(appInfo.lookupSuperTarget(mOnC1, c2)); // C2 is not a subclass of C1.
     assertEquals(mOnI1, appInfo.lookupSuperTarget(mOnI3, c2).method);
     assertEquals(mOnI2, appInfo.lookupSuperTarget(mOnI4, c2).method);
 
diff --git a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
index b4dc614..fd893ea 100644
--- a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
@@ -5,7 +5,6 @@
 
 import static java.util.Collections.emptyList;
 
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
 import com.android.tools.r8.ThrowingBiFunction;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
@@ -17,7 +16,6 @@
 import com.android.tools.r8.jasmin.JasminBuilder.ClassFileVersion;
 import com.android.tools.r8.utils.ThrowingSupplier;
 import java.util.function.BiConsumer;
-import java.util.function.Predicate;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -293,8 +291,7 @@
         "  invokespecial SubClass/<init>()V",
         "  invokespecial SubClass/aMethod()V",
         "  return");
-    ensureExceptionOrCompilerError(builder, IllegalAccessError.class,
-        compiler -> compiler.equals(CompilerUnderTest.R8));
+    ensureException(builder, IllegalAccessError.class);
   }
 
   @Test
@@ -613,18 +610,14 @@
         (a, m) -> runOnArtR8Raw(a, m, keepMainProguardConfiguration(MAIN_CLASS), null));
   }
 
-  private void ensureExceptionOrCompilerError(JasminBuilder app,
-      Class<? extends Throwable> exception,
-      Predicate<CompilerUnderTest> predicate) throws Exception {
+  private void ensureException(JasminBuilder app, Class<? extends Throwable> exception)
+      throws Exception {
     String name = exception.getSimpleName();
     BiConsumer<ThrowingSupplier<ProcessResult, Exception>, CompilerUnderTest> runtest =
         (process, compiler) -> {
           try {
             ProcessResult result = process.get();
-            Assert.assertFalse(compiler != null && predicate.test(compiler));
             Assert.assertTrue(result.stderr.contains(name));
-          } catch (CompilationFailedException e) {
-            Assert.assertTrue(compiler == null || predicate.test(compiler));
           } catch (Exception e) {
             Assert.fail();
           }