Skip to content

Commit dd0b0f7

Browse files
committed
Do not catch {Array,String}IndexOutOfBoundsException.
That does not work in Scala.js, where these exceptions are undefined behavior. See https://www.scala-js.org/doc/semantics.html#undefined-behaviors Instead, perform bounds checks ahead of running into the IOOB.
1 parent 477d2a5 commit dd0b0f7

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

library/src/scala/collection/ArrayOps.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,12 @@ object ArrayOps {
125125
private[this] val len = xs.length
126126
override def knownSize: Int = len - pos
127127
def hasNext: Boolean = pos < len
128-
def next(): A = try {
128+
def next(): A = {
129+
if (pos >= xs.length) Iterator.empty.next()
129130
val r = xs(pos)
130131
pos += 1
131132
r
132-
} catch { case _: ArrayIndexOutOfBoundsException => Iterator.empty.next() }
133+
}
133134
override def drop(n: Int): Iterator[A] = {
134135
if (n > 0) {
135136
val newPos = pos + n
@@ -145,11 +146,12 @@ object ArrayOps {
145146
private final class ReverseIterator[@specialized(Specializable.Everything) A](xs: Array[A]) extends AbstractIterator[A] with Serializable {
146147
private[this] var pos = xs.length-1
147148
def hasNext: Boolean = pos >= 0
148-
def next(): A = try {
149+
def next(): A = {
150+
if (pos < 0) Iterator.empty.next()
149151
val r = xs(pos)
150152
pos -= 1
151153
r
152-
} catch { case _: ArrayIndexOutOfBoundsException => Iterator.empty.next() }
154+
}
153155

154156
override def drop(n: Int): Iterator[A] = {
155157
if (n > 0) pos = Math.max( -1, pos - n)
@@ -227,14 +229,14 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal {
227229
* @return the first element of this array.
228230
* @throws NoSuchElementException if the array is empty.
229231
*/
230-
def head: A = try xs.apply(0) catch { case _: ArrayIndexOutOfBoundsException => throw new NoSuchElementException("head of empty array") }
232+
def head: A = if (nonEmpty) xs.apply(0) else throw new NoSuchElementException("head of empty array")
231233

232234
/** Selects the last element.
233235
*
234236
* @return The last element of this array.
235237
* @throws NoSuchElementException If the array is empty.
236238
*/
237-
def last: A = try xs.apply(xs.length-1) catch { case _: ArrayIndexOutOfBoundsException => throw new NoSuchElementException("last of empty array") }
239+
def last: A = if (nonEmpty) xs.apply(xs.length-1) else throw new NoSuchElementException("last of empty array")
238240

239241
/** Optionally selects the first element.
240242
*
@@ -500,7 +502,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal {
500502
* @tparam A2 the element type of the second resulting collection
501503
* @param f the 'split function' mapping the elements of this array to an [[scala.util.Either]]
502504
*
503-
* @return a pair of arrays: the first one made of those values returned by `f` that were wrapped in [[scala.util.Left]],
505+
* @return a pair of arrays: the first one made of those values returned by `f` that were wrapped in [[scala.util.Left]],
504506
* and the second one made of those wrapped in [[scala.util.Right]]. */
505507
def partitionMap[A1: ClassTag, A2: ClassTag](f: A => Either[A1, A2]): (Array[A1], Array[A2]) = {
506508
val res1 = ArrayBuilder.make[A1]

library/src/scala/collection/StringOps.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,23 @@ object StringOps {
3333
private class StringIterator(private[this] val s: String) extends AbstractIterator[Char] {
3434
private[this] var pos = 0
3535
def hasNext: Boolean = pos < s.length
36-
def next(): Char = try {
36+
def next(): Char = {
37+
if (pos >= s.length) Iterator.empty.next()
3738
val r = s.charAt(pos)
3839
pos += 1
3940
r
40-
} catch { case _: IndexOutOfBoundsException => Iterator.empty.next() }
41+
}
4142
}
4243

4344
private class ReverseIterator(private[this] val s: String) extends AbstractIterator[Char] {
4445
private[this] var pos = s.length-1
4546
def hasNext: Boolean = pos >= 0
46-
def next(): Char = try {
47+
def next(): Char = {
48+
if (pos < 0) Iterator.empty.next()
4749
val r = s.charAt(pos)
4850
pos -= 1
4951
r
50-
} catch { case _: IndexOutOfBoundsException => Iterator.empty.next() }
52+
}
5153
}
5254

5355
private class GroupedIterator(s: String, groupSize: Int) extends AbstractIterator[String] {

0 commit comments

Comments
 (0)