Skip to content
Permalink
Browse files
8268961: Parenthesized pattern with guards does not work
8268896: Parenthesized pattern is not guarded by source level check

Reviewed-by: vromero
  • Loading branch information
Jan Lahoda committed Jun 23, 2021
1 parent 8128ca1 commit bf706207454d8aea57049189befdf2a08e6d1291
Showing 8 changed files with 255 additions and 30 deletions.
@@ -4064,24 +4064,19 @@ public void visitTypeTest(JCInstanceOf tree) {
tree.expr.pos(), attribExpr(tree.expr, env));
Type clazztype;
JCTree typeTree;
boolean checkRawTypes;
if (tree.pattern.getTag() == BINDINGPATTERN) {
if (tree.pattern.getTag() == BINDINGPATTERN ||
tree.pattern.getTag() == PARENTHESIZEDPATTERN) {
attribTree(tree.pattern, env, unknownExprInfo);
clazztype = tree.pattern.type;
if (types.isSubtype(exprtype, clazztype) &&
!exprtype.isErroneous() && !clazztype.isErroneous()) {
log.error(tree.pos(), Errors.InstanceofPatternNoSubtype(exprtype, clazztype));
}
JCBindingPattern pattern = (JCBindingPattern) tree.pattern;
typeTree = pattern.var.vartype;
if (!clazztype.hasTag(TYPEVAR)) {
clazztype = chk.checkClassOrArrayType(pattern.var.vartype.pos(), clazztype);
}
checkRawTypes = true;
typeTree = TreeInfo.primaryPatternTree((JCPattern) tree.pattern).var.vartype;
} else {
clazztype = attribType(tree.pattern, env);
typeTree = tree.pattern;
checkRawTypes = false;
chk.validate(typeTree, env, false);
}
if (!clazztype.hasTag(TYPEVAR)) {
clazztype = chk.checkClassOrArrayType(typeTree.pos(), clazztype);
@@ -4099,7 +4094,6 @@ public void visitTypeTest(JCInstanceOf tree) {
clazztype = types.createErrorType(clazztype);
}
}
chk.validate(typeTree, env, checkRawTypes);
chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo);
}
@@ -4133,13 +4127,15 @@ public void visitBindingPattern(JCBindingPattern tree) {
annotate.annotateLater(tree.var.mods.annotations, env, v, tree.pos());
annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var.pos());
annotate.flush();
chk.validate(tree.var.vartype, env, true);
result = tree.type;
matchBindings = new MatchBindings(List.of(v), List.nil());
}

@Override
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
attribExpr(tree.pattern, env);
result = tree.type = tree.pattern.type;
}

@Override
@@ -764,26 +764,26 @@ public JCExpression parseExpression() {
*/

public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType, boolean inInstanceOf) {
JCPattern pattern;
if (token.kind == LPAREN && parsedType == null) {
int startPos = token.pos;
accept(LPAREN);
JCPattern p = parsePattern(token.pos, null, null, false);
accept(RPAREN);
return toP(F.at(startPos).ParenthesizedPattern(p));
pattern = toP(F.at(startPos).ParenthesizedPattern(p));
} else {
JCPattern pattern;
JCExpression e = parsedType == null ? term(EXPR | TYPE | NOLAMBDA) : parsedType;
mods = mods != null ? mods : F.at(token.pos).Modifiers(0);
JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), e, null));
pattern = toP(F.at(pos).BindingPattern(var));
if (!inInstanceOf && token.kind == AMPAMP) {
checkSourceLevel(Feature.PATTERN_SWITCH);
nextToken();
JCExpression guard = term(EXPR | NOLAMBDA);
pattern = F.at(pos).GuardPattern(pattern, guard);
}
return pattern;
}
if (!inInstanceOf && token.kind == AMPAMP) {
checkSourceLevel(Feature.PATTERN_SWITCH);
nextToken();
JCExpression guard = term(EXPR | NOLAMBDA);
pattern = F.at(pos).GuardPattern(pattern, guard);
}
return pattern;
}

/**
@@ -1694,12 +1694,16 @@ boolean isUnboundMemberRef() {
* method reference or a binary expression. To disambiguate, look for a
* matching '>' and see if the subsequent terminal is either '.' or '::'.
*/
@SuppressWarnings("fallthrough")
ParensResult analyzeParens() {
return analyzeParens(0);
}

