Skip to content

Commit 1f55244

Browse files
committed
Add mapNull and nullForGC to ScalaRunTime
1 parent 2819fa5 commit 1f55244

File tree

10 files changed

+42
-35
lines changed

10 files changed

+42
-35
lines changed

library-js/src/scala/runtime/ScalaRunTime.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,14 @@ object ScalaRunTime {
252252
case s => s + "\n"
253253
}
254254

255+
255256
// For backward compatibility with code compiled without -Yexplicit-nulls.
256257
// If `a` is null, return null; otherwise, return `f`.
257-
// Have to add a private mapNull here to avoid errors
258-
private inline def mapNull[A, B](a: A, inline f: B): B =
259-
if((a: A | Null) == null) null.asInstanceOf[B] else f
258+
private[scala] inline def mapNull[A, B](a: A, inline f: B): B =
259+
if ((a: A | Null) == null) null.asInstanceOf[B] else f
260+
261+
// Use `null` in places where we want to make sure the reference is cleared.
262+
private[scala] inline def nullForGC[T]: T = null.asInstanceOf[T]
260263

261264
// For the following functions, both the parameter and the return type are non-nullable.
262265
// However, if a null reference is passed explicitly, this method will still return null.
@@ -266,11 +269,8 @@ object ScalaRunTime {
266269
// Convert arrays to immutable.ArraySeq for use with Java varargs:
267270
def genericWrapArray[T](xs: Array[T]): ArraySeq[T] =
268271
mapNull(xs, ArraySeq.unsafeWrapArray(xs))
269-
def wrapRefArray[T <: AnyRef | Null](xs: Array[T]): ArraySeq[T] = {
270-
if (xs eq null) null.asInstanceOf[ArraySeq[T]]
271-
else if (xs.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq[T]]
272-
else new ArraySeq.ofRef[T](xs)
273-
}
272+
def wrapRefArray[T <: AnyRef | Null](xs: Array[T]): ArraySeq[T] =
273+
mapNull(xs, if (xs.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq[T]] else new ArraySeq.ofRef[T](xs))
274274
def wrapIntArray(xs: Array[Int]): ArraySeq[Int] = mapNull(xs, new ArraySeq.ofInt(xs))
275275
def wrapDoubleArray(xs: Array[Double]): ArraySeq[Double] = mapNull(xs, new ArraySeq.ofDouble(xs))
276276
def wrapLongArray(xs: Array[Long]): ArraySeq[Long] = mapNull(xs, new ArraySeq.ofLong(xs))

library/src/scala/IArray.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,9 @@ object IArray:
332332

333333
// For backward compatibility with code compiled without -Yexplicit-nulls.
334334
// If `a` is null, return null; otherwise, return `f`.
335-
// Have to add a private mapNull here to avoid errors
335+
// Have to add a private mapNull here to avoid errors, use `ScalaRunTime.mapNull` in the future.
336336
private inline def mapNull[A, B](a: A, inline f: B): B =
337-
if((a: A | Null) == null) null.asInstanceOf[B] else f
337+
if ((a: A | Null) == null) null.asInstanceOf[B] else f
338338

339339
// For the following functions, both the parameter and the return type are non-nullable.
340340
// However, if a null reference is passed explicitly, this method will still return null.

library/src/scala/Predef.scala

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import scala.annotation.{elidable, experimental, implicitNotFound, publicInBinar
2020
import scala.annotation.meta.{ companionClass, companionMethod }
2121
import scala.annotation.internal.{ RuntimeChecked }
2222
import scala.compiletime.summonFrom
23+
import scala.runtime.ScalaRunTime.mapNull
2324

2425
/** The `Predef` object provides definitions that are accessible in all Scala
2526
* compilation units without explicit qualification.
@@ -597,14 +598,6 @@ object Predef extends LowPriorityImplicits {
597598
@experimental
598599
inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]]
599600

600-
// For backward compatibility with code compiled without -Yexplicit-nulls.
601-
// If `a` is null, return null; otherwise, return `f`.
602-
private[scala] inline def mapNull[A, B](a: A, inline f: B): B =
603-
if((a: A | Null) == null) null.asInstanceOf[B] else f
604-
605-
// Use `null` in places where we want to make sure the reference is cleared.
606-
private[scala] inline def nullForGC[T]: T = null.asInstanceOf[T]
607-
608601
/** A type supporting Self-based type classes.
609602
*
610603
* A is TC

library/src/scala/collection/Iterator.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import language.experimental.captureChecking
1717
import scala.collection.mutable.{ArrayBuffer, ArrayBuilder, Builder, ImmutableBuilder}
1818
import scala.annotation.tailrec
1919
import scala.annotation.unchecked.uncheckedVariance
20+
import scala.runtime.ScalaRunTime.nullForGC
2021
import scala.runtime.Statics
2122

2223
/** Iterators are data structures that allow to iterate over a sequence
@@ -772,14 +773,14 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
772773
case 1 => if (self.hasNext) { status = 2 ; true } else { status = 3 ; false }
773774
case 0 => true
774775
case _ =>
775-
if (myLeading.finish()) { status = 0 ; true } else { status = 1 ; myLeading = null.asInstanceOf[Leading]; hasNext }
776+
if (myLeading.finish()) { status = 0 ; true } else { status = 1 ; myLeading = nullForGC[Leading]; hasNext }
776777
}
777778
def next() = {
778779
if (hasNext) {
779780
if (status == 0) {
780781
status = 1
781782
val res = myLeading.trailer
782-
myLeading = null.asInstanceOf[Leading]
783+
myLeading = nullForGC[Leading]
783784
res
784785
} else {
785786
status = 1
@@ -1301,7 +1302,7 @@ object Iterator extends IterableFactory[Iterator] {
13011302
if (res eq null) throw new NullPointerException("null during unfold")
13021303
res
13031304
}
1304-
state = null.asInstanceOf[S] // allow GC
1305+
state = nullForGC[S]
13051306
}
13061307
nextResult.nn.isDefined
13071308
}

library/src/scala/collection/SeqView.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import language.experimental.captureChecking
1818

1919
import scala.annotation.nowarn
2020
import scala.collection.generic.CommonErrors
21+
import scala.runtime.ScalaRunTime.nullForGC
2122

2223

2324
trait SeqView[+A] extends SeqOps[A, View, View[A]] with View[A] {
@@ -187,7 +188,7 @@ object SeqView {
187188
}
188189
}
189190
evaluated = true
190-
underlying = nullForGC[SomeSeqOps[A]] // allow GC of unneeded reference
191+
underlying = nullForGC[SomeSeqOps[A]]
191192
res
192193
}
193194

library/src/scala/collection/View.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import language.experimental.captureChecking
1818
import scala.annotation.{nowarn, tailrec}
1919
import scala.collection.mutable.{ArrayBuffer, Builder}
2020
import scala.collection.immutable.LazyList
21+
import scala.runtime.ScalaRunTime.nullForGC
2122
import caps.unsafe.unsafeAssumePure
2223

2324
/** Views are collections whose transformation operations are non strict: the resulting elements
@@ -465,7 +466,7 @@ object View extends IterableFactory[View] {
465466
if(pos == maxlen) pos = 0
466467
len += 1
467468
}
468-
underlying = null.asInstanceOf[Iterator[A]] // allow GC of underlying iterator
469+
underlying = nullForGC[Iterator[A]]
469470
if(len > maxlen) len = maxlen
470471
pos = pos - len
471472
if(pos < 0) pos += maxlen

library/src/scala/collection/immutable/Stream.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import scala.annotation.unchecked.uncheckedVariance
2323
import scala.collection.generic.SerializeEnd
2424
import scala.collection.mutable.{ArrayBuffer, StringBuilder}
2525
import scala.language.implicitConversions
26+
import scala.runtime.ScalaRunTime.nullForGC
27+
2628
import Stream.cons
2729

2830
@deprecated("Use LazyListIterable (which is fully lazy) instead of Stream (which has a lazy tail only)", "2.13.0")

library/src/scala/collection/immutable/Vector.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import scala.collection.generic.{CommonErrors, DefaultSerializable}
2727
import scala.collection.immutable.VectorInline._
2828
import scala.collection.immutable.VectorStatics._
2929
import scala.collection.mutable.ReusableBuilder
30-
30+
import scala.runtime.ScalaRunTime.nullForGC
3131

3232
/** $factoryInfo
3333
* @define Coll `Vector`
@@ -1421,11 +1421,11 @@ final class VectorBuilder[A] extends ReusableBuilder[A, Vector[A]] {
14211421
@inline def nonEmpty: Boolean = knownSize != 0
14221422

14231423
def clear(): Unit = {
1424-
a6 = null.asInstanceOf[Arr6]
1425-
a5 = null.asInstanceOf[Arr5]
1426-
a4 = null.asInstanceOf[Arr4]
1427-
a3 = null.asInstanceOf[Arr3]
1428-
a2 = null.asInstanceOf[Arr2]
1424+
a6 = nullForGC[Arr6]
1425+
a5 = nullForGC[Arr5]
1426+
a4 = nullForGC[Arr4]
1427+
a3 = nullForGC[Arr3]
1428+
a2 = nullForGC[Arr2]
14291429
a1 = new Arr1(WIDTH)
14301430
len1 = 0
14311431
lenRest = 0

library/src/scala/runtime/ScalaRunTime.scala

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ object ScalaRunTime {
5454
classTag[T].runtimeClass.asInstanceOf[jClass[T]]
5555

5656
/** Retrieve generic array element */
57-
def array_apply(xs: AnyRef | Null, idx: Int): Any = {
57+
def array_apply(xs: AnyRef, idx: Int): Any = {
5858
(xs: @unchecked) match {
5959
case x: Array[AnyRef] => x(idx).asInstanceOf[Any]
6060
case x: Array[Int] => x(idx).asInstanceOf[Any]
@@ -70,7 +70,7 @@ object ScalaRunTime {
7070
}
7171

7272
/** update generic array element */
73-
def array_update(xs: AnyRef | Null, idx: Int, value: Any): Unit = {
73+
def array_update(xs: AnyRef, idx: Int, value: Any): Unit = {
7474
(xs: @unchecked) match {
7575
case x: Array[AnyRef] => x(idx) = value.asInstanceOf[AnyRef]
7676
case x: Array[Int] => x(idx) = value.asInstanceOf[Int]
@@ -86,11 +86,11 @@ object ScalaRunTime {
8686
}
8787

8888
/** Get generic array length */
89-
@inline def array_length(xs: AnyRef | Null): Int = java.lang.reflect.Array.getLength(xs)
89+
@inline def array_length(xs: AnyRef): Int = java.lang.reflect.Array.getLength(xs)
9090

9191
// TODO: bytecode Object.clone() will in fact work here and avoids
9292
// the type switch. See Array_clone comment in BCodeBodyBuilder.
93-
def array_clone(xs: AnyRef | Null): AnyRef = (xs: @unchecked) match {
93+
def array_clone(xs: AnyRef): AnyRef = (xs: @unchecked) match {
9494
case x: Array[AnyRef] => x.clone()
9595
case x: Array[Int] => x.clone()
9696
case x: Array[Double] => x.clone()
@@ -107,7 +107,7 @@ object ScalaRunTime {
107107
* Needed to deal with vararg arguments of primitive types that are passed
108108
* to a generic Java vararg parameter T ...
109109
*/
110-
def toObjectArray(src: AnyRef | Null): Array[Object] = {
110+
def toObjectArray(src: AnyRef): Array[Object] = {
111111
def copy[@specialized T <: AnyVal](src: Array[T]): Array[Object] = {
112112
val length = src.length
113113
if (length == 0) Array.emptyObjectArray
@@ -281,6 +281,14 @@ object ScalaRunTime {
281281
case s => s + "\n"
282282
}
283283

284+
// For backward compatibility with code compiled without -Yexplicit-nulls.
285+
// If `a` is null, return null; otherwise, return `f`.
286+
private[scala] inline def mapNull[A, B](a: A, inline f: B): B =
287+
if ((a: A | Null) == null) null.asInstanceOf[B] else f
288+
289+
// Use `null` in places where we want to make sure the reference is cleared.
290+
private[scala] inline def nullForGC[T]: T = null.asInstanceOf[T]
291+
284292
// Convert arrays to immutable.ArraySeq for use with Scala varargs.
285293
// By construction, calls to these methods always receive a fresh (and non-null), non-empty array.
286294
// In cases where an empty array would appear, the compiler uses a direct reference to Nil instead.

library/src/scala/util/Using.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ package scala.util
1414

1515
import scala.language.`2.13`
1616
import scala.util.control.{ControlThrowable, NonFatal}
17+
import scala.runtime.ScalaRunTime.nullForGC
1718

1819
/** A utility for performing automatic resource management. It can be used to perform an
1920
* operation using resources, after which it releases the resources in reverse order
@@ -208,7 +209,7 @@ object Using {
208209
} finally {
209210
closed = true
210211
var rs = resources
211-
resources = null.asInstanceOf[List[Resource[_]]] // allow GC, in case something is holding a reference to `this`
212+
resources = nullForGC[List[Resource[_]]] // allow GC, in case something is holding a reference to `this`
212213
while (rs != null && rs.nonEmpty) {
213214
val resource = rs.head
214215
rs = rs.tail

0 commit comments

Comments
 (0)