8289894: A NullPointerException thrown from guard expression

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2022-07-11 08:59:32 +00:00
parent b542bcba57
commit 25f4b04365
6 changed files with 69 additions and 14 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac/comp
test/langtools/tools/javac/patterns

@ -4348,6 +4348,9 @@ public class Check {
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))) {

@ -531,7 +531,21 @@ public class TransPatterns extends TreeTranslator {
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);

@ -95,7 +95,7 @@ public class CaseStructureTest extends ComboInstance<CaseStructureTest> {
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();

@ -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
@ -164,18 +164,18 @@ public class Guards {
}
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);
}
String guardNPE(Object o) {
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 guardNPE1(Object o) {
return switch (o) {
case null, String s when s.isEmpty() -> "empty";
case String s -> s;
@ -183,6 +183,14 @@ public class Guards {
};
}
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) {

@ -254,4 +254,32 @@ public class SwitchErrors {
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;
}
}
}

@ -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
@ -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