8294670: Enhanced switch statements have an implicit default which does not complete normally

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2022-10-20 15:21:26 +00:00
parent 95dd376ba2
commit 7bc9692a51
4 changed files with 117 additions and 5 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac/comp
test/langtools/tools/javac

@ -694,7 +694,7 @@ public class Flow {
log.error(tree, Errors.NotExhaustiveStatement);
}
}
if (!tree.hasUnconditionalPattern) {
if (!tree.hasUnconditionalPattern && !exhaustiveSwitch) {
alive = Liveness.ALIVE;
}
alive = alive.or(resolveBreaks(tree, prevPendingExits));

@ -84,7 +84,6 @@ public class EnumTypeChanges {
case B -> { return "B"; }
case EnumTypeChangesEnum x when e == EnumTypeChangesEnum.A -> throw new AssertionError();
}
return "";
}
String expressionEnumExhaustive(EnumTypeChangesEnum e) {

@ -23,7 +23,7 @@
/**
* @test
* @bug 8262891 8268871 8274363 8281100
* @bug 8262891 8268871 8274363 8281100 8294670
* @summary Check exhaustiveness of switches over sealed types.
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
@ -402,7 +402,7 @@ public class Exhaustiveness extends TestRunner {
private void test(Object obj) {
switch (obj) {
case String s: return;
};
}
}
}
""",
@ -1010,6 +1010,7 @@ public class Exhaustiveness extends TestRunner {
""");
}
@Test
public void testNonPrimitiveBooleanGuard(Path base) throws Exception {
doTest(base,
new String[0],
@ -1056,6 +1057,119 @@ public class Exhaustiveness extends TestRunner {
"2 errors");
}
@Test //JDK-8294670
public void testImplicitDefaultCannotCompleteNormally(Path base) throws Exception {
doTest(base,
new String[0],
"""
package test;
public class Test {
sealed interface A {}
final class B implements A {}
int test(A arg) {
switch (arg) {
case B b: return 1;
}
}
}
""");
doTest(base,
new String[0],
"""
package test;
public class Test {
sealed interface A {}
final class B implements A {}
int test(A arg) {
switch (arg) {
case B b: return 1;
default: return 1;
}
}
}
""");
doTest(base,
new String[0],
"""
package test;
public class Test {
sealed interface A {}
final class B implements A {}
int test(A arg) {
switch (arg) {
case B b: break;
}
}
}
""",
"Test.java:10:5: compiler.err.missing.ret.stmt",
"- compiler.note.preview.filename: Test.java, DEFAULT",
"- compiler.note.preview.recompile",
"1 error");
doTest(base,
new String[0],
"""
package test;
public class Test {
sealed interface A {}
final class B implements A {}
int test(A arg) {
switch (arg) {
case B b: return 1;
default: break;
}
}
}
""",
"Test.java:11:5: compiler.err.missing.ret.stmt",
"- compiler.note.preview.filename: Test.java, DEFAULT",
"- compiler.note.preview.recompile",
"1 error");
doTest(base,
new String[0],
"""
package test;
public class Test {
sealed interface A {}
final class B implements A {}
int test(A arg) {
switch (arg) {
case B b:
}
}
}
""",
"Test.java:10:5: compiler.err.missing.ret.stmt",
"- compiler.note.preview.filename: Test.java, DEFAULT",
"- compiler.note.preview.recompile",
"1 error");
doTest(base,
new String[0],
"""
package test;
public class Test {
sealed interface A {}
final class B implements A {}
int test(A arg) {
switch (arg) {
case B b: return 1;
default:
}
}
}
""",
"Test.java:11:5: compiler.err.missing.ret.stmt",
"- compiler.note.preview.filename: Test.java, DEFAULT",
"- compiler.note.preview.recompile",
"1 error");
}
private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException {
Path current = base.resolve(".");
Path libClasses = current.resolve("libClasses");

@ -93,7 +93,6 @@ public class SwitchNull {
case C: return 2;
case null: return -1;
}
throw new AssertionError(String.valueOf(e));
}
private int switchEnumWithDefault(E e) {