diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index c6f604b4524..3ad0188ee0c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -2981,43 +2981,36 @@ public class Lower extends TreeTranslator { .VarDef(dollar_s, instanceOfExpr).setType(dollar_s.type); if (types.isUnconditionallyExact(tree.expr.type, tree.pattern.type)) { - exactnessCheck = make - .LetExpr(List.of(var), make.Literal(BOOLEAN, 1).setType(syms.booleanType.constType(1))) - .setType(syms.booleanType); + exactnessCheck = make.Literal(BOOLEAN, 1).setType(syms.booleanType.constType(1)); } else if (tree.expr.type.isReference()) { - JCExpression nullCheck = makeBinary(NE, - make.Ident(dollar_s), - makeNull()); - if (types.isUnconditionallyExact(types.unboxedType(tree.expr.type), tree.pattern.type)) { - exactnessCheck = make - .LetExpr(List.of(var), nullCheck) - .setType(syms.booleanType); - } else if (types.unboxedType(tree.expr.type).isPrimitive()) { - exactnessCheck = getExactnessCheck(tree, - boxIfNeeded(make.Ident(dollar_s), types.unboxedType(tree.expr.type))); - } else { - exactnessCheck = make.at(tree.pos()) - .TypeTest(make.Ident(dollar_s), make.Type(types.boxedClass(tree.pattern.type).type)) - .setType(syms.booleanType); - } + JCExpression nullCheck = + makeBinary(NE, + make.Ident(dollar_s), + makeNull()); - exactnessCheck = make.LetExpr(List.of(var), makeBinary(AND, - nullCheck, - exactnessCheck)) - .setType(syms.booleanType); + if (types.isUnconditionallyExact(types.unboxedType(tree.expr.type), tree.pattern.type)) { + exactnessCheck = nullCheck; + } else if (types.unboxedType(tree.expr.type).isPrimitive()) { + exactnessCheck = + makeBinary(AND, + nullCheck, + getExactnessCheck(tree, boxIfNeeded(make.Ident(dollar_s), types.unboxedType(tree.expr.type)))); + } else { + exactnessCheck = + makeBinary(AND, + nullCheck, + make.at(tree.pos()) + .TypeTest(make.Ident(dollar_s), make.Type(types.boxedClass(tree.pattern.type).type)) + .setType(syms.booleanType)); + } } else if (tree.expr.type.isPrimitive()) { - JCIdent argument = make.Ident(dollar_s); - - JCExpression exactnessCheckCall = - getExactnessCheck(tree, argument); - - exactnessCheck = make.LetExpr(List.of(var), exactnessCheckCall) - .setType(syms.booleanType); + exactnessCheck = getExactnessCheck(tree, make.Ident(dollar_s)); } - result = exactnessCheck; + result = make.LetExpr(List.of(var), exactnessCheck) + .setType(syms.booleanType); } else { tree.expr = translate(tree.expr); tree.pattern = translate(tree.pattern); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 5628fc119cc..06c41156ad4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -276,7 +276,7 @@ public class TransPatterns extends TreeTranslator { if (bindingVar != null && !bindingVar.isUnnamedVariable()) { JCAssign fakeInit = (JCAssign)make.at(TreeInfo.getStartPos(tree)).Assign( - make.Ident(bindingVar), convert(make.Ident(currentValue), castTargetType)).setType(bindingVar.erasure(types)); + make.Ident(bindingVar), convert(make.Ident(currentValue).setType(currentValue.erasure(types)), castTargetType)).setType(bindingVar.erasure(types)); LetExpr nestedLE = make.LetExpr(List.of(make.Exec(fakeInit)), make.Literal(true)); nestedLE.needsCond = true; diff --git a/test/langtools/tools/javac/patterns/PrimitiveInstanceOfPatternOpWithRecordPatterns.java b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfPatternOpWithRecordPatterns.java index aa4d53a8c12..0c22c987f6c 100644 --- a/test/langtools/tools/javac/patterns/PrimitiveInstanceOfPatternOpWithRecordPatterns.java +++ b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfPatternOpWithRecordPatterns.java @@ -41,6 +41,7 @@ public class PrimitiveInstanceOfPatternOpWithRecordPatterns { assertEquals(true, unboxing()); assertEquals(true, unboxingWithObject()); assertEquals(true, wideningReferenceConversionUnboxing()); + assertEquals(true, wideningReferenceConversionUnboxing2()); assertEquals(true, wideningReferenceConversionUnboxingAndWideningPrimitive()); assertEquals(true, unboxingAndWideningPrimitiveExact()); assertEquals(false, unboxingAndWideningPrimitiveNotExact()); @@ -103,13 +104,18 @@ public class PrimitiveInstanceOfPatternOpWithRecordPatterns { !(o2 instanceof R_Object(int i2))); } - public static boolean wideningReferenceConversionUnboxing() { - R_generic i = new R_generic(42); + public static boolean wideningReferenceConversionUnboxing() { + R_generic i = new R_generic(42); return i instanceof R_generic(int _); } - public static boolean wideningReferenceConversionUnboxingAndWideningPrimitive() { - R_generic i = new R_generic(42); + public static boolean wideningReferenceConversionUnboxing2() { + R_generic2 i = new R_generic2(Byte.valueOf((byte) 42)); + return i instanceof R_generic2(byte _); + } + + public static boolean wideningReferenceConversionUnboxingAndWideningPrimitive() { + R_generic i = new R_generic(42); return i instanceof R_generic(double _); } @@ -155,7 +161,9 @@ public class PrimitiveInstanceOfPatternOpWithRecordPatterns { record R_long(long l) {} record R_Integer(Integer i) {} record R_Object(Object i) {} - record R_generic(int i) {} + record R_generic(T i) {} + record R_generic2(T i) {} + record R_ByteValue(Byte b) {} record R_ShortValue(Short s) {} record R_CharacterValue(Character s) {} diff --git a/test/langtools/tools/javac/patterns/PrimitiveInstanceOfPatternOpWithTopLevelPatterns.java b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfPatternOpWithTopLevelPatterns.java new file mode 100644 index 00000000000..545c2482825 --- /dev/null +++ b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfPatternOpWithTopLevelPatterns.java @@ -0,0 +1,183 @@ +/* + * 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 8304487 8325257 + * @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Preview) + * @enablePreview + * @compile PrimitiveInstanceOfPatternOpWithTopLevelPatterns.java + * @run main/othervm PrimitiveInstanceOfPatternOpWithTopLevelPatterns + */ +public class PrimitiveInstanceOfPatternOpWithTopLevelPatterns { + public static final int qualI = 42; + + public static void main(String[] args) { + assertEquals(true, qualifiedExprConversion()); + assertEquals(true, identityPrimitiveConversion()); + assertEquals(true, wideningPrimitiveConversion()); + assertEquals(true, narrowingPrimitiveConversion()); + assertEquals(true, wideningAndNarrowingPrimitiveConversion()); + assertEquals(true, boxingConversion()); + assertEquals(true, boxingAndWideningReferenceConversion()); + assertEquals(true, unboxing()); + assertEquals(true, unboxingWithObject()); + assertEquals(true, wideningReferenceConversionUnboxing(42)); + assertEquals(true, wideningReferenceConversionUnboxing2(Byte.valueOf((byte) 42))); + assertEquals(true, wideningReferenceConversionUnboxingAndWideningPrimitive(42)); + assertEquals(true, unboxingAndWideningPrimitiveExact()); + assertEquals(false, unboxingAndWideningPrimitiveNotExact()); + assertEquals(true, unboxingWhenNullAndWideningPrimitive()); + assertEquals(true, narrowingAndUnboxing()); + assertEquals(true, patternExtractRecordComponent()); + assertEquals(true, exprMethod()); + assertEquals(true, exprStaticallyQualified()); + } + + public static boolean qualifiedExprConversion() { + return PrimitiveInstanceOfTypeComparisonOp.qualI instanceof int; + } + + public static boolean identityPrimitiveConversion() { + int i = 42; + return i instanceof int ii; + } + + public static boolean wideningPrimitiveConversion() { + byte b = (byte) 42; + short s = (short) 42; + char c = 'a'; + + return b instanceof int bb && s instanceof int ss && c instanceof int cc; + } + + public static boolean narrowingPrimitiveConversion() { + long l_within_int_range = 42L; + long l_outside_int_range = 999999999999999999L; + + return l_within_int_range instanceof int lw && !(l_outside_int_range instanceof int lo); + } + + public static boolean wideningAndNarrowingPrimitiveConversion() { + byte b = (byte) 42; + byte b2 = (byte) -42; + char c = (char) 42; + return b instanceof char bb && c instanceof byte cc && !(b2 instanceof char b2b); + } + + public static boolean boxingConversion() { + int i = 42; + + return i instanceof Integer ii; + } + + public static boolean boxingAndWideningReferenceConversion() { + int i = 42; + return i instanceof Object io && + i instanceof Number in && + i instanceof Comparable cc; + } + + public static boolean unboxing() { + Integer i = Integer.valueOf(1); + return i instanceof int ii; + } + + public static boolean unboxingWithObject() { + Object o1 = (int) 42; + Object o2 = (byte) 42; + + return o1 instanceof int o1o && + o2 instanceof byte o2o && + !(o1 instanceof byte o1b && + !(o2 instanceof int o2b )); + } + + public static boolean wideningReferenceConversionUnboxing(T i) { + return i instanceof int ii; + } + + public static boolean wideningReferenceConversionUnboxing2(T i) { + return i instanceof byte bb; + } + + public static boolean wideningReferenceConversionUnboxingAndWideningPrimitive(T i) { + return i instanceof double ii; + } + + public static boolean unboxingAndWideningPrimitiveExact() { + Byte b = Byte.valueOf((byte)42); + Short s = Short.valueOf((short)42); + Character c = Character.valueOf('a'); + + return (b instanceof int bb) && (s instanceof int ss) && (c instanceof int cc); + } + + public static boolean unboxingAndWideningPrimitiveNotExact() { + int smallestIntNotRepresentable = 16777217; // 2^24 + 1 + Integer i = Integer.valueOf(smallestIntNotRepresentable); + + return i instanceof float ii; + } + + public static boolean unboxingWhenNullAndWideningPrimitive() { + Byte b = null; + Short s = null; + Character c = null; + + return !(b instanceof int bb) && !(s instanceof int ss) && !(c instanceof int cc); + } + + public static boolean narrowingAndUnboxing() { + Number n = Byte.valueOf((byte) 42); + + return n instanceof byte nn; + } + + public record P(int i) { } + public static boolean patternExtractRecordComponent() { + Object p = new P(42); + if (p instanceof P(byte b)) { + return b == 42; + } + return false; + } + + public static int meth() {return 42;} + public static boolean exprMethod() { + return meth() instanceof int ii; + } + + public class A1 { + public static int i = 42; + } + public static boolean exprStaticallyQualified() { + return A1.i instanceof int ii; + } + + static void assertEquals(boolean expected, boolean actual) { + if (expected != actual) { + throw new AssertionError("Expected: " + expected + ", actual: " + actual); + } + } +} diff --git a/test/langtools/tools/javac/patterns/PrimitiveInstanceOfTypeComparisonOp.java b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfTypeComparisonOp.java index 56f8ee30770..7110d2b2d8f 100644 --- a/test/langtools/tools/javac/patterns/PrimitiveInstanceOfTypeComparisonOp.java +++ b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfTypeComparisonOp.java @@ -43,6 +43,7 @@ public class PrimitiveInstanceOfTypeComparisonOp { assertEquals(true, unboxing()); assertEquals(true, unboxingWithObject()); assertEquals(true, wideningReferenceConversionUnboxing(42)); + assertEquals(true, wideningReferenceConversionUnboxing2(Byte.valueOf((byte) 42))); assertEquals(true, wideningReferenceConversionUnboxingAndWideningPrimitive(42)); assertEquals(true, unboxingAndWideningPrimitiveExact()); assertEquals(false, unboxingAndWideningPrimitiveNotExact()); @@ -106,16 +107,20 @@ public class PrimitiveInstanceOfTypeComparisonOp { Object o1 = (int) 42; Object o2 = (byte) 42; - return o1 instanceof int i1 && - o2 instanceof byte b1 && - !(o1 instanceof byte b2 && - !(o2 instanceof int i2)); + return o1 instanceof int && + o2 instanceof byte && + !(o1 instanceof byte && + !(o2 instanceof int)); } public static boolean wideningReferenceConversionUnboxing(T i) { return i instanceof int; } + public static boolean wideningReferenceConversionUnboxing2(T i) { + return i instanceof byte; + } + public static boolean wideningReferenceConversionUnboxingAndWideningPrimitive(T i) { return i instanceof double; }