diff --git a/library/src/scala/IArray.scala b/library/src/scala/IArray.scala index c5679ae7aaf9..72124bdf8215 100644 --- a/library/src/scala/IArray.scala +++ b/library/src/scala/IArray.scala @@ -328,54 +328,59 @@ object IArray: extension [T, U >: T: ClassTag](x: T) def +:(arr: IArray[U]): IArray[U] = genericArrayOps(arr).prepended(x) + // For backwards compatibility with code compiled without -Yexplicit-nulls + private inline def mapNull[A, B](a: A, inline f: B): B = + if((a: A|Null) == null) null.asInstanceOf[B] else f + /** Conversion from IArray to immutable.ArraySeq */ implicit def genericWrapArray[T](arr: IArray[T]): ArraySeq[T] = - if arr eq null then null else ArraySeq.unsafeWrapArray(arr) + mapNull(arr, ArraySeq.unsafeWrapArray(arr)) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapRefArray[T <: AnyRef](arr: IArray[T]): ArraySeq.ofRef[T] = // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef] // is as good as another for all T <: AnyRef. Instead of creating 100,000,000 // unique ones by way of this implicit, let's share one. - if (arr eq null) null - else if (arr.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq.ofRef[T]] - else ArraySeq.ofRef(arr.asInstanceOf[Array[T]]) + mapNull(arr, + if (arr.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq.ofRef[T]] + else ArraySeq.ofRef(arr.asInstanceOf[Array[T]]) + ) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapIntArray(arr: IArray[Int]): ArraySeq.ofInt = - if (arr ne null) new ArraySeq.ofInt(arr.asInstanceOf[Array[Int]]) else null + mapNull(arr, new ArraySeq.ofInt(arr.asInstanceOf[Array[Int]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapDoubleIArray(arr: IArray[Double]): ArraySeq.ofDouble = - if (arr ne null) new ArraySeq.ofDouble(arr.asInstanceOf[Array[Double]]) else null + mapNull(arr, new ArraySeq.ofDouble(arr.asInstanceOf[Array[Double]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapLongIArray(arr: IArray[Long]): ArraySeq.ofLong = - if (arr ne null) new ArraySeq.ofLong(arr.asInstanceOf[Array[Long]]) else null + mapNull(arr, new ArraySeq.ofLong(arr.asInstanceOf[Array[Long]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapFloatIArray(arr: IArray[Float]): ArraySeq.ofFloat = - if (arr ne null) new ArraySeq.ofFloat(arr.asInstanceOf[Array[Float]]) else null + mapNull(arr, new ArraySeq.ofFloat(arr.asInstanceOf[Array[Float]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapCharIArray(arr: IArray[Char]): ArraySeq.ofChar = - if (arr ne null) new ArraySeq.ofChar(arr.asInstanceOf[Array[Char]]) else null + mapNull(arr, new ArraySeq.ofChar(arr.asInstanceOf[Array[Char]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapByteIArray(arr: IArray[Byte]): ArraySeq.ofByte = - if (arr ne null) new ArraySeq.ofByte(arr.asInstanceOf[Array[Byte]]) else null + mapNull(arr, new ArraySeq.ofByte(arr.asInstanceOf[Array[Byte]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapShortIArray(arr: IArray[Short]): ArraySeq.ofShort = - if (arr ne null) new ArraySeq.ofShort(arr.asInstanceOf[Array[Short]]) else null + mapNull(arr, new ArraySeq.ofShort(arr.asInstanceOf[Array[Short]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapBooleanIArray(arr: IArray[Boolean]): ArraySeq.ofBoolean = - if (arr ne null) new ArraySeq.ofBoolean(arr.asInstanceOf[Array[Boolean]]) else null + mapNull(arr, new ArraySeq.ofBoolean(arr.asInstanceOf[Array[Boolean]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapUnitIArray(arr: IArray[Unit]): ArraySeq.ofUnit = - if (arr ne null) new ArraySeq.ofUnit(arr.asInstanceOf[Array[Unit]]) else null + mapNull(arr, new ArraySeq.ofUnit(arr.asInstanceOf[Array[Unit]])) /** Convert an array into an immutable array without copying, the original array * must _not_ be mutated after this or the guaranteed immutablity of IArray will diff --git a/library/src/scala/reflect/Selectable.scala b/library/src/scala/reflect/Selectable.scala index 0286eba5a35e..f0bc1f197f5d 100644 --- a/library/src/scala/reflect/Selectable.scala +++ b/library/src/scala/reflect/Selectable.scala @@ -21,7 +21,7 @@ trait Selectable extends scala.Selectable: final def selectDynamic(name: String): Any = val rcls = selectedValue.getClass try - val fld = rcls.getField(name) + val fld = rcls.getField(name).nn ensureAccessible(fld) fld.get(selectedValue) catch case ex: NoSuchFieldException => @@ -35,7 +35,7 @@ trait Selectable extends scala.Selectable: */ final def applyDynamic(name: String, paramTypes: Class[_]*)(args: Any*): Any = val rcls = selectedValue.getClass - val mth = rcls.getMethod(name, paramTypes: _*) + val mth = rcls.getMethod(name, paramTypes: _*).nn ensureAccessible(mth) mth.invoke(selectedValue, args.asInstanceOf[Seq[AnyRef]]: _*) diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index 79a2afc9cb9b..85ca4f5cb3a0 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -5,13 +5,13 @@ package scala.runtime */ object LazyVals { private[this] val unsafe: sun.misc.Unsafe = - classOf[sun.misc.Unsafe].getDeclaredFields.find { field => - field.getType == classOf[sun.misc.Unsafe] && { - field.setAccessible(true) + classOf[sun.misc.Unsafe].getDeclaredFields.nn.find { field => + field.nn.getType == classOf[sun.misc.Unsafe] && { + field.nn.setAccessible(true) true } } - .map(_.get(null).asInstanceOf[sun.misc.Unsafe]) + .map(_.nn.get(null).asInstanceOf[sun.misc.Unsafe]) .getOrElse { throw new ExceptionInInitializerError { new IllegalStateException("Can't find instance of sun.misc.Unsafe") @@ -19,7 +19,7 @@ object LazyVals { } private[this] val base: Int = { - val processors = java.lang.Runtime.getRuntime.availableProcessors() + val processors = java.lang.Runtime.getRuntime.nn.availableProcessors() 8 * processors * processors } private[this] val monitors: Array[Object] = diff --git a/library/src/scala/runtime/Scala3RunTime.scala b/library/src/scala/runtime/Scala3RunTime.scala index fa141628ceec..b1645f5242aa 100644 --- a/library/src/scala/runtime/Scala3RunTime.scala +++ b/library/src/scala/runtime/Scala3RunTime.scala @@ -15,7 +15,8 @@ object Scala3RunTime: * Extracted to minimize the bytecode size at call site. */ def nn[T](x: T | Null): x.type & T = - if (x == null) throw new NullPointerException("tried to cast away nullability, but value is null") + val isNull = x == null + if (isNull) throw new NullPointerException("tried to cast away nullability, but value is null") else x.asInstanceOf[x.type & T] end Scala3RunTime diff --git a/library/src/scala/util/FromDigits.scala b/library/src/scala/util/FromDigits.scala index 1c5346ad6b97..1577f4103e03 100644 --- a/library/src/scala/util/FromDigits.scala +++ b/library/src/scala/util/FromDigits.scala @@ -135,7 +135,7 @@ object FromDigits { case ex: NumberFormatException => throw MalformedNumber() } if (x.isInfinite) throw NumberTooLarge() - if (x == 0.0f && !zeroFloat.pattern.matcher(digits).matches) throw NumberTooSmall() + if (x == 0.0f && !zeroFloat.pattern.matcher(digits).nn.matches) throw NumberTooSmall() x } @@ -153,7 +153,7 @@ object FromDigits { case ex: NumberFormatException => throw MalformedNumber() } if (x.isInfinite) throw NumberTooLarge() - if (x == 0.0d && !zeroFloat.pattern.matcher(digits).matches) throw NumberTooSmall() + if (x == 0.0d && !zeroFloat.pattern.matcher(digits).nn.matches) throw NumberTooSmall() x } diff --git a/project/Build.scala b/project/Build.scala index 5286fb73b4ac..adfb6745c9d8 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -791,6 +791,7 @@ object Build { (Compile / scalacOptions) ++= Seq( // Needed so that the library sources are visible when `dotty.tools.dotc.core.Definitions#init` is called "-sourcepath", (Compile / sourceDirectories).value.map(_.getAbsolutePath).distinct.mkString(File.pathSeparator), + "-Yexplicit-nulls", ), )