8341408: Implement JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)

Reviewed-by: vromero, jlahoda
This commit is contained in:
Aggelos Biboudis 2024-11-06 14:50:54 +00:00
parent 72a45ddbad
commit 6811a11e27
4 changed files with 135 additions and 6 deletions

View File

@ -199,7 +199,27 @@ public class TransPatterns extends TreeTranslator {
@Override
public void visitTypeTest(JCInstanceOf tree) {
if (tree.pattern instanceof JCPattern pattern) {
// Translates regular instanceof type operation to instanceof pattern operator when
// the expression was originally T but was subsequently erased to Object.
//
// $expr instanceof $primitiveType
// =>
// $expr instanceof T $temp && $temp instanceof $primitiveType
if (tree.erasedExprOriginalType!=null && !types.isSameType(tree.expr.type, tree.erasedExprOriginalType)) {
BindingSymbol temp = new BindingSymbol(Flags.FINAL | Flags.SYNTHETIC,
names.fromString("temp" + variableIndex++ + target.syntheticNameChar()),
tree.erasedExprOriginalType,
currentMethodSym);
JCVariableDecl tempDecl = make.at(tree.pos()).VarDef(temp, null);
JCTree resultExpr =
makeBinary(Tag.AND,
make.TypeTest(tree.expr, make.BindingPattern(tempDecl).setType(tree.erasedExprOriginalType)).setType(syms.booleanType),
make.TypeTest(make.Ident(tempDecl), tree.pattern).setType(syms.booleanType));
result = translate(resultExpr);
} else if (tree.pattern instanceof JCPattern pattern) {
//first, resolve any record patterns:
JCExpression extraConditions = null;
if (pattern instanceof JCRecordPattern recordPattern) {

View File

@ -813,8 +813,7 @@ public class TransTypes extends TreeTranslator {
Type selsuper = types.supertype(tree.selector.type);
boolean enumSwitch = selsuper != null &&
selsuper.tsym == syms.enumSym;
Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
tree.selector = translate(tree.selector, target);
tree.selector = translate(tree.selector, erasure(tree.selector.type));
tree.cases = translateCases(tree.cases);
result = tree;
}
@ -852,8 +851,7 @@ public class TransTypes extends TreeTranslator {
Type selsuper = types.supertype(tree.selector.type);
boolean enumSwitch = selsuper != null &&
selsuper.tsym == syms.enumSym;
Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
tree.selector = translate(tree.selector, target);
tree.selector = translate(tree.selector, erasure(tree.selector.type));
tree.cases = translate(tree.cases, tree.type);
tree.type = erasure(tree.type);
result = retype(tree, tree.type, pt);
@ -1067,8 +1065,14 @@ public class TransTypes extends TreeTranslator {
}
public void visitTypeTest(JCInstanceOf tree) {
tree.expr = translate(tree.expr, null);
tree.pattern = translate(tree.pattern, null);
if (tree.pattern.type.isPrimitive()) {
tree.erasedExprOriginalType = erasure(tree.expr.type);
tree.expr = translate(tree.expr, null);
}
else {
tree.expr = translate(tree.expr, null);
}
result = tree;
}

View File

@ -2272,6 +2272,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/**{@code true} if this instanceof test should have
* value {@code true} when the {@code expr} is {@code null}.*/
public boolean allowNull;
public Type erasedExprOriginalType;
protected JCInstanceOf(JCExpression expr, JCTree pattern) {
this.expr = expr;
this.pattern = pattern;

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8341408
* @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Second Preview)
* @enablePreview
*/
import java.util.List;
public class PrimitiveTypesInTestingContextErasure {
public static void main(String[] args) {
erasureSwitch();
erasureInstanceofTypeComparisonOperator();
erasureInstanceofPatternMatchingOperator();
pollutedInstanceofPatternMatchingOperatorReference();
pollutedInstanceofPatternMatchingOperator();
pollutedInstanceofTypeComparisonOperator();
pollutedSwitch();
}
public static void erasureSwitch() {
List<Short> ls = List.of((short) 42);
Short s = 42;
assertTrue(switch(ls.get(0)) {
case int _ -> true; // Short to int
default -> false;
});
}
public static void erasureInstanceofTypeComparisonOperator() {
List<Short> ls = List.of((short) 42);
assertTrue(ls.get(0) instanceof int); // Short to int
}
public static void erasureInstanceofPatternMatchingOperator() {
List<Short> ls = List.of((short) 42);
assertTrue(ls.get(0) instanceof int i); // Short to int
}
public static void pollutedInstanceofPatternMatchingOperator() {
List<Short> ls = (List) List.of("42");
assertTrue(!(ls.get(0) instanceof int i));
}
public static void pollutedInstanceofTypeComparisonOperator() {
List<Short> ls = (List) List.of("42");
assertTrue(!(ls.get(0) instanceof int));
}
public static void pollutedInstanceofPatternMatchingOperatorReference() {
List<Short> ls = (List) List.of("42");
assertTrue(!(ls.get(0) instanceof Short));
}
public static void pollutedSwitch() {
List<Short> ls = (List) List.of("42");
try {
var res = switch(ls.get(0)) {
case int _ -> true;
default -> false;
};
throw new AssertionError("Expected: ClassCastException");
} catch (ClassCastException e) {
;
}
}
static void assertTrue(boolean actual) {
if (!actual) {
throw new AssertionError("Expected: true, but got false");
}
}
}