/* * Copyright (c) 2023, 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 * @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Preview) * @enablePreview * @compile PrimitivePatternsSwitch.java * @run main/othervm PrimitivePatternsSwitch */ public class PrimitivePatternsSwitch { public static void main(String[] args) { assertEquals(1, primitiveSwitch(42)); assertEquals(2, primitiveSwitch(123)); assertEquals(1, primitiveSwitchUnnamed(42)); assertEquals(2, primitiveSwitchUnnamed(123)); assertEquals(42, primitiveSwitch2()); assertEquals(42, primitiveSwitch3()); assertEquals(1, primitiveSwitch4(0.0f)); assertEquals(2, primitiveSwitch4(1.0f)); assertEquals(1, primitiveSwitchUnconditionallyExact(Byte.MAX_VALUE)); assertEquals(42, exhaustive0()); assertEquals(1, exhaustive1WithDefault()); assertEquals(2, exhaustive2WithDefault()); assertEquals(1, exhaustive1()); assertEquals(1, exhaustive2()); assertEquals(1, exhaustive3()); assertEquals(1, exhaustive4()); assertEquals(2, exhaustive5()); assertEquals(1, exhaustive6()); assertEquals(1, exhaustive7(true)); assertEquals(1, exhaustive7s(true)); assertEquals(1, exhaustive8(true)); assertEquals(1, exhaustive9(true)); assertEquals(1, exhaustive9(false)); assertEquals(1, exhaustiveWithRecords1()); assertEquals(1, exhaustiveWithRecords2()); assertEquals(1, exhaustiveWithRecords4()); assertEquals(1, exhaustiveWithRecords5()); assertEquals(1, exhaustiveWithRecords6()); assertEquals(2, ensureProperSelectionWithRecords()); assertEquals(1, ensureProperSelectionWithRecords2()); assertEquals(3, ensureProperSelectionWithRecords3()); assertEquals(42, switchAndDowncastFromObjectPrimitive()); assertEquals(42, dominationBetweenBoxedAndPrimitive()); assertEquals(2, wideningAndUnboxing()); assertEquals(2, wideningAndUnboxingInRecord()); assertEquals(2, wideningAndInferredUnboxingInRecord()); assertEquals(5f, switchOverBoxedFloat(0f)); assertEquals(7f, switchOverBoxedFloat(1f)); assertEquals(9f, switchOverBoxedFloat(2f)); assertEquals(9f, switchOverBoxedFloat(2f)); assertEquals(5f, switchOverPrimitiveDouble(0d)); assertEquals(7f, switchOverPrimitiveDouble(1d)); assertEquals(9f, switchOverPrimitiveDouble(2d)); assertEquals(1, switchOverPrimitiveChar('a')); assertEquals(-1, switchOverPrimitiveChar('x')); assertTrue(switchOverBoxedBooleanWithUnconditional(Boolean.valueOf(true))); assertTrue(switchOverBoxedBooleanWithUnconditional(true)); assertTrue(!switchOverBoxedBooleanWithUnconditional(false)); assertEquals(1, switchOverPrimitiveBooleanWithDefault(true)); assertEquals(2, switchOverPrimitiveBooleanWithDefault(false)); assertEquals(1, switchOverPrimitiveBoolean(true)); assertEquals(2, switchOverPrimitiveBoolean(false)); assertEquals(1, switchOverPrimitiveFloat(0.0f/0.0f)); assertEquals(2, switchOverPrimitiveFloat((float) Math.pow(0.0f/0.0f, 0))); assertEquals(3, switchOverPrimitiveFloat(0.0f)); assertEquals(4, switchOverPrimitiveFloat(-0.0f)); assertEquals(1, switchRedirectedExactnessMethods1('a')); assertEquals(-1, switchRedirectedExactnessMethods1('\u03A9')); assertEquals(1, switchRedirectedExactnessMethods2('\u03A9')); assertEquals(-1, switchRedirectedExactnessMethods2('\uFFFF')); assertEquals(1, switchLongAndUnconditional(32778L)); assertEquals(2, switchLongAndUnconditional(42L)); assertEquals(1, switchByte((byte) 128)); assertEquals(2, switchByte((byte) 42)); assertEquals(1, switchShort((short) 32778)); assertEquals(2, switchShort((short) 42)); assertEquals(1, switchInt(32778)); assertEquals(2, switchInt(42)); assertEquals(1, switchChar( '\u0010')); assertEquals(2, switchChar('a')); assertEquals(1, testIntInNonEnhancedSwitchStatement(1)); assertEquals(0, testIntInNonEnhancedSwitchStatement(0)); assertEquals(1, testFloatInEnhancedSwitchStatement(1.0f)); assertEquals(0, testFloatInEnhancedSwitchStatement(0.0f)); assertEquals(1, testDoubleInEnhancedSwitchStatement(1.0d)); assertEquals(0, testDoubleInEnhancedSwitchStatement(0.0d)); assertEquals(1, testLongInEnhancedSwitchStatement(1l)); assertEquals(0, testLongInEnhancedSwitchStatement(0l)); assertEquals(1, testBooleanInEnhancedSwitchStatement(true)); assertEquals(0, testBooleanInEnhancedSwitchStatement(false)); assertEquals(1, testByteWrapperToIntUnconditionallyExact()); assertEquals(1, testIntegerWrapperToFloat()); assertEquals(-1, testIntegerWrapperToFloatInexact()); assertEquals(Character.MAX_VALUE, testUnboxingAndWideningCharacter1(Character.MAX_VALUE)); assertEquals(Character.MAX_VALUE, testUnboxingAndWideningCharacter2(Character.MAX_VALUE)); assertEquals(Character.MAX_VALUE, testUnboxingAndWideningCharacter3(Character.MAX_VALUE)); assertEquals(Float.MAX_VALUE, testUnboxingAndWideningFloat(Float.MAX_VALUE)); assertEquals(Float.MAX_VALUE, testUnboxingAndWideningFloatExplicitCast(Float.MAX_VALUE)); assertEquals(42f, testUnboxingAndWideningLong(42L)); assertEquals(2, testUnboxingAndWideningLong(Long.MAX_VALUE)); } public static int primitiveSwitch(int i) { return switch (i) { case int j when j == 42-> 1; case int j -> 2; }; } public static int primitiveSwitchUnnamed(int i) { return switch (i) { case int _ when i == 42-> 1; case int _ -> 2; }; } public static int primitiveSwitch2() { Object o = Integer.valueOf(42); switch (o) { case int i: return i; default: break; } return -1; } public static int primitiveSwitch3() { int i = 42; switch (i) { case Integer ii: return ii; } } public static int primitiveSwitch4(float f) { return switch (f) { case 0.0f -> 1; case Float fi when fi == 1f -> 2; case Float fi -> 3; }; } public static int primitiveSwitchUnconditionallyExact(byte c) { return switch (c) { case short _ -> 1; }; } public static int exhaustive0() { Integer i = 42; switch (i) { case int j: return j; } } public static int exhaustive1WithDefault() { int i = 42; return switch (i) { case byte b -> 1; default -> 2; }; } public static int exhaustive2WithDefault() { int i = 30000; return switch (i) { case byte b -> 1; case short s -> 2; default -> 3; }; } public static int exhaustive1() { int i = 42; return switch (i) { case Integer p -> 1; }; } public static int exhaustive2() { int i = 42; return switch (i) { case long d -> 1; }; } public static int exhaustive3() { int i = 42; return switch (i) { case double d -> 1; }; } public static int exhaustive4() { int i = 127; return switch (i) { case byte b -> 1; case double d -> 2; }; } public static int exhaustive5() { int i = 127 + 1; return switch (i) { case byte b -> 1; case double d -> 2; }; } public static int exhaustive6() { Integer i = Integer.valueOf(42); return switch (i) { case int p -> 1; }; } public static int exhaustive7(Boolean b) { switch (b) { case true: return 1; case false: return 2; // with reminder, null, OK } } public static int exhaustive7s(Boolean b) { return switch (b) { case true -> 1; case false -> 2; // with reminder, null, OK }; } public static int exhaustive8(Boolean b) { switch (b) { case boolean bb: return 1; } } public static int exhaustive9(boolean b) { switch (b) { case Boolean bb: return 1; } } public static int exhaustiveWithRecords1() { R_int r = new R_int(42); return switch (r) { // exhaustive, because Integer exhaustive at type int case R_int(Integer x) -> 1; }; } public static int exhaustiveWithRecords2() { R_int r = new R_int(42); return switch (r) { // exhaustive, because double unconditional at int case R_int(double x) -> 1; }; } public static int exhaustiveWithRecords4() { R_Integer r = new R_Integer(42); return switch (r) { // exhaustive, because R_Integer(int) exhaustive at type R_Integer(Integer), because int exhaustive at type Integer case R_Integer(int x) -> 1; }; } public static int exhaustiveWithRecords5() { R_Integer r = new R_Integer(42); return switch (r) { // exhaustive, because double exhaustive at Integer case R_Integer(double x) -> 1; }; } public static int exhaustiveWithRecords6() { R_int r = new R_int(42); return switch (r) { case R_int(byte x) -> 1; case R_int(int x) -> 2; }; } public static int ensureProperSelectionWithRecords() { R_int r = new R_int(4242); return switch (r) { case R_int(byte x) -> 1; case R_int(int x) -> 2; }; } public static int ensureProperSelectionWithRecords2() { R_double r = new R_double(42); switch (r) { case R_double(int i): return meth_int(i); case R_double(double x): return meth_double(x); } } public static int ensureProperSelectionWithRecords3() { R_int r = new R_int(4242); return switch (r) { case R_int(byte x) -> 1; case R_int(int x) when x == 236 -> 2; case R_int(int x) -> 3; }; } public static int meth_int(int i) { return 1; } public static int meth_double(double d) { return 2;} public static int switchAndDowncastFromObjectPrimitive() { Object i = 42; return switch (i) { case Integer ib -> ib; default -> -1; }; } public static int dominationBetweenBoxedAndPrimitive() { Object i = 42; return switch (i) { case Integer ib -> ib; case byte ip -> ip; default -> -1; }; } static int wideningAndUnboxing() { Number o = Integer.valueOf(42); return switch (o) { case byte b -> 1; case int i -> 2; case float f -> 3; default -> 4; }; } static int wideningAndUnboxingInRecord() { Box box = new Box<>(Integer.valueOf(42)); return switch (box) { case Box(byte b) -> 1; case Box(int i) -> 2; case Box(float f) -> 3; default -> 4; }; } static int wideningAndInferredUnboxingInRecord() { Box box = new Box<>(Integer.valueOf(42)); return switch (box) { case Box(byte b) -> 1; case Box(int i) -> 2; case Box(float f) -> 3; default -> 4; }; } public static float switchOverBoxedFloat(Float f) { return switch (f) { case 0f -> 5f + 0f; case Float fi when fi == 1f -> 6f + fi; case Float fi -> 7f + fi; }; } public static double switchOverPrimitiveDouble(Double d) { return switch (d) { case 0d -> 5d + 0d; case Double di when di == 1d -> 6d + di; case Double di -> 7d + di; }; } public static boolean switchOverBoxedBooleanWithUnconditional(Boolean b) { return switch (b) { case true -> true; case Boolean bi -> bi; }; } public static int switchOverPrimitiveBooleanWithDefault(boolean b) { return switch (b) { case true -> 1; default -> 2; }; } public static int switchOverPrimitiveBoolean(boolean b) { return switch (b) { case true -> 1; case false -> 2; }; } public static int switchOverPrimitiveChar(char c) { return switch (c) { case 'a' -> 1; default -> -1; }; } public static final float NaNconstant = Float.NaN; public static int switchOverPrimitiveFloat(float f) { return switch (f) { case NaNconstant -> 1; case 1.0f -> 2; case 0.0f -> 3; case -0.0f -> 4; default -> -1; }; } // tests that Exactness.char_byte is properly redirected to int_byte public static int switchRedirectedExactnessMethods1(char c) { return switch (c) { case byte _ -> 1; default -> -1; }; } // tests that Exactness.char_short is properly redirected to int_short public static int switchRedirectedExactnessMethods2(char c) { return switch (c) { case short _ -> 1; default -> -1; }; } // tests that Exactness.short_byte is properly redirected to int_byte public static int switchRedirectedExactnessMethods2(short c) { return switch (c) { case byte _ -> 1; default -> -1; }; } public static int switchLongAndUnconditional(long l) { return switch (l) { case 32778L -> 1; case long c -> 2; }; } public static int switchByte(byte b) { return switch (b) { case (byte)128 -> 1; case byte c -> 2; }; } public static int switchShort(short s) { return switch (s) { case (short)32778 -> 1; case short c -> 2; }; } public static int switchInt(int i) { return switch (i) { case 32778 -> 1; case int c -> 2; }; } public static int switchChar(char c) { return switch (c) { case '\u0010' -> 1; case char cc -> 2; }; } public static int testIntInNonEnhancedSwitchStatement(int v1) { int i = 0; switch (v1) { case 1: i = 1; break; } return i; } public static int testFloatInEnhancedSwitchStatement(float v1) { int i = 0; switch (v1) { case 1.0f: i = 1; break; default: i = 0; } return i; } public static int testDoubleInEnhancedSwitchStatement(double v1) { int i = 0; switch (v1) { case 1d: i = 1; break; default: i = 0; } return i; } public static int testLongInEnhancedSwitchStatement(long v1) { int i = 0; switch (v1) { case 1l: i = 1; break; default: i = 0; } return i; } public static int testBooleanInEnhancedSwitchStatement(boolean v1) { int i = 0; switch (v1) { case true: i = 1; break; default: i = 0; } return i; } public static int testByteWrapperToIntUnconditionallyExact() { Byte b = Byte.valueOf((byte) 42); return switch (b) { case int p -> 1; }; } public static int testIntegerWrapperToFloat() { Integer i = Integer.valueOf(42); return switch (i) { case float p -> 1; default -> -1; }; } public static int testIntegerWrapperToFloatInexact() { Integer i = Integer.valueOf(Integer.MAX_VALUE); return switch (i) { case float p -> 1; default -> -1; }; } public static char testUnboxingAndWideningCharacter1(Character test) { return switch (test) { case char c -> c; }; } public static int testUnboxingAndWideningCharacter2(Character test) { return switch (test) { case int c -> c; }; } public static float testUnboxingAndWideningCharacter3(Character test) { return switch (test) { case float f -> f; }; } public static float testUnboxingAndWideningLong(Long test) { return switch (test) { case float y -> y; default -> 2; }; } public static double testUnboxingAndWideningFloat(Float test) { return switch (test) { case double y -> y; default -> 2; }; } public static double testUnboxingAndWideningFloatExplicitCast(Object test) { return switch ((Float) test) { case double y -> y; default -> 2; }; } record R_Integer(Integer x) {} record R_int(int x) {} record R_double(double x) {} record Box(N num) {} static void assertEquals(int expected, int actual) { if (expected != actual) { throw new AssertionError("Expected: " + expected + ", actual: " + actual); } } static void assertEquals(float expected, float actual) { if (Float.compare(expected, actual) != 0) { throw new AssertionError("Expected: " + expected + ", but got: " + actual); } } static void assertEquals(double expected, double actual) { if (Double.compare(expected, actual) != 0) { throw new AssertionError("Expected: " + expected + ", but got: " + actual); } } static void assertTrue(boolean actual) { if (!actual) { throw new AssertionError("Expected: true, but got false"); } } }