Fix TypeSwitch for Java 23
Fixes: b/382880986
Change-Id: I5f839ad4f05f761dce620f4de1bee1a2d7d15352
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index aab3dff..0cf6dec 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -868,7 +868,6 @@
createMethod(switchBootstrapType, switchBootstrapMethodProto, createString("typeSwitch"));
public final DexMethod enumSwitchMethod =
createMethod(switchBootstrapType, switchBootstrapMethodProto, createString("enumSwitch"));
- public final DexProto typeSwitchProto = createProto(intType, objectType, intType);
public final DexMethod enumDescMethod =
createMethod(
enumDescType, createProto(enumDescType, classDescType, stringType), ofMethodName);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaringHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaringHelper.java
index 8d20c19..128bda9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaringHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaringHelper.java
@@ -29,9 +29,15 @@
"Unexpected ConstantDynamic in TypeSwitch: " + msg, context.getOrigin());
}
+ private static boolean isTypeSwitchProto(DexProto proto) {
+ return proto.getReturnType().isIntType()
+ && proto.getArity() == 2
+ && proto.getParameter(1).isIntType();
+ }
+
public static boolean isTypeSwitchCallSite(DexCallSite callSite, DexItemFactory factory) {
return callSite.methodName.isIdenticalTo(factory.typeSwitchMethod.getName())
- && callSite.methodProto.isIdenticalTo(factory.typeSwitchProto)
+ && isTypeSwitchProto(callSite.methodProto)
&& methodHandleIsInvokeStaticTo(callSite.bootstrapMethod, factory.typeSwitchMethod);
}
diff --git a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumLessCasesAtRuntimeSwitchTest.java b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumLessCasesAtRuntimeSwitchTest.java
index e367e8a..3625fe1 100644
--- a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumLessCasesAtRuntimeSwitchTest.java
+++ b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumLessCasesAtRuntimeSwitchTest.java
@@ -3,15 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.java23.switchpatternmatching;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.hasJdk21EnumSwitch;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.hasJdk21TypeSwitch;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBuilder;
@@ -19,11 +15,9 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Assume;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -84,38 +78,20 @@
@Test
public void testD8() throws Exception {
- if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O)
- && parameters.getApiLevel().isLessThan(AndroidApiLevel.BAKLAVA)) {
- assertThrows(
- CompilationFailedException.class,
- () ->
- testForD8(parameters.getBackend())
- .apply(this::addModifiedProgramClasses)
- .setMinApi(parameters)
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertOnlyErrors();
- diagnostics.assertErrorsMatch(
- diagnosticMessage(
- containsString("DexValueConstDynamic should be desugared")));
- }));
- } else {
- testForD8(parameters.getBackend())
- .apply(this::addModifiedProgramClasses)
- .setMinApi(parameters)
- .run(parameters.getRuntime(), Main.class)
- .assertFailure();
- }
+ testForD8(parameters.getBackend())
+ .apply(this::addModifiedProgramClasses)
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
}
@Test
- @Ignore("TODO(b/382880986) enable test when fixed.")
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
Assume.assumeTrue(
parameters.isDexRuntime()
|| (parameters.isCfRuntime()
- && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK21)));
+ && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK23)));
testForR8(parameters.getBackend())
.apply(this::addModifiedProgramClasses)
.applyIf(
diff --git a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumMoreCasesAtRuntimeSwitchTest.java b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumMoreCasesAtRuntimeSwitchTest.java
index 8b3f44d..51d0386 100644
--- a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumMoreCasesAtRuntimeSwitchTest.java
+++ b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumMoreCasesAtRuntimeSwitchTest.java
@@ -3,16 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.java23.switchpatternmatching;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.desugarMatchException;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.hasJdk21EnumSwitch;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.hasJdk21TypeSwitch;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.matchException;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBuilder;
@@ -20,11 +17,9 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Assume;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -133,38 +128,21 @@
@Test
public void testD8() throws Exception {
- if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O)
- && parameters.getApiLevel().isLessThan(AndroidApiLevel.BAKLAVA)) {
- assertThrows(
- CompilationFailedException.class,
- () ->
- testForD8(parameters.getBackend())
- .apply(this::addModifiedProgramClasses)
- .setMinApi(parameters)
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertOnlyErrors();
- diagnostics.assertErrorsMatch(
- diagnosticMessage(
- containsString("DexValueConstDynamic should be desugared")));
- }));
- } else {
- testForD8(parameters.getBackend())
- .apply(this::addModifiedProgramClasses)
- .setMinApi(parameters)
- .run(parameters.getRuntime(), Main.class)
- .assertFailure();
- }
+ testForD8(parameters.getBackend())
+ .apply(this::addModifiedProgramClasses)
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(
+ String.format(EXPECTED_OUTPUT, desugarMatchException(), desugarMatchException()));
}
@Test
- @Ignore("TODO(b/382880986) enable test when fixed.")
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
Assume.assumeTrue(
parameters.isDexRuntime()
|| (parameters.isCfRuntime()
- && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK21)));
+ && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK23)));
testForR8(parameters.getBackend())
.apply(this::addModifiedProgramClasses)
.applyIf(
diff --git a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumSwitchTest.java b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumSwitchTest.java
index ddf16a8..585c7c2 100644
--- a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumSwitchTest.java
+++ b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/EnumSwitchTest.java
@@ -3,15 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.java23.switchpatternmatching;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.desugarMatchException;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.hasJdk21TypeSwitch;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.matchException;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBuilder;
@@ -19,11 +16,9 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Assume;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -65,6 +60,7 @@
private <T extends TestBuilder<?, T>> void addModifiedProgramClasses(
TestBuilder<?, T> testBuilder) throws Exception {
+ String d = "com/android/tools/r8/java23/switchpatternmatching/EnumSwitchTest$D";
testBuilder
.addStrippedOuter(getClass())
.addProgramClasses(FakeI.class, E.class, C.class)
@@ -76,57 +72,32 @@
.addProgramClassFileData(
transformer(Main.class)
.transformTypeInsnInMethod(
- "getD",
- (opcode, type, visitor) ->
- visitor.visitTypeInsn(opcode, "switchpatternmatching/EnumSwitchTest$D"))
+ "getD", (opcode, type, visitor) -> visitor.visitTypeInsn(opcode, d))
.transformMethodInsnInMethod(
"getD",
(opcode, owner, name, descriptor, isInterface, visitor) -> {
assert name.equals("<init>");
- visitor.visitMethodInsn(
- opcode,
- "switchpatternmatching/EnumSwitchTest$D",
- name,
- descriptor,
- isInterface);
+ visitor.visitMethodInsn(opcode, d, name, descriptor, isInterface);
})
.transform());
}
@Test
public void testD8() throws Exception {
- if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O)
- && parameters.getApiLevel().isLessThan(AndroidApiLevel.BAKLAVA)) {
- assertThrows(
- CompilationFailedException.class,
- () ->
- testForD8(parameters.getBackend())
- .apply(this::addModifiedProgramClasses)
- .setMinApi(parameters)
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertOnlyErrors();
- diagnostics.assertErrorsMatch(
- diagnosticMessage(
- containsString("DexValueConstDynamic should be desugared")));
- }));
- } else {
- testForD8(parameters.getBackend())
- .apply(this::addModifiedProgramClasses)
- .setMinApi(parameters)
- .run(parameters.getRuntime(), Main.class)
- .assertFailure();
- }
+ testForD8(parameters.getBackend())
+ .apply(this::addModifiedProgramClasses)
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(String.format(EXPECTED_OUTPUT, desugarMatchException()));
}
@Test
- @Ignore("TODO(b/382880986) enable test when fixed.")
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
Assume.assumeTrue(
parameters.isDexRuntime()
|| (parameters.isCfRuntime()
- && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK21)));
+ && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK23)));
testForR8(parameters.getBackend())
.apply(this::addModifiedProgramClasses)
.applyIf(
diff --git a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchRegress382880986Test.java b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchRegress382880986Test.java
index d6c5acb..0f5077e 100644
--- a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchRegress382880986Test.java
+++ b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchRegress382880986Test.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.java23.switchpatternmatching;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.hasJdk21TypeSwitch;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.JdkClassFileProvider;
@@ -13,11 +12,9 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Assume;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -62,17 +59,10 @@
.addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
.run(parameters.getRuntime(), TestClass.class, "hello", "goodbye", "")
- // TODO(b/382880986): This should not fail.
- .applyIf(
- parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
- r ->
- r.assertFailureWithErrorThatMatches(
- containsString("Instruction is unrepresentable in DEX")),
- r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
}
@Test
- @Ignore("TODO(b/382880986) enable test when fixed.")
public void testR8() throws Exception {
Assume.assumeTrue(
parameters.isDexRuntime()
diff --git a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchTest.java b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchTest.java
index 38f7007..4782bf3 100644
--- a/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchTest.java
+++ b/src/test/java23/com/android/tools/r8/java23/switchpatternmatching/StringSwitchTest.java
@@ -3,9 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.java23.switchpatternmatching;
-import static com.android.tools.r8.ToolHelper.DexVm.Version.V6_0_1;
import static com.android.tools.r8.desugar.switchpatternmatching.SwitchTestHelper.hasJdk21TypeSwitch;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -15,11 +13,9 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Assume;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -67,37 +63,16 @@
.addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
.run(parameters.getRuntime(), Main.class)
- // TODO(b/382880986): This should not fail.
- .applyIf(
- parameters.isDexRuntime() && parameters.asDexRuntime().getVersion().isEqualTo(V6_0_1),
- r ->
- r.assertFailureWithErrorThatMatches(
- containsString(
- "Attempt to invoke virtual method 'boolean"
- + " java.lang.String.equalsIgnoreCase(java.lang.String)' on a null"
- + " object reference")),
- parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
- r ->
- r.assertFailureWithErrorThatMatches(
- containsString("Instruction is unrepresentable in DEX")),
- parameters.isCfRuntime()
- && (parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17)
- && parameters.asCfRuntime().isOlderThan(CfVm.JDK23)),
- r -> r.assertFailureWithErrorThatThrows(BootstrapMethodError.class),
- !parameters.isCfRuntime()
- || parameters.isCfRuntime() && parameters.asCfRuntime().isOlderThan(CfVm.JDK17),
- r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
- r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT));
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
}
@Test
- @Ignore("TODO(b/382880986) enable test when fixed.")
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
Assume.assumeTrue(
parameters.isDexRuntime()
|| (parameters.isCfRuntime()
- && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK21)));
+ && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK23)));
testForR8(parameters.getBackend())
.addInnerClassesAndStrippedOuter(getClass())
.applyIf(