@SuppressWarnings("fallthrough")
ParensResult analyzeParens(int startLookahead) {
int depth = 0;
boolean type = false;
ParensResult defaultResult = ParensResult.PARENS;
outer: for (int lookahead = 0; ; lookahead++) {
outer: for (int lookahead = startLookahead; ; lookahead++) {
TokenKind tk = S.token(lookahead).kind;
switch (tk) {
case COMMA:
@@ -1725,7 +1729,7 @@ ParensResult analyzeParens() {
}
break;
case LPAREN:
if (lookahead != 0) {
if (lookahead != startLookahead) {
// '(' in a non-starting position -> parens
return ParensResult.PARENS;
} else if (peekToken(lookahead, RPAREN)) {
@@ -3065,15 +3069,12 @@ private JCCaseLabel parseCaseLabel() {
} else {
if (token.kind == LPAREN) {
int lookahead = 0;
Token ahead;
while ((ahead = S.token(lookahead)).kind != EOF && ahead.kind != RPAREN && ahead.kind != AMPAMP) {
while (S.token(lookahead + 1).kind == LPAREN) {
lookahead++;
}
Token twoBack;
boolean pattern = S.token(lookahead - 1).kind == IDENTIFIER &&
((twoBack = S.token(lookahead - 2)).kind == IDENTIFIER ||
twoBack.kind == GT || twoBack.kind == GTGT || twoBack.kind == GTGTGT);
boolean pattern = analyzeParens(lookahead) == ParensResult.EXPLICIT_LAMBDA;
if (pattern) {
checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
return parsePattern(token.pos, null, null, false);
} else {
return term(EXPR | TYPE | NOLAMBDA);
@@ -1367,6 +1367,15 @@ public static PatternPrimaryType primaryPatternType(JCPattern pat) {
};
}

public static JCBindingPattern primaryPatternTree(JCPattern pat) {
return switch (pat.getTag()) {
case BINDINGPATTERN -> (JCBindingPattern) pat;
case GUARDPATTERN -> primaryPatternTree(((JCGuardPattern) pat).patt);
case PARENTHESIZEDPATTERN -> primaryPatternTree(((JCParenthesizedPattern) pat).pattern);
default -> throw new AssertionError();
};
}

public record PatternPrimaryType(Type type, boolean unconditional) {}

}
@@ -42,6 +42,20 @@ public static void main(String... args) throws Throwable {
ExpressionType.EXPRESSION);
test.disambiguationTest("((0x1))",
ExpressionType.EXPRESSION);
test.disambiguationTest("(a > b)",
ExpressionType.EXPRESSION);
test.disambiguationTest("(a >> b)",
ExpressionType.EXPRESSION);
test.disambiguationTest("(a >>> b)",
ExpressionType.EXPRESSION);
test.disambiguationTest("(a < b | a > b)",
ExpressionType.EXPRESSION);
test.disambiguationTest("(a << b | a >> b)",
ExpressionType.EXPRESSION);
test.disambiguationTest("(a << b || a < b | a >>> b)",
ExpressionType.EXPRESSION);
test.disambiguationTest("(a < c.d > b)",
ExpressionType.PATTERN);
}

private final ParserFactory factory;
@@ -46,6 +46,9 @@ void run() {
runIfTrue(this::typeGuardIfTrueIfStatement);
runIfTrue(this::typeGuardIfTrueSwitchExpression);
runIfTrue(this::typeGuardIfTrueSwitchStatement);
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchStatement);
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchExpression);
runIfTrue(this::typeGuardAfterParenthesizedTrueIfStatement);
}

void run(Function<Object, String> convert) {
@@ -122,6 +125,32 @@ String typeGuardIfTrueIfStatement(Object o) {
}
}

String typeGuardAfterParenthesizedTrueSwitchStatement(Object o) {
switch (o) {
case (Integer i) && i == 0: o = String.valueOf(i); return "true";
case ((Integer i) && i == 2): o = String.valueOf(i); return "second";
case Object x: return "any";
}
}

String typeGuardAfterParenthesizedTrueSwitchExpression(Object o) {
return switch (o) {
case (Integer i) && i == 0: o = String.valueOf(i); yield "true";
case ((Integer i) && i == 2): o = String.valueOf(i); yield "second";
case Object x: yield "any";
};
}

String typeGuardAfterParenthesizedTrueIfStatement(Object o) {
if (o != null && o instanceof ((Integer i) && i == 0)) {
return "true";
} else if (o != null && o instanceof (((Integer i) && i == 2)) && (o = i) != null) {
return "second";
} else {
return "any";
}
}

String testPatternInGuard(Object o) {
if (o instanceof (CharSequence cs && cs instanceof String s)) {
return s;
@@ -2,10 +2,24 @@
* @test /nodynamiccopyright/
* @bug 8263590
* @summary Verify correct warnings are produced for raw types in bindings
* @compile/ref=RawTypeBindingWarning.out -Xlint:rawtypes -XDrawDiagnostics RawTypeBindingWarning.java
* @compile/ref=RawTypeBindingWarning.out -Xlint:rawtypes -XDrawDiagnostics --enable-preview -source ${jdk.version} RawTypeBindingWarning.java
*/
public class RawTypeBindingWarning<T> {
public static boolean t(Object o) {
return o instanceof RawTypeBindingWarning w;
}
public static void t2(Object o) {
switch (o) {
case RawTypeBindingWarning w -> {}
default -> {}
}
switch (o) {
case (RawTypeBindingWarning w) -> {}
default -> {}
}
switch (o) {
case (RawTypeBindingWarning w && false) -> {}
default -> {}
}
}
}
@@ -1,2 +1,7 @@
RawTypeBindingWarning.java:9:29: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
1 warning
RawTypeBindingWarning.java:13:18: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
RawTypeBindingWarning.java:17:19: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
RawTypeBindingWarning.java:21:19: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
- compiler.note.preview.filename: RawTypeBindingWarning.java, DEFAULT
- compiler.note.preview.recompile
4 warnings

0 comments on commit bf70620

Please sign in to comment.