8364991: Incorrect not-exhaustive error

This commit is contained in:
Jan Lahoda 2025-08-07 18:27:35 +02:00
parent 078d0d4968
commit 2cfbc715c0
2 changed files with 80 additions and 10 deletions

View File

@ -822,6 +822,7 @@ public class Flow {
}
}
Set<PatternDescription> patterns = patternSet;
Set<Set<PatternDescription>> seenFallback = new HashSet<>();
boolean useHashes = true;
try {
boolean repeat = true;
@ -843,7 +844,7 @@ public class Flow {
//but hashing in reduceNestedPatterns will not allow that
//disable the use of hashing, and use subtyping in
//reduceNestedPatterns to handle situations like this:
repeat = useHashes;
repeat = useHashes && seenFallback.add(updatedPatterns);
useHashes = false;
} else {
//if a reduction happened, make sure hashing in reduceNestedPatterns
@ -1083,15 +1084,24 @@ public class Flow {
for (int i = 0; i < rpOne.nested.length; i++) {
if (i != mismatchingCandidate) {
if (!rpOne.nested[i].equals(rpOther.nested[i])) {
if (useHashes ||
//when not using hashes,
//check if rpOne.nested[i] is
//a subtype of rpOther.nested[i]:
!(rpOne.nested[i] instanceof BindingPattern bpOne) ||
!(rpOther.nested[i] instanceof BindingPattern bpOther) ||
!types.isSubtype(types.erasure(bpOne.type), types.erasure(bpOther.type))) {
if (useHashes) {
continue NEXT_PATTERN;
}
//when not using hashes,
//check if rpOne.nested[i] is
//a subtype of rpOther.nested[i]:
if (!(rpOther.nested[i] instanceof BindingPattern bpOther)) {
continue NEXT_PATTERN;
}
if (rpOne.nested[i] instanceof BindingPattern bpOne) {
if (!types.isSubtype(types.erasure(bpOne.type), types.erasure(bpOther.type))) {
continue NEXT_PATTERN;
}
} else if (rpOne.nested[i] instanceof RecordPattern nestedRPOne) {
if (!types.isSubtype(types.erasure(nestedRPOne.recordType()), types.erasure(bpOther.type))) {
continue NEXT_PATTERN;
}
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/**
* @test
* @bug 8262891 8268871 8274363 8281100 8294670 8311038 8311815 8325215 8333169 8327368
* @bug 8262891 8268871 8274363 8281100 8294670 8311038 8311815 8325215 8333169 8327368 8364991
* @summary Check exhaustiveness of switches over sealed types.
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
@ -2182,6 +2182,66 @@ public class Exhaustiveness extends TestRunner {
""");
}
@Test //JDK-8364991
public void testDifferentReductionPaths(Path base) throws Exception {
doTest(base,
new String[0],
"""
package test;
public class Test {
private int test(Root r) {
return switch (r) {
case Root(R1 _, _, _) -> 0;
case Root(R2 _, R1 _, _) -> 0;
case Root(R2 _, R2 _, R1 _) -> 0;
case Root(R2 _, R2(R1 _, R1 _), R2(R1 _, R1 _)) -> 0;
case Root(R2 _, R2(R1 _, R1 _), R2(R1 _, R2 _)) -> 0;
case Root(R2 _, R2(R1 _, R1 _), R2(R2 _, R1 _)) -> 0;
case Root(R2 _, R2(R1 _, R1 _), R2(R2 _, R2 _)) -> 0;
case Root(R2 _, R2(R1 _, R2 _), R2(R1 _, R1 _)) -> 0;
case Root(R2 _, R2(R1 _, R2 _), R2(R1 _, R2 _)) -> 0;
case Root(R2 _, R2(R1 _, R2 _), R2(R2 _, R1 _)) -> 0;
case Root(R2 _, R2(R1 _, R2 _), R2(R2 _, R2 _)) -> 0;
case Root(R2 _, R2(R2 _, R1 _), R2(R1 _, R1 _)) -> 0;
case Root(R2 _, R2(R2 _, R1 _), R2(R1 _, R2 _)) -> 0;
case Root(R2 _, R2(R2 _, R1 _), R2(R2 _, R1 _)) -> 0;
case Root(R2 _, R2(R2 _, R1 _), R2(R2 _, R2 _)) -> 0;
case Root(R2 _, R2(R2 _, R2 _), R2(R1 _, R1 _)) -> 0;
case Root(R2 _, R2(R2 _, R2 _), R2(R1 _, R2 _)) -> 0;
case Root(R2 _, R2(R2 _, R2 _), R2(R2 _, R1 _)) -> 0;
case Root(R2 _, R2(R2 _, R2 _), R2 _) -> 0; //functionally equivalent to: Root(R2 _, R2(R2 _, R2 _), R2(R2 _, R2 _))
};
}
sealed interface Base {}
record R1() implements Base {}
record R2(Base b1, Base b2) implements Base {}
record Root(Base b1, Base b2, Base b3) {}
}
""");
}
@Test //JDK-8364991
public void testX(Path base) throws Exception {
doTest(base,
new String[0],
"""
package test;
public class Test {
private int test(Root r) {
return switch (r) {
case Root(R2 _, R2(R1 _)) -> 0;
case Root(R2(R1 _), R2(R2 _)) -> 0;
case Root(R2(R2 _), R2 _) -> 0; //the above is functionally equivalent to: Root(R2(R2 _), R2(R2 _)) -> 0;
};
}
sealed interface Base {}
record R1() implements Base {}
record R2(Base b) implements Base {}
record Root(R2 b2, R2 b3) {}
}
""");
}
private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException {
doTest(base, libraryCode, testCode, false, expectedErrors);
}