Skip to content
This repository has been archived by the owner on Sep 19, 2023. It is now read-only.

JDK-8289894: A NullPointerException thrown from guard expression #120

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -4348,6 +4348,9 @@ void checkSwitchCaseStructure(List<JCCase> cases) {
wasDefault = true;
} else {
JCPattern pat = ((JCPatternCaseLabel) label).pat;
while (pat instanceof JCParenthesizedPattern parenthesized) {
pat = parenthesized.pattern;
}
boolean isTypePattern = pat.hasTag(BINDINGPATTERN);
if (wasPattern || wasConstant || wasDefault ||
(wasNullPattern && (!isTypePattern || wasNonEmptyFallThrough))) {
Expand Down
Expand Up @@ -531,7 +531,21 @@ private void handleSwitch(JCTree tree,
currentValue = temp;
JCExpression test = (JCExpression) this.<JCTree>translate(label.pat);
if (label.guard != null) {
test = makeBinary(Tag.AND, test, translate(label.guard));
JCExpression guard = translate(label.guard);
if (hasJoinedNull) {
JCPattern pattern = label.pat;
while (pattern instanceof JCParenthesizedPattern parenthesized) {
pattern = parenthesized.pattern;
}
Assert.check(pattern.hasTag(Tag.BINDINGPATTERN));
VarSymbol binding = ((JCBindingPattern) pattern).var.sym;
guard = makeBinary(Tag.OR,
makeBinary(Tag.EQ,
make.Ident(binding),
makeNull()),
guard);
}
test = makeBinary(Tag.AND, test, guard);
}
c.stats = translate(c.stats);
JCContinue continueSwitch = make.at(clearedPatterns.head.pos()).Continue(null);
Expand Down
2 changes: 1 addition & 1 deletion test/langtools/tools/javac/patterns/CaseStructureTest.java
Expand Up @@ -95,7 +95,7 @@ protected void doWork() throws Throwable {
task.generate(result -> {
boolean shouldPass = true;
long patternCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.TYPE_PATTERN || l == CaseLabel.PARENTHESIZED_PATTERN).count();
long typePatternCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.TYPE_PATTERN).count();
long typePatternCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.TYPE_PATTERN || l == CaseLabel.PARENTHESIZED_PATTERN).count();
long constantCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.CONSTANT).count();
long nullCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.NULL).count();
long defaultCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.DEFAULT).count();
Expand Down
30 changes: 19 additions & 11 deletions test/langtools/tools/javac/patterns/Guards.java
Expand Up @@ -23,7 +23,7 @@

/*
* @test
* @bug 8262891 8268663
* @bug 8262891 8268663 8289894
* @summary Check guards implementation.
* @compile --enable-preview -source ${jdk.version} Guards.java
* @run main/othervm --enable-preview Guards
Expand Down Expand Up @@ -164,25 +164,33 @@ String testPatternInGuard(Object o) {
}

void testGuardNPE() {
assertEquals("empty", guardNPE(""));
assertEquals("A", guardNPE("A"));
assertEquals("other", guardNPE(1));
try {
guardNPE(null);
throw new AssertionError("Expected exception missing.");
} catch (NullPointerException ex) {
//expected
}
doTestGuardNPE(this::guardNPE1);
doTestGuardNPE(this::guardNPE2);
}

void doTestGuardNPE(Function<Object, String> test) {
assertEquals("empty", test.apply(""));
assertEquals("A", test.apply("A"));
assertEquals("other", test.apply(1));
assertEquals("empty", test.apply(null));
}

String guardNPE(Object o) {
String guardNPE1(Object o) {
return switch (o) {
case null, String s when s.isEmpty() -> "empty";
case String s -> s;
case Object x -> "other";
};
}

String guardNPE2(Object o) {
return switch (o) {
case null, ((((String s)))) when s.isEmpty() -> "empty";
case ((((String s)))) -> s;
case Object x -> "other";
};
}

record Box(Object o) {}

void assertEquals(String expected, String actual) {
Expand Down
28 changes: 28 additions & 0 deletions test/langtools/tools/javac/patterns/SwitchErrors.java
Expand Up @@ -254,4 +254,32 @@ void referenceToPrimitive(Integer i) {
case int j: break;
}
}
void nullAndParenthesized1(Object o) {
record R(Object o) {}
switch (o) {
case null, ((R r)): break;
default: break;
}
}
void nullAndParenthesized2(Object o) {
record R(Object o) {}
switch (o) {
case null, ((R(var v))): break;
default: break;
}
}
void nullAndParenthesized3(Object o) {
record R(Object o) {}
switch (o) {
case ((R r)): case null: break;
default: break;
}
}
void nullAndParenthesized4(Object o) {
record R(Object o) {}
switch (o) {
case ((R(var v))): case null: break;
default: break;
}
}
}
4 changes: 3 additions & 1 deletion test/langtools/tools/javac/patterns/SwitchErrors.out
Expand Up @@ -41,6 +41,8 @@ SwitchErrors.java:232:47: compiler.err.flows.through.from.pattern
SwitchErrors.java:244:18: compiler.err.duplicate.unconditional.pattern
SwitchErrors.java:249:18: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, java.lang.Integer)
SwitchErrors.java:254:18: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
SwitchErrors.java:267:24: compiler.err.flows.through.to.pattern
SwitchErrors.java:281:37: compiler.err.flows.through.from.pattern
SwitchErrors.java:9:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:15:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:21:9: compiler.err.not.exhaustive.statement
Expand All @@ -55,4 +57,4 @@ SwitchErrors.java:164:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:237:9: compiler.err.not.exhaustive.statement
- compiler.note.preview.filename: SwitchErrors.java, DEFAULT
- compiler.note.preview.recompile
55 errors
57 errors