fb390d202c
Reviewed-by: jlahoda
642 lines
19 KiB
Java
642 lines
19 KiB
Java
/*
|
|
* 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<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");
|
|
}
|
|
}
|
|
}
|