1 /* 2 * Copyright (c) 2018, 2019, 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 YIELD_Z = "yield 0;"; 52 private static final String YIELD_S = "yield \"hello world\";"; 53 private static final String YIELD_INT_FN = "yield () -> 0 ;"; 54 private static final String BREAK_N = "break;"; 55 private static final String BREAK_L = "break label;"; 56 private static final String YIELD_L = "yield label;"; 57 private static final String RETURN_Z = "return 0;"; 58 private static final String RETURN_N = "return;"; 59 private static final String RETURN_S = "return \"Hello\";"; 60 private static final String CONTINUE_N = "continue;"; 61 private static final String CONTINUE_L = "continue label;"; 62 private static final String NOTHING = "System.out.println();"; 63 64 // containers that do not require exhaustiveness 65 private static final List<String> CONTAINERS 66 = List.of(RUNNABLE, FOR, WHILE, DO, SSWITCH, IF, BLOCK); 67 // containers that do not require exhaustiveness that are statements 68 private static final List<String> CONTAINER_STATEMENTS 69 = List.of(FOR, WHILE, DO, SSWITCH, IF, BLOCK); 70 71 @AfterMethod 72 public void dumpTemplateIfError(ITestResult result) { 73 // Make sure offending template ends up in log file on failure 74 if (!result.isSuccess()) { 75 System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList())); 76 } 77 } 78 79 private void program(String... constructs) { 80 String s = "class C { static boolean cond = false; static int x = 0; void m() { # } }"; 81 for (String c : constructs) 82 s = s.replace("#", c); 83 addSourceFile("C.java", new StringTemplate(s)); 84 } 85 86 private void assertOK(String... constructs) { 87 reset(); 88 addCompileOptions(); 89 program(constructs); 90 try { 91 compile(); 92 } 93 catch (IOException e) { 94 throw new RuntimeException(e); 95 } 96 assertCompileSucceeded(); 97 } 98 99 private void assertOKWithWarning(String warning, String... constructs) { 100 reset(); 101 addCompileOptions(); 102 program(constructs); 103 try { 104 compile(); 105 } 106 catch (IOException e) { 107 throw new RuntimeException(e); 108 } 109 assertCompileSucceededWithWarning(warning); 110 } 111 112 private void assertFail(String expectedDiag, String... constructs) { 113 reset(); 114 addCompileOptions(); 115 program(constructs); 116 try { 117 compile(); 118 } 119 catch (IOException e) { 120 throw new RuntimeException(e); 121 } 122 assertCompileFailed(expectedDiag); 123 } 124 125 public void testReallySimpleCases() { 126 for (String s : CONTAINERS) 127 assertOK(s, NOTHING); 128 for (String s : CONTAINER_STATEMENTS) 129 assertOK(LABEL, s, NOTHING); 130 } 131 132 public void testLambda() { 133 assertOK(RUNNABLE, RETURN_N); 134 assertOK(RUNNABLE, NOTHING); 135 assertOK(INT_FN, RETURN_Z); 136 assertFail("compiler.err.break.outside.switch.loop", RUNNABLE, BREAK_N); 137 assertFail("compiler.err.no.switch.expression", RUNNABLE, YIELD_Z); 138 assertFail("compiler.err.no.switch.expression", RUNNABLE, YIELD_S); 139 assertFail("compiler.err.break.outside.switch.loop", INT_FN, BREAK_N); 140 assertFail("compiler.err.no.switch.expression", INT_FN, YIELD_Z); 141 assertFail("compiler.err.no.switch.expression", INT_FN, YIELD_S); 142 assertFail("compiler.err.cont.outside.loop", RUNNABLE, CONTINUE_N); 143 assertFail("compiler.err.undef.label", RUNNABLE, BREAK_L); 144 assertFail("compiler.err.undef.label", RUNNABLE, CONTINUE_L); 145 assertFail("compiler.err.cont.outside.loop", INT_FN, CONTINUE_N); 146 assertFail("compiler.err.undef.label", INT_FN, BREAK_L); 147 assertFail("compiler.err.undef.label", INT_FN, CONTINUE_L); 148 assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, BREAK_L); 149 assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, CONTINUE_L); 150 assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, BREAK_L); 151 assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, CONTINUE_L); 152 } 153 154 public void testEswitch() { 155 //Int-valued switch expressions 156 assertOK(ESWITCH_Z, YIELD_Z); 157 assertOK(LABEL, BLOCK, ESWITCH_Z, YIELD_Z); 158 assertFail("compiler.err.break.outside.switch.expression", ESWITCH_Z, BREAK_N); 159 assertFail("compiler.err.prob.found.req", ESWITCH_Z, YIELD_S); 160 assertFail("compiler.err.undef.label", ESWITCH_Z, BREAK_L); 161 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_Z, BREAK_L); 162 assertFail("compiler.err.undef.label", ESWITCH_Z, CONTINUE_L); 163 assertFail("compiler.err.continue.outside.switch.expression", ESWITCH_Z, CONTINUE_N); 164 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_N); 165 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_Z); 166 167 assertOK(INT_ESWITCH_DEFAULT, YIELD_Z); 168 assertFail("compiler.err.break.outside.switch.expression", INT_ESWITCH_DEFAULT, BREAK_N); 169 assertFail("compiler.err.prob.found.req", INT_ESWITCH_DEFAULT, YIELD_S); 170 assertFail("compiler.err.undef.label", INT_ESWITCH_DEFAULT, BREAK_L); 171 172 173 // String-valued switch expressions 174 assertOK(ESWITCH_S, YIELD_S); 175 assertOK(LABEL, BLOCK, ESWITCH_S, YIELD_S); 176 assertFail("compiler.err.break.outside.switch.expression", ESWITCH_S, BREAK_N); 177 assertFail("compiler.err.prob.found.req", ESWITCH_S, YIELD_Z); 178 assertFail("compiler.err.undef.label", ESWITCH_S, BREAK_L); 179 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_S, BREAK_L); 180 assertFail("compiler.err.undef.label", ESWITCH_S, CONTINUE_L); 181 assertFail("compiler.err.continue.outside.switch.expression", ESWITCH_S, CONTINUE_N); 182 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_N); 183 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_S); 184 // Function-valued switch expression 185 assertOK(INT_FN_ESWITCH, YIELD_INT_FN); 186 assertFail("compiler.err.break.outside.switch.expression", INT_FN_ESWITCH, BREAK_N); 187 assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, YIELD_Z); 188 assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, YIELD_S); 189 190 assertFail("compiler.err.undef.label", INT_FN_ESWITCH, BREAK_L); 191 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, INT_FN_ESWITCH, BREAK_L); 192 assertFail("compiler.err.undef.label", INT_FN_ESWITCH, CONTINUE_L); 193 assertFail("compiler.err.continue.outside.switch.expression", INT_FN_ESWITCH, CONTINUE_N); 194 assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_N); 195 assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_S); 196 197 } 198 199 public void testNestedInExpSwitch() { 200 assertOK(ESWITCH_Z, IF, YIELD_Z); 201 assertOK(ESWITCH_Z, BLOCK, YIELD_Z); 202 // 203 assertOK(ESWITCH_Z, IF, IF, YIELD_Z); 204 assertOK(ESWITCH_Z, IF, BLOCK, YIELD_Z); 205 assertOK(ESWITCH_Z, BLOCK, IF, YIELD_Z); 206 assertOK(ESWITCH_Z, BLOCK, BLOCK, YIELD_Z); 207 // 208 assertOK(ESWITCH_Z, IF, IF, IF, YIELD_Z); 209 assertOK(ESWITCH_Z, IF, IF, BLOCK, YIELD_Z); 210 assertOK(ESWITCH_Z, IF, BLOCK, IF, YIELD_Z); 211 assertOK(ESWITCH_Z, IF, BLOCK, BLOCK, YIELD_Z); 212 assertOK(ESWITCH_Z, BLOCK, IF, IF, YIELD_Z); 213 assertOK(ESWITCH_Z, BLOCK, IF, BLOCK, YIELD_Z); 214 assertOK(ESWITCH_Z, BLOCK, BLOCK, IF, YIELD_Z); 215 assertOK(ESWITCH_Z, BLOCK, BLOCK, BLOCK, YIELD_Z); 216 // 217 assertOK(ESWITCH_Z, YIELD_Z, SSWITCH, YIELD_Z); 218 assertOK(ESWITCH_Z, YIELD_Z, FOR, YIELD_Z); 219 assertOK(ESWITCH_Z, YIELD_Z, WHILE, YIELD_Z); 220 assertOK(ESWITCH_Z, YIELD_Z, DO, YIELD_Z); 221 assertFail("compiler.err.no.switch.expression", ESWITCH_Z, INT_FN, YIELD_Z); 222 assertOK(ESWITCH_Z, YIELD_Z, SSWITCH, IF, YIELD_Z); 223 assertOK(ESWITCH_Z, YIELD_Z, FOR, IF, YIELD_Z); 224 assertOK(ESWITCH_Z, YIELD_Z, WHILE, IF, YIELD_Z); 225 assertOK(ESWITCH_Z, YIELD_Z, DO, IF, YIELD_Z); 226 assertOK(ESWITCH_Z, YIELD_Z, BLOCK, SSWITCH, IF, YIELD_Z); 227 assertOK(ESWITCH_Z, YIELD_Z, BLOCK, FOR, IF, YIELD_Z); 228 assertOK(ESWITCH_Z, YIELD_Z, BLOCK, WHILE, IF, YIELD_Z); 229 assertOK(ESWITCH_Z, YIELD_Z, BLOCK, DO, IF, YIELD_Z); 230 } 231 232 public void testBreakExpressionLabelDisambiguation() { 233 assertOK(DEF_LABEL_VAR, ESWITCH_Z, YIELD_L); 234 assertFail("compiler.err.undef.label", DEF_LABEL_VAR, ESWITCH_Z, BREAK_L); 235 assertFail("compiler.err.break.outside.switch.expression", LABEL, FOR, BLOCK, DEF_LABEL_VAR, ESWITCH_Z, BREAK_L); 236 assertOK(DEF_LABEL_VAR, ESWITCH_Z, YIELD_Z, LABEL, FOR, BREAK_L); //label break 237 assertFail("compiler.err.break.outside.switch.expression", DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, BREAK_L); 238 assertOK(DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, YIELD_L); //expression break 239 // 240 } 241 242 public void testFunReturningSwitchExp() { 243 assertOK(INT_FN_ESWITCH, YIELD_INT_FN); 244 } 245 246 public void testContinueLoops() { 247 assertOK(LABEL, FOR, CONTINUE_L); 248 assertOK(LABEL, FOR_EACH, CONTINUE_L); 249 assertOK(LABEL, WHILE, CONTINUE_L); 250 assertOK(LABEL, DO, CONTINUE_L); 251 assertFail("compiler.err.not.loop.label", LABEL, CONTINUE_L); 252 } 253 }