8309467: Pattern dominance should be adjusted

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2023-06-12 08:15:53 +00:00
parent 6c3e621f98
commit 408cadb351
4 changed files with 70 additions and 18 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac/comp
test/langtools/tools/javac/patterns

@ -4695,7 +4695,8 @@ public class Check {
//the current label is potentially dominated by the existing (test) label, check:
boolean dominated = false;
if (label instanceof JCConstantCaseLabel) {
dominated |= !(testCaseLabel instanceof JCConstantCaseLabel);
dominated |= !(testCaseLabel instanceof JCConstantCaseLabel) &&
TreeInfo.unguardedCase(testCase);
} else if (label instanceof JCPatternCaseLabel patternCL &&
testCaseLabel instanceof JCPatternCaseLabel testPatternCaseLabel &&
TreeInfo.unguardedCase(testCase)) {

@ -2,18 +2,12 @@ Domination.java:35:18: compiler.err.pattern.dominated
Domination.java:43:18: compiler.err.pattern.dominated
Domination.java:51:18: compiler.err.pattern.dominated
Domination.java:67:18: compiler.err.pattern.dominated
Domination.java:74:18: compiler.err.pattern.dominated
Domination.java:81:18: compiler.err.pattern.dominated
Domination.java:88:18: compiler.err.pattern.dominated
Domination.java:95:18: compiler.err.pattern.dominated
Domination.java:102:18: compiler.err.pattern.dominated
Domination.java:113:18: compiler.err.pattern.dominated
Domination.java:124:18: compiler.err.pattern.dominated
Domination.java:135:18: compiler.err.pattern.dominated
Domination.java:144:18: compiler.err.pattern.dominated
Domination.java:153:18: compiler.err.pattern.dominated
Domination.java:184:18: compiler.err.pattern.dominated
Domination.java:193:18: compiler.err.pattern.dominated
Domination.java:202:18: compiler.err.pattern.dominated
Domination.java:211:18: compiler.err.pattern.dominated
18 errors
12 errors

@ -269,7 +269,7 @@ public class NewCaseStructureTest extends TestRunner {
@Test
public void testDominance(Path base) throws Exception {
//A case label with a case pattern p (guarded or unguarded) dominates another case label with a case constant c if p dominates c, which is defined as follows:
// A type pattern that declares a pattern variable of type T dominates a constant c of a primitive type P if the wrapper class of P ([5.1.7]) is a subtype of the erasure of T.
// (unguarded case with) A type pattern that declares a pattern variable of type T dominates a constant c of a primitive type P if the wrapper class of P ([5.1.7]) is a subtype of the erasure of T.
doTest(base,
"""
package test;
@ -282,10 +282,22 @@ public class NewCaseStructureTest extends TestRunner {
};
}
}
""");
doTest(base,
"""
package test;
public class Test {
private int test(Integer o) {
return switch (o) {
case Integer i -> 0;
case 0 -> 0;
};
}
}
""",
"Test.java:6:18: compiler.err.pattern.dominated",
"1 error");
// A type pattern that declares a pattern variable of type T dominates an enum constant c of type E if E is a subtype of the erasure of the type of T.
// (unguarded case with) A type pattern that declares a pattern variable of type T dominates an enum constant c of type E if E is a subtype of the erasure of the type of T.
doTest(base,
"""
package test;
@ -299,6 +311,19 @@ public class NewCaseStructureTest extends TestRunner {
}
}
enum E {A, B;}
""");
doTest(base,
"""
package test;
public class Test {
private int test(E o) {
return switch (o) {
case E e -> 0;
case B -> 0;
};
}
}
enum E {A, B;}
""",
"Test.java:6:18: compiler.err.pattern.dominated",
"1 error");
@ -315,19 +340,15 @@ public class NewCaseStructureTest extends TestRunner {
};
}
}
""",
"Test.java:6:18: compiler.err.pattern.dominated",
"1 error");
// A parenthesized pattern dominates a constant c if its contained pattern dominates c.
""");
doTest(base,
"""
package test;
public class Test {
private int test(Integer o) {
private int test(String o) {
return switch (o) {
case Integer i when i > 0 -> 0;
case 0 -> 0;
case Integer i -> 0;
case String s -> 0;
case "a" -> 0;
};
}
}

@ -105,6 +105,18 @@ public class Switches {
emptyFallThrough(1.0);
testSimpleSwitch();
testSimpleSwitchExpression();
assertEquals(0, constantAndPatternGuardInteger(0, true));
assertEquals(0, constantAndPatternGuardInteger(1, true));
assertEquals(1, constantAndPatternGuardInteger(1, false));
assertEquals(2, constantAndPatternGuardInteger(0, false));
assertEquals(0, constantAndPatternGuardString("", true));
assertEquals(0, constantAndPatternGuardString("a", true));
assertEquals(1, constantAndPatternGuardString("a", false));
assertEquals(2, constantAndPatternGuardString("", false));
assertEquals(0, constantAndPatternGuardEnum(E.A, true));
assertEquals(0, constantAndPatternGuardEnum(E.B, true));
assertEquals(1, constantAndPatternGuardEnum(E.B, false));
assertEquals(2, constantAndPatternGuardEnum(E.A, false));
}
void run(Function<Object, Integer> mapper) {
@ -713,6 +725,30 @@ public class Switches {
assertEquals(1, res);
}
int constantAndPatternGuardInteger(Integer i, boolean g) {
return switch (i) {
case Integer j when g -> 0;
case 1 -> 1;
case Integer j -> 2;
};
}
int constantAndPatternGuardString(String s, boolean g) {
return switch (s) {
case String t when g -> 0;
case "a" -> 1;
case String t -> 2;
};
}
int constantAndPatternGuardEnum(E e, boolean g) {
return switch (e) {
case E f when g -> 0;
case E.B -> 1;
case E f -> 2;
};
}
//verify that for cases like:
//case ConstantClassClash ->
//ConstantClassClash is interpreted as a field, not as a class