Make the interpretation of invoke-special more precise
Before putting in bridges to handle the case where we have an
invoke-special to a virtual method in the same class (b/110175213)
this CL will make the initial analysis a bit more intelligent.
This seems to be the closest we can come to supporting invoke-special
without actually implementing it :)
Bug: 144450911
Change-Id: Ifd6aa42a7527468341d1cbb874a953e925576d21
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index fd0c968..afdc15b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -13,6 +14,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.Invoke.Type;
@@ -158,26 +160,10 @@
if (method.name.toString().equals(Constants.INSTANCE_INITIALIZER_NAME)) {
type = Type.DIRECT;
} else if (code.getOriginalHolder() == method.holder) {
- if (!this.itf || builder.appView.options().isInterfaceMethodDesugaringEnabled()) {
- // When desugaring default interface methods, it is expected they are targeted with
- // invoke-direct.
- type = Type.DIRECT;
- } else {
- DexProgramClass clazz = builder.appView.definitionForProgramType(method.holder);
- assert clazz != null;
- DexEncodedMethod encodedMethod = clazz.lookupDirectMethod(method);
- if (encodedMethod != null) {
- assert encodedMethod.isStatic() || encodedMethod.isPrivateMethod();
- type = Type.DIRECT;
- } else {
- // This is a default interface method.
- type = Type.SUPER;
- }
- }
+ type = invokeTypeForInvokeSpecialToNonInitMethodOnHolder(builder.appView, code);
} else {
type = Type.SUPER;
}
- assert type == Type.SUPER || type == Type.DIRECT;
break;
}
case Opcodes.INVOKESTATIC:
@@ -216,4 +202,39 @@
return InliningConstraintVisitor.getConstraintForInvoke(
opcode, method, graphLense, appView, inliningConstraints, invocationContext);
}
+
+ private Type invokeTypeForInvokeSpecialToNonInitMethodOnHolder(
+ AppView<?> appView, CfSourceCode code) {
+ boolean desugaringEnabled = appView.options().isInterfaceMethodDesugaringEnabled();
+ DexEncodedMethod encodedMethod = lookupMethod(appView, method);
+ if (encodedMethod == null) {
+ // The method is not defined on the class, we can use super to target. When desugaring
+ // default interface methods, it is expected they are targeted with invoke-direct.
+ return this.itf && desugaringEnabled ? Type.DIRECT : Type.SUPER;
+ }
+ if (!encodedMethod.isVirtualMethod()) {
+ return Type.DIRECT;
+ }
+ if (encodedMethod.accessFlags.isFinal()) {
+ // This method is final which indicates no subtype will overwrite it, we can use
+ // invoke-virtual.
+ return Type.VIRTUAL;
+ }
+ if (this.itf && encodedMethod.isDefaultMethod()) {
+ return desugaringEnabled ? Type.DIRECT : Type.SUPER;
+ }
+ // We cannot emulate the semantics of invoke-special in this case and should throw a compilation
+ // error.
+ throw new CompilationError(
+ "Failed to compile unsupported use of invokespecial", code.getOrigin());
+ }
+
+ private DexEncodedMethod lookupMethod(AppView<?> appView, DexMethod method) {
+ GraphLenseLookupResult lookupResult =
+ appView.graphLense().lookupMethod(method, method, Type.DIRECT);
+ DexMethod rewrittenMethod = lookupResult.getMethod();
+ DexProgramClass clazz = appView.definitionForProgramType(rewrittenMethod.holder);
+ assert clazz != null;
+ return clazz.lookupMethod(rewrittenMethod);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 28e95f8..a7c90fe 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -39,8 +39,6 @@
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
@@ -251,6 +249,10 @@
&& method.accessFlags.isSynchronized();
}
+ public Origin getOrigin() {
+ return origin;
+ }
+
public DexType getOriginalHolder() {
return code.getOriginalHolder();
}
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index f8e0eb0..13059f6 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -237,6 +237,11 @@
return self();
}
+ public CR assertOnlyErrors() {
+ getDiagnosticMessages().assertOnlyErrors();
+ return self();
+ }
+
public CR assertInfoMessageThatMatches(Matcher<String> matcher) {
getDiagnosticMessages().assertInfoMessageThatMatches(matcher);
return self();
@@ -257,6 +262,16 @@
return self();
}
+ public CR assertErrorMessageThatMatches(Matcher<String> matcher) {
+ getDiagnosticMessages().assertErrorMessageThatMatches(matcher);
+ return self();
+ }
+
+ public CR assertNoErrorMessageThatMatches(Matcher<String> matcher) {
+ getDiagnosticMessages().assertNoErrorMessageThatMatches(matcher);
+ return self();
+ }
+
public CR disassemble(PrintStream ps) throws IOException, ExecutionException {
ToolHelper.disassemble(app, ps);
return self();
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
index 5759c3a..702815a 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
@@ -36,4 +36,8 @@
public TestDiagnosticMessages assertWarningMessageThatMatches(Matcher<String> matcher);
public TestDiagnosticMessages assertNoWarningMessageThatMatches(Matcher<String> matcher);
+
+ public TestDiagnosticMessages assertErrorMessageThatMatches(Matcher<String> matcher);
+
+ public TestDiagnosticMessages assertNoErrorMessageThatMatches(Matcher<String> matcher);
}
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
index 8282c77..478a60d 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
@@ -171,4 +171,14 @@
public TestDiagnosticMessages assertNoWarningMessageThatMatches(Matcher<String> matcher) {
return assertNoMessageThatMatches(getWarnings(), "warning", matcher);
}
+
+ @Override
+ public TestDiagnosticMessages assertErrorMessageThatMatches(Matcher<String> matcher) {
+ return assertMessageThatMatches(getErrors(), "error", matcher);
+ }
+
+ @Override
+ public TestDiagnosticMessages assertNoErrorMessageThatMatches(Matcher<String> matcher) {
+ return assertNoMessageThatMatches(getErrors(), "error", matcher);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java b/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java
index 1765fc2..f72a98f 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.graph;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertTrue;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
@@ -13,7 +12,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRunResult;
-import com.android.tools.r8.TestRuntime.DexRuntime;
import com.android.tools.r8.ToolHelper.DexVm;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
@@ -39,29 +37,23 @@
@Test
public void testCallingFinal()
throws IOException, CompilationFailedException, ExecutionException {
+ boolean hasIncorrectSuperLookup =
+ parameters.isDexRuntime()
+ && parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_4_4_4_HOST)
+ && parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_6_0_1_HOST);
TestRunResult<?> runResult =
testForRuntime(parameters)
.addProgramClasses(Main.class, A.class)
.addProgramClassFileData(
getClassWithTransformedInvoked(B.class), getClassWithTransformedInvoked(C.class))
- .run(parameters.getRuntime(), Main.class);
- // TODO(b/144450911): Remove when fixed.
- if (parameters.isCfRuntime()) {
- runResult.assertSuccessWithOutputLines(
- "Hello from B",
- "Hello from B",
- "Hello from B",
- "Hello from B",
- "Hello from A",
- "Hello from B");
- } else {
- DexRuntime dexRuntime = parameters.getRuntime().asDex();
- if (dexRuntime.getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_TARGET)) {
- runResult.assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
- } else {
- runResult.assertFailureWithErrorThatMatches(containsString("IncompatibleClassChangeError"));
- }
- }
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(
+ "Hello from B",
+ "Hello from B",
+ hasIncorrectSuperLookup ? "Hello from A" : "Hello from B",
+ "Hello from B",
+ "Hello from A",
+ "Hello from B");
}
private byte[] getClassWithTransformedInvoked(Class<?> clazz) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSpecialForInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSpecialForInvokeVirtualTest.java
index 1c0c5b8..816288d 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSpecialForInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSpecialForInvokeVirtualTest.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.graph;
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
@@ -43,17 +41,8 @@
testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
.addProgramClasses(A.class, Main.class)
.addProgramClassFileData(getClassBWithTransformedInvoked())
- .run(parameters.getRuntime(), Main.class);
- // TODO(b/144450911): Remove when fixed.
- if (parameters.isCfRuntime()) {
- runResult.assertSuccessWithOutputLines("Hello World!");
- } else {
- runResult.assertFailureWithErrorThatMatches(
- anyOf(
- containsString("IncompatibleClassChangeError"),
- containsString(
- "com.android.tools.r8.graph.InvokeSpecialForInvokeVirtualTest$B.foo")));
- }
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!");
}
private byte[] getClassBWithTransformedInvoked() throws IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSpecialForNonDeclaredInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSpecialForNonDeclaredInvokeVirtualTest.java
index 5852bc1..a54fa1d 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSpecialForNonDeclaredInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSpecialForNonDeclaredInvokeVirtualTest.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.graph;
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
@@ -43,17 +41,8 @@
testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
.addProgramClasses(A.class, B.class, Main.class)
.addProgramClassFileData(getClassCWithTransformedInvoked())
- .run(parameters.getRuntime(), Main.class);
- // TODO(b/144450911): Remove when fixed.
- if (parameters.isCfRuntime()) {
- runResult.assertSuccessWithOutputLines("Hello World!");
- } else {
- runResult.assertFailureWithErrorThatMatches(
- anyOf(
- containsString("IncompatibleClassChangeError"),
- containsString(
- "com.android.tools.r8.graph.InvokeSpecialForNonDeclaredInvokeVirtualTest$C.foo")));
- }
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!");
}
private byte[] getClassCWithTransformedInvoked() throws IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceTest.java
index bd97457..f49c764 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.graph;
-import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
@@ -40,23 +39,21 @@
@Test
public void testRuntime() throws IOException, CompilationFailedException, ExecutionException {
+ boolean hasSegmentationFaultOnInvokeSuper =
+ parameters.isDexRuntime()
+ && parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_4_4_4_HOST)
+ && parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_6_0_1_HOST);
TestRunResult<?> runResult =
testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
.addProgramClasses(I.class, Main.class)
.addProgramClassFileData(getClassWithTransformedInvoked())
.run(parameters.getRuntime(), Main.class);
- // TODO(b/144450911): Remove when fixed.
+ // TODO(b/110175213): Remove when fixed.
if (parameters.isCfRuntime()) {
runResult.assertSuccessWithOutputLines("Hello World!");
- } else if (parameters.isDexRuntime()
- && parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_TARGET)) {
- runResult.assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
} else {
runResult.assertFailureWithErrorThatMatches(
- anyOf(
- containsString("IncompatibleClassChangeError"),
- containsString(
- "com.android.tools.r8.graph.InvokeSpecialForInvokeVirtualTest$B.foo")));
+ containsString(hasSegmentationFaultOnInvokeSuper ? "SIGSEGV" : "NoSuchMethodError"));
}
}
@@ -80,7 +77,7 @@
public static class B implements I {
public void bar() {
- foo(); // Will be rewritten to invoke-special I.foo()
+ foo(); // Will be rewritten to invoke-special B.foo()
}
}
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceWithBridgeTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceWithBridgeTest.java
index 62b5aba..1253df8 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceWithBridgeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSpecialInterfaceWithBridgeTest.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.graph;
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
@@ -15,7 +13,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRunResult;
-import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.utils.DescriptorUtils;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
@@ -45,20 +42,8 @@
testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
.addProgramClasses(I.class, A.class, Main.class)
.addProgramClassFileData(getClassWithTransformedInvoked())
- .run(parameters.getRuntime(), Main.class);
- // TODO(b/144450911): Remove when fixed.
- if (parameters.isCfRuntime()) {
- runResult.assertSuccessWithOutputLines("Hello World!");
- } else if (parameters.isDexRuntime()
- && parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_TARGET)) {
- runResult.assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
- } else {
- runResult.assertFailureWithErrorThatMatches(
- anyOf(
- containsString("IncompatibleClassChangeError"),
- containsString(
- "com.android.tools.r8.graph.InvokeSpecialForInvokeVirtualTest$B.foo")));
- }
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!");
}
private byte[] getClassWithTransformedInvoked() throws IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSpecialMissingInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSpecialMissingInvokeVirtualTest.java
index 59f8e99..e046730 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSpecialMissingInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSpecialMissingInvokeVirtualTest.java
@@ -43,8 +43,8 @@
testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
.addProgramClasses(A.class, Main.class)
.addProgramClassFileData(getClassWithTransformedInvoked())
- .run(parameters.getRuntime(), Main.class);
- runResult.assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
}
private byte[] getClassWithTransformedInvoked() throws IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSpecialOnSameClassTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSpecialOnSameClassTest.java
index 60a788f..00f4bb3 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSpecialOnSameClassTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSpecialOnSameClassTest.java
@@ -5,15 +5,14 @@
package com.android.tools.r8.graph;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRunResult;
-import com.android.tools.r8.TestRuntime.DexRuntime;
-import com.android.tools.r8.ToolHelper.DexVm;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
@@ -37,21 +36,18 @@
@Test
public void testRuntime() throws IOException, CompilationFailedException, ExecutionException {
- TestRunResult<?> runResult =
- testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
- .addProgramClasses(Main.class)
- .addProgramClassFileData(getClassWithTransformedInvoked())
- .run(parameters.getRuntime(), Main.class);
- // TODO(b/144450911): Remove when fixed.
- if (parameters.isCfRuntime()) {
- runResult.assertSuccessWithOutputLines("Hello World!");
- } else {
- DexRuntime dexRuntime = parameters.getRuntime().asDex();
- if (dexRuntime.getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_TARGET)) {
- runResult.assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
- } else {
- runResult.assertFailureWithErrorThatMatches(containsString("IncompatibleClassChangeError"));
- }
+ try {
+ testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getClassWithTransformedInvoked())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!");
+ // TODO(b/110175213): Remove when fixed.
+ assertTrue(parameters.isCfRuntime());
+ } catch (CompilationFailedException compilation) {
+ assertThat(
+ compilation.getCause().getMessage(),
+ containsString("Failed to compile unsupported use of invokespecial"));
}
}
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSpecialTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSpecialTest.java
index 5e2d674..83d0b83 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSpecialTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSpecialTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.AsmTestBase;
import com.android.tools.r8.ByteDataView;
import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.graph.invokespecial.Main;
@@ -52,13 +53,15 @@
.assertSuccessWithOutput(StringUtils.lines("true", "false"));
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testD8Behavior() throws Exception {
// TODO(b/110175213): Should succeed with output "true\nfalse\n".
testForD8()
.addProgramFiles(inputJar)
- .run(Main.class)
- .assertFailureWithErrorThatMatches(containsString(getExpectedOutput()));
+ .compileWithExpectedDiagnostics(
+ testDiagnosticMessages ->
+ testDiagnosticMessages.assertErrorMessageThatMatches(
+ containsString("Failed to compile unsupported use of invokespecial")));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvokeSpecialTests.java b/src/test/java/com/android/tools/r8/jasmin/InvokeSpecialTests.java
index 1907f33..b0e72f0 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvokeSpecialTests.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvokeSpecialTests.java
@@ -5,6 +5,7 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.ToolHelper;
import com.google.common.collect.ImmutableList;
import org.junit.Rule;
@@ -71,11 +72,12 @@
String javaResult = runOnJava(builder, clazz.name);
assertEquals(expected, javaResult);
- // TODO(zerny): Should we fail early on the above code? Art fails with a verification error
- // because Test.foo is expected to be in the direct method table.
if (ToolHelper.artSupported()) {
- thrown.expect(AssertionError.class);
+ thrown.expect(CompilationFailedException.class);
}
+
+ // TODO(b/110175213): This will fail with a compilation exception since we cannot translate
+ // an invoke-special to a member on the same class.
String artResult = runOnArtD8(builder, clazz.name);
assertEquals(expected, artResult);
}