[m-rev.] for review: fix a bug in the C# implementation of array.shrink/3

Julien Fischer jfischer at opturion.com
Thu Sep 5 16:28:33 AEST 2019


For review by Peter.

-------------------

Fix a bug in the C# implementation of array.shrink/3.

library/array.m:
    Workaround the fact that C#'s 'is' operator has some fairly surprising
    behaviour with arrays of integer types.

tests/hard_coded/array_primitives.{m,exp}:
tests/hard_coded/array_shrinks.{m,exp}:
    Improve the coverage of these tests.

Julien.

diff --git a/library/array.m b/library/array.m
index 809f836..2bb3ff6 100644
--- a/library/array.m
+++ b/library/array.m
@@ -1184,47 +1184,55 @@ ML_shrink_array(System.Array arr, int Size)
  {
      if (arr == null) {
          return null;
-    } else if (arr is int[]) {
+    }
+
+    // We need to use Item here to determine the type instead of arr itself
+    // since both 'arr is int[]' and 'arr is uint[]' evaluate to true;
+    // similarly for the other integer types.  (That behaviour is due to an
+    // inconsistency between the covariance of value-typed arrays in C# and
+    // the CLR.)
+    object Item = arr.GetValue(0);
+    if (Item is int) {
          int[] tmp = (int[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is uint[]) {
+    } else if (Item is uint) {
          uint[] tmp = (uint[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is sbyte[]) {
+    } else if (Item is sbyte) {
          sbyte[] tmp = (sbyte[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is byte[]) {
+    } else if (Item is byte) {
          byte[] tmp = (byte[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is short[]) {
+    } else if (Item is short) {
          short[] tmp = (short[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is ushort[]) {
+    } else if (Item is ushort) {
          ushort[] tmp = (ushort[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is long[]) {
+    } else if (Item is long) {
          long[] tmp = (long[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is ulong[]) {
+    } else if (Item is ulong) {
          ulong[] tmp = (ulong[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is double[]) {
+    } else if (Item is double) {
          double[] tmp = (double[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is char[]) {
+    } else if (Item is char) {
          char[] tmp = (char[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
-    } else if (arr is bool[]) {
+    } else if (Item is bool) {
          bool[] tmp = (bool[]) arr;
          System.Array.Resize(ref tmp, Size);
          return tmp;
diff --git a/tests/hard_coded/array_primitives.exp b/tests/hard_coded/array_primitives.exp
index a49b169..ec52536 100644
--- a/tests/hard_coded/array_primitives.exp
+++ b/tests/hard_coded/array_primitives.exp
@@ -70,3 +70,9 @@ generate = array(["foo", "foo", "foo", "foo", "foo"])
  resize = array(["foo", "foo", "foo", "foo", "foo", "bar", "bar"])
  shrink = array(["foo", "foo"])

+*** Testing with element type: list.list(int) ****
+init = array([[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]])
+generate = array([[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]])
+resize = array([[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [4], [4]])
+shrink = array([[1, 2, 3], [1, 2, 3]])
+
diff --git a/tests/hard_coded/array_primitives.m b/tests/hard_coded/array_primitives.m
index 8df63ea..c70300b 100644
--- a/tests/hard_coded/array_primitives.m
+++ b/tests/hard_coded/array_primitives.m
@@ -45,7 +45,8 @@ main(!IO) :-
      do_test(2u, 3u, !IO),
      do_test(2.0, 3.0, !IO),

-    do_test("foo", "bar", !IO).
+    do_test("foo", "bar", !IO),
+    do_test([1, 2, 3], [4], !IO).

  :- pred do_test(T::in, T::in, io::di, io::uo) is det.

diff --git a/tests/hard_coded/array_shrink.exp b/tests/hard_coded/array_shrink.exp
index f51004b..f31796f 100644
--- a/tests/hard_coded/array_shrink.exp
+++ b/tests/hard_coded/array_shrink.exp
@@ -19,6 +19,10 @@ Array0 = array([1, 2, 3, 4])
  Size = 5
  EXCEPTION: "predicate `array.shrink\'/3: Unexpected: cannot shrink to a larger size"
  ================
+Array0 = array([])
+Size = 0
+Array = array([])
+================
  Array0 = array([1i8, 2i8, 3i8, 4i8])
  Size = 3
  Array = array([1i8, 2i8, 3i8])
diff --git a/tests/hard_coded/array_shrink.m b/tests/hard_coded/array_shrink.m
index 11a5956..5c5b4e6 100644
--- a/tests/hard_coded/array_shrink.m
+++ b/tests/hard_coded/array_shrink.m
@@ -37,6 +37,7 @@ main(!IO) :-
      test_shrink([1, 2, 3, 4], 3, !IO),
      test_shrink([1, 2, 3, 4], 4, !IO),
      test_shrink([1, 2, 3, 4], 5, !IO),  % Should raise exception.
+    test_shrink([] : list(int), 0, !IO),
      test_shrink([1i8, 2i8, 3i8, 4i8], 3, !IO),
      test_shrink([1u8, 2u8, 3u8, 4u8], 3, !IO),
      test_shrink([1i16, 2i16, 3i16, 4i16], 3, !IO),


More information about the reviews mailing list