From 95034225a866a6ccbccb1585b78ab0e2276b2fe4 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Thu, 20 Apr 2017 10:30:38 +0700 Subject: [PATCH] stdlib: Throw NoSuchElementException from array iterators --- .../codegen/box/arrays/primitiveArrays.kt | 196 ++++++++++++++++++ .../collections/ArraysTest/iterators.kt | 54 +++++ runtime/src/main/kotlin/kotlin/Array.kt | 1 + runtime/src/main/kotlin/kotlin/Arrays.kt | 8 + 4 files changed, 259 insertions(+) create mode 100644 backend.native/tests/external/codegen/box/arrays/primitiveArrays.kt create mode 100644 backend.native/tests/external/stdlib/collections/ArraysTest/iterators.kt diff --git a/backend.native/tests/external/codegen/box/arrays/primitiveArrays.kt b/backend.native/tests/external/codegen/box/arrays/primitiveArrays.kt new file mode 100644 index 00000000000..0948cacd472 --- /dev/null +++ b/backend.native/tests/external/codegen/box/arrays/primitiveArrays.kt @@ -0,0 +1,196 @@ +// WITH_RUNTIME + +import kotlin.test.assertTrue +import kotlin.test.assertFalse +import kotlin.test.assertEquals +import kotlin.test.assertFails + +fun box(): String { + assertTrue(eqBoolean(booleanArrayOf(false), BooleanArray(1))) + assertTrue(eqBoolean(booleanArrayOf(false, true, false), BooleanArray(3) { it % 2 != 0 })) + assertTrue(eqBoolean(booleanArrayOf(true), booleanArrayOf(true).copyOf())) + assertTrue(eqBoolean(booleanArrayOf(true, false), booleanArrayOf(true).copyOf(2))) + assertTrue(eqBoolean(booleanArrayOf(true), booleanArrayOf(true, true).copyOf(1))) + assertTrue(eqBoolean(booleanArrayOf(false, true), booleanArrayOf(false) + true)) + assertTrue(eqBoolean(booleanArrayOf(false, true, false), booleanArrayOf(false) + listOf(true, false))) + assertTrue(eqBoolean(booleanArrayOf(true, false), booleanArrayOf(false, true, false, true).copyOfRange(1, 3))) + assertTrue(eqBoolean(booleanArrayOf(false, true, false, true), customBooleanArrayOf(false, *booleanArrayOf(true, false), true))) + assertTrue(booleanArrayOf(true).iterator() is BooleanIterator) + assertEquals(true, booleanArrayOf(true).iterator().nextBoolean()) + assertEquals(true, booleanArrayOf(true).iterator().next()) + assertFalse(booleanArrayOf().iterator().hasNext()) + assertTrue(assertFails { booleanArrayOf().iterator().next() } is NoSuchElementException) + + assertTrue(eqByte(byteArrayOf(0), ByteArray(1))) + assertTrue(eqByte(byteArrayOf(1, 2, 3), ByteArray(3) { (it + 1).toByte() })) + assertTrue(eqByte(byteArrayOf(1), byteArrayOf(1).copyOf())) + assertTrue(eqByte(byteArrayOf(1, 0), byteArrayOf(1).copyOf(2))) + assertTrue(eqByte(byteArrayOf(1), byteArrayOf(1, 2).copyOf(1))) + assertTrue(eqByte(byteArrayOf(1, 2), byteArrayOf(1) + 2)) + assertTrue(eqByte(byteArrayOf(1, 2, 3), byteArrayOf(1) + listOf(2.toByte(), 3.toByte()))) + assertTrue(eqByte(byteArrayOf(2, 3), byteArrayOf(1, 2, 3, 4).copyOfRange(1, 3))) + assertTrue(eqByte(byteArrayOf(1, 2, 3, 4), customByteArrayOf(1.toByte(), *byteArrayOf(2, 3), 4.toByte()))) + assertTrue(byteArrayOf(1).iterator() is ByteIterator) + assertEquals(1, byteArrayOf(1).iterator().nextByte()) + assertEquals(1, byteArrayOf(1).iterator().next()) + assertFalse(byteArrayOf().iterator().hasNext()) + assertTrue(assertFails { byteArrayOf().iterator().next() } is NoSuchElementException) + + assertTrue(eqShort(shortArrayOf(0), ShortArray(1))) + assertTrue(eqShort(shortArrayOf(1, 2, 3), ShortArray(3) { (it + 1).toShort() })) + assertTrue(eqShort(shortArrayOf(1), shortArrayOf(1).copyOf())) + assertTrue(eqShort(shortArrayOf(1, 0), shortArrayOf(1).copyOf(2))) + assertTrue(eqShort(shortArrayOf(1), shortArrayOf(1, 2).copyOf(1))) + assertTrue(eqShort(shortArrayOf(1, 2), shortArrayOf(1) + 2)) + assertTrue(eqShort(shortArrayOf(1, 2, 3), shortArrayOf(1) + listOf(2.toShort(), 3.toShort()))) + assertTrue(eqShort(shortArrayOf(2, 3), shortArrayOf(1, 2, 3, 4).copyOfRange(1, 3))) + assertTrue(eqShort(shortArrayOf(1, 2, 3, 4), customShortArrayOf(1.toShort(), *shortArrayOf(2, 3), 4.toShort()))) + assertTrue(shortArrayOf(1).iterator() is ShortIterator) + assertEquals(1, shortArrayOf(1).iterator().nextShort()) + assertEquals(1, shortArrayOf(1).iterator().next()) + assertFalse(shortArrayOf().iterator().hasNext()) + assertTrue(assertFails { shortArrayOf().iterator().next() } is NoSuchElementException) + + assertTrue(eqChar(charArrayOf(0.toChar()), CharArray(1))) + assertTrue(eqChar(charArrayOf('a', 'b', 'c'), CharArray(3) { 'a' + it })) + assertTrue(eqChar(charArrayOf('a'), charArrayOf('a').copyOf())) + assertTrue(eqChar(charArrayOf('a', 0.toChar()), charArrayOf('a').copyOf(2))) + assertTrue(eqChar(charArrayOf('a'), charArrayOf('a', 'b').copyOf(1))) + assertTrue(eqChar(charArrayOf('a', 'b'), charArrayOf('a') + 'b')) + assertTrue(eqChar(charArrayOf('a', 'b', 'c'), charArrayOf('a') + listOf('b', 'c'))) + assertTrue(eqChar(charArrayOf('b', 'c'), charArrayOf('a', 'b', 'c', 'd').copyOfRange(1, 3))) + assertTrue(eqChar(charArrayOf('a', 'b', 'c', 'd'), customCharArrayOf('a', *charArrayOf('b', 'c'), 'd'))) + assertTrue(charArrayOf('a').iterator() is CharIterator) + assertEquals('a', charArrayOf('a').iterator().nextChar()) + assertEquals('a', charArrayOf('a').iterator().next()) + assertFalse(charArrayOf().iterator().hasNext()) + assertTrue(assertFails { charArrayOf().iterator().next() } is NoSuchElementException) + + assertTrue(eqInt(intArrayOf(0), IntArray(1))) + assertTrue(eqInt(intArrayOf(1, 2, 3), IntArray(3) { it + 1 })) + assertTrue(eqInt(intArrayOf(1), intArrayOf(1).copyOf())) + assertTrue(eqInt(intArrayOf(1, 0), intArrayOf(1).copyOf(2))) + assertTrue(eqInt(intArrayOf(1), intArrayOf(1, 2).copyOf(1))) + assertTrue(eqInt(intArrayOf(1, 2), intArrayOf(1) + 2)) + assertTrue(eqInt(intArrayOf(1, 2, 3), intArrayOf(1) + listOf(2, 3))) + assertTrue(eqInt(intArrayOf(2, 3), intArrayOf(1, 2, 3, 4).copyOfRange(1, 3))) + assertTrue(eqInt(intArrayOf(1, 2, 3, 4), customIntArrayOf(1, *intArrayOf(2, 3), 4))) + assertTrue(intArrayOf(1).iterator() is IntIterator) + assertEquals(1, intArrayOf(1).iterator().nextInt()) + assertEquals(1, intArrayOf(1).iterator().next()) + assertFalse(intArrayOf().iterator().hasNext()) + assertTrue(assertFails { intArrayOf().iterator().next() } is NoSuchElementException) + + assertTrue(eqFloat(floatArrayOf(0f), FloatArray(1))) + assertTrue(eqFloat(floatArrayOf(1f, 2f, 3f), FloatArray(3) { (it + 1).toFloat() })) + assertTrue(eqFloat(floatArrayOf(1f), floatArrayOf(1f).copyOf())) + assertTrue(eqFloat(floatArrayOf(1f, 0f), floatArrayOf(1f).copyOf(2))) + assertTrue(eqFloat(floatArrayOf(1f), floatArrayOf(1f, 2f).copyOf(1))) + assertTrue(eqFloat(floatArrayOf(1f, 2f), floatArrayOf(1f) + 2f)) + assertTrue(eqFloat(floatArrayOf(1f, 2f, 3f), floatArrayOf(1f) + listOf(2f, 3f))) + assertTrue(eqFloat(floatArrayOf(2f, 3f), floatArrayOf(1f, 2f, 3f, 4f).copyOfRange(1, 3))) + assertTrue(eqFloat(floatArrayOf(1f, 2f, 3f, 4f), customFloatArrayOf(1f, *floatArrayOf(2f, 3f), 4f))) + assertTrue(floatArrayOf(1f).iterator() is FloatIterator) + assertEquals(1f, floatArrayOf(1f).iterator().nextFloat()) + assertEquals(1f, floatArrayOf(1f).iterator().next()) + assertFalse(floatArrayOf().iterator().hasNext()) + assertTrue(assertFails { floatArrayOf().iterator().next() } is NoSuchElementException) + + assertTrue(eqDouble(doubleArrayOf(0.0), DoubleArray(1))) + assertTrue(eqDouble(doubleArrayOf(1.0, 2.0, 3.0), DoubleArray(3) { (it + 1).toDouble() })) + assertTrue(eqDouble(doubleArrayOf(1.0), doubleArrayOf(1.0).copyOf())) + assertTrue(eqDouble(doubleArrayOf(1.0, 0.0), doubleArrayOf(1.0).copyOf(2))) + assertTrue(eqDouble(doubleArrayOf(1.0), doubleArrayOf(1.0, 2.0).copyOf(1))) + assertTrue(eqDouble(doubleArrayOf(1.0, 2.0), doubleArrayOf(1.0) + 2.0)) + assertTrue(eqDouble(doubleArrayOf(1.0, 2.0, 3.0), doubleArrayOf(1.0) + listOf(2.0, 3.0))) + assertTrue(eqDouble(doubleArrayOf(2.0, 3.0), doubleArrayOf(1.0, 2.0, 3.0, 4.0).copyOfRange(1, 3))) + assertTrue(eqDouble(doubleArrayOf(1.0, 2.0, 3.0, 4.0), customDoubleArrayOf(1.0, *doubleArrayOf(2.0, 3.0), 4.0))) + assertTrue(doubleArrayOf(1.0).iterator() is DoubleIterator) + assertEquals(1.0, doubleArrayOf(1.0).iterator().nextDouble()) + assertEquals(1.0, doubleArrayOf(1.0).iterator().next()) + assertFalse(doubleArrayOf().iterator().hasNext()) + assertTrue(assertFails { doubleArrayOf().iterator().next() } is NoSuchElementException) + + assertTrue(eqLong(longArrayOf(0), LongArray(1))) + assertTrue(eqLong(longArrayOf(1, 2, 3), LongArray(3) { it + 1L })) + assertTrue(eqLong(longArrayOf(1), longArrayOf(1).copyOf())) + assertTrue(eqLong(longArrayOf(1, 0), longArrayOf(1).copyOf(2))) + assertTrue(eqLong(longArrayOf(1), longArrayOf(1, 2).copyOf(1))) + assertTrue(eqLong(longArrayOf(1, 2), longArrayOf(1) + 2)) + assertTrue(eqLong(longArrayOf(1, 2, 3), longArrayOf(1) + listOf(2L, 3L))) + assertTrue(eqLong(longArrayOf(2, 3), longArrayOf(1, 2, 3, 4).copyOfRange(1, 3))) + assertTrue(eqLong(longArrayOf(1, 2, 3, 4), customLongArrayOf(1L, *longArrayOf(2, 3), 4L))) + assertTrue(longArrayOf(1).iterator() is LongIterator) + assertEquals(1L, longArrayOf(1).iterator().nextLong()) + assertEquals(1L, longArrayOf(1).iterator().next()) + assertFalse(longArrayOf().iterator().hasNext()) + assertTrue(assertFails { longArrayOf().iterator().next() } is NoSuchElementException) + + // If `is` checks work... + if (intArrayOf() is IntArray) { + assertTrue(booleanArrayOf(false) is BooleanArray) + assertTrue(byteArrayOf(0) is ByteArray) + assertTrue(shortArrayOf(0) is ShortArray) + assertTrue(charArrayOf('a') is CharArray) + assertTrue(intArrayOf(0) is IntArray) + assertTrue(floatArrayOf(0f) is FloatArray) + assertTrue(doubleArrayOf(0.0) is DoubleArray) + assertTrue(longArrayOf(0) is LongArray) + } + + // Rhino `instanceof` fails to distinguish TypedArray's + if (intArrayOf() is IntArray && (byteArrayOf() as Any) !is IntArray) { + assertTrue(checkExactArrayType(booleanArrayOf(false), booleanArray = true)) + assertTrue(checkExactArrayType(byteArrayOf(0), byteArray = true)) + assertTrue(checkExactArrayType(shortArrayOf(0), shortArray = true)) + assertTrue(checkExactArrayType(charArrayOf('a'), charArray = true)) + assertTrue(checkExactArrayType(intArrayOf(0), intArray = true)) + assertTrue(checkExactArrayType(floatArrayOf(0f), floatArray = true)) + assertTrue(checkExactArrayType(doubleArrayOf(0.0), doubleArray = true)) + assertTrue(checkExactArrayType(longArrayOf(0), longArray = true)) + assertTrue(checkExactArrayType(arrayOf(), array = true)) + } + + return "OK" +} + +fun eqBoolean(expected: BooleanArray, actual: BooleanArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } +fun eqByte(expected: ByteArray, actual: ByteArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } +fun eqShort(expected: ShortArray, actual: ShortArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } +fun eqChar(expected: CharArray, actual: CharArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } +fun eqInt(expected: IntArray, actual: IntArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } +fun eqLong(expected: LongArray, actual: LongArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } +fun eqFloat(expected: FloatArray, actual: FloatArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } +fun eqDouble(expected: DoubleArray, actual: DoubleArray): Boolean = actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v } + +fun customBooleanArrayOf(vararg arr: Boolean): BooleanArray = arr +fun customByteArrayOf(vararg arr: Byte): ByteArray = arr +fun customShortArrayOf(vararg arr: Short): ShortArray = arr +fun customCharArrayOf(vararg arr: Char): CharArray = arr +fun customIntArrayOf(vararg arr: Int): IntArray = arr +fun customFloatArrayOf(vararg arr: Float): FloatArray = arr +fun customDoubleArrayOf(vararg arr: Double): DoubleArray = arr +fun customLongArrayOf(vararg arr: Long): LongArray = arr + +fun checkExactArrayType( + a: Any?, + booleanArray: Boolean = false, + byteArray: Boolean = false, + shortArray: Boolean = false, + charArray: Boolean = false, + intArray: Boolean = false, + longArray: Boolean = false, + floatArray: Boolean = false, + doubleArray: Boolean = false, + array: Boolean = false +): Boolean { + return a is BooleanArray == booleanArray && + a is ByteArray == byteArray && + a is ShortArray == shortArray && + a is CharArray == charArray && + a is IntArray == intArray && + a is LongArray == longArray && + a is FloatArray == floatArray && + a is DoubleArray == doubleArray && + a is Array<*> == array +} \ No newline at end of file diff --git a/backend.native/tests/external/stdlib/collections/ArraysTest/iterators.kt b/backend.native/tests/external/stdlib/collections/ArraysTest/iterators.kt new file mode 100644 index 00000000000..4c2260cbef1 --- /dev/null +++ b/backend.native/tests/external/stdlib/collections/ArraysTest/iterators.kt @@ -0,0 +1,54 @@ +import kotlin.test.* + +public fun compare(expected: T, actual: T, block:CompareContext.() -> Unit) { + CompareContext(expected, actual).block() +} + +public class CompareContext(public val expected: T, public val actual: T) { + + public fun equals(message: String = "") { + assertEquals(expected, actual, message) + } + public fun

