| /* | |
| * Copyright (c) 2023, 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 | |
| * @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<Number> box = new Box<>(Integer.valueOf(42)); | |
| return switch (box) { | |
| case Box<Number>(byte b) -> 1; | |
| case Box<Number>(int i) -> 2; | |
| case Box<Number>(float f) -> 3; | |
| default -> 4; | |
| }; | |
| } | |
| static int wideningAndInferredUnboxingInRecord() { | |
| Box<Number> 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 extends Number>(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"); | |
| } | |
| } | |
| } |