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