Skip to content

Commit bf70620

Browse files
committed
8268961: Parenthesized pattern with guards does not work
8268896: Parenthesized pattern is not guarded by source level check Reviewed-by: vromero
1 parent 8128ca1 commit bf70620

8 files changed

Lines changed: 255 additions & 30 deletions

File tree

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4064,24 +4064,19 @@ public void visitTypeTest(JCInstanceOf tree) {
40644064
tree.expr.pos(), attribExpr(tree.expr, env));
40654065
Type clazztype;
40664066
JCTree typeTree;
4067-
boolean checkRawTypes;
4068-
if (tree.pattern.getTag() == BINDINGPATTERN) {
4067+
if (tree.pattern.getTag() == BINDINGPATTERN ||
4068+
tree.pattern.getTag() == PARENTHESIZEDPATTERN) {
40694069
attribTree(tree.pattern, env, unknownExprInfo);
40704070
clazztype = tree.pattern.type;
40714071
if (types.isSubtype(exprtype, clazztype) &&
40724072
!exprtype.isErroneous() && !clazztype.isErroneous()) {
40734073
log.error(tree.pos(), Errors.InstanceofPatternNoSubtype(exprtype, clazztype));
40744074
}
4075-
JCBindingPattern pattern = (JCBindingPattern) tree.pattern;
4076-
typeTree = pattern.var.vartype;
4077-
if (!clazztype.hasTag(TYPEVAR)) {
4078-
clazztype = chk.checkClassOrArrayType(pattern.var.vartype.pos(), clazztype);
4079-
}
4080-
checkRawTypes = true;
4075+
typeTree = TreeInfo.primaryPatternTree((JCPattern) tree.pattern).var.vartype;
40814076
} else {
40824077
clazztype = attribType(tree.pattern, env);
40834078
typeTree = tree.pattern;
4084-
checkRawTypes = false;
4079+
chk.validate(typeTree, env, false);
40854080
}
40864081
if (!clazztype.hasTag(TYPEVAR)) {
40874082
clazztype = chk.checkClassOrArrayType(typeTree.pos(), clazztype);
@@ -4099,7 +4094,6 @@ public void visitTypeTest(JCInstanceOf tree) {
40994094
clazztype = types.createErrorType(clazztype);
41004095
}
41014096
}
4102-
chk.validate(typeTree, env, checkRawTypes);
41034097
chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
41044098
result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo);
41054099
}
@@ -4133,13 +4127,15 @@ public void visitBindingPattern(JCBindingPattern tree) {
41334127
annotate.annotateLater(tree.var.mods.annotations, env, v, tree.pos());
41344128
annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var.pos());
41354129
annotate.flush();
4130+
chk.validate(tree.var.vartype, env, true);
41364131
result = tree.type;
41374132
matchBindings = new MatchBindings(List.of(v), List.nil());
41384133
}
41394134

41404135
@Override
41414136
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
41424137
attribExpr(tree.pattern, env);
4138+
result = tree.type = tree.pattern.type;
41434139
}
41444140

41454141
@Override

src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -764,26 +764,26 @@ public JCExpression parseExpression() {
764764
*/
765765

766766
public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType, boolean inInstanceOf) {
767+
JCPattern pattern;
767768
if (token.kind == LPAREN && parsedType == null) {
768769
int startPos = token.pos;
769770
accept(LPAREN);
770771
JCPattern p = parsePattern(token.pos, null, null, false);
771772
accept(RPAREN);
772-
return toP(F.at(startPos).ParenthesizedPattern(p));
773+
pattern = toP(F.at(startPos).ParenthesizedPattern(p));
773774
} else {
774-
JCPattern pattern;
775775
JCExpression e = parsedType == null ? term(EXPR | TYPE | NOLAMBDA) : parsedType;
776776
mods = mods != null ? mods : F.at(token.pos).Modifiers(0);
777777
JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), e, null));
778778
pattern = toP(F.at(pos).BindingPattern(var));
779-
if (!inInstanceOf && token.kind == AMPAMP) {
780-
checkSourceLevel(Feature.PATTERN_SWITCH);
781-
nextToken();
782-
JCExpression guard = term(EXPR | NOLAMBDA);
783-
pattern = F.at(pos).GuardPattern(pattern, guard);
784-
}
785-
return pattern;
786779
}
780+
if (!inInstanceOf && token.kind == AMPAMP) {
781+
checkSourceLevel(Feature.PATTERN_SWITCH);
782+
nextToken();
783+
JCExpression guard = term(EXPR | NOLAMBDA);
784+
pattern = F.at(pos).GuardPattern(pattern, guard);
785+
}
786+
return pattern;
787787
}
788788