propertyEquals(message: String = "", getter: T.() -> P) { + assertEquals(expected.getter(), actual.getter(), message) + } + public fun propertyFails(getter: T.() -> Unit) { assertFailEquals({expected.getter()}, {actual.getter()}) } + public fun

compareProperty(getter: T.() -> P, block: CompareContext

.() -> Unit) { + compare(expected.getter(), actual.getter(), block) + } + + private fun assertFailEquals(expected: () -> Unit, actual: () -> Unit) { + val expectedFail = assertFails(expected) + val actualFail = assertFails(actual) + //assertEquals(expectedFail != null, actualFail != null) + assertTypeEquals(expectedFail, actualFail) + } +} + +public fun CompareContext>.iteratorBehavior() { + propertyEquals { hasNext() } + + while (expected.hasNext()) { + propertyEquals { next() } + propertyEquals { hasNext() } + } + propertyFails { next() } +} + +fun box() { + fun checkContract(array: T, toList: T.() -> List, iterator: T.() -> Iterator) = + compare(array.toList().iterator(), array.iterator()) { + iteratorBehavior() + } + + checkContract(arrayOf("a", "b", "c"), { toList() }, { iterator() }) + checkContract(intArrayOf(), { toList() }, { iterator() }) + checkContract(intArrayOf(1, 2, 3), { toList() }, { iterator() }) + checkContract(shortArrayOf(1, 2, 3), { toList() }, { iterator() }) + checkContract(byteArrayOf(1, 2, 3), { toList() }, { iterator() }) + checkContract(longArrayOf(1L, 2L, 3L), { toList() }, { iterator() }) + checkContract(doubleArrayOf(2.0, 3.0, 9.0), { toList() }, { iterator() }) + checkContract(floatArrayOf(2f, 3f, 9f), { toList() }, { iterator() }) + checkContract(charArrayOf('a', 'b', 'c'), { toList() }, { iterator() }) + checkContract(booleanArrayOf(true, false), { toList() }, { iterator() }) +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/Array.kt b/runtime/src/main/kotlin/kotlin/Array.kt index d2a065e2290..bc092ac20e5 100644 --- a/runtime/src/main/kotlin/kotlin/Array.kt +++ b/runtime/src/main/kotlin/kotlin/Array.kt @@ -54,6 +54,7 @@ private class IteratorImpl(val collection: Array) : Iterator { var index : Int = 0 public override fun next(): T { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } diff --git a/runtime/src/main/kotlin/kotlin/Arrays.kt b/runtime/src/main/kotlin/kotlin/Arrays.kt index 3994571c58d..c5d39975baa 100644 --- a/runtime/src/main/kotlin/kotlin/Arrays.kt +++ b/runtime/src/main/kotlin/kotlin/Arrays.kt @@ -70,6 +70,7 @@ private class ByteIteratorImpl(val collection: ByteArray) : ByteIterator() { var index : Int = 0 public override fun nextByte(): Byte { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } @@ -119,6 +120,7 @@ private class CharIteratorImpl(val collection: CharArray) : CharIterator() { var index : Int = 0 public override fun nextChar(): Char { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } @@ -168,6 +170,7 @@ private class ShortIteratorImpl(val collection: ShortArray) : ShortIterator() { var index : Int = 0 public override fun nextShort(): Short { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } @@ -217,6 +220,7 @@ private class IntIteratorImpl(val collection: IntArray) : IntIterator() { var index : Int = 0 public override fun nextInt(): Int { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } @@ -266,6 +270,7 @@ private class LongIteratorImpl(val collection: LongArray) : LongIterator() { var index : Int = 0 public override fun nextLong(): Long { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } @@ -315,6 +320,7 @@ private class FloatIteratorImpl(val collection: FloatArray) : FloatIterator() { var index : Int = 0 public override fun nextFloat(): Float { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } @@ -360,6 +366,7 @@ private class DoubleIteratorImpl(val collection: DoubleArray) : DoubleIterator() var index : Int = 0 public override fun nextDouble(): Double { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] } @@ -405,6 +412,7 @@ private class BooleanIteratorImpl(val collection: BooleanArray) : BooleanIterato var index : Int = 0 public override fun nextBoolean(): Boolean { + if (!hasNext()) throw NoSuchElementException("$index") return collection[index++] }