Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ private Set<PatternDescription> reduceBindingPatterns(Type selectorType, Set<Pat
if (clazz.isSealed() && clazz.isAbstract() &&
//if a binding pattern for clazz already exists, no need to analyze it again:
!existingBindings.contains(clazz)) {
ListBuffer<PatternDescription> bindings = new ListBuffer<>();
//do not reduce to types unrelated to the selector type:
Type clazzErasure = types.erasure(clazz.type);
if (components(selectorType).stream()
Expand All @@ -232,16 +231,26 @@ private Set<PatternDescription> reduceBindingPatterns(Type selectorType, Set<Pat

return instantiated != null && types.isCastable(selectorType, instantiated);
});
Set<Symbol> filteredPermitted = new HashSet<>(permitted);

for (PatternDescription pdOther : patterns) {
if (pdOther instanceof BindingPattern bpOther) {
Set<Symbol> currentPermittedSubTypes =
allPermittedSubTypes(bpOther.type.tsym, s -> true);
Set<Symbol> currentSubTypes;

if (bpOther.type.tsym.isAbstract()) {
currentSubTypes =
permitted.stream()
.filter(perm -> types.isSubtype(types.erasure(perm.type),
types.erasure(bpOther.type)))
.collect(Collectors.toSet());
} else {
currentSubTypes = Set.of();
}

PERMITTED: for (Iterator<Symbol> it = permitted.iterator(); it.hasNext();) {
PERMITTED: for (Iterator<Symbol> it = filteredPermitted.iterator(); it.hasNext();) {
Symbol perm = it.next();

for (Symbol currentPermitted : currentPermittedSubTypes) {
for (Symbol currentPermitted : currentSubTypes) {
if (types.isSubtype(types.erasure(currentPermitted.type),
types.erasure(perm.type))) {
it.remove();
Expand All @@ -256,7 +265,7 @@ private Set<PatternDescription> reduceBindingPatterns(Type selectorType, Set<Pat
}
}

if (permitted.isEmpty()) {
if (filteredPermitted.isEmpty()) {
toAdd.add(new BindingPattern(clazz.type));
}
}
Expand Down
53 changes: 52 additions & 1 deletion test/langtools/tools/javac/patterns/Exhaustiveness.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

/**
* @test
* @bug 8262891 8268871 8274363 8281100 8294670 8311038 8311815 8325215 8333169 8327368 8364991
* @bug 8262891 8268871 8274363 8281100 8294670 8311038 8311815 8325215 8333169 8327368 8364991 8366968
* @summary Check exhaustiveness of switches over sealed types.
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
Expand Down Expand Up @@ -2276,6 +2276,57 @@ record Root(R2 b2, R2 b3) {}
"1 error");
}

@Test //JDK-8366968
public void testNonSealedDiamond(Path base) throws Exception {
doTest(base,
new String[0],
"""
class Demo {

sealed interface Base permits Special, Value {}

non-sealed interface Value extends Base {}

sealed interface Special extends Base permits SpecialValue {}

non-sealed interface SpecialValue extends Value, Special {}

static int demo(final Base base) {
return switch (base) {
case Value value -> 0;
};

}

}
""");
}

@Test //JDK-8366968
public void testNonAbstract(Path base) throws Exception {
doTest(base,
new String[0],
"""
class Demo {
sealed interface I permits Base, C3 { }
sealed class Base implements I permits C1, C2 { }
final class C1 extends Base { }
final class C2 extends Base { }
final class C3 implements I { }

void method1(I i) {
switch (i) {
case C1 _ -> {}
case C2 _ -> {}
case C3 _ -> {}
}
}
}
""",
"Demo.java:9:9: compiler.err.not.exhaustive.statement",
"1 error");
}

private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException {
doTest(base, libraryCode, testCode, false, expectedErrors);
}
Expand Down