blob: dbb7dcc84dc4ace97e4570d18402124f9c91b9f2 [file] [log] [blame]
Clément Béraf48bfff2024-05-15 11:22:09 +02001// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4package switchpatternmatching;
5
6import static org.junit.Assert.assertTrue;
7import static org.junit.Assume.assumeTrue;
8import static switchpatternmatching.SwitchTestHelper.hasJdk21EnumSwitch;
9import static switchpatternmatching.SwitchTestHelper.hasJdk21TypeSwitch;
10
Clément Béra2ab2d972024-05-15 11:32:33 +020011import com.android.tools.r8.JdkClassFileProvider;
Clément Béraf48bfff2024-05-15 11:22:09 +020012import com.android.tools.r8.TestBase;
13import com.android.tools.r8.TestBuilder;
14import com.android.tools.r8.TestParameters;
15import com.android.tools.r8.TestParametersCollection;
16import com.android.tools.r8.TestRuntime.CfVm;
17import com.android.tools.r8.ToolHelper;
18import com.android.tools.r8.utils.StringUtils;
19import com.android.tools.r8.utils.codeinspector.CodeInspector;
20import org.junit.Assume;
21import org.junit.Test;
22import org.junit.runner.RunWith;
23import org.junit.runners.Parameterized;
24import org.junit.runners.Parameterized.Parameter;
25import org.junit.runners.Parameterized.Parameters;
26
27@RunWith(Parameterized.class)
28public class EnumLessCasesAtRuntimeSwitchTest extends TestBase {
29
30 @Parameter public TestParameters parameters;
31
32 @Parameters(name = "{0}")
33 public static TestParametersCollection data() {
Clément Béra2ab2d972024-05-15 11:32:33 +020034 return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
Clément Béraf48bfff2024-05-15 11:22:09 +020035 }
36
37 public static String EXPECTED_OUTPUT =
38 StringUtils.lines("TYPE", "null", "E1", "E3", "E5", "a C", "ENUM", "null", "1", "3", "0");
39
40 @Test
41 public void testJvm() throws Exception {
42 assumeTrue(parameters.isCfRuntime());
43 CodeInspector inspector = new CodeInspector(ToolHelper.getClassFileForTestClass(Main.class));
44 assertTrue(
45 hasJdk21EnumSwitch(inspector.clazz(Main.class).uniqueMethodWithOriginalName("enumSwitch")));
46 assertTrue(
47 hasJdk21TypeSwitch(inspector.clazz(Main.class).uniqueMethodWithOriginalName("typeSwitch")));
48
49 parameters.assumeJvmTestParameters();
50 testForJvm(parameters)
51 .apply(this::addModifiedProgramClasses)
52 .run(parameters.getRuntime(), Main.class)
53 .applyIf(
54 parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK21),
55 r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT),
56 r -> r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class));
57 }
58
59 private <T extends TestBuilder<?, T>> void addModifiedProgramClasses(
60 TestBuilder<?, T> testBuilder) throws Exception {
61 testBuilder
62 .addStrippedOuter(getClass())
63 .addProgramClasses(FakeI.class, C.class, I.class, Main.class)
64 .addProgramClassFileData(
65 transformer(CompileTimeE.class)
66 .setImplements(FakeI.class)
67 .setClassDescriptor(RuntimeE.class.descriptorString())
68 .transform())
69 .addProgramClassFileData(
70 transformer(RuntimeE.class)
71 .setImplements(I.class)
72 .setClassDescriptor(CompileTimeE.class.descriptorString())
73 .transform());
74 }
75
76 @Test
77 public void testD8() throws Exception {
Clément Béra2ab2d972024-05-15 11:32:33 +020078 testForD8(parameters.getBackend())
Clément Béraf48bfff2024-05-15 11:22:09 +020079 .apply(this::addModifiedProgramClasses)
80 .setMinApi(parameters)
81 .run(parameters.getRuntime(), Main.class)
82 .assertSuccessWithOutput(EXPECTED_OUTPUT);
83 }
84
85 @Test
86 public void testR8() throws Exception {
Clément Béra2ab2d972024-05-15 11:32:33 +020087 parameters.assumeR8TestParameters();
88 Assume.assumeTrue(
89 parameters.isDexRuntime()
90 || (parameters.isCfRuntime()
91 && parameters.getCfRuntime().isNewerThanOrEqual(CfVm.JDK21)));
Clément Béraf48bfff2024-05-15 11:22:09 +020092 testForR8(parameters.getBackend())
93 .apply(this::addModifiedProgramClasses)
Clément Béra2ab2d972024-05-15 11:32:33 +020094 .applyIf(
95 parameters.isCfRuntime(),
96 b -> b.addLibraryProvider(JdkClassFileProvider.fromSystemJdk()))
Clément Béraf48bfff2024-05-15 11:22:09 +020097 .setMinApi(parameters)
98 .addKeepMainRule(Main.class)
99 .run(parameters.getRuntime(), Main.class)
100 .assertSuccessWithOutput(EXPECTED_OUTPUT);
101 }
102
103 sealed interface I permits CompileTimeE, C {}
104
105 public enum CompileTimeE implements I {
106 E1,
107 E2, // Case missing at runtime.
108 E3,
109 E4, // Case missing at runtime.
110 E5
111 }
112
113 interface FakeI {}
114
115 public enum RuntimeE implements FakeI {
116 E1,
117 E3,
118 E5
119 }
120
121 static final class C implements I {}
122
123 static class Main {
124
125 static void typeSwitch(I i) {
126 switch (i) {
127 case CompileTimeE.E1 -> {
128 System.out.println("E1");
129 }
130 case CompileTimeE.E2 -> { // Case missing at runtime.
131 System.out.println("E2");
132 }
133 case CompileTimeE.E3 -> {
134 System.out.println("E3");
135 }
136 case CompileTimeE.E4 -> { // Case missing at runtime.
137 System.out.println("E4");
138 }
139 case CompileTimeE.E5 -> {
140 System.out.println("E5");
141 }
142 case C c -> {
143 System.out.println("a C");
144 }
145 }
146 }
147
148 static void enumSwitch(CompileTimeE e) {
149 switch (e) {
150 case null -> System.out.println("null");
151 case CompileTimeE.E1 -> System.out.println("1");
152 case CompileTimeE.E2 -> System.out.println("2"); // Case missing at runtime.
153 case CompileTimeE t when t == CompileTimeE.E3 -> System.out.println("3");
154 case CompileTimeE t when t.name().equals("E4") ->
155 System.out.println("4"); // Case missing at runtime.
156 case CompileTimeE t -> System.out.println("0");
157 }
158 }
159
160 public static void main(String[] args) {
161 System.out.println("TYPE");
162 try {
163 typeSwitch(null);
164 } catch (NullPointerException e) {
165 System.out.println("null");
166 }
167 typeSwitch(CompileTimeE.E1);
168 typeSwitch(CompileTimeE.E3);
169 typeSwitch(CompileTimeE.E5);
170 typeSwitch(new C());
171
172 System.out.println("ENUM");
173 enumSwitch(null);
174 enumSwitch(CompileTimeE.E1);
175 enumSwitch(CompileTimeE.E3);
176 enumSwitch(CompileTimeE.E5);
177 }
178 }
179}