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 void program(String... constructs) { 79 String s = "class C { static boolean cond = false; static int x = 0; void m() { # } }"; 80 for (String c : constructs) 81 s = s.replace("#", c); 82 addSourceFile("C.java", new StringTemplate(s)); 83 } 84 85 private void assertOK(String... constructs) { 86 reset(); 87 addCompileOptions("--enable-preview", "-source", "12"); 88 program(constructs); 89 try { 90 compile(); 91 } 92 catch (IOException e) { 93 throw new RuntimeException(e); 94 } 95 assertCompileSucceeded(); 96 } 97 98 private void assertOKWithWarning(String warning, String... constructs) { 99 reset(); 100 addCompileOptions("--enable-preview", "-source", "12"); 101 program(constructs); 102 try { 103 compile(); 104 } 105 catch (IOException e) { 106 throw new RuntimeException(e); 107 } 108 assertCompileSucceededWithWarning(warning); 109 } 110 111 private void assertFail(String expectedDiag, String... constructs) { 112 reset(); 113 addCompileOptions("--enable-preview", "-source", "12"); 114 program(constructs); 115 try { 116 compile(); 117 } 118 catch (IOException e) { 119 throw new RuntimeException(e); 120 } 121 assertCompileFailed(expectedDiag); 122 } 123 124 public void testReallySimpleCases() { 125 for (String s : CONTAINERS) 126 assertOK(s, NOTHING); 127 for (String s : CONTAINER_STATEMENTS) 128 assertOK(LABEL, s, NOTHING); 129 } 130 131 public void testLambda() { 132 assertOK(RUNNABLE, RETURN_N); 133 assertOK(RUNNABLE, NOTHING); 134 assertOK(INT_FN, RETURN_Z); 135 assertFail("compiler.err.break.outside.switch.loop", RUNNABLE, BREAK_N); 136 assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_Z); 137 assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_S); 138 assertFail("compiler.err.break.outside.switch.loop", INT_FN, BREAK_N); 139 assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_Z); 140 assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_S); 141 assertFail("compiler.err.cont.outside.loop", RUNNABLE, CONTINUE_N); 142 assertFail("compiler.err.undef.label", RUNNABLE, BREAK_L); 143 assertFail("compiler.err.undef.label", RUNNABLE, CONTINUE_L); 144 assertFail("compiler.err.cont.outside.loop", INT_FN, CONTINUE_N); 145 assertFail("compiler.err.undef.label", INT_FN, BREAK_L); 146 assertFail("compiler.err.undef.label", INT_FN, CONTINUE_L); 147 assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, BREAK_L); 148 assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, CONTINUE_L); 149 assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, BREAK_L); 150 assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, CONTINUE_L); 151 } 152 153 public void testEswitch() { 154 //Int-valued switch expressions 155 assertOK(ESWITCH_Z, BREAK_Z); 156 assertOK(LABEL, BLOCK, ESWITCH_Z, BREAK_Z); 157 assertFail("compiler.err.break.missing.value", ESWITCH_Z, BREAK_N); 158 assertFail("compiler.err.prob.found.req", ESWITCH_Z, BREAK_S); 159 assertFail("compiler.err.cant.resolve.location", ESWITCH_Z, BREAK_L); 160 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_Z, BREAK_L); 161 assertFail("compiler.err.undef.label", ESWITCH_Z, CONTINUE_L); 162 assertFail("compiler.err.cont.outside.loop", ESWITCH_Z, CONTINUE_N); 163 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_N); 164 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_Z); 165 166 assertOK(INT_ESWITCH_DEFAULT, BREAK_Z); 167 assertFail("compiler.err.break.missing.value", INT_ESWITCH_DEFAULT, BREAK_N); 168 assertFail("compiler.err.prob.found.req", INT_ESWITCH_DEFAULT, BREAK_S); 169 assertFail("compiler.err.cant.resolve.location", INT_ESWITCH_DEFAULT, BREAK_L); 170 171 172 // String-valued switch expressions 173 assertOK(ESWITCH_S, BREAK_S); 174 assertOK(LABEL, BLOCK, ESWITCH_S, BREAK_S); 175 assertFail("compiler.err.break.missing.value", ESWITCH_S, BREAK_N); 176 assertFail("compiler.err.prob.found.req", ESWITCH_S, BREAK_Z); 177 assertFail("compiler.err.cant.resolve.location", ESWITCH_S, BREAK_L); 178 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_S, BREAK_L); 179 assertFail("compiler.err.undef.label", ESWITCH_S, CONTINUE_L); 180 assertFail("compiler.err.cont.outside.loop", ESWITCH_S, CONTINUE_N); 181 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_N); 182 assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_S); 183 // Function-valued switch expression 184 assertOK(INT_FN_ESWITCH, BREAK_INT_FN); 185 assertFail("compiler.err.break.missing.value", INT_FN_ESWITCH, BREAK_N); 186 assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_Z); 187 assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_S); 188 189 assertFail("compiler.err.cant.resolve.location", INT_FN_ESWITCH, BREAK_L); 190 assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, INT_FN_ESWITCH, BREAK_L); 191 assertFail("compiler.err.undef.label", INT_FN_ESWITCH, CONTINUE_L); 192 assertFail("compiler.err.cont.outside.loop", INT_FN_ESWITCH, CONTINUE_N); 193 assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_N); 194 assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_S); 195 196 } 197 198 public void testNestedInExpSwitch() { 199 assertOK(ESWITCH_Z, IF, BREAK_Z); 200 assertOK(ESWITCH_Z, BLOCK, BREAK_Z); 201 // 202 assertOK(ESWITCH_Z, IF, IF, BREAK_Z); 203 assertOK(ESWITCH_Z, IF, BLOCK, BREAK_Z); 204 assertOK(ESWITCH_Z, BLOCK, IF, BREAK_Z); 205 assertOK(ESWITCH_Z, BLOCK, BLOCK, BREAK_Z); 206 // 207 assertOK(ESWITCH_Z, IF, IF, IF, BREAK_Z); 208 assertOK(ESWITCH_Z, IF, IF, BLOCK, BREAK_Z); 209 assertOK(ESWITCH_Z, IF, BLOCK, IF, BREAK_Z); 210 assertOK(ESWITCH_Z, IF, BLOCK, BLOCK, BREAK_Z); 211 assertOK(ESWITCH_Z, BLOCK, IF, IF, BREAK_Z); 212 assertOK(ESWITCH_Z, BLOCK, IF, BLOCK, BREAK_Z); 213 assertOK(ESWITCH_Z, BLOCK, BLOCK, IF, BREAK_Z); 214 assertOK(ESWITCH_Z, BLOCK, BLOCK, BLOCK, BREAK_Z); 215 // 216 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, BREAK_Z); 217 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, BREAK_Z); 218 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, BREAK_Z); 219 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, BREAK_Z); 220 assertFail("compiler.err.break.complex.value.no.switch.expression", ESWITCH_Z, INT_FN, BREAK_Z); 221 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, IF, BREAK_Z); 222 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, IF, BREAK_Z); 223 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, IF, BREAK_Z); 224 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, IF, BREAK_Z); 225 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, SSWITCH, IF, BREAK_Z); 226 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, FOR, IF, BREAK_Z); 227 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, WHILE, IF, BREAK_Z); 228 assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, DO, IF, BREAK_Z); 229 } 230 231 public void testBreakExpressionLabelDisambiguation() { 232 assertOK(DEF_LABEL_VAR, ESWITCH_Z, BREAK_L); 233 assertFail("compiler.err.break.ambiguous.target", LABEL, FOR, BLOCK, DEF_LABEL_VAR, ESWITCH_Z, BREAK_L); 234 assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, ESWITCH_Z, LABEL, FOR, BREAK_L); //label break 235 assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, BREAK_L); //expression break 236 // 237 } 238 239 public void testFunReturningSwitchExp() { 240 assertOK(INT_FN_ESWITCH, BREAK_INT_FN); 241 } 242 243 public void testContinueLoops() { 244 assertOK(LABEL, FOR, CONTINUE_L); 245 assertOK(LABEL, FOR_EACH, CONTINUE_L); 246 assertOK(LABEL, WHILE, CONTINUE_L); 247 assertOK(LABEL, DO, CONTINUE_L); 248 assertFail("compiler.err.not.loop.label", LABEL, CONTINUE_L); 249 } 250 }