From 1425b74cc6b5d61253b88655cca27467c9a77596 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 17 Aug 2024 18:31:55 +0200 Subject: [PATCH] Fix Array.appendAll() arraycopy type mismatch (#2795) Internal `Array.appendAll` optimizations sometimes would result in returning arrays of the wrong type. ```java private interface SomeInterface { } enum OneEnum implements SomeInterface { A1, A2, A3; } enum SecondEnum implements SomeInterface { A1, A2, A3; } public static void main(String[] args) { Array empty = Array.empty(); Array copy1 = empty.appendAll(Array.of(OneEnum.values())); Array copy2 = copy1.appendAll(Array.of(SecondEnum.values())); } ``` ---- fixes: https://github.com/vavr-io/vavr/issues/2781 --- .../main/java/io/vavr/collection/Array.java | 2 +- .../io/vavr/collection/AbstractSeqTest.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/vavr/src/main/java/io/vavr/collection/Array.java b/vavr/src/main/java/io/vavr/collection/Array.java index 80c424e71..c995bfdbe 100644 --- a/vavr/src/main/java/io/vavr/collection/Array.java +++ b/vavr/src/main/java/io/vavr/collection/Array.java @@ -621,7 +621,7 @@ public Array appendAll(Iterable elements) { if (source.length == 0) { return this; } else { - final Object[] arr = copyOf(delegate, delegate.length + source.length); + final Object[] arr = copyOf(delegate, delegate.length + source.length, Object[].class); System.arraycopy(source, 0, arr, delegate.length, source.length); return wrap(arr); } diff --git a/vavr/src/test/java/io/vavr/collection/AbstractSeqTest.java b/vavr/src/test/java/io/vavr/collection/AbstractSeqTest.java index d2c195e4a..fc0e1bfe6 100644 --- a/vavr/src/test/java/io/vavr/collection/AbstractSeqTest.java +++ b/vavr/src/test/java/io/vavr/collection/AbstractSeqTest.java @@ -228,6 +228,16 @@ public void shouldAppendAllNonNilToNonNil() { assertThat(actual).isEqualTo(expected); } + @Test + public void shouldAppendAllWhenUsedWithTypeHierarchy() { + final Seq empty = of(); + final Seq all = empty + .appendAll(of(OneEnum.values())) + .appendAll(of(SecondEnum.values())); + + assertThat(all).isEqualTo(this.of(OneEnum.A1, OneEnum.A2, OneEnum.A3, SecondEnum.A1, SecondEnum.A2, SecondEnum.A3)); + } + @Test public void shouldReturnSameSeqWhenEmptyAppendAllEmpty() { final Seq empty = empty(); @@ -2276,4 +2286,14 @@ public void shouldTestIndexedSeqEndsWithNonIndexedSeq() { assertThat(of(1, 2, 3, 4).endsWith(Stream.of(2, 3, 5))).isFalse(); } + private interface SomeInterface { + } + + enum OneEnum implements SomeInterface { + A1, A2, A3; + } + + enum SecondEnum implements SomeInterface { + A1, A2, A3; + } }