1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.IOException; 25 import java.util.List; 26 27 import org.testng.ITestResult; 28 import org.testng.annotations.AfterMethod; 29 import org.testng.annotations.Test; 30 import tools.javac.combo.JavacTemplateTestBase; 31 32 import static java.util.stream.Collectors.toList; 33 34 @Test 35 public class ExpSwitchNestingTest extends JavacTemplateTestBase { 36 private static final String RUNNABLE = "Runnable r = () -> { # };"; 37 private static final String INT_FN = "java.util.function.IntSupplier r = () -> { # };"; 38 private static final String LABEL = "label: #"; 39 private static final String DEF_LABEL_VAR = "int label = 0; { # }"; 40 private static final String FOR = "for (int i=0; i<10; i++) { # }"; 41 private static final String FOR_EACH = "for (int i : new int[] {}) { # }"; 42 private static final String WHILE = "while (cond) { # }"; 43 private static final String DO = "do { # } while (cond);"; 44 private static final String SSWITCH = "switch (x) { case 0: # };"; 45 private static final String ESWITCH_Z = "int res = switch (x) { case 0 -> { # } default -> 0; };"; 46 private static final String ESWITCH_S = "String res_string = switch (x) { case 0 -> { # } default -> \"default\"; };"; 47 private static final String INT_FN_ESWITCH = "java.util.function.IntSupplier r = switch (x) { case 0 -> { # } default -> null; };"; 48 private static final String INT_ESWITCH_DEFAULT = "int res = switch (x) { default -> { # } };"; 49 private static final String IF = "if (cond) { # } else throw new RuntimeException();"; 50 private static final String BLOCK = "{ # }"; 51 private static final String BREAK_Z = "break 0;"; 52 private static final String BREAK_S = "break \"hello world\";"; 53 private static final String BREAK_INT_FN = "break () -> 0 ;"; 54 private static final String BREAK_N = "break;"; 55 private static final String BREAK_L = "break label;"; 56 private static final String RETURN_Z = "return 0;"; 57 private static final String RETURN_N = "return;"; 58 private static final String RETURN_S = "return \"Hello\";"; 59 private static final String CONTINUE_N = "continue;"; 60 private static final String CONTINUE_L = "continue label;"; 61 private static final String NOTHING = "System.out.println();"; 62 63 // containers that do not require exhaustiveness 64 private static final List<String> CONTAINERS 65 = List.of(RUNNABLE, FOR, WHILE, DO, SSWITCH, IF, BLOCK); 66 // containers that do not require exhaustiveness that are statements 67 private static final List<String> CONTAINER_STATEMENTS 68 = List.of(FOR, WHILE, DO, SSWITCH, IF, BLOCK); 69 70 @AfterMethod 71 public void dumpTemplateIfError(ITestResult result) { 72 // Make sure offending template ends up in log file on failure 73 if (!result.isSuccess()) { 74 System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList())); 75 } 76 } 77 78 private static String[] PREVIEW_OPTIONS = {"--enable-preview", "-source", "13"}; 79 80 private void program(String... constructs) { 81 String s = "class C { static boolean cond = false; static int x = 0; void m() { # } }"; 82 for (String c : constructs) 83 s = s.replace("#", c); 84 addSourceFile("C.java", new StringTemplate(s)); 85 } 86 87 private void assertOK(String... constructs) { 88 reset(); 89 addCompileOptions(PREVIEW_OPTIONS); 90 program(constructs); 91 try { 92 compile(); 93 } 94 catch (IOException e) { 95 throw new RuntimeException(e); 96 } 97 assertCompileSucceeded(); 98 } 99 100 private void assertOKWithWarning(String warning, String... constructs) { 101 reset(); 102 addCompileOptions(PREVIEW_OPTIONS); 103 program(constructs); 104 try { 105 compile(); 106 } 107 catch (IOException e) { 108 throw new RuntimeException(e); 109 } 110 assertCompileSucceededWithWarning(warning); 111 } 112 113 private void assertFail(String expectedDiag, String... constructs) { 114 reset(); 115 addCompileOptions(PREVIEW_OPTIONS); 116 program(constructs); 117 try { 118 compile(); 119 } 120 catch (IOException e) { 121 throw new RuntimeException(e); 122 } 123 assertCompileFailed(expectedDiag); 124 } 125 126 public void testReallySimpleCases() { 127 for (String s : CONTAINERS) 128 assertOK(s, NOTHING); 129 for (String s : CONTAINER_STATEMENTS) 130 assertOK(LABEL, s, NOTHING); 131 } 132 133 public void testLambda() { 134 assertOK(RUNNABLE, RETURN_N); 135 assertOK(RUNNABLE, NOTHING); 136 assertOK(INT_FN, RETURN_Z); 137 assertFail("compiler.err.break.outside.switch.loop", RUNNABLE, BREAK_N); 138 assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_Z); 139 assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_S); 140 assertFail("compiler.err.break.outside.switch.loop", INT_FN, BREAK_N); 141 assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_Z); 142 assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_S); 143 assertFail("compiler.err.cont.outside.loop", RUNNABLE, CONTINUE_N); 144 assertFail("compiler.err.undef.label", RUNNABLE, BREAK_L); 145 assertFail("compiler.err.undef.label", RUNNABLE, CONTINUE_L); 146 assertFail("compiler.err.cont.outside.loop", INT_FN, CONTINUE_N); 147 assertFail("compiler.err.undef.label", INT_FN, BREAK_L); 148 assertFail("compiler.err.undef.label", INT_FN, CONTINUE_L); 149 assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, BREAK_L); 150 assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, CONTINUE_L); 151 assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, BREAK_L); 152 assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, CONTINUE_L); 153 } 154 155 public void testEswitch() { 156 //Int-valued switch expressions 157 assertOK(ESWITCH_Z, BREAK_Z); 158 assertOK(LABEL, BLOCK, ESWITCH_Z, BREAK_Z); 159 assertFail("compiler.err.break.missing.value", ESWITCH_Z, BREAK_N); 160 assertFail("compiler.err.prob.found.req", ESWITCH_Z, BREAK_S); 161 assertFail("compiler.err.cant.resolve.location", ESWITCH_Z, BREAK_L); 162 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_Z, BREAK_L); 163 assertFail("compiler.err.undef.label", ESWITCH_Z, CONTINUE_L); 164 assertFail("compiler.err.cont.outside.loop", ESWITCH_Z, CONTINUE_N); 165 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_N); 166 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_Z); 167 168 assertOK(INT_ESWITCH_DEFAULT, BREAK_Z); 169 assertFail("compiler.err.break.missing.value", INT_ESWITCH_DEFAULT, BREAK_N); 170 assertFail("compiler.err.prob.found.req", INT_ESWITCH_DEFAULT, BREAK_S); 171 assertFail("compiler.err.cant.resolve.location", INT_ESWITCH_DEFAULT, BREAK_L); 172 173 174 // String-valued switch expressions 175 assertOK(ESWITCH_S, BREAK_S); 176 assertOK(LABEL, BLOCK, ESWITCH_S, BREAK_S); 177 assertFail("compiler.err.break.missing.value", ESWITCH_S, BREAK_N); 178 assertFail("compiler.err.prob.found.req", ESWITCH_S, BREAK_Z); 179 assertFail("compiler.err.cant.resolve.location", ESWITCH_S, BREAK_L); 180 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_S, BREAK_L); 181 assertFail("compiler.err.undef.label", ESWITCH_S, CONTINUE_L); 182 assertFail("compiler.err.cont.outside.loop", ESWITCH_S, CONTINUE_N); 183 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_N); 184 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_S); 185 // Function-valued switch expression 186 assertOK(INT_FN_ESWITCH, BREAK_INT_FN); 187 assertFail("compiler.err.break.missing.value", INT_FN_ESWITCH, BREAK_N); 188 assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_Z); 189 assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_S); 190 191 assertFail("compiler.err.cant.resolve.location", INT_FN_ESWITCH, BREAK_L); 192 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, INT_FN_ESWITCH, BREAK_L); 193 assertFail("compiler.err.undef.label", INT_FN_ESWITCH, CONTINUE_L); 194 assertFail("compiler.err.cont.outside.loop", INT_FN_ESWITCH, CONTINUE_N); 195 assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_N); 196 assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_S); 197 198 } 199 200 public void testNestedInExpSwitch() { 201 assertOK(ESWITCH_Z, IF, BREAK_Z); 202 assertOK(ESWITCH_Z, BLOCK, BREAK_Z); 203 // 204 assertOK(ESWITCH_Z, IF, IF, BREAK_Z); 205 assertOK(ESWITCH_Z, IF, BLOCK, BREAK_Z); 206 assertOK(ESWITCH_Z, BLOCK, IF, BREAK_Z); 207 assertOK(ESWITCH_Z, BLOCK, BLOCK, BREAK_Z); 208 // 209 assertOK(ESWITCH_Z, IF, IF, IF, BREAK_Z); 210 assertOK(ESWITCH_Z, IF, IF, BLOCK, BREAK_Z); 211 assertOK(ESWITCH_Z, IF, BLOCK, IF, BREAK_Z); 212 assertOK(ESWITCH_Z, IF, BLOCK, BLOCK, BREAK_Z); 213 assertOK(ESWITCH_Z, BLOCK, IF, IF, BREAK_Z); 214 assertOK(ESWITCH_Z, BLOCK, IF, BLOCK, BREAK_Z); 215 assertOK(ESWITCH_Z, BLOCK, BLOCK, IF, BREAK_Z); 216 assertOK(ESWITCH_Z, BLOCK, BLOCK, BLOCK, BREAK_Z); 217 // 218 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, BREAK_Z); 219 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, BREAK_Z); 220 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, BREAK_Z); 221 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, BREAK_Z); 222 assertFail("compiler.err.break.complex.value.no.switch.expression", ESWITCH_Z, INT_FN, BREAK_Z); 223 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, IF, BREAK_Z); 224 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, IF, BREAK_Z); 225 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, IF, BREAK_Z); 226 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, IF, BREAK_Z); 227 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, SSWITCH, IF, BREAK_Z); 228 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, FOR, IF, BREAK_Z); 229 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, WHILE, IF, BREAK_Z); 230 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, DO, IF, BREAK_Z); 231 } 232 233 public void testBreakExpressionLabelDisambiguation() { 234 assertOK(DEF_LABEL_VAR, ESWITCH_Z, BREAK_L); 235 assertFail("compiler.err.break.ambiguous.target", LABEL, FOR, BLOCK, DEF_LABEL_VAR, ESWITCH_Z, BREAK_L); 236 assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, ESWITCH_Z, LABEL, FOR, BREAK_L); //label break 237 assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, BREAK_L); //expression break 238 // 239 } 240 241 public void testFunReturningSwitchExp() { 242 assertOK(INT_FN_ESWITCH, BREAK_INT_FN); 243 } 244 245 public void testContinueLoops() { 246 assertOK(LABEL, FOR, CONTINUE_L); 247 assertOK(LABEL, FOR_EACH, CONTINUE_L); 248 assertOK(LABEL, WHILE, CONTINUE_L); 249 assertOK(LABEL, DO, CONTINUE_L); 250 assertFail("compiler.err.not.loop.label", LABEL, CONTINUE_L); 251 } 252 }