789789
/**
@@ -1694,12 +1694,16 @@ boolean isUnboundMemberRef() {
16941694
* method reference or a binary expression. To disambiguate, look for a
16951695
* matching '>' and see if the subsequent terminal is either '.' or '::'.
16961696
*/
1697-
@SuppressWarnings("fallthrough")
16981697
ParensResult analyzeParens() {
1698+
return analyzeParens(0);
1699+
}
1700+
1701+
@SuppressWarnings("fallthrough")
1702+
ParensResult analyzeParens(int startLookahead) {
16991703
int depth = 0;
17001704
boolean type = false;
17011705
ParensResult defaultResult = ParensResult.PARENS;
1702-
outer: for (int lookahead = 0; ; lookahead++) {
1706+
outer: for (int lookahead = startLookahead; ; lookahead++) {
17031707
TokenKind tk = S.token(lookahead).kind;
17041708
switch (tk) {
17051709
case COMMA:
@@ -1725,7 +1729,7 @@ ParensResult analyzeParens() {
17251729
}
17261730
break;
17271731
case LPAREN:
1728-
if (lookahead != 0) {
1732+
if (lookahead != startLookahead) {
17291733
// '(' in a non-starting position -> parens
17301734
return ParensResult.PARENS;
17311735
} else if (peekToken(lookahead, RPAREN)) {
@@ -3065,15 +3069,12 @@ private JCCaseLabel parseCaseLabel() {
30653069
} else {
30663070
if (token.kind == LPAREN) {
30673071
int lookahead = 0;
3068-
Token ahead;
3069-
while ((ahead = S.token(lookahead)).kind != EOF && ahead.kind != RPAREN && ahead.kind != AMPAMP) {
3072+
while (S.token(lookahead + 1).kind == LPAREN) {
30703073
lookahead++;
30713074
}
3072-
Token twoBack;
3073-
boolean pattern = S.token(lookahead - 1).kind == IDENTIFIER &&
3074-
((twoBack = S.token(lookahead - 2)).kind == IDENTIFIER ||
3075-
twoBack.kind == GT || twoBack.kind == GTGT || twoBack.kind == GTGTGT);
3075+
boolean pattern = analyzeParens(lookahead) == ParensResult.EXPLICIT_LAMBDA;
30763076
if (pattern) {
3077+
checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
30773078
return parsePattern(token.pos, null, null, false);
30783079
} else {
30793080
return term(EXPR | TYPE | NOLAMBDA);

src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,15 @@ public static PatternPrimaryType primaryPatternType(JCPattern pat) {
13671367
};
13681368
}
13691369

1370+
public static JCBindingPattern primaryPatternTree(JCPattern pat) {
1371+
return switch (pat.getTag()) {
1372+
case BINDINGPATTERN -> (JCBindingPattern) pat;
1373+
case GUARDPATTERN -> primaryPatternTree(((JCGuardPattern) pat).patt);
1374+
case PARENTHESIZEDPATTERN -> primaryPatternTree(((JCParenthesizedPattern) pat).pattern);
1375+
default -> throw new AssertionError();
1376+
};
1377+
}
1378+
13701379
public record PatternPrimaryType(Type type, boolean unconditional) {}
13711380

13721381
}

test/langtools/tools/javac/patterns/DisambiguateParenthesizedPattern.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ public static void main(String... args) throws Throwable {
4242
ExpressionType.EXPRESSION);
4343
test.disambiguationTest("((0x1))",
4444
ExpressionType.EXPRESSION);
45+
test.disambiguationTest("(a > b)",
46+
ExpressionType.EXPRESSION);
47+
test.disambiguationTest("(a >> b)",
48+
ExpressionType.EXPRESSION);
49+
test.disambiguationTest("(a >>> b)",
50+
ExpressionType.EXPRESSION);
51+
test.disambiguationTest("(a < b | a > b)",
52+
ExpressionType.EXPRESSION);
53+
test.disambiguationTest("(a << b | a >> b)",
54+
ExpressionType.EXPRESSION);
55+
test.disambiguationTest("(a << b || a < b | a >>> b)",
56+
ExpressionType.EXPRESSION);
57+
test.disambiguationTest("(a < c.d > b)",
58+
ExpressionType.PATTERN);
4559
}
4660

4761
private final ParserFactory factory;

test/langtools/tools/javac/patterns/Guards.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ void run() {
4646
runIfTrue(this::typeGuardIfTrueIfStatement);
4747
runIfTrue(this::typeGuardIfTrueSwitchExpression);
4848
runIfTrue(this::typeGuardIfTrueSwitchStatement);
49+
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchStatement);
50+
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchExpression);
51+
runIfTrue(this::typeGuardAfterParenthesizedTrueIfStatement);
4952
}
5053

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

128+
String typeGuardAfterParenthesizedTrueSwitchStatement(Object o) {
129+
switch (o) {
130+
case (Integer i) && i == 0: o = String.valueOf(i); return "true";
131+
case ((Integer i) && i == 2): o = String.valueOf(i); return "second";
132+
case Object x: return "any";
133+
}
134+
}
135+
136+
String typeGuardAfterParenthesizedTrueSwitchExpression(Object o) {
137+
return switch (o) {
138+
case (Integer i) && i == 0: o = String.valueOf(i); yield "true";
139+
case ((Integer i) && i == 2): o = String.valueOf(i); yield "second";
140+
case Object x: yield "any";
141+
};
142+
}
143+
144+
String typeGuardAfterParenthesizedTrueIfStatement(Object o) {
145+
if (o != null && o instanceof ((Integer i) && i == 0)) {
146+
return "true";
147+
} else if (o != null && o instanceof (((Integer i) && i == 2)) && (o = i) != null) {
148+
return "second";
149+
} else {
150+
return "any";
151+
}
152+
}
153+
125154
String testPatternInGuard(Object o) {
126155
if (o instanceof (CharSequence cs && cs instanceof String s)) {
127156
return s;

test/langtools/tools/javac/patterns/RawTypeBindingWarning.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,24 @@
22
* @test /nodynamiccopyright/
33
* @bug 8263590
44
* @summary Verify correct warnings are produced for raw types in bindings
5-
* @compile/ref=RawTypeBindingWarning.out -Xlint:rawtypes -XDrawDiagnostics RawTypeBindingWarning.java
5+
* @compile/ref=RawTypeBindingWarning.out -Xlint:rawtypes -XDrawDiagnostics --enable-preview -source ${jdk.version} RawTypeBindingWarning.java
66
*/
77
public class RawTypeBindingWarning<T> {
88
public static boolean t(Object o) {
99
return o instanceof RawTypeBindingWarning w;
1010
}
11+
public static void t2(Object o) {
12+
switch (o) {
13+
case RawTypeBindingWarning w -> {}
14+
default -> {}
15+
}
16+
switch (o) {
17+
case (RawTypeBindingWarning w) -> {}
18+
default -> {}
19+
}
20+
switch (o) {
21+
case (RawTypeBindingWarning w && false) -> {}
22+
default -> {}
23+
}
24+
}
1125
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
RawTypeBindingWarning.java:9:29: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
2-
1 warning
2+
RawTypeBindingWarning.java:13:18: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
3+
RawTypeBindingWarning.java:17:19: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
4+
RawTypeBindingWarning.java:21:19: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
5+
- compiler.note.preview.filename: RawTypeBindingWarning.java, DEFAULT
6+
- compiler.note.preview.recompile
7+
4 warnings

0 commit comments

Comments
 (0)