Skip to content

[DO NOT MERGE] Try to enable explicit nulls for Scala 3 stdlib #23319

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: sync-scala-library
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/src/scala/AnyVal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ package scala
* explained in greater detail in the [[https://docs.scala-lang.org/overviews/core/value-classes.html Value Classes and Universal Traits]].
*/
abstract class AnyVal extends Any {
def getClass(): Class[_ <: AnyVal] = null
def getClass(): Class[_ <: AnyVal] = null.asInstanceOf
}
2 changes: 1 addition & 1 deletion library/src/scala/Array.scala
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ object Array {
def get: UnapplySeqWrapper[T] = this
def lengthCompare(len: Int): Int = a.lengthCompare(len)
def apply(i: Int): T = a(i)
def drop(n: Int): scala.Seq[T] = ArraySeq.unsafeWrapArray(a.drop(n)) // clones the array, also if n == 0
def drop(n: Int): scala.Seq[T] = ArraySeq.unsafeWrapArray(a.drop(n)).nn // clones the array, also if n == 0
def toSeq: scala.Seq[T] = a.toSeq // clones the array
}
}
Expand Down
22 changes: 11 additions & 11 deletions library/src/scala/Enumeration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ abstract class Enumeration (initial: Int) extends Serializable {
private val vmap: mutable.Map[Int, Value] = new mutable.HashMap

/** The cache listing all values of this enumeration. */
@transient private var vset: ValueSet = null
@transient private var vset: ValueSet | Null = null
@transient @volatile private var vsetDefined = false

/** The mapping from the integer used to identify values to their
Expand All @@ -119,17 +119,17 @@ abstract class Enumeration (initial: Int) extends Serializable {
vset = (ValueSet.newBuilder ++= vmap.values).result()
vsetDefined = true
}
vset
vset.nn
}

/** The integer to use to identify the next created value. */
protected var nextId: Int = initial

/** The string to use to name the next created value. */
protected var nextName: Iterator[String] = _
protected var nextName: Iterator[String] | Null = _

private def nextNameOrNull =
if (nextName != null && nextName.hasNext) nextName.next() else null
private def nextNameOrNull: String | Null =
if (nextName != null && nextName.nn.hasNext) nextName.nn.next() else null

/** The highest integer amongst those used to identify values in this
* enumeration. */
Expand Down Expand Up @@ -175,7 +175,7 @@ abstract class Enumeration (initial: Int) extends Serializable {
* @param name A human-readable name for that value.
* @return Fresh value called `name`.
*/
protected final def Value(name: String): Value = Value(nextId, name)
protected final def Value(name: String | Null): Value = Value(nextId, name)

/** Creates a fresh value, part of this enumeration, called `name`
* and identified by the integer `i`.
Expand All @@ -185,10 +185,10 @@ abstract class Enumeration (initial: Int) extends Serializable {
* @param name A human-readable name for that value.
* @return Fresh value with the provided identifier `i` and name `name`.
*/
protected final def Value(i: Int, name: String): Value = new Val(i, name)
protected final def Value(i: Int, name: String | Null): Value = new Val(i, name)

private def populateNameMap(): Unit = {
@tailrec def getFields(clazz: Class[_], acc: Array[JField]): Array[JField] = {
@tailrec def getFields(clazz: Class[?] | Null, acc: Array[JField]): Array[JField] = {
if (clazz == null)
acc
else
Expand Down Expand Up @@ -246,7 +246,7 @@ abstract class Enumeration (initial: Int) extends Serializable {
* identification behaviour.
*/
@SerialVersionUID(0 - 3501153230598116017L)
protected class Val(i: Int, name: String) extends Value with Serializable {
protected class Val(i: Int, name: String | Null) extends Value with Serializable {
def this(i: Int) = this(i, nextNameOrNull)
def this(name: String) = this(nextId, name)
def this() = this(nextId)
Expand All @@ -259,13 +259,13 @@ abstract class Enumeration (initial: Int) extends Serializable {
if (i < bottomId) bottomId = i
def id: Int = i
override def toString(): String =
if (name != null) name
if (name != null) name.nn
else try thisenum.nameOf(i)
catch { case _: NoSuchElementException => "<Invalid enum: no field for #" + i + ">" }

protected def readResolve(): AnyRef = {
val enumeration = thisenum.readResolve().asInstanceOf[Enumeration]
if (enumeration.vmap == null) this
if (enumeration.vmap eq null) this
else enumeration.vmap(i)
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/Option.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ object Option {
* @param x the value
* @return Some(value) if value != null, None if value == null
*/
def apply[A](x: A): Option[A] = if (x == null) None else Some(x)
def apply[A](x: A | Null): Option[A] = if (x == null) None else Some(x)

/** An Option factory which returns `None` in a manner consistent with
* the collections hierarchy.
Expand Down
38 changes: 19 additions & 19 deletions library/src/scala/Predef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ object Predef extends LowPriorityImplicits {
* @return The runtime [[Class]] representation of type `T`.
* @group utilities
*/
def classOf[T]: Class[T] = null // This is a stub method. The actual implementation is filled in by the compiler.
def classOf[T]: Class[T] = null.asInstanceOf // This is a stub method. The actual implementation is filled in by the compiler.

/**
* Retrieve the single value of a type with a unique inhabitant.
Expand Down Expand Up @@ -412,7 +412,7 @@ object Predef extends LowPriorityImplicits {
* @param x the object to print; may be null.
* @group console-output
*/
def print(x: Any): Unit = Console.print(x)
def print(x: Any | Null): Unit = Console.print(x)

/** Prints a newline character on the default output.
* @group console-output
Expand All @@ -424,7 +424,7 @@ object Predef extends LowPriorityImplicits {
* @param x the object to print.
* @group console-output
*/
def println(x: Any): Unit = Console.println(x)
def println(x: Any | Null): Unit = Console.println(x)

/** Prints its arguments as a formatted string to the default output,
* based on a string pattern (in a fashion similar to printf in C).
Expand Down Expand Up @@ -541,46 +541,46 @@ private[scala] abstract class LowPriorityImplicits extends LowPriorityImplicits2
@inline implicit def booleanWrapper(x: Boolean): runtime.RichBoolean = new runtime.RichBoolean(x)

/** @group conversions-array-to-wrapped-array */
implicit def genericWrapArray[T](xs: Array[T]): ArraySeq[T] =
implicit def genericWrapArray[T](xs: Array[T] | Null): ArraySeq[T] | Null =
if (xs eq null) null
else ArraySeq.make(xs)

// 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.
/** @group conversions-array-to-wrapped-array */
implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): ArraySeq.ofRef[T] = {
implicit def wrapRefArray[T <: AnyRef](xs: Array[T] | Null): ArraySeq.ofRef[T] | Null = {
if (xs eq null) null
else if (xs.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq.ofRef[T]]
else new ArraySeq.ofRef[T](xs)
else if (xs.nn.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq.ofRef[T]]
else new ArraySeq.ofRef[T](xs.nn)
}

/** @group conversions-array-to-wrapped-array */
implicit def wrapIntArray(xs: Array[Int]): ArraySeq.ofInt = if (xs ne null) new ArraySeq.ofInt(xs) else null
implicit def wrapIntArray(xs: Array[Int] | Null): ArraySeq.ofInt | Null = if (xs ne null) new ArraySeq.ofInt(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapDoubleArray(xs: Array[Double]): ArraySeq.ofDouble = if (xs ne null) new ArraySeq.ofDouble(xs) else null
implicit def wrapDoubleArray(xs: Array[Double] | Null): ArraySeq.ofDouble | Null = if (xs ne null) new ArraySeq.ofDouble(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapLongArray(xs: Array[Long]): ArraySeq.ofLong = if (xs ne null) new ArraySeq.ofLong(xs) else null
implicit def wrapLongArray(xs: Array[Long] | Null): ArraySeq.ofLong | Null = if (xs ne null) new ArraySeq.ofLong(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapFloatArray(xs: Array[Float]): ArraySeq.ofFloat = if (xs ne null) new ArraySeq.ofFloat(xs) else null
implicit def wrapFloatArray(xs: Array[Float] | Null): ArraySeq.ofFloat | Null = if (xs ne null) new ArraySeq.ofFloat(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapCharArray(xs: Array[Char]): ArraySeq.ofChar = if (xs ne null) new ArraySeq.ofChar(xs) else null
implicit def wrapCharArray(xs: Array[Char] | Null): ArraySeq.ofChar | Null = if (xs ne null) new ArraySeq.ofChar(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapByteArray(xs: Array[Byte]): ArraySeq.ofByte = if (xs ne null) new ArraySeq.ofByte(xs) else null
implicit def wrapByteArray(xs: Array[Byte] | Null): ArraySeq.ofByte | Null = if (xs ne null) new ArraySeq.ofByte(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapShortArray(xs: Array[Short]): ArraySeq.ofShort = if (xs ne null) new ArraySeq.ofShort(xs) else null
implicit def wrapShortArray(xs: Array[Short] | Null): ArraySeq.ofShort | Null = if (xs ne null) new ArraySeq.ofShort(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapBooleanArray(xs: Array[Boolean]): ArraySeq.ofBoolean = if (xs ne null) new ArraySeq.ofBoolean(xs) else null
implicit def wrapBooleanArray(xs: Array[Boolean] | Null): ArraySeq.ofBoolean | Null = if (xs ne null) new ArraySeq.ofBoolean(xs.nn) else null
/** @group conversions-array-to-wrapped-array */
implicit def wrapUnitArray(xs: Array[Unit]): ArraySeq.ofUnit = if (xs ne null) new ArraySeq.ofUnit(xs) else null
implicit def wrapUnitArray(xs: Array[Unit] | Null): ArraySeq.ofUnit | Null = if (xs ne null) new ArraySeq.ofUnit(xs.nn) else null

/** @group conversions-string */
implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null
implicit def wrapString(s: String | Null): WrappedString | Null = if (s ne null) new WrappedString(s.nn) else null
}

private[scala] abstract class LowPriorityImplicits2 {
@deprecated("implicit conversions from Array to immutable.IndexedSeq are implemented by copying; use `toIndexedSeq` explicitly if you want to copy, or use the more efficient non-copying ArraySeq.unsafeWrapArray", since="2.13.0")
implicit def copyArrayToImmutableIndexedSeq[T](xs: Array[T]): IndexedSeq[T] =
implicit def copyArrayToImmutableIndexedSeq[T](xs: Array[T] | Null): IndexedSeq[T] | Null =
if (xs eq null) null
else new ArrayOps(xs).toIndexedSeq
else new ArrayOps(xs.nn).toIndexedSeq
}
20 changes: 10 additions & 10 deletions library/src/scala/Specializable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ object Specializable {
// Smuggle a list of types by way of a tuple upon which Group is parameterized.
class Group[T >: Null](value: T) extends SpecializedGroup

final val Primitives: Group[(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit)] = null
final val Everything: Group[(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit, AnyRef)] = null
final val Bits32AndUp: Group[(Int, Long, Float, Double)] = null
final val Integral: Group[(Byte, Short, Int, Long, Char)] = null
final val AllNumeric: Group[(Byte, Short, Int, Long, Char, Float, Double)] = null
final val BestOfBreed: Group[(Int, Double, Boolean, Unit, AnyRef)] = null
final val Unit: Group[Tuple1[Unit]] = null
final val Primitives: Group[(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit)] = null.asInstanceOf
final val Everything: Group[(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit, AnyRef)] = null.asInstanceOf
final val Bits32AndUp: Group[(Int, Long, Float, Double)] = null.asInstanceOf
final val Integral: Group[(Byte, Short, Int, Long, Char)] = null.asInstanceOf
final val AllNumeric: Group[(Byte, Short, Int, Long, Char, Float, Double)] = null.asInstanceOf
final val BestOfBreed: Group[(Int, Double, Boolean, Unit, AnyRef)] = null.asInstanceOf
final val Unit: Group[Tuple1[Unit]] = null.asInstanceOf

final val Arg: Group[(Int, Long, Float, Double)] = null
final val Args: Group[(Int, Long, Double)] = null
final val Return: Group[(Int, Long, Float, Double, Boolean, Unit)] = null
final val Arg: Group[(Int, Long, Float, Double)] = null.asInstanceOf
final val Args: Group[(Int, Long, Double)] = null.asInstanceOf
final val Return: Group[(Int, Long, Float, Double, Boolean, Unit)] = null.asInstanceOf
}
2 changes: 1 addition & 1 deletion library/src/scala/StringContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ object StringContext {
}

// Matched all of pattern to all of name. Success.
Some(collection.immutable.ArraySeq.unsafeWrapArray(
Option.fromNullable(collection.immutable.ArraySeq.unsafeWrapArray(
Array.tabulate(patternChunks.length - 1)(n => input.slice(matchStarts(n), matchEnds(n)))
))
}
Expand Down
7 changes: 4 additions & 3 deletions library/src/scala/collection/ArrayOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ object ArrayOps {
private class ArrayView[A](xs: Array[A]) extends AbstractIndexedSeqView[A] {
def length = xs.length
def apply(n: Int) = xs(n)
override def toString: String = immutable.ArraySeq.unsafeWrapArray(xs).mkString("ArrayView(", ", ", ")")
override def toString: String =
immutable.ArraySeq.unsafeWrapArray(xs).nn.mkString("ArrayView(", ", ", ")")
}

/** A lazy filtered array. No filtering is applied until one of `foreach`, `map` or `flatMap` is called. */
Expand Down Expand Up @@ -1081,7 +1082,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal {
* @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
* or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
*/
def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, Array[A]] = new LazyZip2(xs, immutable.ArraySeq.unsafeWrapArray(xs), that)
def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, Array[A]] = new LazyZip2(xs, immutable.ArraySeq.unsafeWrapArray(xs).nn, that)

/** Returns an array formed from this array and another iterable collection
* by combining corresponding elements in pairs.
Expand Down Expand Up @@ -1435,7 +1436,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal {
@`inline` final def toSeq: immutable.Seq[A] = toIndexedSeq

def toIndexedSeq: immutable.IndexedSeq[A] =
immutable.ArraySeq.unsafeWrapArray(Array.copyOf(xs, xs.length))
immutable.ArraySeq.unsafeWrapArray(Array.copyOf(xs, xs.length)).nn

/** Copy elements of this array to another array.
* Fills the given array `xs` starting at index 0.
Expand Down
Loading