Skip to content

Commit 6811a11

Browse files
committed
8341408: Implement JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)
Reviewed-by: vromero, jlahoda
1 parent 72a45dd commit 6811a11

File tree

4 files changed

+135
-6
lines changed

4 files changed

+135
-6
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,27 @@ protected TransPatterns(Context context) {
199199

200200
@Override
201201
public void visitTypeTest(JCInstanceOf tree) {
202-
if (tree.pattern instanceof JCPattern pattern) {
202+
// Translates regular instanceof type operation to instanceof pattern operator when
203+
// the expression was originally T but was subsequently erased to Object.
204+
//
205+
// $expr instanceof $primitiveType
206+
// =>
207+
// $expr instanceof T $temp && $temp instanceof $primitiveType
208+
if (tree.erasedExprOriginalType!=null && !types.isSameType(tree.expr.type, tree.erasedExprOriginalType)) {
209+
BindingSymbol temp = new BindingSymbol(Flags.FINAL | Flags.SYNTHETIC,
210+
names.fromString("temp" + variableIndex++ + target.syntheticNameChar()),
211+
tree.erasedExprOriginalType,
212+
currentMethodSym);
213+
214+
JCVariableDecl tempDecl = make.at(tree.pos()).VarDef(temp, null);
215+
216+
JCTree resultExpr =
217+
makeBinary(Tag.AND,
218+
make.TypeTest(tree.expr, make.BindingPattern(tempDecl).setType(tree.erasedExprOriginalType)).setType(syms.booleanType),
219+
make.TypeTest(make.Ident(tempDecl), tree.pattern).setType(syms.booleanType));
220+
221+
result = translate(resultExpr);
222+
} else if (tree.pattern instanceof JCPattern pattern) {
203223
//first, resolve any record patterns:
204224
JCExpression extraConditions = null;
205225
if (pattern instanceof JCRecordPattern recordPattern) {

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -813,8 +813,7 @@ public void visitSwitch(JCSwitch tree) {
813813
Type selsuper = types.supertype(tree.selector.type);
814814
boolean enumSwitch = selsuper != null &&
815815
selsuper.tsym == syms.enumSym;
816-
Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
817-
tree.selector = translate(tree.selector, target);
816+
tree.selector = translate(tree.selector, erasure(tree.selector.type));
818817
tree.cases = translateCases(tree.cases);
819818
result = tree;
820819
}
@@ -852,8 +851,7 @@ public void visitSwitchExpression(JCSwitchExpression tree) {
852851
Type selsuper = types.supertype(tree.selector.type);
853852
boolean enumSwitch = selsuper != null &&
854853
selsuper.tsym == syms.enumSym;
855-
Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
856-
tree.selector = translate(tree.selector, target);
854+
tree.selector = translate(tree.selector, erasure(tree.selector.type));
857855
tree.cases = translate(tree.cases, tree.type);
858856
tree.type = erasure(tree.type);
859857
result = retype(tree, tree.type, pt);
@@ -1067,8 +1065,14 @@ public void visitTypeCast(JCTypeCast tree) {
10671065
}
10681066

10691067
public void visitTypeTest(JCInstanceOf tree) {
1070-
tree.expr = translate(tree.expr, null);
10711068
tree.pattern = translate(tree.pattern, null);
1069+
if (tree.pattern.type.isPrimitive()) {
1070+
tree.erasedExprOriginalType = erasure(tree.expr.type);
1071+
tree.expr = translate(tree.expr, null);
1072+
}
1073+
else {
1074+
tree.expr = translate(tree.expr, null);
1075+
}
10721076
result = tree;
10731077
}
10741078

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,6 +2272,8 @@ public static class JCInstanceOf extends JCExpression implements InstanceOfTree
22722272
/**{@code true} if this instanceof test should have
22732273
* value {@code true} when the {@code expr} is {@code null}.*/
22742274
public boolean allowNull;
2275+
public Type erasedExprOriginalType;
2276+
22752277
protected JCInstanceOf(JCExpression expr, JCTree pattern) {
22762278
this.expr = expr;
22772279
this.pattern = pattern;
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
/*
24+
* @test
25+
* @bug 8341408
26+
* @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Second Preview)
27+
* @enablePreview
28+
*/
29+
30+
import java.util.List;
31+
32+
public class PrimitiveTypesInTestingContextErasure {
33+
public static void main(String[] args) {
34+
erasureSwitch();
35+
erasureInstanceofTypeComparisonOperator();
36+
erasureInstanceofPatternMatchingOperator();
37+
38+
pollutedInstanceofPatternMatchingOperatorReference();
39+
pollutedInstanceofPatternMatchingOperator();
40+
pollutedInstanceofTypeComparisonOperator();
41+
pollutedSwitch();
42+
}
43+
44+
public static void erasureSwitch() {
45+
List<Short> ls = List.of((short) 42);
46+
Short s = 42;
47+
48+
assertTrue(switch(ls.get(0)) {
49+
case int _ -> true; // Short to int
50+
default -> false;
51+
});
52+
}
53+
54+
public static void erasureInstanceofTypeComparisonOperator() {
55+
List<Short> ls = List.of((short) 42);
56+
57+
assertTrue(ls.get(0) instanceof int); // Short to int
58+
}
59+
60+
public static void erasureInstanceofPatternMatchingOperator() {
61+
List<Short> ls = List.of((short) 42);
62+
63+
assertTrue(ls.get(0) instanceof int i); // Short to int
64+
}
65+
66+
public static void pollutedInstanceofPatternMatchingOperator() {
67+
List<Short> ls = (List) List.of("42");
68+
69+
assertTrue(!(ls.get(0) instanceof int i));
70+
}
71+
72+
public static void pollutedInstanceofTypeComparisonOperator() {
73+
List<Short> ls = (List) List.of("42");
74+
75+
assertTrue(!(ls.get(0) instanceof int));
76+
}
77+
78+
public static void pollutedInstanceofPatternMatchingOperatorReference() {
79+
List<Short> ls = (List) List.of("42");
80+
81+
assertTrue(!(ls.get(0) instanceof Short));
82+
}
83+
84+
public static void pollutedSwitch() {
85+
List<Short> ls = (List) List.of("42");
86+
87+
try {
88+
var res = switch(ls.get(0)) {
89+
case int _ -> true;
90+
default -> false;
91+
};
92+
throw new AssertionError("Expected: ClassCastException");
93+
} catch (ClassCastException e) {
94+
;
95+
}
96+
}
97+
98+
static void assertTrue(boolean actual) {
99+
if (!actual) {
100+
throw new AssertionError("Expected: true, but got false");
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)