From 9c33bc9f9fe105bf7a2edf76236b079d8779e03c Mon Sep 17 00:00:00 2001 From: Theresa Mammarella Date: Tue, 14 Nov 2023 11:35:33 -0500 Subject: [PATCH 1/2] Move old ValueTypeArrayTests to src_qtypes Signed-off-by: Theresa Mammarella --- .../test/lworld/ValueTypeArrayTests.java | 753 ++++++++++++++++++ 1 file changed, 753 insertions(+) create mode 100644 test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java diff --git a/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java new file mode 100644 index 00000000000..a45bc18bf5e --- /dev/null +++ b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java @@ -0,0 +1,753 @@ +/******************************************************************************* + * Copyright IBM Corp. and others 2022 + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] https://openjdk.org/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 + *******************************************************************************/ +package org.openj9.test.lworld; + +import org.testng.Assert; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** + * Test array element assignment involving arrays of type {@code Object}, + * of an interface type, and of value types, with values of those types, + * or possibly, a null reference. + */ +@Test(groups = { "level.sanity" }) +public class ValueTypeArrayTests { + private ValueTypeArrayTests() {} + + /** + * A simple interface class + */ + interface SomeIface {} + + /** + * A simple value type class + */ + static value class PointV implements SomeIface { + double x; + double y; + + PointV(double x, double y) { + this.x = x; + this.y = y; + } + } + + /** + * A simple primitive value type class + */ + static primitive class PointPV implements SomeIface { + double x; + double y; + + PointPV(double x, double y) { + this.x = x; + this.y = y; + } + } + + /** + * A simple identity class + */ + static class Bogus implements SomeIface {}; + + static Object nullObj = null; + static SomeIface bogusIfaceObj = new Bogus(); + static PointV pointVal = new PointV(1.0, 2.0); + static PointPV pointPrimVal = new PointPV(1.0, 2.0); + + static void assign(Object[] arr, int idx, Object value) { + arr[idx] = value; + } + + static void assign(Object[] arr, int idx, SomeIface value) { + arr[idx] = value; + } + + static void assign(Object[] arr, int idx, PointV value) { + arr[idx] = value; + } + + static void assign(Object[] arr, int idx, PointPV value) { + arr[idx] = value; + } + + static void assign(SomeIface[] arr, int idx, SomeIface value) { + arr[idx] = value; + } + + static void assign(SomeIface[] arr, int idx, PointV value) { + arr[idx] = value; + } + + static void assign(SomeIface[] arr, int idx, PointPV value) { + arr[idx] = value; + } + + static void assign(PointV[] arr, int idx, PointV value) { + arr[idx] = value; + } + + static void assign(PointPV[] arr, int idx, PointPV value) { + arr[idx] = value; + } + + static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int srcKind) { + if (arrKind == OBJ_TYPE) { + if (srcKind == OBJ_TYPE) { + assign(arr, idx, src); + } else if (srcKind == IFACE_TYPE) { + assign(arr, idx, (SomeIface) src); + } else if (srcKind == VAL_TYPE) { + assign(arr, idx, (PointV) src); + } else if (srcKind == PRIM_TYPE) { + assign(arr, idx, (PointPV) src); + } else { + fail("Unexpected source type requested "+srcKind); + } + } else if (arrKind == IFACE_TYPE) { + if (srcKind == OBJ_TYPE) { + // Meaningless combination + } else if (srcKind == IFACE_TYPE) { + assign((SomeIface[]) arr, idx, (SomeIface) src); + } else if (srcKind == VAL_TYPE) { + assign((SomeIface[]) arr, idx, (PointV) src); + } else if (srcKind == PRIM_TYPE) { + assign((SomeIface[]) arr, idx, (PointPV) src); + } else { + fail("Unexpected source type requested "+srcKind); + } + } else if (arrKind == VAL_TYPE) { + if (srcKind == OBJ_TYPE) { + // Meaningless combination + } else if (srcKind == IFACE_TYPE) { + // Meaningless combination + } else if (srcKind == VAL_TYPE) { + assign((PointV[]) arr, idx, (PointV) src); + } else if (srcKind == PRIM_TYPE) { + // Meaningless combination + } else { + fail("Unexpected source type requested "+srcKind); + } + } else if (arrKind == PRIM_TYPE) { + if (srcKind == OBJ_TYPE) { + // Meaningless combination + } else if (srcKind == IFACE_TYPE) { + // Meaningless combination + } else if (srcKind == VAL_TYPE) { + // Meaningless combination + } else if (srcKind == PRIM_TYPE) { + assign((PointPV[])arr, idx, (PointPV) src); + } else { + fail("Unexpected source type requested "+srcKind); + } + } else { + fail("Unexpected array type requested "+arrKind); + } + } + + /** + * Represents a null reference. + */ + static final int NULL_REF = 0; + + /** + * Represents the type Object or Object[] + */ + static final int OBJ_TYPE = 1; + + /** + * Represents the types SomeIface or SomeIface[]. + * {@link SomeIface} is an interface class defined by this test. + */ + static final int IFACE_TYPE = 2; + + /** + * Represents the type PointV or PointV[]. + * {@link PointV} is a non-primitive value type class defined by this test. + */ + static final int VAL_TYPE = 3; + + /** + * Represents the type PointPV or PointPV[]. + * {@link PointPV} is a primitive value type class defined by this test. + */ + static final int PRIM_TYPE = 4; + + /** + * Convenient constant reference to the ArrayIndexOutOfBoundsException class + */ + static final Class AIOOBE = ArrayIndexOutOfBoundsException.class; + + /** + * Convenient constant reference to the ArrayStoreException class + */ + static final Class ASE = ArrayStoreException.class; + + /** + * Convenient constant reference to the NullPointerException class + */ + static final Class NPE = NullPointerException.class; + + /** + * The expected kind of exception that will be thrown, if any, for an + * assignment to an array whose component type is one of {@link #OBJ_TYPE}, + * {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #PRIM_TYPE} with a source + * of one of those same types or {@link #NULL_REF}. + * + *

expectedAssignmentExceptions[actualArrayKind][actualSourceKind] + */ + static Class expectedAssignmentExceptions[][] = + new Class[][] { + null, // NULL_REF for array is not a possibility + new Class[] {null, null, null, null, null}, // All values can be assigned to Object[] + new Class[] {null, ASE, null, null, null}, // ASE for SomeIface[] = Object + new Class[] {null, ASE, ASE, null, ASE}, // ASE for PointV[] = PointPV, SomeIface + new Class[] {NPE, ASE, ASE, ASE, null}, // NPE for PointPV[] = null; ASE for PointPV[] = PointV + }; + + /** + * Indicates whether a value or an array with component class + * that is one of {@link #NULL_REF}, {@link #OBJ_TYPE}, + * {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #PRIM_TYPE} can be + * cast to another member of that same set of types without triggering a + * ClassCastException or NullPointerException + * + *

permittedCast[actual][static] + */ + static boolean permittedCast[][] = + new boolean[][] { + new boolean[] { false, true, true, true, false }, // NULL_REF cannot be cast to primitive value + new boolean[] { false, true, false, false, false }, // OBJ_TYPE to Object + new boolean[] { false, true, true, false, false }, // IFACE_TYPE to Object, SomeIface + new boolean[] { false, true, true, true , false }, // VAL_TYPE to Object, SomeIface, PointV + new boolean[] { false, true, true, false, true } // PRIM_TYPE to Object, SomeIface, PointPV + }; + + /** + * Dispatch to a particular test method that will test with parameters cast to a specific pair + * of static types. Those types are specified by the staticArrayKind and + * staticSourceKind parameters, each of which has one of the values + * {@link #OBJ_TYPE}, {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #PRIM_TYPE}. + * + * @param arr Array to which sourceVal will be assigned + * @param sourceVal Value that will be assigned to an element of arr + * @param staticArrayKind A value indicating the static type of array that is to be tested + * @param staticSourceKind A value indicating the static type that is to be tested for the source of the assignmentt + */ + static void runTest(Object[] arr, Object sourceVal, int staticArrayKind, int staticSourceKind) throws Throwable { + boolean caughtThrowable = false; + int actualArrayKind = arr instanceof PointPV[] + ? PRIM_TYPE + : arr instanceof PointV[] + ? VAL_TYPE + : arr instanceof SomeIface[] + ? IFACE_TYPE + : OBJ_TYPE; + int actualSourceKind = sourceVal == null + ? NULL_REF + : sourceVal instanceof PointPV + ? PRIM_TYPE + : sourceVal instanceof PointV + ? VAL_TYPE + : sourceVal instanceof SomeIface + ? IFACE_TYPE + : OBJ_TYPE; + + // Would a cast from the actual type of array to the specified static array type, or the actual type of the + // source value to the specified static type trigger a ClassCastException or NPE? If so, skip the test. + if (!permittedCast[actualArrayKind][staticArrayKind] || !permittedCast[actualSourceKind][staticSourceKind]) { + return; + } + + Class expectedExceptionClass = expectedAssignmentExceptions[actualArrayKind][actualSourceKind]; + + try { + assignDispatch(arr, 1, sourceVal, staticArrayKind, staticSourceKind); + } catch (Throwable t) { + caughtThrowable = true; + assertEquals(t.getClass(), expectedExceptionClass, "ActualArrayKind == "+actualArrayKind+"; StaticArrayKind == " + +staticArrayKind+"; actualSourceKind == "+actualSourceKind+"; staticSourceKind == "+staticSourceKind); + } + + if (expectedExceptionClass != null) { + assertTrue(caughtThrowable, + "Expected exception kind "+expectedExceptionClass.getName()+" to be thrown. ActualArrayKind == "+actualArrayKind + +"; StaticArrayKind == "+staticArrayKind+"; actualSourceKind == "+actualSourceKind+"; staticSourceKind == " + +staticSourceKind); + } + + // ArrayIndexOutOfBoundsException must be checked before both + // NullPointerException for primitive value type and ArrayStoreException. + // This call to assignDispatch will attempt an out-of-bounds element assignment, + // and is always expected to throw an ArrayIndexOutOfBoundsException. + boolean caughtAIOOBE = false; + + try { + assignDispatch(arr, 2, sourceVal, staticArrayKind, staticSourceKind); + } catch(ArrayIndexOutOfBoundsException aioobe) { + caughtAIOOBE = true; + } catch (Throwable t) { + assertTrue(false, "Expected ArrayIndexOutOfBoundsException, but saw "+t.getClass().getName()); + } + + assertTrue(caughtAIOOBE, "Expected ArrayIndexOutOfBoundsException"); + } + + /** + * Test various types of arrays and source values along with various statically declared types + * for the arrays and source values to ensure required ArrayStoreExceptions, + * ArrayIndexOutOfBoundsExceptions and NullPointerExceptions are + * detected. + * @throws java.lang.Throwable if the attempted array element assignment throws an exception + */ + @Test(priority=1,invocationCount=2) + static public void testValueTypeArrayAssignments() throws Throwable { + Object[][] testArrays = new Object[][] {new Object[2], new SomeIface[2], new PointV[2], new PointPV[2]}; + int[] kinds = {OBJ_TYPE, IFACE_TYPE, VAL_TYPE, PRIM_TYPE}; + Object[] vals = new Object[] {null, bogusIfaceObj, new PointV(1.0, 2.0), new PointPV(3.0, 4.0)}; + + for (int i = 0; i < testArrays.length; i++) { + Object[] testArray = testArrays[i]; + + for (int j = 0; j < kinds.length; j++) { + int staticArrayKind = kinds[j]; + + for (int k = 0; k < kinds.length; k++) { + int staticValueKind = kinds[k]; + // runTest's parameters are of type Object[] and Object. It ultimately dispatches to an assign + // method whose parameters have more specific static types. This condition filters out the + // combinations of static types that aren't permitted from the point of view of the Java language. + // + // Cases: + // - the two types are the same (staticArrayKind == staticValueKind) + // OR + // - the type of the array is Object[] or SomeIface[] (staticArrayKind < VAL_TYPE) + // AND + // - the type of the array is less specific than that of the source (staticArrayKind < staticValueKind) + // + if (staticArrayKind == staticValueKind + || (staticArrayKind < staticValueKind && staticArrayKind < VAL_TYPE)) { + runTest(testArrays[i], nullObj, staticArrayKind, staticValueKind); + runTest(testArrays[i], bogusIfaceObj, staticArrayKind, staticValueKind); + runTest(testArrays[i], pointVal, staticArrayKind, staticValueKind); + runTest(testArrays[i], pointPrimVal, staticArrayKind, staticValueKind); + } + } + } + } + } + + static primitive class SomePrimitiveClassWithDoubleField{ + public double d; + + SomePrimitiveClassWithDoubleField(double x) { + this.d = x; + } + } + + static primitive class SomePrimitiveClassWithFloatField{ + public float f; + + SomePrimitiveClassWithFloatField(float x) { + this.f = x; + } + } + + static primitive class SomePrimitiveClassWithLongField{ + public long l; + + SomePrimitiveClassWithLongField(long x) { + this.l = x; + } + } + + static class SomeIdentityClassWithDoubleField{ + public double d; + + SomeIdentityClassWithDoubleField(double x) { + this.d = x; + } + } + + static class SomeIdentityClassWithFloatField{ + public float f; + + SomeIdentityClassWithFloatField(float x) { + this.f = x; + } + } + + static class SomeIdentityClassWithLongField{ + public long l; + + SomeIdentityClassWithLongField(long x) { + this.l = x; + } + } + + interface SomeInterface1WithSingleImplementer {} + + interface SomeInterface2WithSingleImplementer {} + + static primitive class SomePrimitiveClassImplIf implements SomeInterface1WithSingleImplementer { + public double d; + public long l; + + SomePrimitiveClassImplIf(double val1, long val2) { + this.d = val1; + this.l = val2; + } + } + + static class SomeIdentityClassImplIf implements SomeInterface2WithSingleImplementer { + public double d; + public long l; + + SomeIdentityClassImplIf(double val1, long val2) { + this.d = val1; + this.l = val2; + } + } + + static class SomeClassHolder { + public static int ARRAY_LENGTH = 10; + SomeInterface1WithSingleImplementer[] data_1; + SomeInterface1WithSingleImplementer[] data_2; + + SomeInterface2WithSingleImplementer[] data_3; + SomeInterface2WithSingleImplementer[] data_4; + SomeInterface2WithSingleImplementer data_5; + + SomeClassHolder() { + data_1 = new SomePrimitiveClassImplIf[ARRAY_LENGTH]; + data_2 = new SomePrimitiveClassImplIf[ARRAY_LENGTH]; + + data_3 = new SomeIdentityClassImplIf[ARRAY_LENGTH]; + data_4 = new SomeIdentityClassImplIf[ARRAY_LENGTH]; + + data_5 = new SomeIdentityClassImplIf((double)(12345), (long)(12345)); + + for (int i = 0; i < ARRAY_LENGTH; i++) { + data_1[i] = new SomePrimitiveClassImplIf((double)i, (long)i); + data_2[i] = new SomePrimitiveClassImplIf((double)(i+1), (long)(i+1)); + + data_3[i] = data_5; + data_4[i] = new SomeIdentityClassImplIf((double)(i+1), (long)(i+1)); + } + } + } + + static void readArrayElementWithDoubleField(SomePrimitiveClassWithDoubleField[] data) throws Throwable { + for (int i=0; i Date: Tue, 14 Nov 2023 11:35:40 -0500 Subject: [PATCH 2/2] Update ValueTypeArrayTests for lw5 - fix formatting for qtypes and lw5 - replace primitive with null-restricted - update testStoreNullToNullRestrictedArrayElement1 and testStoreNullToNullRestrictedArrayElement2 to throw ArrayStoreException and disable tests until support for nullrestricted arrays is added - comment out ArrayStoreException for assigning null to nullrestricted array in expectedExceptionClass until support for nullrestricted arrays is added Signed-off-by: Theresa Mammarella --- .../test/lworld/ValueTypeArrayTests.java | 618 +++++++++--------- .../test/lworld/ValueTypeArrayTests.java | 512 +++++++-------- 2 files changed, 572 insertions(+), 558 deletions(-) rename test/functional/Valhalla/{src => src_lw5}/org/openj9/test/lworld/ValueTypeArrayTests.java (50%) diff --git a/test/functional/Valhalla/src/org/openj9/test/lworld/ValueTypeArrayTests.java b/test/functional/Valhalla/src_lw5/org/openj9/test/lworld/ValueTypeArrayTests.java similarity index 50% rename from test/functional/Valhalla/src/org/openj9/test/lworld/ValueTypeArrayTests.java rename to test/functional/Valhalla/src_lw5/org/openj9/test/lworld/ValueTypeArrayTests.java index a45bc18bf5e..1cc390c4ac8 100644 --- a/test/functional/Valhalla/src/org/openj9/test/lworld/ValueTypeArrayTests.java +++ b/test/functional/Valhalla/src_lw5/org/openj9/test/lworld/ValueTypeArrayTests.java @@ -53,13 +53,15 @@ static value class PointV implements SomeIface { } /** - * A simple primitive value type class + * A simple nullrestricted(flattenable) value type class */ - static primitive class PointPV implements SomeIface { + static value class PointFV implements SomeIface { double x; double y; - PointPV(double x, double y) { + public implicit PointFV(); + + PointFV(double x, double y) { this.x = x; this.y = y; } @@ -73,7 +75,7 @@ static class Bogus implements SomeIface {}; static Object nullObj = null; static SomeIface bogusIfaceObj = new Bogus(); static PointV pointVal = new PointV(1.0, 2.0); - static PointPV pointPrimVal = new PointPV(1.0, 2.0); + static PointFV! pointFlattenableVal = new PointFV(1.0, 2.0); static void assign(Object[] arr, int idx, Object value) { arr[idx] = value; @@ -87,7 +89,7 @@ static void assign(Object[] arr, int idx, PointV value) { arr[idx] = value; } - static void assign(Object[] arr, int idx, PointPV value) { + static void assign(Object[] arr, int idx, PointFV! value) { arr[idx] = value; } @@ -99,7 +101,7 @@ static void assign(SomeIface[] arr, int idx, PointV value) { arr[idx] = value; } - static void assign(SomeIface[] arr, int idx, PointPV value) { + static void assign(SomeIface[] arr, int idx, PointFV! value) { arr[idx] = value; } @@ -107,7 +109,7 @@ static void assign(PointV[] arr, int idx, PointV value) { arr[idx] = value; } - static void assign(PointPV[] arr, int idx, PointPV value) { + static void assign(PointFV![] arr, int idx, PointFV! value) { arr[idx] = value; } @@ -119,8 +121,8 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s assign(arr, idx, (SomeIface) src); } else if (srcKind == VAL_TYPE) { assign(arr, idx, (PointV) src); - } else if (srcKind == PRIM_TYPE) { - assign(arr, idx, (PointPV) src); + } else if (srcKind == FLATTENABLE_TYPE) { + assign(arr, idx, (PointFV!) src); } else { fail("Unexpected source type requested "+srcKind); } @@ -131,8 +133,8 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s assign((SomeIface[]) arr, idx, (SomeIface) src); } else if (srcKind == VAL_TYPE) { assign((SomeIface[]) arr, idx, (PointV) src); - } else if (srcKind == PRIM_TYPE) { - assign((SomeIface[]) arr, idx, (PointPV) src); + } else if (srcKind == FLATTENABLE_TYPE) { + assign((SomeIface[]) arr, idx, (PointFV!) src); } else { fail("Unexpected source type requested "+srcKind); } @@ -143,20 +145,20 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s // Meaningless combination } else if (srcKind == VAL_TYPE) { assign((PointV[]) arr, idx, (PointV) src); - } else if (srcKind == PRIM_TYPE) { + } else if (srcKind == FLATTENABLE_TYPE) { // Meaningless combination } else { fail("Unexpected source type requested "+srcKind); } - } else if (arrKind == PRIM_TYPE) { + } else if (arrKind == FLATTENABLE_TYPE) { if (srcKind == OBJ_TYPE) { // Meaningless combination } else if (srcKind == IFACE_TYPE) { // Meaningless combination } else if (srcKind == VAL_TYPE) { // Meaningless combination - } else if (srcKind == PRIM_TYPE) { - assign((PointPV[])arr, idx, (PointPV) src); + } else if (srcKind == FLATTENABLE_TYPE) { + assign((PointFV![])arr, idx, (PointFV!) src); } else { fail("Unexpected source type requested "+srcKind); } @@ -183,15 +185,15 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s /** * Represents the type PointV or PointV[]. - * {@link PointV} is a non-primitive value type class defined by this test. + * {@link PointV} is a non-flattenable value type class defined by this test. */ static final int VAL_TYPE = 3; /** - * Represents the type PointPV or PointPV[]. - * {@link PointPV} is a primitive value type class defined by this test. + * Represents the type PointFV or PointFV[]. + * {@link PointFV} is a flattenable value type class defined by this test. */ - static final int PRIM_TYPE = 4; + static final int FLATTENABLE_TYPE = 4; /** * Convenient constant reference to the ArrayIndexOutOfBoundsException class @@ -211,7 +213,7 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s /** * The expected kind of exception that will be thrown, if any, for an * assignment to an array whose component type is one of {@link #OBJ_TYPE}, - * {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #PRIM_TYPE} with a source + * {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #FLATTENABLE_TYPE} with a source * of one of those same types or {@link #NULL_REF}. * *

expectedAssignmentExceptions[actualArrayKind][actualSourceKind] @@ -221,14 +223,15 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s null, // NULL_REF for array is not a possibility new Class[] {null, null, null, null, null}, // All values can be assigned to Object[] new Class[] {null, ASE, null, null, null}, // ASE for SomeIface[] = Object - new Class[] {null, ASE, ASE, null, ASE}, // ASE for PointV[] = PointPV, SomeIface - new Class[] {NPE, ASE, ASE, ASE, null}, // NPE for PointPV[] = null; ASE for PointPV[] = PointV + new Class[] {null, ASE, ASE, null, ASE}, // ASE for PointV[] = PointFV, SomeIface + // TODO first ASE for nullrestricted null assignment disabled until OpenJ9 has full support for nullrestricted arrays + new Class[] {/*ASE*/ null, ASE, ASE, ASE, null}, // ASE for PointFV[] = null; ASE for PointFV[] = PointV }; /** * Indicates whether a value or an array with component class * that is one of {@link #NULL_REF}, {@link #OBJ_TYPE}, - * {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #PRIM_TYPE} can be + * {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #FLATTENABLE_TYPE} can be * cast to another member of that same set of types without triggering a * ClassCastException or NullPointerException * @@ -236,18 +239,18 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s */ static boolean permittedCast[][] = new boolean[][] { - new boolean[] { false, true, true, true, false }, // NULL_REF cannot be cast to primitive value + new boolean[] { false, true, true, true, false }, // NULL_REF cannot be cast to null-restricted value new boolean[] { false, true, false, false, false }, // OBJ_TYPE to Object new boolean[] { false, true, true, false, false }, // IFACE_TYPE to Object, SomeIface new boolean[] { false, true, true, true , false }, // VAL_TYPE to Object, SomeIface, PointV - new boolean[] { false, true, true, false, true } // PRIM_TYPE to Object, SomeIface, PointPV + new boolean[] { false, true, true, false, true } // FLATTENABLE_TYPE to Object, SomeIface, PointFV }; /** * Dispatch to a particular test method that will test with parameters cast to a specific pair * of static types. Those types are specified by the staticArrayKind and * staticSourceKind parameters, each of which has one of the values - * {@link #OBJ_TYPE}, {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #PRIM_TYPE}. + * {@link #OBJ_TYPE}, {@link #IFACE_TYPE}, {@link #VAL_TYPE} or {@link #FLATTENABLE_TYPE}. * * @param arr Array to which sourceVal will be assigned * @param sourceVal Value that will be assigned to an element of arr @@ -256,8 +259,8 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s */ static void runTest(Object[] arr, Object sourceVal, int staticArrayKind, int staticSourceKind) throws Throwable { boolean caughtThrowable = false; - int actualArrayKind = arr instanceof PointPV[] - ? PRIM_TYPE + int actualArrayKind = arr instanceof PointFV![] + ? FLATTENABLE_TYPE : arr instanceof PointV[] ? VAL_TYPE : arr instanceof SomeIface[] @@ -265,8 +268,8 @@ static void runTest(Object[] arr, Object sourceVal, int staticArrayKind, int sta : OBJ_TYPE; int actualSourceKind = sourceVal == null ? NULL_REF - : sourceVal instanceof PointPV - ? PRIM_TYPE + : sourceVal instanceof PointFV! + ? FLATTENABLE_TYPE : sourceVal instanceof PointV ? VAL_TYPE : sourceVal instanceof SomeIface @@ -297,7 +300,7 @@ static void runTest(Object[] arr, Object sourceVal, int staticArrayKind, int sta } // ArrayIndexOutOfBoundsException must be checked before both - // NullPointerException for primitive value type and ArrayStoreException. + // NullPointerException for null-restricted value type and ArrayStoreException. // This call to assignDispatch will attempt an out-of-bounds element assignment, // and is always expected to throw an ArrayIndexOutOfBoundsException. boolean caughtAIOOBE = false; @@ -322,9 +325,9 @@ static void runTest(Object[] arr, Object sourceVal, int staticArrayKind, int sta */ @Test(priority=1,invocationCount=2) static public void testValueTypeArrayAssignments() throws Throwable { - Object[][] testArrays = new Object[][] {new Object[2], new SomeIface[2], new PointV[2], new PointPV[2]}; - int[] kinds = {OBJ_TYPE, IFACE_TYPE, VAL_TYPE, PRIM_TYPE}; - Object[] vals = new Object[] {null, bogusIfaceObj, new PointV(1.0, 2.0), new PointPV(3.0, 4.0)}; + Object[][] testArrays = new Object[][] {new Object[2], new SomeIface[2], new PointV[2], new PointFV![2]}; + int[] kinds = {OBJ_TYPE, IFACE_TYPE, VAL_TYPE, FLATTENABLE_TYPE}; + Object[] vals = new Object[] {null, bogusIfaceObj, new PointV(1.0, 2.0), new PointFV(3.0, 4.0)}; for (int i = 0; i < testArrays.length; i++) { Object[] testArray = testArrays[i]; @@ -346,342 +349,351 @@ static public void testValueTypeArrayAssignments() throws Throwable { // - the type of the array is less specific than that of the source (staticArrayKind < staticValueKind) // if (staticArrayKind == staticValueKind - || (staticArrayKind < staticValueKind && staticArrayKind < VAL_TYPE)) { + || (staticArrayKind < staticValueKind && staticArrayKind < VAL_TYPE)) { runTest(testArrays[i], nullObj, staticArrayKind, staticValueKind); runTest(testArrays[i], bogusIfaceObj, staticArrayKind, staticValueKind); runTest(testArrays[i], pointVal, staticArrayKind, staticValueKind); - runTest(testArrays[i], pointPrimVal, staticArrayKind, staticValueKind); + runTest(testArrays[i], pointFlattenableVal, staticArrayKind, staticValueKind); } } } } } - static primitive class SomePrimitiveClassWithDoubleField{ - public double d; + static value class SomeFlattenableClassWithDoubleField { + public double d; + + public implicit SomeFlattenableClassWithDoubleField(); - SomePrimitiveClassWithDoubleField(double x) { + SomeFlattenableClassWithDoubleField(double x) { this.d = x; } - } + } - static primitive class SomePrimitiveClassWithFloatField{ - public float f; + static value class SomeFlattenableClassWithFloatField { + public float f; - SomePrimitiveClassWithFloatField(float x) { + public implicit SomeFlattenableClassWithFloatField(); + + SomeFlattenableClassWithFloatField(float x) { this.f = x; } - } + } + + static value class SomeFlattenableClassWithLongField { + public long l; - static primitive class SomePrimitiveClassWithLongField{ - public long l; + public implicit SomeFlattenableClassWithLongField(); - SomePrimitiveClassWithLongField(long x) { + SomeFlattenableClassWithLongField(long x) { this.l = x; } - } + } - static class SomeIdentityClassWithDoubleField{ - public double d; + static class SomeIdentityClassWithDoubleField{ + public double d; SomeIdentityClassWithDoubleField(double x) { this.d = x; } - } + } - static class SomeIdentityClassWithFloatField{ - public float f; + static class SomeIdentityClassWithFloatField{ + public float f; SomeIdentityClassWithFloatField(float x) { this.f = x; } - } + } - static class SomeIdentityClassWithLongField{ - public long l; + static class SomeIdentityClassWithLongField{ + public long l; SomeIdentityClassWithLongField(long x) { this.l = x; } - } + } + + interface SomeInterface1WithSingleImplementer {} - interface SomeInterface1WithSingleImplementer {} + interface SomeInterface2WithSingleImplementer {} - interface SomeInterface2WithSingleImplementer {} + static value class SomeFlattenableClassImplIf implements SomeInterface1WithSingleImplementer { + public double d; + public long l; - static primitive class SomePrimitiveClassImplIf implements SomeInterface1WithSingleImplementer { - public double d; - public long l; + public implicit SomeFlattenableClassImplIf(); - SomePrimitiveClassImplIf(double val1, long val2) { + SomeFlattenableClassImplIf(double val1, long val2) { this.d = val1; this.l = val2; } - } + } - static class SomeIdentityClassImplIf implements SomeInterface2WithSingleImplementer { - public double d; - public long l; + static class SomeIdentityClassImplIf implements SomeInterface2WithSingleImplementer { + public double d; + public long l; SomeIdentityClassImplIf(double val1, long val2) { this.d = val1; this.l = val2; } - } + } - static class SomeClassHolder { - public static int ARRAY_LENGTH = 10; - SomeInterface1WithSingleImplementer[] data_1; - SomeInterface1WithSingleImplementer[] data_2; + static class SomeClassHolder { + public static int ARRAY_LENGTH = 10; + SomeInterface1WithSingleImplementer[] data_1; + SomeInterface1WithSingleImplementer[] data_2; - SomeInterface2WithSingleImplementer[] data_3; - SomeInterface2WithSingleImplementer[] data_4; - SomeInterface2WithSingleImplementer data_5; + SomeInterface2WithSingleImplementer[] data_3; + SomeInterface2WithSingleImplementer[] data_4; + SomeInterface2WithSingleImplementer data_5; SomeClassHolder() { - data_1 = new SomePrimitiveClassImplIf[ARRAY_LENGTH]; - data_2 = new SomePrimitiveClassImplIf[ARRAY_LENGTH]; - - data_3 = new SomeIdentityClassImplIf[ARRAY_LENGTH]; - data_4 = new SomeIdentityClassImplIf[ARRAY_LENGTH]; - - data_5 = new SomeIdentityClassImplIf((double)(12345), (long)(12345)); - - for (int i = 0; i < ARRAY_LENGTH; i++) { - data_1[i] = new SomePrimitiveClassImplIf((double)i, (long)i); - data_2[i] = new SomePrimitiveClassImplIf((double)(i+1), (long)(i+1)); - - data_3[i] = data_5; - data_4[i] = new SomeIdentityClassImplIf((double)(i+1), (long)(i+1)); - } - } - } - - static void readArrayElementWithDoubleField(SomePrimitiveClassWithDoubleField[] data) throws Throwable { - for (int i=0; iClassCastException or NullPointerException * @@ -346,7 +346,7 @@ static public void testValueTypeArrayAssignments() throws Throwable { // - the type of the array is less specific than that of the source (staticArrayKind < staticValueKind) // if (staticArrayKind == staticValueKind - || (staticArrayKind < staticValueKind && staticArrayKind < VAL_TYPE)) { + || (staticArrayKind < staticValueKind && staticArrayKind < VAL_TYPE)) { runTest(testArrays[i], nullObj, staticArrayKind, staticValueKind); runTest(testArrays[i], bogusIfaceObj, staticArrayKind, staticValueKind); runTest(testArrays[i], pointVal, staticArrayKind, staticValueKind); @@ -357,317 +357,317 @@ static public void testValueTypeArrayAssignments() throws Throwable { } } - static primitive class SomePrimitiveClassWithDoubleField{ - public double d; + static primitive class SomePrimitiveClassWithDoubleField{ + public double d; SomePrimitiveClassWithDoubleField(double x) { this.d = x; } - } + } - static primitive class SomePrimitiveClassWithFloatField{ - public float f; + static primitive class SomePrimitiveClassWithFloatField{ + public float f; SomePrimitiveClassWithFloatField(float x) { this.f = x; } - } + } - static primitive class SomePrimitiveClassWithLongField{ - public long l; + static primitive class SomePrimitiveClassWithLongField{ + public long l; SomePrimitiveClassWithLongField(long x) { this.l = x; } - } + } - static class SomeIdentityClassWithDoubleField{ - public double d; + static class SomeIdentityClassWithDoubleField{ + public double d; SomeIdentityClassWithDoubleField(double x) { this.d = x; } - } + } - static class SomeIdentityClassWithFloatField{ - public float f; + static class SomeIdentityClassWithFloatField{ + public float f; SomeIdentityClassWithFloatField(float x) { this.f = x; } - } + } - static class SomeIdentityClassWithLongField{ - public long l; + static class SomeIdentityClassWithLongField{ + public long l; SomeIdentityClassWithLongField(long x) { this.l = x; } - } + } - interface SomeInterface1WithSingleImplementer {} + interface SomeInterface1WithSingleImplementer {} - interface SomeInterface2WithSingleImplementer {} + interface SomeInterface2WithSingleImplementer {} - static primitive class SomePrimitiveClassImplIf implements SomeInterface1WithSingleImplementer { - public double d; - public long l; + static primitive class SomePrimitiveClassImplIf implements SomeInterface1WithSingleImplementer { + public double d; + public long l; SomePrimitiveClassImplIf(double val1, long val2) { this.d = val1; this.l = val2; } - } + } - static class SomeIdentityClassImplIf implements SomeInterface2WithSingleImplementer { - public double d; - public long l; + static class SomeIdentityClassImplIf implements SomeInterface2WithSingleImplementer { + public double d; + public long l; SomeIdentityClassImplIf(double val1, long val2) { this.d = val1; this.l = val2; } - } + } - static class SomeClassHolder { - public static int ARRAY_LENGTH = 10; - SomeInterface1WithSingleImplementer[] data_1; - SomeInterface1WithSingleImplementer[] data_2; + static class SomeClassHolder { + public static int ARRAY_LENGTH = 10; + SomeInterface1WithSingleImplementer[] data_1; + SomeInterface1WithSingleImplementer[] data_2; - SomeInterface2WithSingleImplementer[] data_3; - SomeInterface2WithSingleImplementer[] data_4; - SomeInterface2WithSingleImplementer data_5; + SomeInterface2WithSingleImplementer[] data_3; + SomeInterface2WithSingleImplementer[] data_4; + SomeInterface2WithSingleImplementer data_5; SomeClassHolder() { - data_1 = new SomePrimitiveClassImplIf[ARRAY_LENGTH]; - data_2 = new SomePrimitiveClassImplIf[ARRAY_LENGTH]; - - data_3 = new SomeIdentityClassImplIf[ARRAY_LENGTH]; - data_4 = new SomeIdentityClassImplIf[ARRAY_LENGTH]; - - data_5 = new SomeIdentityClassImplIf((double)(12345), (long)(12345)); - - for (int i = 0; i < ARRAY_LENGTH; i++) { - data_1[i] = new SomePrimitiveClassImplIf((double)i, (long)i); - data_2[i] = new SomePrimitiveClassImplIf((double)(i+1), (long)(i+1)); - - data_3[i] = data_5; - data_4[i] = new SomeIdentityClassImplIf((double)(i+1), (long)(i+1)); - } - } - } - - static void readArrayElementWithDoubleField(SomePrimitiveClassWithDoubleField[] data) throws Throwable { - for (int i=0; i