mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-28 15:51:02 +00:00
8274363: Transitively sealed classes not considered exhaustive in switches
Reviewed-by: vromero
This commit is contained in:
parent
1887028408
commit
292d7bb1d5
@ -207,6 +207,7 @@ public class Flow {
|
||||
private final JCDiagnostic.Factory diags;
|
||||
private Env<AttrContext> attrEnv;
|
||||
private Lint lint;
|
||||
private final DeferredCompletionFailureHandler dcfh;
|
||||
private final boolean allowEffectivelyFinalInInnerClasses;
|
||||
|
||||
public static Flow instance(Context context) {
|
||||
@ -331,6 +332,7 @@ public class Flow {
|
||||
lint = Lint.instance(context);
|
||||
rs = Resolve.instance(context);
|
||||
diags = JCDiagnostic.Factory.instance(context);
|
||||
dcfh = DeferredCompletionFailureHandler.instance(context);
|
||||
Source source = Source.instance(context);
|
||||
allowEffectivelyFinalInInnerClasses = Feature.EFFECTIVELY_FINAL_IN_INNER_CLASSES.allowedInSource(source);
|
||||
}
|
||||
@ -770,12 +772,9 @@ public class Flow {
|
||||
|
||||
case TYP -> {
|
||||
for (Type sup : types.directSupertypes(sym.type)) {
|
||||
if (sup.tsym.kind == TYP && sup.tsym.isAbstract() && sup.tsym.isSealed()) {
|
||||
boolean hasAll = ((ClassSymbol) sup.tsym).permitted
|
||||
.stream()
|
||||
.allMatch(covered::contains);
|
||||
|
||||
if (hasAll && covered.add(sup.tsym)) {
|
||||
if (sup.tsym.kind == TYP) {
|
||||
if (isTransitivelyCovered(sup.tsym, covered) &&
|
||||
covered.add(sup.tsym)) {
|
||||
todo = todo.prepend(sup.tsym);
|
||||
}
|
||||
}
|
||||
@ -785,6 +784,26 @@ public class Flow {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTransitivelyCovered(Symbol sealed, Set<Symbol> covered) {
|
||||
DeferredCompletionFailureHandler.Handler prevHandler =
|
||||
dcfh.setHandler(dcfh.speculativeCodeHandler);
|
||||
try {
|
||||
if (covered.stream().anyMatch(c -> sealed.isSubClass(c, types)))
|
||||
return true;
|
||||
if (sealed.kind == TYP && sealed.isAbstract() && sealed.isSealed()) {
|
||||
return ((ClassSymbol) sealed).permitted
|
||||
.stream()
|
||||
.allMatch(s -> isTransitivelyCovered(s, covered));
|
||||
}
|
||||
return false;
|
||||
} catch (CompletionFailure cf) {
|
||||
//safe to ignore, the symbol will be un-completed when the speculative handler is removed.
|
||||
return false;
|
||||
} finally {
|
||||
dcfh.setHandler(prevHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExhaustive(Type seltype, Set<Symbol> covered) {
|
||||
transitiveCovers(covered);
|
||||
return switch (seltype.getTag()) {
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8262891 8268871
|
||||
* @bug 8262891 8268871 8274363
|
||||
* @summary Check exhaustiveness of switches over sealed types.
|
||||
* @library /tools/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
@ -775,23 +775,50 @@ public class Exhaustiveness extends TestRunner {
|
||||
"1 error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransitiveSealed(Path base) throws Exception {
|
||||
doTest(base,
|
||||
new String[0],
|
||||
"""
|
||||
package test;
|
||||
public class Test {
|
||||
sealed interface A {}
|
||||
sealed interface B1 extends A {}
|
||||
sealed interface B2 extends A {}
|
||||
sealed interface C extends A {}
|
||||
final class D1 implements B1, C {}
|
||||
final class D2 implements B2, C {}
|
||||
|
||||
void test(A arg) {
|
||||
int i = switch (arg) {
|
||||
case B1 b1 -> 1;
|
||||
case B2 b2 -> 2;
|
||||
};
|
||||
}
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException {
|
||||
Path current = base.resolve(".");
|
||||
Path libSrc = current.resolve("lib-src");
|
||||
for (String code : libraryCode) {
|
||||
tb.writeJavaFiles(libSrc, code);
|
||||
}
|
||||
|
||||
Path libClasses = current.resolve("libClasses");
|
||||
|
||||
Files.createDirectories(libClasses);
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("--enable-preview",
|
||||
"-source", JAVA_VERSION)
|
||||
.outdir(libClasses)
|
||||
.files(tb.findJavaFiles(libSrc))
|
||||
.run();
|
||||
if (libraryCode.length != 0) {
|
||||
Path libSrc = current.resolve("lib-src");
|
||||
|
||||
for (String code : libraryCode) {
|
||||
tb.writeJavaFiles(libSrc, code);
|
||||
}
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("--enable-preview",
|
||||
"-source", JAVA_VERSION)
|
||||
.outdir(libClasses)
|
||||
.files(tb.findJavaFiles(libSrc))
|
||||
.run();
|
||||
}
|
||||
|
||||
Path src = current.resolve("src");
|
||||
tb.writeJavaFiles(src, testCode);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user